;01.30.81 17:51 RJC: Renamed "form" "edm1" and "form2" "edm2". ; Moved "edm1" "edm2" "phi" and "prmpt" to ; spare bytes of RSTs. Removed CICO and ; it's entry in the jump table. Added ; RAM byte "echofl" and code to set it on ; pwrup, and at "loader:" and "done:". ; Changed CI to echo if "echofl"=0 only. ; Effect is to turn off echo on "l" comnd. ; WARNING! Jump table changed (sorry). ;12.03.80 00:00 RJC: CR delay: removed "CRDLY equ", added "sta ; dlyram" after "answer" init, changed all ; "mvi a,' '" to "xra a" to init answer, ; moved pwrup "answer" and "dlyram" init ; to before printing of startup message, ; changed "mvi a,CRDLY+1" to "lda dlyram" ; in CO, changed "jz" to "jm" in CO, added ; "dlyram db 1" to RAM constants. ; Changed "rz" to "rnz" in CO. ; Removed extraneous "cpi 'D'" at end of "d_p" ;11.21.80 17:13 RJC: Added "jmp comnd" to jump table. ;11.10.80 20:01 RJC: Changed restart vectors to vector ALL ; interrupts except RST0 to RAM. ; Rewrote comments in beginning and "loader" ;10.14.80 22:58 RJC: Added initialization of "answer" on power up ; Added "ath" entry point in "ghd" and added ; to jump table. ;05.10.80 12:17 RJC: Removed extraneous "jmp error" in goto cmd. ; Changed "rst 0" to "ret" in edit comments. ; Changed "jmp msg" to "call msg" "ret"; prbad ;05.01.80 16:12 RJC: Modified comment about tying RxD to DSR/ to ; recommend doing it at TTL signal levels. ;04.29.80 20.17 RJC: Removed "push/pop d" from msg and moved ; "inx h" to before "jz mdn" so that d&e ; point to byte after eol on exit. ; Added "EOL equ 0ffh". ; Changed WIDTH comments from 29 and 53 column ; to 28 and 52 columns. ;04.15.80 19:38 RJC: Changed CO to take character in a-reg. ; Changed repeat to take char in A-register ; and count in C-register. ; Expanded comments in beginning. ; Rearranged comments so that assembled i.lst ; would fit in 80 columns. ;04.11.80 18:16 RJC: Added comment-tie RS232 DSR input to RS232 ; receive data input. ;04.05.80 00:01 RJC: Recalculate cycles not counted by 8253 for ; baud rate calculation. ;04.04.80 17:25 RJC: All functions tested. Monitor "done". ;**************************************************************** ;* * ;* Copyright 1980 Raymond J. Clark * ;* * ;* Permission is granted to copy this material in * ;* whole or in part by any means and for any purpose * ;* other than sale, barter, or profit of any kind. * ;* In return it is requested that this notice * ;* accompany the portion copied in recognition of the * ;* time and effort spent developing it. * ;* * ;**************************************************************** ; ; **** sccs-85 1024 byte monitor **** ; ; **** Start up message: **** ; **** **** ; **** Mxxx.v **** ; **** xxx = last used address **** ; **** v = version number which **** ; **** is incremented every **** ; **** time code is changed. **** ; ; Hardware configuration assumed: ; ; 8253: Timer 1 clock input driven by high frequency ; greater than 20*baud-rate. Lower frequencies ; may work if freq/(16*n) is within 5% of baud ; rate where n is some integer. Monitor finds n. ; 8251: RxC and TxC driven by 8253 timer 1 output. ; DSR/ input same as RxD input. See "baud1" ; RAM: From RAM to RAM+03fH ; From MEMTOP down for internal storage and stack ; ; On power up type "d". 8253 divisor calculated automatically. ; ; With 4 MHz crystal: ; Works from 150 to 9600 baud. ; ; With 3.579 MHz Color Burst crystal: ; Works from 110 to 9600 baud. Communicates at ; 19200 baud but tape load function will not work. ; ; ; *** Commands: ; ; L load intel hex tape. Bias not implemented. ; "answer" = G on exit if no errors detected. ; If errors were found, answer = B ; E edit memory in hex. See comments in code. ; G goto address. Stack pointer reset. ; D dump memory in hex. ; P punch intel hex tape. ; (cr) nop. Does not change one byte "answer" ; ? print one byte message (answer) left by last ; command. This is cleared before the execution ; of each command. ; ; The "answer" is cleared before each command is run, ; except ? and (cr) do not clear it. ; ; The L, G, D, and P commands call an "ok" subroutine to ; give you a last chance to abort the command. A (cr) will ; go ahead and execute the command, anything else aborts. ; ; RAM address MEMTOP contains a number from 00h to 80h ; which is the number of times d10ms is to be called after ; outputing each carriage return (0dh). On rst 0 it is ; initialized to 00h. It will have to be made non-zero ; for some terminals, up to 40h for some. BASE equ 00000h ;base address of monitor RAM equ 1000h ;address of first byte of RAM MEMTOP equ 1fffh ;address of last byte of RAM EOL equ 0ffh ;end of string (line) character WIDTH equ 0fh ;controls the width of "dump" "punch" ; ;commands: ; ; 0fh = 16 bytes, 52 columns ; ; 07h = 8 bytes, 28 columns time1 equ 21h timctl equ 23h sercon equ 01h serdat equ 00h ;================================================================ ; ; vectors for hardware interrupts ; rst0 equ RAM+ 000h ; not used - monitor reset rst1 equ RAM+ 008h ; rst2 equ RAM+ 010h ; rst3 equ RAM+ 018h ; rst4 equ RAM+ 020h ; trap equ RAM+ 024h ; rst5 equ RAM+ 028h ; rst55 equ RAM+ 02ch ; rst6 equ RAM+ 030h ; rst65 equ RAM+ 034h ; rst7 equ RAM+ 038h ; rst75 equ RAM+ 03ch ; ;================================================================ ; ; RST 0 entry point - power up reset ;rst 0 org BASE+0 lxi sp,STACKINIT ; initialize stackpointer jmp entry nop nop ;================================================================ ; ; RST 1 entry point org BASE+08h ; rst 1 jmp rst1 ; phi: db ' TO ' ;these lines were moved from the db EOL ;ROM constant sect. to save space ;================================================================ ; ; RST 2 entry point org BASE+10h ; rst 2 jmp rst2 edm1: db ') = ' ;these lines were moved from the db EOL ;ROM constant sect. to save space ;================================================================ ; ; RST 3 entry point org BASE+18h ; rst 3 jmp rst3 edm2: db 0dh, 0ah ;these lines were moved from the db '(' ;ROM constand sect. to save space db EOL ; nop ;================================================================ ; ; RST 4 entry point org BASE+20h ; rst 4 jmp rst4 nop ;================================================================ ; ; TRAP entry point org BASE+24h ; trap jmp trap nop ;================================================================ ; ; RST 5 entry point org BASE+28h ; rst 5 jmp rst5 nop ;================================================================ ; ; RST 5.5 entry point org BASE+2ch ; rst 5.5 jmp rst55 nop ;================================================================ ; ; RST 6 entry point org BASE+30h ; rst 6 jmp rst6 nop ;================================================================ ; ; RST 6.5 entry point org BASE+34h ; rst 6.5 jmp rst65 nop ;================================================================ ; ; RST 7 entry point org BASE+38h ; rst 7 jmp rst7 nop ;================================================================ ; ; RST 7.5 entry point ;rst 5.5 org BASE+3ch jmp rst75 nop ;================================================================ ;================================================================ org BASE+40h ; Jump table for monitor subroutines ; ; All references to these labels should go through this ; so that changes in the actual routine's location in ; future versions of the monitor do not effect non-monitor ; programs. These locations will never change. ; jmp CI ;char returned in A register jmp CO ;char passed in A register jmp crlf ;prints (cr) (lf) jmp ghw ;word ret in h&l or cy=1 & bad char in A jmp ghb ;byte ret in A or CY=1 & bad char in A jmp ghd ;digit ret in A or CY=1 & bad char in A jmp msg ;address of EOL terminated msg in d&e jmp phw ;word passed in h&l jmp phb ;byte passed in A jmp phd ;digit passed in A jmp space ;print space jmp sub16 ;(h&l) <- (h&l) - (d&e) jmp ucase ;upper to lower case conversion jmp ath ;ascii to hex conversion jmp comnd ;beginning of monitor command loop ; jmp cmp16 ;uncomment when cmp16 routine included ; Power-up and Reset initialization ; ;Twiddle, twiddle little thumbs. . . . ; entry: equ $ ; ; ; hardware mvi a,10 ; ; delay is twiddle:call d10ms ;delay 10 mS ; long dcr a ; ; enough jnz twiddle ; ; ; now initialize usart chip ; mvi a,082h ;force usart to expect command word out sercon mvi a,040h ;now make usart to expect mode word out sercon ; mvi a,0ceh ;mode byte - out sercon ; 11 00 11 10 ; ; | | | ------- X16 clock ; ; | | --------- 8 bits of data ; ; | ------------ no parity ; ; --------------- 2 stop bit ; mvi a,037h ;command byte - out sercon ; 0 0 1 1 0 1 1 1 ; ; | | | | | | | -- xmit enable ; ; | | | | | | ---- dtr/ = 1 ; ; | | | | | ------ rcvr enable ; ; | | | | -------- norm op, (not break) ; ; | | | ---------- reset error flags ; ; | | ------------ rts/ = 1 ; ; | -------------- 1 = internal reset ; ; ---------------- asyncronous mode ; ; Calculate baud rate assuming user types a control-d ; ; ***** DSR/ must be connected to RxD. * ; * ; These could be connected on the RS232 side of the * ; 1489 RS232 receiver. On the SCCS-85 be sure to cut the * ; trace on the bottom of the board connecting the RS232 * ; dataset ready input to the +12 volt power supply. * ; An RS232 transmiter is only intended to drive one * ; RS232 receiver. For this reason it would be better to * ; to connect these at TTL signal levels between the 1489 * ; and the 8251. This can be done by jumpering pins 3 * ; and 22 on the 8251. Be sure to disconnect the output * ; of the 1489 that was originally driving the 8251 DSR/ * ; pin. Either bend pin 3 up on the 1489 so that it does * ; not go in the socket or cut the trace from the 1489 to * ; the 8251. * ; baud1: in sercon ;wait for line to drop rlc ; jnc baud1 ; ; mvi a,070h ;set up timer to time next 4 bits out timctl ; mvi a,-35 ; 8085 ;34 cycles not counted by timer ; mvi a,-41 ; 8080 ;40 cycles not counted by timer out time1 ; plus one for +1 after 1's comp mvi a,0ffh ; out time1 ; ; ; at baud1: ;avg time out of loop after drop. ; ; loop 24 cycles long..............- 12 ; ;rlc................................- 4 ; ;jnc baud1...with cy=0 8085/8080 - 7/10 ; ;mvi a,070h......................- 7 ; ;out timctl......................- 10 ; ;mvi a,-35.......................- 7 ; ;out time1.......................- 10 ; ;mvi a,0ffh......................- 7 ; ;out time1.......................- 10 ; ; at baud4: ;avg time into loop since rose. ; ; loop 24 cycles long..............+ 12 ; ;rlc................................+ 4 ; ;jnc baud4 with cy=0 8085/8080 + 7/10 ; ;mvi a,40h.......................+ 7 ; ;out timctl......................+ 10 ; ; ------ ; ;total cycles not counted by timer..-34/40 ; ; 8085/80 ; baud3: in sercon ;wait for line to rise rlc ; jc baud3 ; baud4: in sercon ;wait for line to drop rlc ; jnc baud4 ; ; mvi a,40h ;counter latching command out timctl ; mvi a,70h ;set up timer to read lsb,msb out timctl ; in time1 ;get lsb of count mov l,a ; in time1 ;get msb of count mov h,a ; mov a,l ;compliment count - don't need to cma ; add one because taken into mov l,a ; account in initial load of mov a,h ; counter. cma ; mov h,a ; ; mvi c,6 ;shift count right 6 baud5: ora a ;cy=0 to come in left end of H mov a,h ; rar ; mov h,a ; mov a,l ; rar ; mov l,a ; dcr c ; jnz baud5 ; aci 0 ;round mov l,a ; mov a,h ;propagate possible round-up aci 0 ; carry into H. mov h,a ; ; ; initialize timer chip to generate 16X baudrate for ; mvi a,76h ;init timer 1 to divide by n out timctl ; mov a,l ; out time1 ; mov a,h ; out time1 ; ; ; Initialize "answer" ; xra a ; on power up answer is blank sta answer ; sta echofl ; 0=echo 1=no echo sta dlyram ; number of 10ms delays on ; ; Print startup message ; lxi d,start ;print startup message call msg ; ; in serdat ;eat possible garbage character ; ; COMMAND LEVEL - get character; jump to appropriate routine comnd: equ $ lxi d,prmpt ;print command prompt call msg ; call CI ; call space ; ; ani 7fh ;put in if ucase taken out call ucase ;convert low to up case & strips parity ; cpi 0dh ;special case, (cr) is nop that does not jz comnd ; clear the answer ; lxi d,comnd ;addr for pseudo call completed by pchl push d ; ; cpi '?' ;special case '?', must not clear jz ask ; answer first. ; lxi h,cmds ;scan command table cmdnxt: cmp m ; jz cmdfnd ;if matches go process inx h ; inx h ; inx h ; mov b,m ;check for end of table dcr b ; jp cmdnxt ;not end...try next entry ; error: call prbad ;print error message and return. "comnd" ret ; is on stack as return addr for command ; cmdfnd: equ $ push psw xra a ;clear answer sta answer ; pop psw inx h ;get address mov e,m ; inx h ; mov d,m ; xchg ; pchl ; ; ;****************** end of command level ************************ ;**************************************************************** ; ; print one byte note left by last command ; ask: call space lda answer call CO ret ; ;***************** end of 20 questions ************************** ;**************************************************************** ; GOTO routine - starts execution in memory location goto: call ghw ;get hex word jc error ; call okck ; rc ; ; lxi sp,STACKINIT ;initialize stack pointer pchl ;jmp to location, return addr is on stack ; ;*************** end of goto routine **************************** ; ; ;**************************************************************** ; Memory editor routine ; ; MEMED - Hexadecimal Memory Editor ; ; 1) Computer types (cr),(lf),"(" ; 2) User enters one of the following: ; a) Valid Hex Word (four hex digits) - goto ; step 3 ; b) "/" - Exit editor by doing a "ret" ; c) Anything else - type " what ?" and ; goto 1 ; 3) Computer types ") = xx ", where xx is the con- ; tents (in hex) of the memory byte addressed. ; 4) The user now has a number of things he can ; type: ; a) Valid Hex Byte (two hex digits) - overwrite ; the memory location addressed with this ; byte. Then read another character from ; the user and continue with 4b. ; ; b) A non-hex character - do one of the follow- ; ing: ; ; i) (cr) or " " - Address the next sequen- ; tial location and print the address and ; contents like this: ; ; (cr),(lf),"(addr) = xx " ; ; ii) '.' - Re-display the same location like ; this: ; ; (cr),(lf),"(addr) = xx " ; ; iii) "-" - Address the next previous loca- ; tion and print the address and contents ; like this: ; ; (cr),(lf),"(addr) = xx " ; ; iv) "/" - Goto step 1 and read a new ad- ; dress ; ; v) Anything else - Type " what ; ?" and treat like a "." ; ; Note - If option "a" is not executed then memory ; is not altered. ; memed: lxi d,edm2 ;print "cr, lf, (" call msg call ghw jnc ok ;get hex word into HL, jump if valid cpi '/' ;bad char received - was it "/" rz ;go back to command level if so call prbad ;print "what ?" jmp memed ;then try again ok: call discon ;display contents of location call edit ;then begin editing jmp memed ;loupe if edit returns ; ; end memed ; ; ; Get either a new hex byte to be written where HL points, ; followed by another command, or just another command. ; edit: call ghb ;get the new hex byte if typed jc next ;jmp if other than hex byte received mov m,a ;else store it in memory call space ;space to reinforce that once two digits ; ; are entered, location is changed. call CI ;and get another char & echo it ani 7fh ;kill top bit ; next: cpi 0dh ;carriage return? jnz e1 inx h jmp pr ;yes- print NEXT location ; e1: cpi ' ' ;or blank jnz e2 inx h jmp pr ;yes- do the same ; e2: cpi '.' ; period? jz pr ;print current location ; e3: cpi '-' ; dash? jnz e4 dcx h jmp pr ;yes - print previous location ; e4: cpi '/' ;slash? rz ;edit all done if so ; call prbad ;if none of the above, print "what ?" ; pr: call dismem ;display the new current memory location jmp edit ;and loop ; Print CR, LF then an ( followed by the contents of HL in hex. dismem: lxi d,edm2 ;do cr,lf, "(" call msg call phw call discon ret ; ; **** discon **** ; ; print ') = ' followed by the contents of the memory loc. ; pointed to by HL ; discon: lxi d,edm1 call msg mov a,m ;get contents of mem loc. call phb ;print it call space ret ; ; ;********************** end of memory editor ******************** ;**************************************************************** ; ; Hex-format loader ; ; ":" record mark ; xx record length - number of data bytes ; xxxx load address of first byte, remaining bytes in ; record go sequentially ; xx record type - "00" = data, "01" = eof ; ... data bytes ; xx check sum such that sum of ALL hex bytes, ; including checksum = 0 ; ; NOTE: record length = 00 taken as eof ; loader: sta echofl ;non-zero value (l) turns off echo ; ; load1: call getrec ;read in one rec, (a) = record length ora a ;set z-flag on record length mvi a,'G' ;answer to question = Good jz done ;if length = 0 then done ; mov a,d ;(d) = error flag on getrec return ora a ;see if the "error" flag is non-zero. jz load1 ;if not, go do next record ; mvi a,'B' ;store "Bad" flag in answer to question done: sta answer ; xra a ;zero echofl to turn off echo sta echofl ; ret ;return to command level ; ; end loader ; ; ; *** getrec *** read in one record ; getrec: call fndmrk ;skip to record mark ; call lghb ;get the record length mov c,a ; into the C reg. ; call lghb ;get load address field into h & l mov h,a ; call lghb ; mov l,a ; ; call lghb ;get the record-type byte and ignore ; call data ;put the next (C) bytes into memory ; ;starting where HL points call lghb ;read the checksum byte ; mov a,c ;put the record length back into A reg. ; ret ;return from getrec. (d) contains the ; ; sum off all hex bytes read, and so ; ; is effectively an error flag ; end getrec ; ; ; *** fndmrk *** - find record mark ; ignores all text until ":" found, then ret ; fndmrk: call CI ;get character ani 07fh ;strip off 8th bit cpi ':' ; jnz fndmrk ;not record mark - get next char ; mvi d,0 ;clear D register (error accumulator) ret ; ; ; end fndmrk ; ; *** data *** - input all data bytes ; (c) = number of bytes to read in ; (d) = error flag accumulator maintained by lghb ; data: mov b,c ;copy C reg. to B loop: mov a,b ;get remaining byte count ora a ;get flags rz ;return from subr. if none left dcr b ;else decrement b reg. call lghb ;get byte from data field mov m,a ;store in memory inx h ;bump pointer jmp loop ;go back for next char. ; ; end data ; ; ; *** lghb *** - loader get hex byte ; same as ghb except adds byte gotten to error ; accumulator in d register ; lghb: call ghb ;get byte push psw ;save byte add d ;add to (d) mov d,a ;put sum in d-reg pop psw ;restore byte ret ; ; ; end lghb ; ;************* end of loader ************************************ ; ;**************************************************************** ; ; Common code for dump and punch routine. ; Must not destroy a-register ; d_p: lxi d,plo ;prompt for lo limit call msg call ghw jc error ;jump if error lxi d,phi ;prompt for hi limit call msg xchg call ghw xchg jc error call okck rc ;return if aborted by okck call ; ; (h&l) = beginning address (d&e) = ending address ; push h ; call sub16 ;calc number of bytes to be processed xchg ; pop h ; dcx d ;d&e = number of bytes ; ; Call routine originally requested ; cpi 'P' jz punch ; else dump ; ; Dump routine ; dump: call crlf ;go to new line call phw ;print memory address mov a,l ;make locations with same lower 4 bits ani WIDTH ; land in same columns in first line mov c,a ; as in other lines add a ;multiply by 3... add c ; mov c,a ;move count to c mvi a,' ' ;space over to appropriate column call repeat ;print (c) (a) times di1: call space mov a,m ;get byte call phb ;print it inx h ;point to next byte inx d ;decrement count of number of bytes left mov a,e ; ora d ; rz ;return if zero left mov a,l ani WIDTH ;print crlf on multiple of 16 jnz di1 call crlf ;go to new line call phw ;print memory address jmp di1 ; ;******************* end of dump ******************************** ; ; *** Punch Hex Tape in INTEL format *** ; ;preliminary processing done at d_p ; punch: call crlf ; mvi a,':' ;print record mark call CO ; mov a,e ;calc number of bytes in record cma ; & start accumulating check sum ani WIDTH ; inr a ; call phb ;print number of bytes in record add h ;add load address to check sum add l ; mov b,a ;initialize checksum call phw ;load address xra a ; call phb ;record type ; pnxtbyt:mov a,m ; call phb ; add b ;accumulate checksum mov b,a ; inx d ; mov a,e ; ora d ; jz pdone ; inx h ; mov a,e ;test for end of record ani WIDTH ; jnz pnxtbyt ; ; mov a,b ;end of record processing cma ;compliment checksum inr a ; call phb ; jmp punch ; ; pdone: mov a,b ;compliment last checksum cma ; inr a ; call phb ; lxi d,endrec ; call msg ; ret ; ; ; ; end punch ; ; ; ;**************************************************************** ; ; UTILITY ROUTINES - in alphabetical order (sort of) ; ;**************************************************************** ; ; I/O routines ; ; CI: in sercon ;wait for data ready ani 2 ; jz CI ; in serdat ;get byte push psw ;save psw lda echofl ;check echo flag ora a ; jnz c3 ;if not zero echo-ret on CO pop psw ;echo character ; ; ***** CI must be directly followed by CO so that it can drop ; through !!! ***** ; ;**** CO Console Output - destroys only flags... ; ; ...char passed in a register CO: push psw ; c1: in sercon ; rrc ; jnc c1 ; pop psw ; out serdat ; cpi 0dh ;if cr then delay rnz ; push psw ; lda dlyram ; c2: dcr a ; jm c3 ; call d10ms ;delay 10mS jmp c2 ; c3: pop psw ;used by CI - do not change ret ; ;;****** cmp16 ** 16 bit compare h&l and d&e ******************** ;; ;; if( h&l = d&e ) z=1, cy=0 *** crafty and very *** ;; if( h&l > d&e ) z=0, cy=0 *** useful routine if *** ;; if( h&l < d&e ) z=0, cy=1 *** ever room *** ;; ;cmp16: push h ;save psw & h&l ; push psw ; ; mov a,h ;if h != d enough info found ; sub d ; ; jnz cmp16e ; ; mov a,l ;if h=d then compare lower bytes ; sub e ; ;cmp16e: pop h ; ; mov a,h ; ; pop h ; ; ret ; ;; ; ;; end cmd16 ; ; crlf: push d lxi d,mcrlf call msg pop d ret ; ; d10ms - Delay 10 mS ; d10ms: push h ; push psw ; lxi h,769 ; dtwidl: mov a,l ; ;~0.01 seconds on a 4 MHz 8085 5 ora h ; ; 4 dcx h ; ; 10 jnz dtwidl ; ; 8085/8080 7/10 pop psw ; ; total 26/29 pop h ; ret ; ; ; ; end d10ms ; ; ; GHW - Get Hex Word ; ; Read 4 hex digits frm terminal & convert to 16 bit word ; ; INPUT : None ; OUTPUT : if (no non-hex charaters typed) ; ; (h&l) = hex word typed ; (a) = garbage ; CY = 0 ; else ; (h&l) = garbage ; (a) = bad character as received from CO ; CY = 1 ; ; REGISTERS CHANGED: h, l, flags ; ghw: push b push psw call ghb ; get first byte in a-register jc ghwend ; return if bad char mov h,a ; move byte to final destination call ghb ; get second byte jc ghwend ; mov l,a ; pop b ; mov a,b ; pop b ; ret ; ghwend: pop b ; pop b ; do NOT restore a ret ; ; ; ; end ghw ; ; ; ; GHB - Get Hex Byte ; ; Read 2 hex digits from terminal & convert to 8 bit word ; ; INPUT : None ; OUTPUT : if (no non-hex charaters typed) ; ; (a) = Hex byte typed ; CY = 0 ; else ; (a) = bad character as received from CO ; CY = 1 ; ; REGISTERS CHANGED: a, flags ; ghb: push b ; save b&c call ghd ; get first hex digit in a-reg jc ghbend ; if bad char quit and pass back rlc ; shift to upper half of byte rlc ; . rlc ; . rlc ; . mov b,a ; save first digit call ghd ; get second digit jc ghbend ; bad char read, ret it to caller ; ; ora b ; combine first and second digits ; ; ghbend: pop b ; restore original b&c ret ; ; ; ; end ghb ; ; ; ; GHD - Get Hex Digit ; ; Read 1 hex digit from terminal & convert to 4 bit nibble ; ; INPUT : None ; ; ATH - Ascii To Hex ; ; Alternate entry point does not call CI. User passes ; character to be converted in a-register. ; ; INPUT : character to be converted in a-register ; ; Both: ; ; OUTPUT : if (valid hex character typed) ; ; (a) = 0xh, x = hex digit typed ; CY = 0 ; else ; (a) = bad character as received from CO ; CY = 1 ; ; REGISTERS CHANGED: a, c, flags ; ghd: call CI ; get character & echo ; ani 07fh ; put in if ucase taken out ath: call ucase ; map lower to upper case and ; ; strip parity. cpi '0' rc ; non-hex character cpi ':' ; if (a) =< '9'+1 jc ghd2 ; '0'-'9' typed - convert cpi 'A' ; if (a) < 'A' rc ; non-hex character cpi 'G' ; if (a) >= 'G' cmc ; . rc ; non-hex character sui 07h ; shift 'A'-'F' down ghd2: sui '0' ; convert ret ; ; ; ; end ghd ; ; ; Subroutine to print message pointed to by DE and ; terminated by EOL byte. ; DE left pointing to the byte following the EOL so that ; strings of messages can be easily printed if they are ; in sequntial memory. ; * No other registers destroyed * msg: push psw loupe: ldax d ;get char cpi EOL ;end of string? inx d ;bump pointer jz mdn ;jump if so call CO ;else print it jmp loupe ;do it again mdn: pop psw ret ; ; ; routine to verify an entry ; okck: push d push psw lxi d,mok call msg call CI ani 07fh cpi 0dh jz okckend lxi d,abort call msg stc okckend:pop d mov a,d pop d ret ; ; end okck ; ; ; PHW - Print Hex Word ; ; Convert 16 bit word to ascii and print ; ; INPUT : (h&l) = word to be printed ; OUTPUT : None ; ; REGISTERS CHANGED: None ; phw: push psw ; save a-register and flags mov a,h ; call phb ; print high-order byte mov a,l ; call phb ; print low-order byte pop psw ; restore a-register and flags ret ; ; ; ; end phw ; ; ; ; PHB - Print Hex Byte ; ; Convert 8 bit byte to ascii and print ; ; INPUT : (a) = Byte to be printed ; OUTPUT : None ; ; REGISTERS CHANGED: Flags ; phb: push b ; save b&c mov b,a ; save lower nibble rrc ; shift to lower half of byte rrc ; . rrc ; . rrc ; . call phd ; print upper hex digit mov a,b ; get lower nibble call phd ; ...and print mov a,b ; restore original byte to a pop b ; restore b&c ret ; ; ; ; end phb ; ; ; ; PHD - Print Hex Digit ; ; Convert hex digit to ascii and print it ; ; INPUT : (a) = ?xh where x is the hex digit to be printed ; the ? nibble is immaterial ; OUTPUT : None ; ; REGISTERS CHANGED: flags ; phd: push b ;save a&c mov b,a ; ani 0fh ; mask off lower nibble adi '0' ; convert '0'-'9' to ascii cpi '9'+1 ; if '0'-'9' jc phd1 ; then done adi 'A'-':' ; convert 'A'-'F' phd1: call CO ; print digit mov a,b ;restore registers pop b ; ret ; ; ; ; end phd ; ; ; ; ***** prbad - print ' WHAT ?' **** DESTROYS D&E **** ; prbad: lxi d,bad ; call msg ; ret ; ; ; end prbad ; ; ;Subroutine to print (a) (c) times ; uses a, c...(c) = 0 on exit repeat: inr c ;check for printing (c) 0 times dcr c ; rep1: rz call CO dcr c jmp rep1 ; ; ***** space ***** print space ; space: push psw mvi a,' ' call CO pop psw ret ; ; ***** sub16 ***** 16 bit subtract (h&l) <- (h&l) - (d&e) ; ; if (d&e) < (h&l) CY = 1 ; if (d&e) >= (h&l) CY = 0 ; sub16: push d ; push psw ; mov a,l ; sub e ; mov l,a ; mov a,h ; sbb d ; mov h,a ; pop d ; mov a,d ; pop d ; ret ; ; ; UCASE - subroutine which checks the A reg for a lower case ; ASCII letter. If one present, it is converted to upper case. ; If not present, nothing done. Strips parity first. ucase: ani 07fh ;strip parity cpi 61h cmc rnc ;don't convert if before 'a' cpi 7bh rnc ;don't convert if after 'z' sui 20h ;convert lower to upper ret ; ; ROM constant allocation - alphabetical order (sortof) ; abort: db ' ABORTED !' mcrlf: db 0dh,0ah,EOL bad: db ' WHAT ?' db EOL cmds: db 'L' ;command table dw loader ; db 'E' ; dw memed ; db 'G' ; dw goto ; db 'D' ; dw d_p ;common code for dump and punch db 'P' ; commands. dw d_p ; . db 0 ;end of table mark endrec: db 0dh,0ah ;end of record for punch db ':00000001FF' ; db EOL ;edm1: db ') = ' ;these lines were moved to ; db EOL ;5 extra bytes of RST 2 ;edm2: db 0dh, 0ah ;these lines were moved to ; db '(' ;4 of the 5 bytes of RST 3 ; db EOL ; mok: db ' OK ?' db EOL ;phi: db ' TO ' ;these lines were moved to ; db EOL ;5 extra bytes of RST 1 plo: db ' FROM ' db EOL prmpt: db 0dh, 0ah db ' >' db EOL start: db 0dh,0ah db 'M3FF.E' db 0dh,0ah,EOL ; ; RAM allocation if alphabetical order ; org MEMTOP-2 ;MEMTOP - (# bytes alloc - 1) ; STACKINIT equ $ ;initial stack pointer overlaps ; ;lowest byte allocated. ; answer ds 1 ;answer to question echofl ds 1 ;echo flag: 0=echo 1=no echo dlyram ds 1 ;number of 10mS delays on ; ;range: 00h to 80h ; ; At this point $ should = MEMTOP ; end