home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
utils
/
asmutl
/
hd64180a.lbr
/
EXECCORE.AZM
/
EXECCORE.ASM
Wrap
Assembly Source File
|
1991-08-04
|
38KB
|
1,752 lines
title 'Executive Command Processor - CORE BOARD Version'
;
;----------------------------------------------------------------
; Executive Command Processor for CORE BOARD
;
; This module provides services much in the way that a dos does.
; It is called by a RESTART or anything else, it interprets
; register setups and performs the functions specified.
; This module interfaces into the I/O drivers rather than
; providing its own I/O. It does however have some code to
; provide some of the more general purpose routines.
;
; This program is Copyright (C) 1987 by SME Systems P/L
; 22 Queen Street Mitcham
;
;
; Written by Richard Holmes 08/12/1987
; Last Update by Richard Holmes 19/10/1988
;
; Added the price print function 36 05/02/88
; Added the time print function 37 06/02/88
; Added ????$HDLR interrupt handlers 20/02/88
; Added bel$cnt for interrupt driven bell 19/10/88
;----------------------------------------------------------------
;
maclib z80
;
; maclib iocmd ; I/O Driver command library
public exec ; The ONLY entry point.
;
; Interrupt handlers
public bel$cnt ; Delayed int. bell.
public con$hdlr, aux$hdlr ; Con and aux ints
public tmr0$hdlr, tmr1$hdlr ; Timer ints
public int0$hdlr, int1$hdlr, int2$hdlr ; INT pin ints
public csio$hdlr ; CSIO ints
;
; I/O Drivers for the character display devices
extrn sys$ini
extrn con$ini,con$ist,con$ost,con$inp,con$out,con$cmd ; Console
extrn aux$ini,aux$ist,aux$ost,aux$inp,aux$out,aux$cmd ; Aux serial
extrn lcd$ini,lcd$ost,lcd$out,lcd$cmd ; Main LCD
extrn prn$ini,prn$ost,prn$out ; Printer
;
extrn ms$delay,clr$wdt
;
extrn clk$rd,clk$wr
extrn clr$led,set$led,tog$led,zro$led
extrn set$bel,clr$bel
;
extrn hrs,min
;
cmd$max equ 69 ; Total of 69 commands allowed max.
max$chn equ 6 ; Last used channel number
;
psh$max equ 5 ; Maximum channel "pushes" allowed
psh$siz equ 18 ; Bytes to "push" (routines * 3)
;
cr equ 0dh
lf equ 0ah
esc equ 01bh
;
; I/O Commands for intelligent devices to process.
;
clr$scr equ 01 ; Clear screen
clr$eos equ 02 ; Clear to end of screen
clr$eol equ 03 ; Clear to end of line
cur$adr equ 04 ; Cursor address
vid$att equ 05 ; Select video attribute (flash, reverse etc)
gxy$cmd equ 06 ; Get the current X-Y address
;
page
;----------------------------------------------------------------
; The Executive Processor
;
; On Entry
; C = command number,
; All else are parameters.
;----------------------------------------------------------------
;
exec:
push h
push b
push d
;
lxi h,table
mvi b,0 ; BC = offset.
dad b
dad b ; HL = table base + (2 * offset)
;
mov e,m
inx h
mov d,m ; DE = address from table
xchg ; Hl -> routine
; Restore registers and goto routine
pop d
pop b
xthl ; Top stack = address, HL restored
ret ; Goes to routine.
;
;----------------------------------------------------------------
; A table of addresses of the routines.
;----------------------------------------------------------------
;
table:
dw cmd$0 ; Reset hardware
dw cmd$1 ;
dw cmd$2 ;
dw cmd$3 ;
dw cmd$4 ;
dw cmd$5 ;
dw cmd$6 ;
dw cmd$7 ;
dw cmd$8 ;
dw cmd$9 ;
;
dw cmd$10 ;
dw cmd$11 ;
dw cmd$12 ;
dw cmd$13 ;
dw cmd$14 ;
dw cmd$15 ;
dw cmd$16 ;
dw cmd$17 ;
dw cmd$18 ;
dw cmd$19 ;
;
dw cmd$20 ;
dw cmd$21 ;
dw cmd$22 ;
dw cmd$23 ;
dw cmd$24 ;
dw cmd$25 ;
dw cmd$26 ;
dw cmd$27 ;
dw cmd$28 ;
dw cmd$29 ;
;
dw cmd$30 ;
dw cmd$31 ;
dw cmd$32 ;
dw cmd$33 ;
dw cmd$34 ;
dw cmd$35 ;
dw cmd$36 ;
dw cmd$37 ;
dw cmd$38 ;
dw cmd$39 ; Get current X-Y address
;
dw cmd$40 ;
dw cmd$41 ;
dw cmd$42 ;
dw cmd$43 ;
dw cmd$44 ;
dw cmd$45 ;
dw cmd$46 ;
dw cmd$47 ;
dw cmd$48 ;
dw cmd$49 ; Set bell count
;
dw cmd$50 ; Spare
dw cmd$51 ; Spare
dw cmd$52 ; Spare
dw cmd$53 ;
dw cmd$54 ;
dw cmd$55 ;
dw cmd$56 ; Spare
dw cmd$57 ;
dw cmd$58 ;
dw cmd$59 ;
;
dw cmd$60
dw cmd$61
dw cmd$62
dw cmd$63
dw cmd$64
dw cmd$65
dw cmd$66
dw cmd$67
dw cmd$68
dw cmd$69
;
page
;----------------------------------------------------------------
; T H E C O M M A N D S
;----------------------------------------------------------------
;
cmd$0: ; Reset EXEC, initialize
call clr$wdt
; Init all the interrupt handers to be returns
mvi a,(RET) ; Loads a return into A
sta con$hdlr
sta aux$hdlr
sta tmr0$hdlr
sta tmr1$hdlr
sta int0$hdlr
sta int1$hdlr
sta int2$hdlr
sta csio$hdlr
;
call clr$wdt
call sys$ini ; Initialize all hardware
xra a
sta dsp$flg ; Clear the display the code flag
sta exe$dbg ; Clear the debugging flag
sta lzb$mode ; Print all characters LZB mode
call psh$pop$ini
;
; Initialize/Reset all I/O channels.
xra a ; Force ALL channel initialize
call init$chan ; Initialize channels routine
mvi a,1 ; Main console.
call sel$chn ; Channel select console first time.
;
;
call zro$led ; Clear leds
jmp exec$end
;
;
;
cmd$1: ; Select I/O Channel for I/O
call sel$chn ; Select the channel
jmp exec$end
;
cmd$2: ; Reset One/all i/o channels
call init$chan
jmp exec$end
;
cmd$3: ; Return current channel number
lda cur$chn
jmp exec$end
;
cmd$4: ; Read current channel into accumulator
call chn$inp
jmp exec$end
;
cmd$5: ; Write to current channel
call chn$out
jmp exec$end
;
;
cmd$6: ; Return channel input status
call chn$ist
jmp exec$end
;
cmd$7: ; Return channel output status
call chn$ost
jmp exec$end
;
cmd$8: ; Print string at mDE
ldax d
inx d ; -> next
ora a
jz exec$end
call chn$out ; Channel output routine
jr cmd$8
;
;
cmd$9: ; Print string at return address
xthl ; get address of string (ret address)
push psw
inline2:
mov a,m
inx h ; point to next character
ora a
jrz inline3
call chn$out
jr inline2
inline3:
pop psw
xthl ; load return address after the '$'
jmp exec$end
;
;
;
cmd$10: ; Print X-Y prefixed string at return address
xthl ; HL -> string, old hl in stack
xchg ; now DE --> string
call setxy ; set it up
xchg ; now hl --> string start again
call print
xthl ; hl = original value, stack = return address
jmp exec$end
;
;----------------------------------------------------------------
; Print the string --> by DE. Use the two bytes at the start of it
; as a screen address.
;----------------------------------------------------------------
;
xypstring:
push h
call setxy ; set up screen
xchg ; now hl --> string start
call print
xchg ; Restore DE --> past end of string
pop h
ret
;
;
; ---- Utility to print a string till a $. ----
; On return HL -> to next byte after the string (code maybe)
;
print:
push psw
inx h
inx h ; skip over cursor address
print2:
mov a,m
inx h ; Point to next character
ora a ; null is allowed to end a string
jrz print3
call chn$out
jr print2
;
print3:
pop psw
ret
;
;----------------------------------------------------------------
; Set the cursor up according to two bytes in ram which contain
; the X and Y addresses in them. The bytes --> by DE.
;----------------------------------------------------------------
;
setxy:
push d ; save
push h
xchg ; HL --> bytes
mov d,m ; load X value
inx h
mov e,m
call cmd$12 ; Cursor Set up
pop h ; restore all now
pop d
ret
;
;----------------------------------------------------------------
; Print the MENU at mDE. A menu is a list of asciiz strings
; each prefixed with an X-Y cursor address. This code will
; put each string at the specified address. The routine is
; terminated with an 0FFh byte.
;----------------------------------------------------------------
;
cmd$11: ; Print menu at mDE
push d ; save all
push h
push psw
xchg ; Hl -> menu of X-Y prefixed strings
pmenu2:
call clrwdt ; Reset watchdog
mov d,m ; X address
inx h
mov e,m
inx h
call cmd$12 ; Cursor address the string now
pmenu$string:
mov a,m
inx h ; -> next byte
ora a ; Is it 00 ?
jrz pmenu$eos ; Exit on 00 to end ofline code
call chn$out ; Send the byte to the channel
jr pmenu$string ; Keep printing till the 00
;
pmenu$eos:
mov a,m ; Is next byte 0FFh to terminate.
cpi 0ffh ; end of menu ??
jrnz pmenu2
;
pop psw
pop h
pop d
jmp exec$end
;
;
cmd$12: ; Cursor address the screen/channel
mvi c,cur$adr ; Cursor address command
call chn$cmd ; Process the command via the channel
jmp exec$end
;
cmd$13: ; Clear screen
mvi c,clr$scr ; Clear all screen code
call chn$cmd
jmp exec$end
;
;
cmd$14: ; Clear to end of line
mvi c,clr$eol ; Clear to end of line
call chn$cmd
jmp exec$end
;
cmd$15: ; Clear to end of screen
mvi c,clr$eos ; Clear to end of screen code
call chn$cmd
jmp exec$end
;
cmd$16: ; Select visual attribute
mvi c,vid$att ; Set visual attribute
call chn$cmd
jmp exec$end
;
cmd$17: ; Print accumulator as 2 hex digits
prhex:
push psw
rrc
rrc
rrc
rrc
call phexl
pop psw
phexl: ani 0fh
adi 90h
daa
aci 40h
daa
call chn$out
jmp exec$end
;
;
cmd$18: ; Print accumulator as decimal
push h
push b
push d
push psw
mov e,a
mvi d,0
lxi h,?result
call hexbcd
lda ?result + 1
mvi c,0 ; LZB status register clear
call ccoe ; Print hundreds digit
; Second top
lda ?result
push psw
rar
rar
rar
rar
call ccoe ; Print tens digit
;
pop psw
call nibasc
call chn$out ; print units
;
pop psw
pop d
pop b
pop h
jmp exec$end
;
;
cmd$19: ; Print DE as 4 hex digits
push psw
push d
mov a,d
call prhex
mov a,e
call prhex
pop d
pop psw
ret
jmp exec$end
;
;
cmd$20: ; Print DE as decimal unsigned decimal, with LZB
push h
push d
push b
lxi h,?result
call hexbcd ; convert to ascii in internal buffer
;
; Now print the 5 digit number. Suppress leading digits.
lda lzb$mode
mov c,a ; Load the flag
lda ?result+2 ; Get the MSDigit
ani 0fh
call ccoe ; Conditional output with lzb
;
lda ?result + 1
push psw
rar
rar
rar
rar
call ccoe
;
pop psw
call ccoe
;
lda ?result ; Least significant 2 digits
push psw
rar
rar
rar
rar
call ccoe
;
pop psw
call nibasc ; Always print last digit
call chn$out
pop b
pop d
pop h
jmp exec$end
;
;================================================================
;
; Print HLDE as a 32 bit decimal number
;
;================================================================
;
cmd$21: ; Print HLDE as 32 bit unsigned decimal
push h
push b
;
call convert$hlde
;
; ---------------- Now print the result ----------------
;
; Use the specified leading zero print type.
;
mvi b,05 ; bytes = 10 digits
lda lzb$mode
mov c,a ; Load leading zero printing type
lxi h,?result+4 ; -> MSDigit
lzb$hlde:
mov a,m
rar
rar
rar
rar
call ccoe
; See if last digit and if so, force the number out.
mov a,b
cpi 1
jnz lz$hlde1
mvi c,080h ; Force digits out of lz printer
lz$hlde1:
mov a,m
call ccoe
;
dcx h ; -> next byte
djnz lzb$hlde
;
pop b
pop h
ret
;
;----------------------------------------------------------------
; Convert 32 bits HLDE into 10 ascii decimal digits in the
; ?result buffer.
;----------------------------------------------------------------
;
convert$hlde:
sded ?binnum ; save LSW
shld ?binnum + 2 ; Save MSW
;
; Do the conversion
lxi h,?result ; -> result buffer
mvi b,5 ; bytes to clear
hlde1:
mvi m,00
inx h
djnz hlde1 ; clear 5 bytes = 10 digits
;
mvi b,32 ; 32 bits to convert
hlde$loop:
lxi h,?binnum
mvi c,4 ; bytes in the binary number
xra a ; clear carry
h$rloop:
mov a,m
ral
mov m,a
inx h
dcr c
jnz h$rloop ; keep rotating till C = 0
;
lxi h,?result ; restore the result address
mvi c,5 ; 5 byte result = 10 digits
;
h$bloop:
mov a,m
adc m
daa
mov m,a ; save
inx h
dcr c
jnz h$bloop
;
djnz hlde$loop ; do for all bits requited.
;
ret
;
;----------------------------------------------------------------
; Set the LZB Mode
;
; LZB modes
; 00 = normal LZB, default
; 01 = Force all characters out
; 02 = Space fill all leading zeros
;----------------------------------------------------------------
;
cmd$22: ; Set leading Zero blanking mode
push b
mvi c,080h ; 80 hex internally = nolzbing
cpi 2
jrz cmd$22$do
;
mvi c,040h ; 40h internally = lzb
cpi 1
jrz cmd$22$do
mvi c,0 ; All else = 0 so normal lzbing.
;
cmd$22$do:
mov a,c
sta lzb$mode
pop b
jmp exec$end
;
page
;================================================================
; ---- Read a text string ----
;
; This routine reads a line of input from the console and puts it into
; a standard CP/M console buffer pointed to by DE on entry. This is
; a little nicer that CP/M as it allows buffers to be pre-initialized
; so that it is printed when the buffer is input so that defaults can
; be loaded before entry of data, then edited.
;
; On Entry
; DE -> console buffer max size byte
;
; On Exit
; buffer filled from console to max size limit
; All registers preserved
;
;================================================================
;
cmd$23:
get$txt:
push psw
ldax d ; get buffer size in bytes
ora a
jz cbuff$end
push h
push b
push d
xchg ; put string address into HL
mov c,a ; Now C = buffer maximum size
init:
mvi b,00 ; characters read = 0
inx h ; hl -> size of character read now
;
; Here we detect if there is some data in the buffer to be pre printed
; and if there is the we print it.
;
mov a,m ; get number of chars. in the buffer
inx h ; point to string space now.
ora a
jrz rdloop
; Print the initialized character string, save the size for later
mov b,a
push b ; save
init2:
mov a,m ; get the character
inx h ; point to next string space byte
call dspchr ; print it, maybe control character
djnz init2 ; print all characters
pop b ; restore # of characters
;
;
; On entry here HL-> string space, next free byte, B = number of characters
; in the string. C = number of bytes in the buffer.
;
rdloop:
call chn$inp ; Fetch a character
cpi 0dh ; end if carriage return
jrz exitrd ; exit
cpi 0ah
jrz exitrd
cpi 08 ; backspace ??
jrnz rdlp1 ; if not then continue
call backsp ; else backspace
jr rdloop ; keep on backspacing
rdlp1:
cpi 018h ; delete line ?
jrnz rdlp2
del1:
call backsp ; delete a character
jrnz del1 ; keep on till all character deaded
jr rdloop ; start again ebonettes
;
; If here we check if the buffer is full. If so we ring the bell
rdlp2:
mov e,a ; save the character
mov a,b ; load byte count
cmp c ; is it equal to the maximum ?
jrc strch ; store the character if not full
;
mvi a,7 ; Else load the bell code
call chn$out ; And send to ring the bell
jr rdloop ; get more characters
;
; Buffer not full so save the character
strch:
mov a,e ; get character
mov m,a ; save it
inx h ; point to next buffer byte
inr b ; increment byte count
call dspchr ; display the (maybe control) character
jr rdloop ; do again, more characters
;
; Display a control character by preceeding it with a '^'
;
dspchr:
cpi 020h ; was it a space ?
jnc chn$out ; if not then print & return
mov e,a ; else save character
mvi a,'^' ; indicate a control character
call chn$out
mov a,e ; restore character
adi 040h ; make printable
jmp chn$out
;
; Send a backspace and detect if at the start of the line.
;
backsp:
mov a,b ; get character count
ora a
rz ; return if line empty
dcx h ; decrement byte pointer
mov a,m ; get the character
cpi 020h ; is it a control character ?
jrnc bsp1 ; if not then delete 1 char only
call bsp ; send a backspace
bsp1:
call bsp ; backspace 1
dcr b ; one less string byte
ret
;
; Send the backspace
bsp:
mvi a,08
call chn$out ; Go back a char not req-r for cp/m
mvi a,' ' ; erase the character
call chn$out
mvi a,08
jmp chn$out ; send and return
;
; Set the number of bytes read into the buffer byte at DE + 1.
;
exitrd:
pop d ; restore all registers (buffer addr)
mov a,b ; get # of characters
inx d
stax d ; save in characters read byte
dcx d ; restore de
;
pop b
pop h
cbuff$end:
pop psw
ora a ; Clear carry
ret
;
;
cmd$24: ; Read a hex number from channel
call ihhl ; Read HEX into HL
jmp exec$end
;
cmd$25: ; Read a decimal number from channel
call idhl ; Read decimal into HL
jmp exec$end
;
cmd$26: ; Print a space
space:
mvi a,' '
call chn$out
jmp exec$end
;
cmd$27: ; Do a carriage return and line-feed
mvi a,cr
call chn$out
mvi a,lf
call chn$out
jmp exec$end
;
cmd$28: ; Push the current channel
push h
push b
push d
;
call psh$chn
;
pop d
pop b
pop h
;
jmp exec$end
;
cmd$29: ; Pop the current channel
push h
push b
push d
;
call pop$chn
;
pop d
pop b
pop h
jmp exec$end
;
;
cmd$30: ; Read RS-232 channel 0 (console)
call con$inp
jmp exec$end
;
cmd$31: ; Write to RS-232 channel 0 (console)
call con$out
jmp exec$end
;
cmd$32: ; Return RS-232 channel 0 input status
call con$ist
jmp exec$end
;
cmd$33: ; Return RS-232 channel 0 output status
call con$ost
jmp exec$end
;
cmd$34: ; Read real time clock
call clk$rd
jmp exec$end
;
cmd$35: ; Write to real time clock
call clk$wr
jmp exec$end
;
;----------------------------------------------------------------
; ==== Dinos Requirement ====
;
; Print an integer as if it were a price.
;----------------------------------------------------------------
;
cmd$36: ;
push h
push d
push b
lxi h,?result
call hexbcd ; convert to ascii in internal buffer
;
mvi a,'$'
call chn$out ; Print leading dollar sign
; Now print the 5 digit number. Suppress leading digits.
lda lzb$mode
mov c,a ; Load the flag
lda ?result+2 ; Get the MSDigit
ani 0fh
call ccoe ; Conditional output with lzb
;
lda ?result + 1
push psw
rar
rar
rar
rar
call ccoe
;
pop psw
call ccoe
;
; Print a '.' then force the last two digits out.
mvi a,'.'
call chn$out
;
call prn$last2 ; Print last 2 digits
pop b
pop d
pop h
jmp exec$end
;
;----------------------------------------------------------------
; Print a time in HH:MM format. This is a DINOS routine
; that is used a LOT.
;----------------------------------------------------------------
;
cmd$37: ;
push h
push d
push b
;
; Do hours
lda hrs
mov e,a
mvi d,0 ; DE = hours now.
lxi h,?result
call hexbcd ; convert to ascii in internal buffer
call prn$last2
;
mvi a,':'
call chn$out ; Channel output print.
;
; Do minutes.
lda min
mov e,a
mvi d,0 ; DE = Minutes now.
lxi h,?result
call hexbcd ; convert to ascii in internal buffer
call prn$last2
;
pop b
pop d
pop h
jmp exec$end
;
; A subroutine to print the least significant 2 digits of a
; converted number. This is used to force out a time and
; for printing a PRICE where the last 2 digits are required.
;
prn$last2:
lda ?result ; Least significant 2 digits
push psw
rar
rar
rar
rar
call nibasc
call chn$out ; Print low nibble. Was high nibble
;
pop psw
call nibasc ; Always print last digit
jmp chn$out
;
;----------------------------------------------------------------
; ---- Print DE as a time. ----
;
; On Entry
; D = hours
; E = minutes
;----------------------------------------------------------------
;
cmd$38: ;
push h
push d
push b
;
push d
;
mov e,d ; Make E = hours
mvi d,0 ; DE = hours now.
lxi h,?result
call hexbcd ; convert to ascii in internal buffer
call prn$last2
;
mvi a,':'
call chn$out ; Channel output print.
;
; Do minutes.
pop d
mvi d,0 ; DE = Minutes now.
lxi h,?result
call hexbcd ; convert to ascii in internal buffer
call prn$last2
;
pop b
pop d
pop h
jmp exec$end
;
;
cmd$39: ;
mvi c,gxy$cmd ; Get current X-Y address
call chn$cmd
jmp exec$end
;
cmd$40: ; Clear watchdog
call clr$wdt
jmp exec$end
;
cmd$41: ; Read switch number in (A)
jmp exec$end
;
cmd$42: ; Clear all leds
call zro$led
jmp exec$end
;
cmd$43: ; Set led number in A
call set$led
jmp exec$end
;
cmd$44: ; Clear led number in A
call clr$led
jmp exec$end
;
cmd$45: ; Toggle led number in A
call tog$led
jmp exec$end
;
;
; ---- Do a delay of milliseconds in DE ----
;
cmd$46: ; Delay milliseconds in DE
call ms$delay
jmp exec$end
;
cmd$47: ; Turn on beeper
call set$bel
jmp exec$end
;
cmd$48: ; Turn off the beeper
call clr$bel
jmp exec$end
;
; Save DE as 10's of milliseconds of delay time for bell to be
; on then turn on the bell. After the time, the bell will be
; turned off by the interrupt handler.
;
cmd$49:
sded bel$cnt ; Load delay time in 10's of Milliseconds
call set$bel ; Turn on
jmp exec$end
;
;
cmd$50: ;
jmp exec$end
;
cmd$51: ; Compare two strings
jmp exec$end
;
cmd$52: ; Compare string to table of strings
jmp exec$end
;
cmd$53: ; Index via A into table of words and retun vaue in A
lda usr$a
mov c,a
xchg ; HL -> table now
dad b ; HL = HL + offset
dad b ; (2 * offset)
mov e,m
inx h
mov d,m
xchg ; HL = the word
jmp exec$end
;
cmd$54: ; Convert low nibble of A to ascii
nibasc:
ani 0fh
adi 090h
daa
aci 040h
daa
jmp exec$end
;
cmd$55: ; Capitalize accumulator
caps:
cpi 'a' ; Convert lower case to upper
jc exec$end
cpi 'z'+1
jnc exec$end
ani 5fh
jmp exec$end
;
cmd$56: ; Test memory
jmp exec$end
;
cmd$57: ; Put A into the EXEC code display flag. 00 = off
lda usr$a
sta dsp$flg ; Save to the display flag
jmp exec$end
;
;
cmd$58: ; Clear cumulatinve checksum
push h
lxi h,0 ; do a clear
shld rem
pop h
jmp exec$end
;
;
;----------------------------------------------------------------
; This routine generates a polynomial to generate a 16 bit cyclic-
; redundancy checksum. The checksum is able to distinguish between
; two very similar data items since any differences in quickly
; show up in the checksum. This is useful for data integrity checking
; in disk files or over modem lines etc.
;
; A cyclic-redundancy-check number is generated by the ccitt
; standard polynominal:
; x^16 + x^15 + x^13 + x^7 + x^4 + x^2 + x + 1
;
; The routine for doing this is in 8080 and comes from the
; 'EDN' magazine June 5 1979 issue Page 84. Written By Fred Gutman.
;
; Written R.C.H. 22/09/83
; Last Update R.C.H. 26/08/88
;----------------------------------------------------------------
;
; On Entry
; DE -> Memory to be checksummed
; BC = bytes to be checksummed
;
; On Exit
; HL = result
; psw lost
;----------------------------------------------------------------
;
cmd$59:
push d
push b
lhld rem
;
loop59:
call clr$wdt ; Stop watchdog
ldax d ; Get character
sta mess ; Save character
;
mov a,h ; High 8 bits of remainder
ani 128 ; q-bit mask
push psw ; save status
dad h ; 2 x r(x)
lda mess ; message bit in lsb
add l
mov l,a
pop psw
jz qb2 ; if q-bit is zero
qb:
mov a,h
xri 0a0h ; ms half of gen. poly
mov h,a
mov a,l
xri 97h ; ls half of gen. poly
mov l,a
qb2:
inx d ; -> next memory variable
dcx b ; Decrement byte count
mov a,b
ora c
jnz loop59 ; Keep on till BC = 0
;
shld rem ; Save result
pop b
pop d
jmp exec$end
;
page
;================================================================
; Interrupt vector routines.
;
; These routines are used to fill in the jump table in ram
; so that an external program can tie into the interrupt system.
; The CLR routine loads a simple RETURN into ALL the vectors
; so that they are effectively turned OFF.
;
;
; On Entry to these routines,
; DE -> Driver address
;
; On Exit
; ????$hdlr is loaded with a JMP <address>
;----------------------------------------------------------------
;
cmd$60: ; DE-install all interrupt handlers. This is handy.
mvi a,(ret)
sta con$hdlr
sta aux$hdlr
sta tmr0$hdlr
sta tmr1$hdlr
sta int0$hdlr
sta int1$hdlr
sta int2$hdlr
sta csio$hdlr
jmp exec$end
;
cmd$61:
sded con$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta con$hdlr
jmp exec$end
;
cmd$62:
sded aux$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta aux$hdlr
jmp exec$end
;
;
cmd$63:
sded tmr0$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta tmr0$hdlr
jmp exec$end
;
;
cmd$64:
sded tmr1$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta tmr1$hdlr
jmp exec$end
;
;
cmd$65:
sded int0$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta int0$hdlr
jmp exec$end
;
;
cmd$66:
sded int1$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta int1$hdlr
jmp exec$end
;
;
cmd$67:
sded int2$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta int2$hdlr
jmp exec$end
;
;
cmd$68:
sded csio$hdlr+1 ; Save address
mvi a,(JMP) ; Load a jump instruction
sta csio$hdlr
jmp exec$end
;
;
;
cmd$69:
jmp exec$end
;
;
exec$end: ; All routines EXIT via this point
ret
;
;----------------------------------------------------------------
; Select a channel.
;
; Do this by moving the addresses of the channel routines
; into the channel addresses in ram.
;
; On Entry
; A = channel number to be used
;----------------------------------------------------------------
;
sel$chn:
ora a
rz
cpi max$chn + 1
rnc
;
push h
push b
push d
;
sta cur$chn
mov c,a
mvi b,0 ; BC = offset into a table of words
lxi h,ini$tbl ; -> table of initialization addresses
lxi d,chn$ini ; The one to be loaded
call load$chn ; Load words
;
lxi h,ist$tbl
lxi d,chn$ist
call load$chn
;
lxi h,ost$tbl
lxi d,chn$ost
call load$chn
;
lxi h,inp$tbl
lxi d,chn$inp
call load$chn
;
lxi h,out$tbl
lxi d,chn$out
call load$chn
;
lxi h,iocmd$tbl
lxi d,chn$cmd
call load$chn
mvi a,(jmp) ; Load a jump instruction
sta chn$ini ; Channel Initialize
sta chn$ist ; Channel Input status
sta chn$ost ; Channel Output status
sta chn$inp ; Channel Input
sta chn$out ; Channel Output
sta chn$cmd ; Channel command processor
pop d
pop b
pop h
ret
;
load$chn:
push b
dad b
dad b ; HL -> word address of routine
; HL -> address
; DE -> Channel jmp instruction
inx d ; -> address
lxi b,2 ; 2 bytes to move
ldir ; Copy address from tyable -> channel vector
pop b
ret
;
;----------------------------------------------------------------
; Tables I/O routines.
;
; Note that this table sets up the order in which the channel
; numbers work so that changing the order completely changes
; what is called.
;
; This table has been setup AS;
; Channel 1 = Console
; 2 = Aux device
; 3 = spare
; 4 = spare
; 5 = Printer
; 6 = LCD driver
;
ini$tbl: ; Channel Initialize
dw dev$null
dw con$ini ; Console Init required
dw aux$ini ; AUX init
dw dev$null ; No spare init required
dw dev$null ; No spare init required
dw prn$ini ; No centronic printer init required
dw lcd$ini ; Initialize the LCD driver
;
ist$tbl: ; Channel Input status
dw dev$null
dw con$ist ; Console port
dw aux$ist ; AUX port
dw dev$null ; Spare serial 1
dw dev$null ; Spare serial 2
dw dev$null ; Printer
dw dev$null ; LCD
;
ost$tbl: ; Channel Output status
dw dev$null
dw con$ost ; Console port
dw aux$ost ; AUX port
dw dev$null ; Spare serial 1
dw dev$null ; Spare serial 2
dw prn$ost ; Printer ready flag
dw lcd$ost ; LCD ready fla
;
inp$tbl: ; Channel Input
dw dev$null
dw con$inp ; Console port
dw aux$inp ; AUX port
dw dev$null ; Spare serial 1
dw dev$null ; Spare serial 2
dw dev$null ; Printers dont recrive
dw dev$null ; LCDs dont receive
;
out$tbl: ; Channel Output
dw dev$null
dw con$out ; Console port
dw aux$out ; AUX port
dw dev$null ; Spare serial 1
dw dev$null ; Spare serial 2
dw prn$out ; Printer output
dw lcd$out ; LCD output
;
iocmd$tbl: ; Channel I/O Command processors
dw dev$null
dw con$cmd ; Console port
dw aux$cmd ; AUX port
dw dev$null ; Spare serial 1
dw dev$null ; Spare serial 2
dw dev$null ; No Printer command processor
dw lcd$cmd ; LCD output command processor
;
; The null driver. Simple return/no function.
;
dev$null:
ret
;
;----------------------------------------------------------------
; Push / Pop Initialize
;
; Setup push / pop counter and the next save address pointer.
;
; Push Channel
;
; Take all the channel jump addresses and save them into the
; "push" stack in ram.
;
; POP Channel
; Do the reverse. Copy the saved jumps back into the ram area.
;
;----------------------------------------------------------------
;
psh$pop$ini:
xra a
sta psh$cnt ; No pushes yet
lxi h,psh$stk ; -> stack to push into
shld psh$ptr ; Save as a push pointer
ret
;
; -- Push a channel by copying to ram. --
;
psh$chn:
lda psh$cnt
cpi psh$max ; At max ?
jrz psh$pop$err
inr a
sta psh$cnt ; Flags another push done
; Do the push
lxi b,psh$siz ; Push size
lded psh$ptr ; DESTINATION -> next free ram
lxi h,channels ; SOURCE -> channel routines.
ldir ; Copy channels -> ram
sded psh$ptr ; Saves the new pointer
jmp psh$pop$ok ; Exit with an "ok" flag.
;
; Get from stack area to the jump vectors
;
pop$chn:
lda psh$cnt
ora a
jz psh$pop$err
dcr a
sta psh$cnt ; One less to pop later.
;
; Move data from stack area back to the jump vectors
lhld psh$ptr ; Get the source address
dcx h ; -> last USED byte in the "stack"
lxi d,channels + psh$siz - 1 ; -> Destination
lxi b,psh$siz ; Bytes
lddr ; Move DOWN
inx h ; Adjust to -> next free
shld psh$ptr ; Save end pointer
;
psh$pop$ok:
xra a
ora a
ret
;
; -- On an error, return a carry --
;
psh$pop$err:
xra a
stc ; CARRY = error
ret
;
;----------------------------------------------------------------
; Initialize I/O Channels.
;
; On Entry
; If A = 0
; initialize all I/O channels
;
; > 0
; only initialize the required channel.
;----------------------------------------------------------------
;
init$chan:
ora a
jnz chn$ini ; > 0 and initialize current channel only
;
; ELSE...
; ---- Initialize ALL the I/O Channels in the system ----
;
init$chan$all:
push h
push b
mvi c,1 ; Starting channel
mvi b,6 ; Total channels
icl:
call clr$wdt
mov a,c ; Channel number
push b
call sel$chn ; Select a channel
call chn$ini ; Initialize channel.
pop b
inr c
call clr$wdt
djnz icl
;
pop b
pop b
ret
;
;================================================================
; The following two entry points read ascii from the KEYBOARD
; and convert to a number into the HL register pair.
;
; 1) IDHL Read a DECIMAL number into HL. Note that the result
; is HEX still so that it can be used as a counter
; ie. 100 input returns HL = 64.
; 2) IHHL Read a HEX number into HL
;
; Both routines return zero in A if the last character read was a legal
; digit else A will contain the error character.
;================================================================
;
idhl:
call get$buf ; load the buffer from console
lxi h,0
lda bufsiz
ora a
rz ; quit if nothing read
; Now read the buffer, condition, put into HL.
push b ; save
push d
mov b,a ; use as a counter
idhl2:
call get$chr ; Get a character
; Convert to a binary value now of 0..9
sui '0'
jrc inp$err ; Error since a non number
cpi 9 + 1 ; Check if greater than 9
jrnc inp$err
; Now shift the result to the right by multiplying by 10 then add in this digit
mov d,h ; copy HL -> DE
mov e,l
dad h ; * 2
dad h ; * 4
dad d ; * 5
dad h ; * 10 total now
; Now add in the digit from the buffer
mov e,a
mvi d,00
dad d ; all done now
; Loop on till all characters done
djnz idhl2 ; do next character from buffer
jr inp$end ; all done
;
;
;----------------------------------------------------------------
; Read a HEX number into HL from the keyboard.
;----------------------------------------------------------------
;
ihhl:
call get$buf
lxi h,00
lda bufsiz
ora a
rz ; return if no character read
;
push b
push d ; save
mov b,a
;
ihhl2:
call get$chr ; get a character
; Now convert the nibble to a hex digit 0..F
sui '0'
cpi 9 + 1
jrc ihhl3 ; mask in then
sui 'A'-'0'-10
cpi 16
jrnc inp$err
;
; Shift the result left 4 bits and MASK in the digit in A
ihhl3:
dad h
dad h
dad h
dad h ; shifted right 4 now
ora l ; mask in the digit
mov l,a ; put back
djnz ihhl2 ; keep on till all digits done
;
inp$end:
xra a ; Zero is a goo exit
inp$end2:
pop d
pop b
ret
;
inp$err: ; Here when a non digit is encountered
lda buftmp
jr inp$end2
;
; Subroutines for shared code etc....
;
get$buf: ; Load the buffer from the screen via CBUFF.
push d
mvi a,6
sta buffer ; Set up ready for user
xra a
sta buffer+1 ; clear buffer original value
lxi d,buffer
call get$txt ; Get a text buffer full
pop d
lxi h,buftxt ; point to the start of text
shld bufadr ; set up a pointer
lxi h,00 ; clear the result register
ret
;
; Get a character from the buffer, capitalize it on the way
;
get$chr:
push h
lhld bufadr
mov a,m ; get the character
sta buftmp ; save the character
inx h ; point to next character
shld bufadr
pop h ; restore
; Now capitalize it
jmp caps
;
;================================================================
;
; Convert the hex number in DE into DECIMAL in HL
;
;================================================================
;
hexbcd:
sded ?binnum ; save the number to convert
push b
push h
; Do the conversion
mvi b,3 ; 3 bytes to clear
hexbcd1:
mvi m,00
inx h
djnz hexbcd1 ; clear 3 bytes
;
mvi b,16 ; 16 bits to convert
cloop:
lxi h,?binnum
mvi c,2 ; bytes in the binary number
xra a ; clear carry
rloop:
mov a,m
ral
mov m,a
inx h
dcr c
jnz rloop ; keep rotating till C = 0
;
pop h
push h ; restore the result address
mvi c,3 ; 3 byte result = 6 digits
;
bloop:
mov a,m
adc m
daa
mov m,a ; save
inx h
dcr c
jnz bloop
;
djnz cloop ; do for all bits requited.
;
pop h
pop b ; clear stack
ret ; trick code here boys
;
;----------------------------------------------------------------
; Conditional print of A. This is part of the leading zero
; printing routine. It prints a '0' if register C is > 0.
; If the number in A is > 0, register C is set to 80 so
; that all following numbers are forced out.
;
;----------------------------------------------------------------
;
ccoe:
ani 0000$1111b ; Eliminate top 4 bits
ora a ; Low nibble > 0 ?
jrz ccoe1
setb 7,c ; Set top bit.
;
ccoe1:
bit 7,c ; Forcing number out ?
jrz ccoe$space ; If not, exit.
call nibasc ; Else convert A to ascii
jmp chn$out ; And channel print it.
;
ccoe$space:
bit 6,c
rz ; Clea bit 6 = not space fill
mvi a,' '
jmp chn$out ; Print a channel space
;
; ================ D A T A ================
;
dseg
;
bel$cnt ds 2
;
mess: db 0 ; char for crc calc
rem: dw 0 ;crc remainder storage
;
?binnum ds 10
?result ds 10
buftmp db 00 ; A temporary character store
bufadr: db 00,00
buffer: db 6 ; maximum characters
bufsiz: db 00 ; characters read
buftxt: db 00,00,00,00,00,00 ; text buffer
;
lzb$mode ds 1 ; Leading zero blanking mode
;
cur$chn ds 1 ; Current output channel
;
dsp$flg ds 1 ; EXEC display code flag.
exe$dbg ds 1 ; EXEC debugging flag.
;
cur$cmd ds 1 ; Current command
usr$a ds 1 ; Saved Accumulator
usr$sp ds 2 ; Saved SP
usr$de ds 2 ; Saved DE
usr$hl ds 2 ; Saved HL
usr$bc ds 2 ; Saved BC
;
channels:
chn$ini ds 3 ; Channel Initialize
chn$ist ds 3 ; Channel Input status
chn$ost ds 3 ; Channel Output status
chn$inp ds 3 ; Channel Input
chn$out ds 3 ; Channel Output
chn$cmd ds 3 ; Channel COMMAND Processor
;
; The following are the flags and buffer to impliment the push/pop
; facility that allows the user to push and pop channel pointers.
;
psh$ptr ds 2 ; -> next free byte in "push" stack
psh$cnt ds 1 ; Push counter
;
psh$stk ds psh$max * psh$siz ; Channel push stack
;
; Interrupt handlers. These are either RET or JMP instructions. The
; exec routines are provided to select either.
;
con$hdlr:
ds 3
aux$hdlr:
ds 3
tmr0$hdlr:
ds 3
tmr1$hdlr:
ds 3
int0$hdlr:
ds 3
int1$hdlr;
ds 3
int2$hdlr:
ds 3
csio$hdlr:
ds 3
;
;
end
;
;