home *** CD-ROM | disk | FTP | other *** search
- title 'CORE Board Subroutines'
- ;
- ;----------------------------------------------------------------
- ; ---- CORE SUBROUTINES Module ----
- ;
- ; This is a library of subroutines for CORE BOARD that must
- ; do simple functions like arithmetic, caps, delay etc.
- ;
- ; Written By Richard Holmes 04-02-86
- ; Last Update by Richard Holmes 29-06-86
- ;
- ;----------------------------------------------------------------
- ;
- public phacc,prhex,phexl,crlf ; ptxt
- public caps,delay,bell
- public nibasc,hexbcd,pdde,phde,pdacc
- public pdhl,get$yn,get$yns,makasc
- public space,space2,space3,lz$pdde,lz$pdacc
- public slash,colon,comma,idhl,ihhl,get$txt
- public inline,phhl,ptxt
- ;
- public rnd$ini,rnd$8,rnd$16
- ;
- extrn clr$wdt,cie,coe,cst
- ;
- maclib core
- maclib z80
- ;
- ;----------------------------------------------------------------
- ; Print the message at the return address till a '$' or
- ; a null.
- ; Return to the program at the address just after the null
- ; or '$'.
- ;----------------------------------------------------------------
- ;
- inline:
- xthl ; get address of string (ret address)
- push psw
- inline2:
- mov a,m
- inx h ; point to next character
- cpi '$'
- jrz inline3
- ora a
- jrz inline3
- call coe
- jr inline2
- inline3:
- pop psw
- xthl ; load return address after the '$'
- ret ; back to code immediately after string
- ;
- ;
- ;================================================================
- ; 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
- ;
- ;================================================================
- ; ---- 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.
- ;
- ; On Entry
- ; DE -> console buffer max size byte
- ;
- ; On Exit
- ; buffer filled from console to max size limit
- ; All registers preserved
- ;
- ;================================================================
- ;
- 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 cie ; 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
- call bell ; else 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 coe ; if not then print & return
- mov e,a ; else save character
- mvi a,'^' ; indicate a control character
- call coe
- mov a,e ; restore character
- adi 040h ; make printable
- jmp coe
- ;
- ; 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 coe ; Go back a char not req-r for cp/m
- mvi a,' ' ; erase the character
- call coe
- mvi a,08
- jmp coe ; 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
- ;
- ;================================================================
- ;
- ; Conversion routines
- ;
- ;================================================================
- ;
- ; ---- Convert low nibble of A to ascii ----
- ;
- ;================================================================
- ;
- nibasc:
- ani 0fh
- adi 090h
- daa
- aci 040h
- daa
- ret
- ;
- ;================================================================
- ;
- ; 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
- ;
- ;================================================================
- ; Print HL as decimals
- ;================================================================
- ;
- pdhl:
- push d
- push h
- xchg ; DE = value
- call pdde ; Print it
- pop h
- pop d
- ret
- ;
- ;================================================================
- ;
- ; ---- Print DE as decimal ----
- ;
- ;================================================================
- ;
- pdde:
- push h
- push d
- lxi h,?result
- call hexbcd ; convert to ascii in internal buffer
- ; Now print the 5 digit number
- lda ?result+2 ; get the MSDigit
- ora a ; A null ? - Suppress it if so
- jrz pdde1
- call nibasc ; convert lower nibble
- call coe ; Print it
- ; Now do other 4 digits
- pdde1:
- lda ?result+1
- call prhex ; Print it high 2
- lda ?result
- call prhex ; low 2
- pop d
- pop h
- ret
- ;
- ;================================================================
- ;
- ; ---- Leading Zero Print of DE in decimal ----
- ;
- ;================================================================
- ;
- lz$pdde:
- 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.
- mvi c,0
- lda ?result+2 ; Get the MSDigit
- ani 0fh
- call ccoe ; Conditional output
- ;
- 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 coe
- pop b
- pop d
- pop h
- ret
- ;
- ;----------------------------------------------------------------
- ; 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 ?
- rz ; If not, exit.
- call nibasc ; Else convert A to ascii
- jmp coe ; And print it.
- ;
- ;================================================================
- ; ---- Print HL as 4 hex digits ----
- ;================================================================
- ;
- phhl:
- xchg
- call phde
- xchg
- ret
- ;
- ;================================================================
- ;
- ; ---- Print DE as 4 hex digits ----
- ;
- ;================================================================
- ;
- phde:
- push psw
- push d
- mov a,d
- call prhex
- mov a,e
- call prhex
- pop d
- pop psw
- ret
- ;
- ;================================================================
- ;
- ; ---- Print decimal accumulator ----
- ; Note that if A > 99 the top digit is also printed, not if < 99
- ;
- ;================================================================
- ;
- pdacc:
- push d
- push h
- push psw
- mov e,a
- mvi d,0
- lxi h,?result
- call hexbcd
- pop psw
- push psw
- cpi 99
- jrc pdacc1 ; < 99, skip it
- lda ?result + 1 ; Top digit
- call nibasc
- call coe ; Print top digit 1 or 2
- pdacc1:
- lda ?result + 0
- call prhex ; Print low 2 digits
- pop psw
- pop h
- pop d
- ret
- ;
- ;================================================================
- ;
- ; ---- Leading zero print the accumulator in decimal ----
- ;
- ;================================================================
- ;
- lz$pdacc:
- 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 coe ; print units
- ;
- pop psw
- pop d
- pop b
- pop h
- ret
- ;
- ;================================================================
- ;
- ; Delay the number of milliseconds in DE
- ;
- ;================================================================
- ;
- delay:
- mov a,e
- ora d
- rz
- ;
- push d ; save it
- delay2:
- call clr$wdt
- call delay3
- dcx d ; one less millisecond less overhead
- mov a,d
- ora e
- jrnz delay2 ; keep on till DE = 0
- pop d ; restore users initial value
- ret ; back to user
- ;
- ; Delay 1 millisecond less the overhead involved in the above code.
- ;
- ; This routine must delay 3957 t-states
- ;
- delay3:
- push b ; 11
- mvi b,224 ; 7
- delay4: ; This loop does (4 + 13) * 230 - 5 = 3905 t
- nop ; 4
- djnz delay4 ; 13
- ; Fudge 14 machine cycles
- lxi b,0 ; 10
- nop ; 4
- pop b ; 10
- ;
- ret
- ;
- ;================================================================
- ;
- ; ---- Capitalize the accumulator ----
- ;
- ;================================================================
- ;
- caps:
- cpi 'a' ; Convert lower case to upper
- rc
- cpi 'z'+1
- rnc
- ani 5fh
- cpi 03
- jz 0h ; Exit if control C
- ret
- ;
- ;================================================================
- ;
- ; ---- Ring the console bell ----
- ;
- ;================================================================
- ;
- bell:
- push psw
- mvi a,7
- call coe
- pop psw
- ret
- ;
- ;================================================================
- ;
- ; ---- Print a cr/lf pair ----
- ;
- ;================================================================
- ;
- crlf:
- push psw
- mvi a,cr
- call coe
- mvi a,lf
- call coe
- pop psw
- ret
- ;
- ;================================================================
- ;
- ; Print text at DE till a 00 or a '$'
- ;
- ;================================================================
- ;
- ptxt:
- ldax d
- ora a
- rz
- cpi '$'
- rz
- call coe
- inx d
- jr ptxt
- ;
- ;================================================================
- ;
- ; ---- Get a Y or an N from console ----
- ;
- ;================================================================
- ;
- get$yn:
- call cie
- cpi cr
- jrz get$yn
- cpi lf
- jrz get$yn
- ;
- cpi esc
- rz
- call caps
- call coe
- cpi 'Y'
- rz
- cpi 'N'
- rz
- ; Not valid then
- call bell ; Ding a ling
- call bsp ; Backspace
- jr get$yn ; Wait for a N or Y
- ;
- ;================================================================
- ;
- ; ---- Get a Y, an N or an S from console ----
- ;
- ;================================================================
- ;
- get$yns:
- call cie
- cpi cr
- jrz get$yns
- cpi lf
- jrz get$yns
- ;
- cpi esc
- rz
- call caps
- call coe
- cpi 'Y'
- rz
- cpi 'N'
- rz
- cpi 'S'
- rz
- ; Not valid then
- call bell
- call bsp
- jr get$yn ; Wait for a N or Y
- ;
- ;================================================================
- ; Here the character in A is converted into ascii or is given
- ; a '.' if hex. The result is put into A for easy access via coe.
- ;================================================================
- ;
- makasc:
- ani 07fh ; Make in the range
- cpi 020h ; Lower than a space is illegal
- jrc noasc ; Not ascii
- cpi 07bh ; Higher than upper case is illegal too
- rc ; return with ascii character in C
- noasc: mvi A,02eh ; Replace with a '.'
- ret
- ;
- ;================================================================
- ;
- ; ---- Space printing on the console ----
- ;
- ;================================================================
- ;
- space3:
- call space
- space2:
- call space
- space:
- mvi a,' '
- jmp coe
- ;
- ;================================================================
- ;
- ; ---- Print a comma ----
- ;
- ;================================================================
- ;
- comma:
- push psw
- mvi a,','
- call coe
- pop psw
- ret
- ;
- ;
- ;================================================================
- ;
- ; ---- Print a slash ----
- ;
- ;================================================================
- ;
- slash:
- push psw
- mvi a,'/'
- call coe
- pop psw
- ret
- ;
- ;================================================================
- ;
- ; ---- Print a colon ----
- ;
- ;================================================================
- ;
- colon:
- push psw
- mvi a,':'
- call coe
- pop psw
- ret
- ;
- ;================================================================
- ;
- ; ---- Print the hex digits in A ----
- ;
- ;================================================================
- ;
- phacc:
- prhex: push psw
- rrc
- rrc
- rrc
- rrc
- call phexl
- pop psw
- phexl: ani 0fh
- adi 90h
- daa
- aci 40h
- daa
- jmp coe
- ;
- ;----------------------------------------------------------------
- ; Random number generator. This is used for testing the UCP
- ;----------------------------------------------------------------
- ;
- ;----------------------------------------------------------------
- ; Initialize random generator.
- ;
- ; On entry
- ; DE -> string to randomize, length at front
- ;----------------------------------------------------------------
- ;
- rnd$ini:
- ldax d
- cpi 5
- rc ; Error if less than 5 elements in the array
- push d
- push b
- mov b,a ; Load counter
- xchg
- inx h ; Now HL -> first seed byte
- ldar ; Get refresh register value
- dcr b ; Do one less than the required
- initloop:
- add m
- rrc
- mov m,a
- inr m
- mov a,m
- inx h
- djnz initloop
- ; Restore and exit gracefully
- xchg ; Restore HL
- pop b
- pop d ; Restore other registers
- ret
- ;
- ;----------------------------------------------------------------
- ; Return 16 bit random in HL.
- ;
- ; On entry
- ; DE -> random string
- ;----------------------------------------------------------------
- ;
- rnd$16:
- call rnd$8
- mov h,a ; msb byte
- call rnd$8
- mov l,a ; lsb byte
- ret
- ;
- ;----------------------------------------------------------------
- ; Return an 8 bit random number in A
- ;
- ; On entry
- ; DE -> random string
- ;----------------------------------------------------------------
- ;
- rnd$8:
- ldax d ; A = number of seeds
- cpi 5 ; Check if less than 5 seed values
- rc ; Return with a carry to indicate an error
- ; Here we load the number of cells into B then decrtement so as to skip
- ; these which are operated on later.
- push b
- push d ; Saver address of seed array
- mov b,a
- dcr b
- dcr b
- inx d ; DE -> first seed in the array
- xchg ; Put memory pointer into HL
- ;
- ;Loop for N-2 times.
- loop: inr m ;INCREMENT SEED VALUE.
- mov a,m
- inx h ;HL POINTS TO NEXT SEED VALUE IN ARRAY.
- add m
- rrc ;ROTATE RIGHT CIRCULAR ACCUMULATOR.
- mov m,a
- djnz loop
- ;
- ; Last iteration to compute random byte in register a.
- inx h ; HL -> last byte in the array
- add m
- cma ; complement the accumulator
- rrc ; rotate it right
- mov m,a
- xra a ; Clear carry
- mov a,m ; Re-load value, carry not set.
- ;
- ; Restore the registers and return with the value in A
- ERROR:
- xchg ; Restore HL
- pop d
- pop b
- ret
- ;
- dseg
- ;
- ?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
- ;
- end
- ;
- ;