home *** CD-ROM | disk | FTP | other *** search
- title 'Executive Command Processor'
- ;
- ;----------------------------------------------------------------
- ; Executive Command Processor
- ;
- ; 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 17/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
- ;----------------------------------------------------------------
- ;
- maclib z80
- ;
- ; maclib iocmd ; I/O Driver command library
- public exec ; The ONLY entry point.
- ;
- ; Interrupt handlers
- 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)
- ;
- 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 ;
- ;
- 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 ; Spare
- ;
- dw cmd$50 ; Spare
- dw cmd$51 ;
- dw cmd$52 ;
- dw cmd$53 ;
- dw cmd$54 ;
- dw cmd$55 ;
- dw cmd$56 ;
- 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: ;
- 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
- ;
- cmd$49: ;
- 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
- ;
- 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
- ;
- ;