home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
utils
/
asmutl
/
hd64180a.lbr
/
CSUBS.AZM
/
CSUBS.ASM
Wrap
Assembly Source File
|
1991-08-04
|
20KB
|
933 lines
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
;
;