home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol026
/
sysmon.asm
< prev
next >
Wrap
Assembly Source File
|
1985-02-09
|
36KB
|
1,477 lines
;
; sysmon.asm - system monitor
;
; revision 02.00 - 05/12/81
;
; Copyright (C) 1978, 1979, 1980, 1981 by Terence M. Kennedy
; All Rights Reserved Worldwide
;
; Permission is hereby granted to the SIG/M library to distribute
; this work in whatever form and manner it pleases. This permission
; is non-transferable.
;
; Computer hobbyists may use this code, in any form, modified or
; unmodified, for non-commercial purposes.
;
; Refer all requests for commercial distribution to the SIG/M Library.
;
; I define 'Commercial distribution' to include distribution by
; the 'CP/M User's Group' run by Intersoft Corp. (Lifeboat Associates)
;
; NOTE: CP/M is a (registered) trademark of Digital Research, Inc.,
; Pacific Grove, California. Reference to this trademark within
; the body of this text is only to indicate that this code will
; interface with said trademarked product, and does not imply
; that the owner of the trademark owns, approves, or uses this
; code.
;
false equ 0 ;logical false value
true equ not false ;logical true value
;
testing equ true ;if testing
help equ true ;if '?' command to display commands desired
cpmio equ true ;if using CP/M console I/O instead of hardware
;
if (not testing) and cpmio
--> cannot have cpmio true and testing false <--
endif
;
if testing
pbase equ 00100h ;program base
dbase equ 02000h ;data area base
endif
;
if not testing
pbase equ 0e000h ;program base in bytesaver
dbase equ 0bf00h ;data area base (below bytesaver)
endif
;
if cpmio ;if using CP/M I/O calls
conrdy equ 006h ;console status
conin equ 009h ;console input
conout equ 00ch ;console output
endif
;
wboot equ 0000h ;CP/M warm boot entry point
;
; misc. equates
;
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
bs equ 08h ;back space
sl equ '/' ;slash
cntrlc equ 'C'-40h ;control-C
cntrlq equ 'Q'-40h ;control-Q
cntrls equ 'S'-40h ;control-S
cntrlx equ 'X'-40h ;control-X
cntrlz equ 'Z'-40h ;control-Z
bell equ 07h ;ring console bell
;
; device equates
;
fpanel equ 0ffh ;front panel device address
consta equ 000h ;console status port
condat equ 001h ;console data port
rdrsta equ 002h ;reader status port
rdrdat equ 003h ;reader data port
dsksta equ 07fh ;disk drive status
dskcmd equ 07fh ;disk drive command port
dskc2 equ 07ch ;disk drive 2nd command port
dmah equ 07eh ;high order byte of dma address
dmal equ 07dh ;low order byte of dma address
;
; device control bits
;
trk0 equ 004h ;if at track 0
iof equ 008h ;if I/O is complete
notrdy equ 080h ;if drive is not ready
done equ notrdy or iof ;done w/ command (one way or another)
errors equ 0f0h ;error bits
tbe equ 080h ;transmit buffer empty (all serial ports)
rda equ 040h ;data available (all serial ports)
readf equ 0bfh ;read disk function
;
; data areas (uninitialized)
;
org dbase
;
userpc: ds 2 ;user's PC for R command
svc: ds 1 ;supervisor call no.
ibuf: ds 128 ;input buffer
stack: ds 64 ;program stack
pflag1: ds 1 ;parameter flags
pflag2: ds 1
param1: ds 2 ;parameters
param2: ds 2
cbuf: ds 1 ;command buffer
dmpad: ds 2 ;dump address
temp: ds 10h ;temp. workspace for B, I & O commands
oflst equ temp ;object file loader state
oflce equ temp+1 ;object file loader checksum error flag
oflcs equ temp+2 ;object file loader checksum
oflbc equ temp+3 ;object file loader byte count
oflbb equ temp+4 ;object file loader byte buffer
oflla equ temp+5 ;object file loader load address (word value)
oflfrr equ temp+7 ;object file loader first record read flag
addr: ds 2 ;hexmon current address
data: ds 1 ;hexmon working data
diagfg: ds 1 ;diagnostic load flag
srcnam: ds 10h ;name of tape file searching for
fndnam: ds 10h ;name of tape file found
;
; code area
;
org pbase
;
monitr: jmp main ;jump to main code
super: jmp supvsr ;jump to supervisor
main: lxi sp,stack+64 ;set up sp
lxi h,0 ;clear user PC to 0
shld userpc
lxi h,cs ;clear screen code
call wasc ;send it
in fpanel ;read sense switches
cpi 0ffh ;test for no front panel
jz main1 ;if no panel
cpi 80h ;test if entering sysmon
jnz boot ;no, boot disk right away
main1: lxi h,signon ;get signon message
call wasc ;send to con:
call weolc ;do cr/lf
prompt: mvi a,'@' ;our prompt
call wacc ;to console
lxi h,ibuf ;input buffer pointer
call rasc ;get command line
mov a,m ;test if terminated with '/'
cpi sl
jz hexmon ;if so, use hex monitor
mvi m,' ' ;insure at least one blank at end
inx h ;followed by cr
mvi m,cr
lxi d,ibuf ;points to 1st character of input line
parse: ldax d ;get command
cpi ' ' ;test for null command
jz prompt ;if so, re-issue prompt
sta cbuf ;if not, put command keyword in cbuf
inx d ;points to param1 now
parse1: xra a ;clear parameter flags
sta pflag1
sta pflag2
call dhs ;decode first parameter
jc comerr ;if command error in param.
sta pflag1 ;save parameter flag
shld param1 ;and parameter
call dhs ;decode second parameter (same as first)
jc comerr
sta pflag2
shld param2
lda pflag1 ;get first parameter flag
ora a ;see if set
jnz $+9 ;yes, skip next code
lxi h,100h ;no, default to 100 hex
shld param1
lda pflag2 ;get second parameter flag
ora a ;test it
jnz $+9 ;if already got one
lhld param1 ;else default it to same as first one
shld param2
decode: lxi h,ctable ;lookup table for keywords
decod1: lxi d,cbuf ;points to command input by user
mvi c,1 ;compare only 1 character
mvi b,1 ;set match flag
decod2: ldax d ;get command
cmp m ;compare w/ keyword table
jz $+5 ;if match
mvi b,0 ;else reset match flag
inx d
inx h
dcr c ;this would flush rest of keyword if >1 char.
jnz decod2
dcr b ;test match flag
jz match ;if successful match
inx h ;else skip address field
inx h
mov a,m ;test if end of table
ora a
jnz decod1 ;if not at end
lxi h,badcom ;at end, send 'bad command' message
call wasc
jmp prompt ;and go back to main prompt
match: mov e,m ;copy address to DE
inx h
mov d,m
lxi b,prompt ;create return address
push b ;this puts prompt on stack for second RET
push d ;this puts the routine address on the stack
lhld param2 ;put second parameter in DE (see xchg below)
xchg
lhld param1 ;put first parameter in HL
ret ;this causes jmp to address in D, pushed above
comerr: lxi h,badstx ;give 'bad syntax' message
call wasc
jmp prompt
;
; command table
;
ctable: db 'D' ;dump command
dw dump
db 'H' ;halt command
dw halt
db 'B' ;boot standard system
dw boot
db 'S' ;boot diagnostic system
dw diag
db 'R' ;display register set
dw regdis
db 'E' ;enter command
dw enter
db 'M' ;move command
dw move
db 'F' ;fill command
dw fill
db 'G' ;go command
dw go
db 'I' ;input command
dw rip
db 'O' ;output command
dw wop
db 'L' ;load diagnostic tape
dw loader
;
if help
db '?' ;output command summary
dw hlpdis
endif
;
if testing
db 'Q' ;quit command
dw wboot ;to CP/M warm boot
db 'T' ;supervisor call test
dw svctst
endif
;
db 0 ;end of command table
;
; supvsr - supervisor call handler
;
supvsr: push h ;save user parameters
push d
push b
push psw
sup1: lxi h,stable ;supervisor call table pointer
sup2: lda svc ;get supervisor call no.
cmp m ;compare with call no. in table
inx h ;point to address in any case
jz sup3 ;if found
inx h ;skip to next svc no.
inx h
mov a,m
cpi 0ffh
jz sup4 ;if at end of table
jmp sup2 ;and retry
sup3: mvi a,jmp ;stuff a jump in temp. area
sta temp
mov e,m ;get address from table
inx h
mov d,m
xchg ;put in hl
shld temp+1 ;save address in temp+1
pop psw ;restore user's registers
pop b
pop d
pop h
jmp temp ;go to routine
sup4: mvi b,8 ;8 bytes to remove
sup5: inx sp
dcr b
jnz sup5 ;if not done
lxi h,ilsum1 ;print illegal supervisor call message
call wasc
lda svc ;print svc no. causing error
call whbc
lxi h,ilsum2 ;print rest of message
call wasc
inx sp ;get high byte
lxi h,0 ;copy sp to hl
dad sp
mov d,m ;get byte 1
dcx h
mov e,m
xchg
dcx h ;point to call address
dcx h
dcx h
mov a,h ;output hi byte
call whbc
mov a,l ;output low byte
call whbc
call weolc ;do 2 cr/lf's
sup6: call weolc ;do cr/lf
lxi sp,stack+64 ;reset sp
jmp prompt ;and issue prompt
;
; supervisor call table
;
stable: db 0 ;return to monitor
dw sup6
db 1 ;return version number
dw vers
db 2 ;console in
dw racc
db 3 ;console out
dw wacc
db 4 ;console status
dw const
db 5 ;console string in
dw rasc
db 6 ;console string out
dw wasc
db 7 ;do cr/lf on console
dw weolc
db 8 ;ring bell on console
dw ding
db 9 ;test for legal digit
dw legal
db 10 ;decode hex string
dw dhs
db 11 ;write hex digit to console
dw whdc
db 12 ;write hex byte to console
dw whbc
db 13 ;dump hex & ascii on console
dw dmp
db 14 ;dump register set
dw regdis
db 15 ;compute difference
dw diff
db 16 ;move up
dw moveup
db 17 ;move down
dw movedn
db 18 ;boot dos
dw boot
db 19 ;boot ddos
dw diag
db 20 ;delay
dw delay
db 21 ;read byte from reader
dw reader
db 22 ;process object byte
dw ofl
db 0ffh ;end of table
;
; loader - load specified diagnostic from tape
;
loader: lxi h,askfil ;ask for filename
call wasc
lxi h,srcnam ;input buffer address
call rasc ;read user's response
lxi h,askply ;tell him to press play
call wasc ;do cr/lf
load1: call reader ;get character
cpi ';' ;test for header
jnz load1 ;skip till found
lxi h,fndnam ;pointer to 'found name'
load2: call reader ;get filename
cpi cr ;see if all done
jz load3
mov m,a ;store away
inx h ;next free loc.
jmp load2 ;do next char
load3: mvi m,0 ;force end of string
lxi h,found ;print 'Found '
call wasc
lxi h,fndnam ;send name we found on tape
call wasc ;to console
lxi d,srcnam ;pointer to search name
lxi h,fndnam ;pointer to name found on tape
mvi b,10h ;max. no. of bytes to compare
load4: mov c,m ;byte from found name
ldax d ;byte from wanted name
cpi cr ;test if last byte in source
jz load5 ;if so...
cmp c ;compare
jnz load1 ;if not a match
inx h ;next bytes
inx d
dcr b ;see if have done 10h yet...
jnz load4 ;if not
load5: lxi h,loadng ;print 'Loading'
call wasc
xra a ;initialize loader
sta oflst
sta oflce
sta oflfrr
load6: call reader ;get character
cpi cntrlz ;test if eof
jz load7 ;if so...
call ofl ;process byte
lda oflce ;test for checksum error
ora a
jz load6 ;if ok
jmp load8 ;if error
load7: lxi h,execad ;print 'Execute address: '
call wasc
lhld addr ;now print address
mov a,h ;hi byte first
call whbc
mov a,l ;next, the low byte
call whbc
call weolc ;do cr/lf
call weolc
ret ;return to main monitor
load8: lxi h,cksume ;print 'Checksum error'
call wasc
ret
;
; diag - boot diagnostic system from disk
;
diag: mvi a,0ffh ;set diagnostic flag
jmp bootd ;proceed as a standard boot
;
; boot - boot DOS from diskette (maybe)
;
boot:
;
if testing ;prevent odd things from
jmp main1 ;happening to first-time SIG/M users
endif
;
mvi a,0 ;reset diag. flag
bootd: sta diagfg
in dsksta ;get disk status
cpi 0ffh ;test if no disk in computer
jnz boot2 ;if disk is there
boot1: lxi h,wutdsk ;what disk?
call wasc
jmp main1 ;back to system monitor
boot2: mvi a,0ffh ;issue null commands to update status
out dskc2
out dskcmd
mvi a,35 ;do 35 ms head load delay
call delay
boot21: in dsksta ;get status again
ani trk0 ;test track 0 bit
jz boot3 ;if at track 0
mvi a,0ffh ;this code steps the head in
out dskcmd
ani 0fdh
out dskcmd
ori 002h
out dskcmd
mvi a,8 ;delay 8 ms between steps
call delay ;do delay
jmp boot21 ;test track 0 again
boot3: mvi a,0f0h ;set dma address to 1000h(-3)
out dmah
mvi a,002h
out dmal
mvi a,0 ;track 0
sta 0ffdh ;@ dma-3
mvi a,1 ;sector 1
sta 0ffeh ;@ dma-2
mvi a,0fbh ;sd id mark (not really needed)
sta 0fffh
mvi a,readf ;issue read function
out dskcmd ;issue as command
boot4: in dsksta ;read status
ani done ;test if done
jz boot4 ;not yet...
in dsksta ;read status again
push psw ;save full byte for later
ani errors ;test for errors
jz boot5 ;if no errors
lxi h,booter ;say boot error
call wasc ;send
pop psw ;get status back
call whbc ;to console
call weolc ;do cr/lf
jmp main1 ;to main monitor
boot5: pop psw ;clean up stack
lxi h,1000h ;source address of move
lxi d,80h ;no. of bytes to move
lxi b,0 ;destination address
call moveup ;do move
lda 0 ;get first byte of bootstrap
cpi 0e5h ;test for push h
jnz boot6 ;if not, execute code
lxi h,nosys ;say no system
call wasc ;send
jmp main1 ;go to monitor
;
if not testing ;if running from rom
boot6: lda diagfg ;get diagnostic flag
cpi 0ffh ;see if set
jz 0 ;if so, proceed directly to boot
lxi h,bootc ;source
lxi d,0bh ;no. of bytes
lxi b,temp ;destination
call moveup ;do move
jmp temp ;turn off rom, turn on ram, jmp to bootstrap
endif
;
if testing ;if running from ram
boot6: jmp 0 ;we don't need to turn off rom board
endif
;
if not testing
bootc: db 3eh,0 ;mvi a,0
db 0d3h,40h ;out 40h
db 3eh,1 ;mvi a,1
db 0d3h,41h ;out 41h
db 0c3h,0,0 ;jmp 0
endif
;
if help
;
; hlpdis - display help menu [optional]
;
hlpdis: lxi h,hlpmsg ;print the whole thing
call wasc
jmp weolc ;exit w/ cr/lf
endif
;
if testing
;
; svctst - test supervisor call
;
svctst: mov a,l ;put svc no. into A
sta svc ;save in svc
call super ;call supervisor
jmp weolc ;exit w/ cr/lf
endif
;
; regdis - display 8080 register set
;
regdis: push h ;save registers
push d
push b
push psw
lxi h,regmsg ;issue register message
call wasc
lhld userpc ;get user's PC
call reg1 ;display it
lxi h,regsp ;issue SP message
call wasc
lxi h,0
dad sp ;sneaky way to get SP
call reg1
lxi h,regaf ;issue AF message
call wasc
pop h ;get AF
call reg1
lxi h,regbc ;issue BC message
call wasc
pop h ;get BC
call reg1
lxi h,regde ;issue DE message
call wasc
pop h ;get DE
call reg1
lxi h,reghl ;issue HL message
call wasc
pop h ;get HL
call reg1
jmp weolc ;exit via cr/lf
reg1: mov a,h ;get high byte
call whbc
mov a,l ;get low byte
call whbc
ret ;return to caller
;
; rip - read input port
;
rip: mvi a,in ;input instruction
sta temp ;save in temp code area
mov a,l ;HL (param1) has input port address
sta temp+1
mvi a,ret ;return instruction
sta temp+2
call temp ;execute code just built
call whbc ;write result on console
jmp weolc ;equal to call weolc ! ret
;
; wop - write output port
;
wop: mvi a,out ;output instruction
sta temp ;mainly the same as above
mov a,l
sta temp+1
mvi a,ret
sta temp+2
mov a,e ;get value to send from param2
call temp
jmp weolc
;
; halt - halt computer
;
halt: hlt ;that was simple!!!
;
; dump - dump memory to console in hex & ascii
;
dump: lda pflag1 ;see if address was typed
ora a
jz weolc ;no, exit
call diff ;get difference between param1 & param2 in DE
inx d ;+1
shld dmpad ;save param1 as starting dump address
jmp dmp ;do actual dump
;
; enter - enter bytes into memory
;
enter: mov a,h ;prompt w/ current load address
call whbc
mov a,l
call whbc
mvi a,':'
call wacc
mvi a,' '
call wacc
push h ;save load address
lxi h,ibuf ;read user's input
call rasc
dcr b ;test for empty line
jz enter3 ;empty, exit
lxi d,ibuf ;pointer to buffer
enter1: call dhs ;decode 1 byte
jc enterr ;if error
ora a ;test for end of line
jz enter2
mov a,l ;L has low byte of entered value
pop h ;restore load address
mov m,a ;move byte into memory
inx h ;increment load address
push h ;save again...
jmp enter1 ;do next byte on line
enter2: pop h ;restore load address
jmp enter ;get next line
enter3: pop h ;clean up stack
jmp weolc ;exit w/ cr/lf
enterr: pop h ;clean up stack
lxi h,badval ;send 'bad hex value' message
jmp wasc ;exit
;
move: lda pflag1 ;make sure we have two parameters
ora a
jz moverr
lda pflag2
ora a
jz moverr
call diff ;find difference between param1 & param2
inx d ;+1
push d ;save param1 & param2
push h
lxi h,moveto ;ask 'to?'
call wasc
lxi h,ibuf ;get answer
call rasc
lxi d,ibuf ;reset pointer
call dhs ;decode answer
jnc move1 ;if ok
pop h ;else clean up stack
pop d
jmp enterr+1 ;print 'bad hex value' message
move1: xchg ;DE= address to move to
mov b,d ;copy to BC
mov c,e
pop h ;get source address
call diff ;compute distance to move
pop d ;restore size of block to move
jnc movedn ;move downward
jmp moveup ;move upward
moverr: lxi h,twopar ;issue 'two parameters' message
jmp wasc
;
; fill - fill memory with specified value
;
fill: lda pflag1 ;test for two parameters
ora a
jz moverr
lda pflag2
ora a
jz moverr
call diff ;compute # of bytes to fill
inx d ;+1
push h ;save parameters (h now has length)
push d
lxi h,fillw ;print 'With?'
call wasc
lxi h,ibuf ;get answer
call rasc
lxi d,ibuf
call dhs ;decode it
jnc fill1 ;if ok
pop d
pop h ;clean up stack
jmp enterr+1 ;print 'bad hex value'
fill1: mov b,l ;byte to fill w/ --> B
pop d
pop h ;restore source & length
fill2: mov a,d ;return when count=0
ora e
rz
mov m,b ;place fill byte
inx h ;loc=loc+1
dcx d ;# to do=# to do-1
jmp fill2
;
; go - go to location specified by param1
;
go: mvi a,call ;stuff call instruction
sta temp ;place in temp code
shld temp+1 ;save param1 as address of call
mvi a,jmp ;save jump
sta temp+3
lxi h,go1 ;where to return to...
shld temp+4
jmp temp ;execute code
go1: jmp weolc ;exit w/ cr/lf
;
; hexmon - hexadecimal monitor
;
hexmon: call wacc ;echo '/'
lxi d,ibuf ;decode address(?) just entered
call dhs
jc hex8 ;if not valid
shld addr ;save address
hex1: mvi a,' ' ;send a blank
call wacc
mov a,m ;get data that's there
call whbc ;and send to console
hex2: mvi a,' ' ;another blank
call wacc
hex3: call racc ;get character
cpi cr ;test cr
push psw ;save flags
cz weolc ;do cr/lf if cr
pop psw ;restore flags
jz prompt ;if so, go back to main prompt
cpi '^' ;test for open previous
jz hex5 ;if match...
cpi lf ;test for open next
jz hex7 ;if match...
push psw ;save value
call legal ;test for legal value
jc hex10 ;if invalid, kill stack and retry
rlc ;move to high nibble
rlc
rlc
rlc
sta data ;save as data byte
pop psw ;restore ascii version
call wacc ;echo to console
hex4: call racc ;get next nibble
push psw
call legal ;test if valid
jc hex9 ;if not, kill pushed stuff & try again
mov b,a ;save in B
lda data ;data already has hi nibble
ora b ;add in low nibble
sta data ;save as data again
pop psw ;restore ascii
call wacc
lhld addr ;get working address
lda data ;get data
mov m,a ;move
call weolc ;do cr/lf
inx h ;next address
jmp hex6
hex5: call wacc ;echo '^'
call weolc ;do cr/lf
lhld addr
dcx h ;prev. address
hex6: shld addr ;save as current
mov a,h ;print on console
call whbc
mov a,l
call whbc
mvi a,sl ;put up slash
call wacc
jmp hex1 ;go to entry mode
hex7: call weolc ;open next address
lhld addr
inx h
jmp hex6
hex8: lxi h,baddr ;say bad address
call wasc
jmp prompt ;return to prompt
hex9: pop psw ;kill old char.
call ding ;ring bell
jmp hex4 ;try again
hex10: pop psw ;kill old
call ding
jmp hex3 ;and retry
;
; utility routine section - many are available by external programs
;
;
; ding - ring console bell
;
ding: push psw ;save user's A
mvi a,bell
call wacc ;print a bell
pop psw ;restore user's A
ret ;return to caller
;
; vers - return version number in hl
;
vers: lxi h,0100h ;version 01.00
ret ;give to user
;
; moveup - move memory towards zero
;
moveup: mov a,d ;de=# of bytes to move
ora e
rz ;if done moving
mov a,m ;get byte from source
inx h ;increment source address
stax b ;save in destination
inx b ;increment destination address
dcx d ;decrement # of bytes left to move
jmp moveup ;go do another...
;
; movedn - move memory towards ffff
;
movedn: dad d ;add source address to # of bytes, giving last
mov a,c ;byte to move
add e
mov c,a
mov a,b
adc d
mov b,a
movdn1: mov a,d ;see if done
ora e
rz ;if done
dcx h ;decrement source address
mov a,m ;get byte
dcx b ;decrement destination address
stax b ;store at dest. address
dcx d ;1 less byte to move...
jmp movdn1 ;go again
;
; diff - compute difference between de & hl and place in de
;
diff: mov a,e ;do first 8-bit subtract
sub l
mov e,a ;return to E
mov a,d ;now do second
sbb h
mov d,a ;and return to D
ret ;return to caller
;
; dmp - dump memory in hex and ascii to console
;
dmp: mov a,d ;see if done
ora e
jz weolc ;if so, exit via weolc
;
if not cpmio ;if hardware I/O
in condat ;get current data from console
cpi cntrlc ;see if ^C typed...
jnz dmp1
endif
;
if cpmio
jmp dmp1 ;can't stop output under CP/M
endif
;
jmp weolc ;...and exit
dmp1: call weolc ;start new line
lda dmpad+1 ;get high byte of address
call whbc ;write to console
lda dmpad ;do same w/ low byte
call whbc
push h ;save address
push d ;save count
mvi c,16 ;16 bytes per line
dmp2: mov a,d ;test if done with hex for this line
ora e
jz dmp3
mvi a,' ' ;put a blank between bytes
call wacc
mov a,m ;get byte to be dumped
inx h ;increment pointer
call whbc ;print hex byte on console
push h ;save address
lhld dmpad ;increment user's relative address
inx h
shld dmpad
pop h ;restore our address
dcx d ;decrement # of bytes left
dcr c ;decrement # of bytes left on this line
jnz dmp2 ;if more
jmp dmp4 ;if not more, do ascii
dmp3: inr c ;this puts ascii in right place if last address
dcr c ;to dump was not on 16 byte boundary
jz dmp4 ;if done
mvi a,' ' ;print 3 spaces
call wacc
call wacc
call wacc
jmp dmp3+1 ;continue
dmp4: pop d ;restore byte count
pop h ;restore pointer
mvi a,' ' ;print 2 spaces
call wacc
call wacc
mvi c,16 ;16 ascii bytes / line
dmp5: mov a,d ;test if done
ora e
jz weolc
mov a,m ;fetch next byte
inx h ;increment pointer
ani 7fh ;mask out parity bit
cpi 20h ;test if printable
jnc $+5 ;if it isn't .lt. 20h
mvi a,'.' ;else use .
cpi 7fh ;see if rubout
jc $+5 ;if not
mvi a,'.' ;it is, substitute rubout
call wacc ;output to console
dcx d ;1 less byte to do
dcr c ;1 less on this line also
jnz dmp5 ;if still more on this line
jmp dmp ;start a new line
;
; whbc - write hex byte to console
;
whbc: push psw ;save byte
rrc ;do high nibble first
rrc
rrc
rrc
call whdc ;do digit
pop psw ;get byte back
push psw ;save again
call whdc ;do low nibble
pop psw ;return w/ value
ret
;
; whdc - write hex digit to console
;
whdc: ani 0fh ;only look at low nibble
cpi 10 ;see if A-F
jc $+5 ;no, 0-9
adi 7 ;make A-F
adi '0' ;make ascii
jmp wacc ;send & exit
;
; weolc - do cr/lf on console
;
weolc: push psw ;save acc
mvi a,cr ;send cr
call wacc
mvi a,lf ;send lf
call wacc
pop psw ;restore acc
ret ;exit
;
; wasc - write ascii string to console
;
wasc: mov a,m ;get character
inx h ;increment pointer
ora a ;see if terminator
rz ;return if so
call wacc ;else send character
jmp wasc ;and do another...
;
; rasc - read ascii string from console
;
rasc: push h ;save buffer pointer
mvi b,0 ;0 characters entered
rasc1: call racc ;get a character
cpi cntrlx ;test for control-x
jnz rasc2 ;no it, continue
call rasc7 ;skip old line
pop h ;restore buffer pointer
jmp rasc ;try again
rasc2: cpi bs ;test for backspace
jnz rasc3 ;if not
inr b ;see if at beginning of line
dcr b
jz rasc1 ;if so, simply input again
dcx h ;decrement pointer
dcr b ;decrement count
mvi a,bs ;do bs/space/bs
call wacc
mvi a,' '
call wacc
mvi a,bs
call wacc
jmp rasc1 ;get another character
rasc3: mov m,a ;put in buffer
inr b ;increment count
mov a,b ;test if room left in buffer
cpi 126
jm rasc4 ;if still room
mvi m,cr ;else stuff cr
pop h ;restore pointer
ret ;and exit
rasc4: mov a,m ;get character back
cpi cr ;test for cr
jz rasc5 ;if so, exit
cpi sl
jz rasc6 ;test for slash
inx h ;increment pointer
call wacc ;echo character
jmp rasc1 ;and go get another
rasc5: inx sp ;kill stuff on stack
inx sp
jmp weolc ;and exit
rasc6: inx sp ;kill stuff on stack
inx sp
ret ;return to user w/o cr
rasc7: mov a,b ;get count to backspace over
cpi 0
rz ;if none, exit...
mov a,m ;get character
dcx h
cpi 20h
jc rasc8 ;if not printing
cpi 7fh
jz rasc8 ;likewise
mvi a,bs ;backspace over current char
call wacc
mvi a,' '
call wacc
mvi a,bs
call wacc
rasc8: dcr b
jnz rasc7
ret
;
; dhs - decode hex string (ascii string @DE into binary in HL)
;
dhs: lxi h,0 ;set result=0
push b ;save B register
mvi b,0 ;clear 'digits found' counter
dhs1: ldax d ;get character
cpi cr ;test for cr
jz dhs5
inx d
cpi ' ' ;test for space
jz dhs1 ;skip if so
cpi ',' ;test for comma
jz dhs1 ;skip if so
dhs2: dad h ;HL=HL*16
dad h
dad h
dad h
cpi 61h ;see if l/c
jc dhs3 ;no
sui 20h ;make it u/c
dhs3: sui '0' ;convert to binary
jc dhserr ;if error
cpi 10 ;see if <10
jc dhs4 ;yes
sui 7 ;no, adjust for A-F
cpi 10 ;see if maybe between 9 & A
jc dhserr
dhs4: cpi 16 ;test if within bounds
jnc dhserr ;no, error
add l ;add to result
mov l,a ;replace
jnc $+4
inr h ;if carry
inr b ;increment 'digits found' counter
ldax d ;get next byte
cpi cr ;all these cause an exit
jz dhs5
cpi ' '
jz dhs5
cpi ','
jz dhs5
cpi sl ;test for slash
jz dhs5
inx d ;points to next
jmp dhs2 ;decode value in A
dhs5: ldax d ;normal exit
mov a,b ;count to A
pop b ;restore old B (user's)
yup: stc ;general purpose 'yes'
cmc
ret
dhserr: dcx d ;error exit
ldax d ;put offending character in A
pop b ;restore user's BC
nope: stc ;general purpose 'no'
ret ;exit
;
; legal - test if an ascii character is a legal hex value
;
legal: sui '0' ;remove ascii offset
jc nope ;if less, it isn't
cpi 10 ;if less than 10...
jc legal1 ;...it's ok
sui 7 ;test for a-f
cpi 10
jc nope
legal1: cpi 16 ;now see if < 16
jnc nope ;if greater
jmp yup ;if less than
;
; ofl - Intel object file loader
; Thanks to: L. E. Hughes / 8080 SDC / Florida
;
ofl: push psw ;save character
lda oflst ;check state
cpi 1
jnc ofl1
pop psw ;state 0 - wait for a colon
cpi ':'
rnz ;wasn't it - throw away
xra a ;clear checksum
sta oflcs
inr a ;set state=1
sta oflst
ret
ofl1: cpi 2 ;test if state 1
jnc ofl2 ;no, skip
inr a ;set state=2
sta oflst
call oflcb ;clear byte buffer
pop psw
jmp oflad ;accum. first digit of byte count
ofl2: cpi 3 ;test if state 2
jnc ofl3 ;no, skip
inr a ;set state=3
sta oflst
pop psw
call oflad ;get 2nd digit of byte count
sta oflbc ;save result as byte count
jmp ofluc ;add result into checksum
ofl3: cpi 4 ;test if state 3
jnc ofl4 ;no, skip
inr a
sta oflst ;set state=4
call oflcb ;clear byte buffer
pop psw
jmp oflad ;accum. 1st digit of hi address byte
ofl4: cpi 5 ;test if state 4
jnc ofl5 ;no, skip
inr a
sta oflst ;set state=5
pop psw
call oflad ;accum. 2nd digit of hi address byte
sta oflla+1 ;save hi byte of load address
jmp ofluc ;update checksum
ofl5: cpi 6 ;test if state 5
jnc ofl6 ;no, skip
inr a
sta oflst ;set state=6
call oflcb ;clear byte buffer
pop psw ;accum. 1st digit of low address byte
jmp oflad
ofl6: cpi 7 ;test if state 6
jnc ofl7 ;no, skip
inr a
sta oflst ;set state=7
pop psw ;accum. 2nd digit of low address byte
call oflad
sta oflla ;save low byte of load address
push psw ;save for later
lda oflfrr ;see if first address
cpi 0
jnz ofl61 ;no, skip this...
inr a ;say not first time
sta oflfrr
lhld oflla ;get load address
shld addr ;save for user
ofl61: pop psw ;restore low byte
jmp ofluc ;update checksum
ofl7: cpi 9 ;test if state 8
jnc ofl8 ;no, skip
inr a
sta oflst ;set state=9
pop psw ;ignore record type
ret
ofl8: cpi 10 ;test if state 9
jnc ofl10 ;no, skip
inr a
sta oflst ;set state=10
lda oflbc ;get byte count
ora a
jz ofl9 ;skip if no data bytes in record
call oflcb ;clear byte buffer
pop psw
jmp oflad ;accum. 1st digit of next data byte
ofl9: mvi a,11 ;set state=12 (all data bytes read)
sta oflst
jmp ofl11
ofl10: cpi 11 ;test if state 10
jnc ofl11 ;no, skip
dcr a ;loop at previous state
sta oflst
pop psw
call oflad ;accum. 2nd digit of next data byte
push h
lhld oflla
mov m,a ;load byte
inx h ;increment load address
shld oflla
pop h
call ofluc ;update checksum
lda oflbc ;decrement byte count
dcr a
sta oflbc
ret
ofl11: cpi 12 ;test if state 11
jnc ofl12 ;no, skip
inr a
sta oflst ;set state=12
call oflcb ;clear byte buffer
pop psw
jmp oflad ;accum. 1st digit of checksum
ofl12: pop psw
call oflad ;accum. 2nd byte of checksum
call ofluc ;add into new checksum
sta oflce ;save as checksum
xra a
sta oflst ;back at state 0
ret
oflcb: xra a ;clear byte buffer
sta oflbb
ret
oflad: call legal ;convert to binary
push b ;accum. hex digit
mov b,a
lda oflbb ;fetch byte buffer
add a ; * 16
add a
add a
add a
add b ;add in new digit
sta oflbb ;replace old value
pop b
ret
ofluc: push h ;update checksum
lxi h,oflcs ;point to checksum
add m ;add in new byte
mov m,a
pop h
ret
;
; this is the console driver
;
;
; racc - read ascii character from console
;
if not cpmio ;if hardware I/O
racc: in consta ;read status port
ani rda ;test rda bit
jz racc
in condat ;get data
ani 7fh ;strip parity bit
endif
;
if cpmio ;if running w/ CP/M I/O calls
racc: push b ;save user registers
push d
push h
mvi a,conin ;perform conin function
call cbios
pop h ;restore registers
pop d
pop b
endif ;fall thru to case changer
;
cpi 61h ;translate to u/c
rm
cpi 7bh
rp
sui 20h
ret
;
; wacc - write ascii character to console, handling ^S/^Q
;
if not cpmio ;if hardware I/O
wacc: push psw ;save user's A
in consta ;get status
ani rda ;see if something typed
jz wacc1 ;no, do straight output
in condat ;yes, get char.
cpi cntrls ;test for ^S
jz wacc2 ;yes, do wait loop
wacc1: in consta ;get status again
ani tbe ;test tbe
jz wacc+1 ;not there, wait
pop psw ;restore character
out condat ;send it
ret ;exit
wacc2: in consta ;wait for ^Q
ani rda
jz wacc2 ;wait for a key
in condat
cpi cntrlq ;test if ^Q
jnz wacc2 ;no, get another
jmp wacc1 ;return & output
endif
;
if cpmio ;if running w/ CP/M I/O calls
wacc: push b ;save user registers
push d
push h
push psw
mov c,a ;put char in C
mvi a,conout ;do conout function
call cbios
pop psw
pop h ;restore user registers
pop d
pop b
ret
endif
;
if cpmio ;link to CP/M I/O handler
;
; cbios - call bios routine
;
cbios: push h
push d
lhld wboot+1
sui 3
mov e,a
mvi d,0
dad d
pop d
xthl
ret
endif
;
; delay - delay @(A) milliseconds
;
delay: mvi c,0b0h ;time constant (2 mhz)
delay1: dcr c
jnz delay1
dcr a
jnz delay
ret
;
; const - see if user has typed anything
;
if not cpmio ;if using hardware I/O calls
const: in consta ;get status
ani rda ;test rda
rz ;A=0=nothing
mvi a,0ffh ;A=FF=something
ret
endif
;
if cpmio ;if using CP/M I/O calls
const: push h ;save registers
push d
push b
mvi a,conrdy ;issue cbios call
call cbios
pop b
pop d
pop h
σσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσin rdrdat ;get data
ani 7fh ;strip parity
ret ;exit to caller
;
; message text area - all texts go here
;
;
cs: db 27,28,0 ;clear screen code, terminated w/ a zero
;
signon: db 'SYSMON 02.00 - 04/10/81',cr,lf
;
if help
db 'Type ? for command summary...',cr,lf
endif
;
db 0
;
badcom: db bell,'Unknown command',cr,lf,0
;
badstx: db bell,'Syntax error in command',cr,lf,0
;
badval: db bell,'Non-hexadecimal value entered',cr,lf,0
;
moveto: db 'Move to? ',0
;
fillw: db 'Fill with? ',0
;
twopar: db bell,'Two parameters are required',cr,lf,0
;
wutdsk: db bell,'Disk drive not ready...',cr,lf,0
;
booter: db bell,'Boot error, controller status: ',0
;
nosys: db bell,'No system image on disk...',cr,lf,0
;
baddr: db bell,bs,' <-- Bad address entered...',cr,lf,0
;
askfil: db 'Filename? ',0
;
askply: db cr,lf,'Press PLAY on tape unit...',cr,lf,0
;
found: db cr,lf,'Found ',0
;
loadng: db cr,lf,'Loading...',0
;
execad: db cr,lf,'Execute address: ',0
;
cksume: db cr,lf,bell,'Checksum error!',cr,lf,0
;
regmsg: db 'Register set:'
db cr,lf,' PC: ',0
regsp: db cr,lf,' SP: ',0
regaf: db cr,lf,' AF: ',0
regbc: db cr,lf,' BC: ',0
regde: db cr,lf,' DE: ',0
reghl: db cr,lf,' HL: ',0
;
ilsum1: db cr,lf,bell,'Illegal SVC (',0
ilsum2: db ') from user PC: ',0
;
if help
hlpmsg: db cr,lf,' *** Command Summary ***',cr,lf,lf
db ' B - Boot operating system from disk.',cr,lf
db ' D [start] [end] - Dump memory in ascii & hex from',cr,lf
db ' [start] to [end], inclusive.',cr,lf
db ' E [address] - Enter hex data beginning at [address].',cr,lf
db ' Terminate w/ blank line.',cr,lf
db ' F [start] [end] - Fill memory with constant value. The',cr,lf
db ' system will ask for the [constant].',cr,lf
db ' G [address] - Jump to [address] and execute the code',cr,lf
db ' there. Exit w/ a RET instruction.',cr,lf
db ' H - Halt the computer.',cr,lf
db ' I [port] - Input and display the data at [port].',cr,lf
db ' L - Load diagnostic tape from tape unit.',cr,lf
db ' - The system will ask for the [filename].',cr,lf
db ' M [from] [len] - Move [len] bytes of data from address',cr,lf
db ' [from]. The system will ask for the',cr,lf
db ' [to] address.',cr,lf
db ' O [port] [data] - Output [data] to [port].',cr,lf
;
if testing
db ' Q - Quit and return to operating system.',cr,lf
endif
;
db ' R - Display 8080 register set.',cr,lf
db ' S - Perform load of diagnostics disk.',cr,lf
;
if testing
db ' T [call] - Tests user SVC [call] with whatever is',cr,lf
db ' currently in BC, DE, & HL.',cr,lf
endif
;
db lf
db ' [addr]/ - Open memory location [addr] and display',cr,lf
db ' its contents. Enter CR to return to the',cr,lf
db ' prompt, LF to open the next location, ^',cr,lf
db ' to open the previous one, or 2 hex dig-',cr,lf
db ' its to replace the ones displayed.',cr,lf
db lf
db ' Arguments default to 100h except for M & F, which must be',cr,lf
db 'explicitly entered. Do not enter the [], they are used only',cr,lf
db 'for illustration. Arguments may be seperated by '','' or '' ''.',cr,lf
db lf
db 0
endif
;
end