home *** CD-ROM | disk | FTP | other *** search
- ;
- ; 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