--- /dev/null
+;\r
+; MON85: A software debugger for the 8080/8085 processor\r
+;\r
+; Copyright 1979-2007 Dave Dunfield\r
+; All rights reserved.\r
+;\r
+; Version 1.2 - 2012 Roman Borik\r
+;\r
+; New in version 1.2\r
+; - Support for undocumented 8085 instructions.\r
+; DSUB B, ARHL, RDEL, LDHI d8, LDSI d8, LHLX D, SHLX D, JNK a16, JK a16, RSTV\r
+; - Command R displays all flags of F register (SZKA3PVC). If flag is not set\r
+; dash '-' is displayed.\r
+; - Added restart vector RST 8 (0040h) for possibility to handle RSTV call.\r
+; - Changed TRACE mode. After entering TRACE mode, instruction on actual PC and\r
+; content of registers (if it is switched on) are displayed.\r
+; Entering a space ' ' executes this instruction, and returns to the 'T>'\r
+; prompt with the next instruction.\r
+; - Instructions LXI, DAD, INX, DCX displays argument 'SP' rather than 'S'.\r
+; - Commands that requires 1 byte parameter raises error if entered value\r
+; not fit to 1 byte.\r
+; - Command 'C' checks overlap of source and destination block and for copying\r
+; uses appropriate direction.\r
+; - Command 'F' checks <start> and <end> parameters and raises error,\r
+; if <end> is lower than <start>.\r
+; - Added command 'H' to send out memory content in Intel HEX format.\r
+; - Sending of LF and CR characters were reversed and are sent in the usual\r
+; order - CR first and followed by LF.\r
+\r
+\r
+ROM EQU 0000h ; Debugger goes here\r
+DRAM EQU 0FFA0h ; Debugger RAM (96 bytes required)\r
+\r
+;\r
+; Debugger data area (in RAM)\r
+;\r
+ ORG DRAM ; Monitor data goes here\r
+;\r
+UBASE: DS 2 ; Base address of user program\r
+HL: DS 2 ; Saved HL register pair\r
+DE: DS 2 ; Saved DE register pair\r
+BC: DS 2 ; Saved BC register pair\r
+PSW: DS 2 ; Saved PSW (A + CC)\r
+SP: DS 2 ; Saved Stack Pointer\r
+PC: DS 2 ; Saved Program Counter\r
+OFLAG: DS 1 ; Output suspended flag\r
+TFLAG: DS 1 ; Flag to enable TRACING\r
+SFLAG: DS 1 ; Flag to enable SUBROUTINE tracing\r
+AFLAG: DS 1 ; Flag to enable AUTO REGISTER DISPLAY\r
+BRKTAB: DS 24 ; Breakpoint table\r
+INST: DS 6 ; Save area for "faking" instructions\r
+BUFFER: DS 48 ; Input/temp buffer & stack\r
+DSTACK EQU $&0FFFFh ; Debugger stack\r
+;\r
+; Startup code... Kick off the monitor\r
+;\r
+ ORG ROM ; Debugger code goes here\r
+;\r
+ LXI SP,DSTACK ; Set up initial stack pointer\r
+ JMP TEST ; Execute main program\r
+ DS 2 ; Filler bytes to first int\r
+;\r
+; Interrupt handlers for RESTART interrupts\r
+;\r
+; Although they RST 1.5, 2.5 and 3.5 vectors are not used by the\r
+; 8085 hardware, they are included since the space must contain\r
+; SOMETHING, and who knows, perhaps someone uses them for jump\r
+; table addresses etc...\r
+;\r
+; Restart 1 is the entry point for breakpoints\r
+RST1: JMP ENTRY ; Execute handler\r
+ DS 1 ; Filler to next int\r
+RST15: CALL RSTINT ; Invoke interrupt\r
+ DB 12 ; Offset to handler\r
+RST2: CALL RSTINT ; Invoke interrupt\r
+ DB 16 ; Offset to handler\r
+RST25: CALL RSTINT ; Invoke interrupt\r
+ DB 20 ; Offset to handler\r
+RST3: CALL RSTINT ; Invoke interrupt\r
+ DB 24 ; Offset to handler\r
+RST35: CALL RSTINT ; Invoke interrupt\r
+ DB 28 ; Offset to handler\r
+RST4: CALL RSTINT ; Invoke interrupt\r
+ DB 32 ; Offset to handler\r
+TRAP: CALL RSTINT ; Invoke interrupt\r
+ DB 36 ; Offset to handler\r
+RST5: CALL RSTINT ; Invoke interrupt\r
+ DB 40 ; Offset to handler\r
+RST55: CALL RSTINT ; Invoke interrupt\r
+ DB 44 ; Offset to handler\r
+RST6: CALL RSTINT ; Invoke interrupt\r
+ DB 48 ; Offset to handler\r
+RST65: CALL RSTINT ; Invoke interrupt\r
+ DB 52 ; Offset to handler\r
+RST7: CALL RSTINT ; Invoke interrupt\r
+ DB 56 ; Offset to handler\r
+RST75: CALL RSTINT ; Invoke interrupt\r
+ DB 60 ; Offset to handler\r
+RST8: CALL RSTINT ; Invoke interrupt\r
+ DB 64 ; Offset to handler\r
+;\r
+; Process a RESTART interrupt, get offset & vector to code\r
+; To speed processing, it is assumed that the user program\r
+; base address begins on a 256 byte page boundary.\r
+;\r
+RSTINT: XTHL ; Save HL, Get PTR to offset\r
+ PUSH PSW ; Save A and CC\r
+ MOV A,M ; Get offset\r
+ LHLD UBASE ; Get high of user program\r
+ MOV L,A ; Set low address\r
+ POP PSW ; Restore A & CC\r
+ XTHL ; Restore HL, set \r
+ RET ; Vector to interrupt\r
+;\r
+; Register -> text translation tables used by the disassembler. These tables\r
+; go here (near beginning) so that we can be sure the high address will not\r
+; cross a page boundary allowing us to index by modifying low address only.\r
+;\r
+RTAB: DB "BCDEHLMA" ; Table of register names\r
+RPTAB: DB "BDHS" ; Table of register pairs\r
+;\r
+; Entry point for breakpoints & program tracing\r
+;\r
+; Save the user program registers\r
+ENTRY: SHLD HL ; Save HL\r
+ XCHG ; Get DE\r
+ SHLD DE ; Save DE\r
+ POP H ; Get RET addrss\r
+ SHLD PC ; Save PC\r
+ PUSH B ; Copy BC\r
+ POP H ; And get it\r
+ SHLD BC ; Save PC\r
+ PUSH PSW ; Copy PSW\r
+ POP H ; And get it\r
+ SHLD PSW ; Save PSW\r
+ LXI H,0 ; Start with zero\r
+ DAD SP ; Get SP\r
+ SHLD SP ; Save SP\r
+ LXI SP,DSTACK ; Move to our stack\r
+ LHLD PC ; Get RET addrss\r
+ DCX H ; Backup to actual instruction\r
+ SHLD PC ; Save PC\r
+ LXI D,BRKTAB ; Point to breakpoint table\r
+ MVI B,'0' ; Assume breakpoint #0\r
+; Search breakpoint table & see if this is a breakpoint\r
+TRYBRK: LDAX D ; Get HIGH byte from table\r
+ INX D ; Advance\r
+ CMP H ; Does it match?\r
+ LDAX D ; Get LOW byte from table\r
+ INX D ; Advance\r
+ JNZ NOTBRK ; No, try next\r
+ CMP L ; Does it match?\r
+ JZ FOUND ; Yes, we have an entry\r
+NOTBRK: INX D ; Skip saved code byte\r
+ INR B ; Advance breakpoint number\r
+ MOV A,B ; Get breakpoint number\r
+ CPI '0'+8 ; Table exausted\r
+ JC TRYBRK ; No, keep looking\r
+; This interrupt is NOT a breakpoint\r
+ JMP NOBK ; Enter with no breakpoint\r
+; This interrupt is a breakpoint, display the message\r
+FOUND: CALL PRTMSG ; Output message\r
+ DB "** Breakpoint ",0\r
+ MOV A,B ; Get breakpoint number\r
+ CALL OUT ; Output it\r
+ CALL CRLF ; New line\r
+; Reenter monitor, first, restore all breakpoint opcodes\r
+NOBK: LXI H,BRKTAB ; Point to breakpoint table\r
+ MVI B,8 ; 8 breakpoints\r
+FIXL: MOV D,M ; Get HIGH address\r
+ INX H ; Advance\r
+ MOV E,M ; Get LOW address\r
+ INX H ; Advance\r
+ MOV A,D ; Get high\r
+ ORA E ; Test for ZERO\r
+ JZ NOFIX ; Breakpoint is not set\r
+ MOV A,M ; Get opcode\r
+ STAX D ; And patch user code\r
+NOFIX: INX H ; Skip opcode\r
+ DCR B ; Reduce count\r
+ JNZ FIXL ; Not finished, keep going\r
+ LDA TFLAG ; Get trace mode flag\r
+ ANA A ; Is it enabled?\r
+ JNZ TRTB ; Yes, enter trace mode\r
+ LDA AFLAG ; Get auto register display flag\r
+ ANA A ; Is it enabled?\r
+ CNZ REGDIS ; Yes, display the registers\r
+ JMP REST ; Enter monitor\r
+; Prompt for and handle trace mode commands\r
+TRTB: CALL PRTMSG ; Output message\r
+ DB "T> ",0 ; Trace mode prompt\r
+ LHLD PC ; Get PC\r
+ XCHG ; Move to DE\r
+ CALL DINST ; Disassemble the instruction\r
+ CALL CRLF ; New line\r
+ LDA AFLAG ; Get auto register display flag\r
+ ANA A ; Is it enabled?\r
+ CNZ REGDIS ; Yes, display the registers\r
+TRL: CALL INCHR ; Get a command character\r
+ CPI ' ' ; Execute command?\r
+ JZ NOADR ; Yes, handle it\r
+ CPI 1Bh ; ESCAPE?\r
+ JZ RECR ; Yes, abort\r
+ CPI '?' ; Register display?\r
+ JNZ TRL ; No, ignore it\r
+ CALL REGDIS ; Display the registers\r
+ JMP TRTB ; And go again\r
+;\r
+; Main entry point for the 8080 debugger\r
+;\r
+TEST: CALL INIT ; Set up hardware\r
+ CALL PRTMSG ; Output herald message\r
+ DB 0Dh,0Ah\r
+ DB "MON85 Version 1.2"\r
+ DB 0Dh,0Ah,0Ah\r
+ DB "Copyright 1979-2007 Dave Dunfield"\r
+ DB 0Dh,0Ah\r
+ DB "2012 Roman Borik"\r
+ DB 0Dh,0Ah\r
+ DB "All rights reserved."\r
+ DB 0Ah,0\r
+ LXI H,UBASE ; Point to start of reserved RAM\r
+ MVI C,(DSTACK-UBASE)&0FFh ; Number of bytes to zero\r
+INIL1: MVI M,0 ; Clear a byte\r
+ INX H ; Advance\r
+ DCR C ; Reduce count\r
+ JNZ INIL1 ; Clear em all\r
+ LXI H,0FFFFh ; Set flags\r
+ SHLD SFLAG ; Turn on SUBTRACE & AUTOREG\r
+ LXI H,UBASE ; Default user stack (below monitor RAM)\r
+ SHLD SP ; Set user SP\r
+; Newline and prompt for command\r
+RECR: CALL CRLF ; Output a newline\r
+; Prompt for an input command\r
+REST: LXI SP,DSTACK ; Reset stack pointer\r
+ CALL PRTMSG ; Output message\r
+ DB "C> ",0 ; Command prompt\r
+ CALL INPT ; Get command character\r
+; Look up command in table\r
+ MOV B,A ; Save for later\r
+ LXI H,CTABLE ; Point to command table\r
+REST1: MOV A,M ; Get char\r
+ INX H ; Advance\r
+ CMP B ; Do it match?\r
+ JZ REST2 ; Yes, go for it\r
+ INX H ; Skip HIGH address\r
+ INX H ; Skip LOW address\r
+ ANA A ; end of table?\r
+ JNZ REST1 ; Its OK\r
+; Error has occured, issue message & return for command\r
+ERROR: MVI A,'?' ; Error indicator\r
+ CALL OUT ; Display\r
+ JMP RECR ; And wait for command\r
+; We have command, execute it\r
+REST2: INX D ; Skip command character\r
+ MOV A,M ; Get low address\r
+ INX H ; Skip to next\r
+ MOV H,M ; Get HIGH address\r
+ MOV L,A ; Set LOW\r
+ CALL SKIP ; Set 'Z' of no operands\r
+ PCHL ; And execute\r
+; Table of commands to execute\r
+CTABLE: DB 'A' ; Set AUTOREG flag\r
+ DW AUTO\r
+ DB 'B' ; Set/Display breakpoint\r
+ DW SETBRK\r
+ DB 'C' ; Copy memory\r
+ DW COPY\r
+ DB 'D' ; Disassemble\r
+ DW GODIS\r
+ DB 'E' ; Edit memory\r
+ DW EDIT\r
+ DB 'F' ; Fill memory\r
+ DW FILL\r
+ DB 'G' ; Go (begin execution)\r
+ DW GO\r
+ DB 'H' ; Send out memory as Intel HEX\r
+ DW SNDHEX\r
+ DB 'I' ; Input from port\r
+ DW INPUT\r
+ DB 'L' ; Load from serial port\r
+ DW LOAD\r
+ DB 'M' ; Memory display\r
+ DW MEMRY\r
+ DB 'O' ; Output to port\r
+ DW OUTPUT\r
+ DB 'R' ; Set/Display Registers\r
+ DW REGIST\r
+ DB 'S' ; Set SUBTRACE flag\r
+ DW SUBON\r
+ DB 'T' ; Set TRACE mode\r
+ DW TRACE\r
+ DB 'U' ; Set/Display user base\r
+ DW USRBASE\r
+ DB '?' ; Help command\r
+ DW HELP\r
+ DB 0 ; End of table\r
+ DW REST ; Handle NULL command\r
+;\r
+; Help command\r
+;\r
+HELP: LXI H,HTEXT ; Point to help text\r
+ SUB A ; Get a zero\r
+ STA OFLAG ; Clear the output flag\r
+; Output each line\r
+HELP1: MVI C,25 ; Column counter\r
+HELP2: MOV A,M ; Get character\r
+ INX H ; Advance to next\r
+ ANA A ; End of line?\r
+ JZ HELP4 ; Yes, terminate\r
+ CPI '!' ; Separator?\r
+ JZ HELP3 ; Yes, output\r
+ CALL OUT ; Write character\r
+ DCR C ; Reduce count\r
+ JMP HELP2 ; Keep going\r
+; Fill with spaces to discription column\r
+HELP3: CALL SPACE ; Output a space\r
+ DCR C ; Reduce count\r
+ JNZ HELP3 ; Do them all\r
+ MVI A,'-' ; Spperator\r
+ CALL OUT ; Display\r
+ CALL SPACE ; And space over\r
+ JMP HELP2 ; Output rest of line\r
+; End of line encountered...\r
+HELP4: CALL CHKSUS ; New line\r
+ MOV A,M ; Get next byte\r
+ ANA A ; End of text?\r
+ JNZ HELP1 ; Do them all\r
+ JMP RECR ; And go home\r
+;\r
+; Input from port\r
+;\r
+INPUT: CALL CALC8 ; Get port number\r
+ MVI A,0DBh ; 'IN' instruction\r
+ MVI H,0C9h ; 'RET' instruction\r
+ STA INST ; Set RAM instruction\r
+ SHLD INST+1 ; Set RAM instruction\r
+ CALL PRTMSG ; Output message\r
+ DB "DATA=",0\r
+ CALL INST ; Perform the read\r
+ CALL HPR ; Output it\r
+ JMP RECR ; Newline & EXIT\r
+;\r
+; Output to port\r
+;\r
+OUTPUT: CALL CALC8 ; Get port number\r
+ MVI A,0D3h ; 'OUT' instruction\r
+ MVI H,0C9h ; 'RET' instruction\r
+ STA INST ; Set RAM instruction\r
+ SHLD INST+1 ; Set RAM instruction\r
+ CALL CALC8 ; Get data byte\r
+ CALL INST ; Output the data\r
+ JMP REST ; Back to command prompt\r
+;\r
+; Set breakpoint command\r
+;\r
+SETBRK: JZ DISBRK ; No operands, display breakpoints\r
+; Set a breakpoint\r
+ CALL CALC8 ; Get hex operand\r
+ CPI 8 ; In range?\r
+ JNC ERROR ; No, invalud\r
+ LXI H,BRKTAB-3 ; Point to breakpoint table\r
+ LXI B,3 ; Offset for a breakpoint\r
+SBRLP: DAD B ; Advance to next breakpoint\r
+ DCR A ; Reduce count\r
+ JP SBRLP ; Go until we are there\r
+ PUSH H ; Save table address\r
+ CALL CALC ; Get address\r
+ POP D ; Restore address\r
+ XCHG ; D=brkpt address, H=table address\r
+ MOV M,D ; Set HIGH address in table\r
+ INX H ; Advance\r
+ MOV M,E ; Set LOW address in table\r
+ INX H ; Advance\r
+ LDAX D ; Get opcode from memory\r
+ MOV M,A ; Save in table\r
+ JMP REST ; And get next command\r
+; Display breakpoints\r
+DISBRK: LXI D,BRKTAB ; Point to breakpoint table\r
+ MVI B,'0' ; Begin with breakpoint zero\r
+DISLP: MVI A,'B' ; Lead in character\r
+ CALL OUT ; Output\r
+ MOV A,B ; Get breakpoint number\r
+ CALL OUT ; Output\r
+ MVI A,'=' ; Seperator character\r
+ CALL OUT ; Output\r
+ LDAX D ; Get HIGH address\r
+ MOV H,A ; Copy\r
+ INX D ; Advance\r
+ LDAX D ; Get LOW address\r
+ MOV L,A ; Copy\r
+ ORA H ; Is breakpoint set?\r
+ JZ NOTSET ; No, don't display\r
+ CALL HLOUT ; Output in hex\r
+ JMP GIVLF ; And proceed\r
+; Breakpoint is not set\r
+NOTSET: CALL PRTMSG ; Output message\r
+ DB "****",0 ; Indicate not set\r
+GIVLF: MVI A,' ' ; Get a space\r
+ CALL OUT ; Output\r
+ CALL OUT ; Output\r
+ MOV A,B ; Get breakpoint address\r
+ CPI '0'+3 ; Halfway through?\r
+ CZ CRLF ; Yes, new line\r
+ INX D ; Skip low byte\r
+ INX D ; Skip opcode\r
+ INR B ; Advance breakpoint number\r
+ MOV A,B ; Get number again\r
+ CPI '0'+8 ; All done?\r
+ JC DISLP ; No, keep going\r
+ CALL CRLF ; New line\r
+ LXI H,AUTMSG ; Message for AFLAG\r
+ LDA AFLAG ; Get flag state\r
+ CALL DISON ; Display ON/OFF indication\r
+ LXI H,SUBMSG ; Message for SFLAG\r
+ LDA SFLAG ; Get flag state\r
+ CALL DISON ; Display ON/OFF indication\r
+ LXI H,TRCMSG ; Message for TFLAG\r
+ LDA TFLAG ; Get flag state\r
+ CALL DISON ; Display ON/OFF indication\r
+ CALL CRLF ; New line\r
+ JMP REST ; Back for another command\r
+; Display ON/OFF flag state\r
+DISON: PUSH PSW ; Save A\r
+ CALL PRTSTR ; Output message\r
+ POP PSW ; Restore A\r
+ LXI H,OFF ; Assume OFF\r
+ ANA A ; Test A\r
+ JZ PRTSTR ; Yes, display OFF\r
+ LXI H,ON ; Convert to ON\r
+ JMP PRTSTR ; And display ON\r
+;\r
+; GO command, Begin program execution\r
+;\r
+GO: JZ NOHEX ; Address not given, assume default\r
+ CALL CALC ; Get argument\r
+ SHLD PC ; Save new PC value\r
+NOHEX: LDA TFLAG ; Get trace flag\r
+ ANA A ; Enabled?\r
+ JNZ TRTB ; Yes, wait for prompt\r
+; Single-step one instruction...\r
+; Used for first instruction even when NOT tracing, so\r
+; that we can insert breakpoints\r
+NOADR: SUB A ; Get NOP\r
+ MOV H,A ; Set high\r
+ MOV L,A ; Set LOW\r
+ STA INST ; Set first byte\r
+ SHLD INST+1 ; Set second & third\r
+ LHLD PC ; Get PC\r
+ XCHG ; Set DE to PC\r
+ CALL LOOK ; Lookup instruction\r
+ MOV B,A ; Save the TYPE/LENGTH byte\r
+ ANI 03h ; Mask TYPE, save LENGTH\r
+ MOV C,A ; Save for count\r
+; Copy instruction into "faking" area\r
+ LXI H,INST ; Point to saved instruction\r
+GOSET: LDAX D ; Get byte from code\r
+ MOV M,A ; Save in instruction\r
+ INX H ; Advance output\r
+ INX D ; Advance input\r
+ DCR C ; Reduce count\r
+ JNZ GOSET ; Copy it all\r
+ XCHG ; HL = addrss to execute\r
+ MVI A,0C3h ; Get a JMP instruction\r
+ STA INST+3 ; Set up a JUMP instruction\r
+ SHLD INST+4 ; Set target address\r
+ LDA TFLAG ; Get trace flag\r
+ ANA A ; Are we tracing?\r
+ JZ NOTRC ; No, we are not\r
+ PUSH B ; Save TYPE/LENGTH\r
+ LHLD INST+4 ; Get termination address\r
+ INX H ; Skip this one\r
+ SHLD BUFFER ; Save for "fake" handling\r
+ LXI H,FAKE ; Point to FAKE routine\r
+ SHLD INST+4 ; Save new addres\r
+ POP B ; Restore TYPE/LENGTH\r
+; Simulate any control transfer instruction\r
+ LDA INST ; Get instruction\r
+ CPI 0E9h ; Is it PCHL?\r
+ JNZ NOPCHL ; No, skip\r
+ LHLD HL ; Get user HL value\r
+ JMP HLJMP ; And simulate a jump\r
+NOPCHL: CPI 0CBh ; Is it RSTV?\r
+ JNZ NORSTV ; No, skip\r
+ LDA PSW ; Get status flags\r
+ ANI 2 ; Check V flag\r
+ JNZ NOTRC ; Is set, execute instruction\r
+ STA INST ; Change to NOP\r
+ JMP NOTRC ; Not set, execute NOP\r
+NORSTV: CPI 0DDh ; Is it JNK?\r
+ JZ JNKJK ; Yes, go\r
+ CPI 0FDh ; Is it JK?\r
+ JNZ NOJNK ; No, skip\r
+JNKJK: ANI 20h ; Save K flag from instruction code\r
+ MOV C,A\r
+ LDA PSW ; Get status flags\r
+ ANI 20h ; Save only K flag\r
+ XRA C ; Compare them\r
+ JZ NOPSH ; If they are equal, make jump\r
+ JMP NOTRC ; No jump \r
+NOJNK: MOV A,B ; Get TYPE back\r
+ CPI 0Bh ; Is it a 'JUMP'\r
+ JZ GOJMP ; Yes, handle it\r
+ CPI 05h ; Is it a 'RETURN'\r
+ JZ CALRET ; Yes, handle it\r
+ ANI 0F8h ; Save only conditional bits\r
+ JZ NOTRC ; Not conditional, always execute instruction\r
+ ANI 08h ; Does this test require COMPLEMENTED flags\r
+ LDA PSW ; Get status flags\r
+ JZ NOCOM ; No need to complement\r
+ CMA ; Invert for NOT tests\r
+NOCOM: MOV C,A ; Save PSW bits\r
+ MOV A,B ; Get conditon back\r
+ RAL ; Is it SIGN flag?\r
+ JC SIGN ; Yes, handle it\r
+ RAL ; Is it ZERO flag?\r
+ JC ZERO ; Yes, handle it\r
+ RAL ; Is it PARITY flag?\r
+ JC PARITY ; Yes, handle it\r
+; This instruction is conditional on the CARRY flag\r
+CARRY: MOV A,C ; Get flag bits\r
+ ANI 01h ; Test CARRY flag\r
+ JMP ENFLG ; And proceed\r
+; This instruction is conditional on the SIGN flag\r
+SIGN: MOV A,C ; Get flag bits\r
+ ANI 80h ; Test SIGN flag\r
+ JMP ENFLG ; And proceed\r
+; This instruction is conditional on the ZERO flag\r
+ZERO: MOV A,C ; Get flag bits\r
+ ANI 40h ; Test ZERO flag\r
+ JMP ENFLG ; And proceed\r
+; This instruction is conditional on the PARITY flag\r
+PARITY: MOV A,C ; Get flag bits\r
+ ANI 04h ; Test PARITY flag\r
+; Execute conditional instruction\r
+ENFLG: JZ NOTRC ; Not executed\r
+ MOV A,B ; Get type back\r
+ ANI 04h ; Is it JUMP\r
+ JNZ CALRET ; No, try next\r
+; Simulate a JUMP instruction\r
+GOJMP: LDA INST ; Get instruction\r
+ CPI 0CDh ; Is it a CALL\r
+ JZ PADR ; Yes\r
+ ANI 0C7h ; Mask conditional\r
+ CPI 0C4h ; Conditional call?\r
+ JNZ NOPSH ; No, its a jump\r
+; Simulate a subroutine trace\r
+PADR: LDA SFLAG ; Get subroutine tracing flag\r
+ ANA A ; Is it set?\r
+ JZ NOTRC ; No, simulate as one instruction\r
+ LHLD BUFFER ; Get termination address\r
+ DCX H ; Backup\r
+ XCHG ; D = address\r
+ LHLD SP ; Get user SP\r
+ DCX H ; Backup\r
+ MOV M,D ; Set HIGH return address\r
+ DCX H ; Backup\r
+ MOV M,E ; Set LOW return address\r
+ SHLD SP ; Resave user SP\r
+; Continue simulation of a JUMP type instruction\r
+NOPSH: LHLD INST+1 ; Get target address\r
+ JMP HLJMP ; And proceed\r
+; Handle simulation of RETURN instruction\r
+CALRET: LHLD SP ; Get sser SP\r
+ MOV E,M ; Get LOW return address\r
+ INX H ; Advance\r
+ MOV D,M ; Get HIGH return address\r
+ INX H ; Advance\r
+ SHLD SP ; Resave user SP\r
+ XCHG ; Set HL = address\r
+; Simulate a jump to the address in HL\r
+HLJMP: INX H ; Advance\r
+ SHLD BUFFER ; Save new target address\r
+ SUB A ; Get NOP\r
+ MOV H,A ; Set HIGH\r
+ MOV L,A ; Set LOW\r
+ STA INST ; NOP first byte\r
+ SHLD INST+1 ; NOP second byte\r
+; Dispatch the user program\r
+; First, insert any breakpoints into the object code\r
+NOTRC: LXI D,BRKTAB ; Point to breakpoint table\r
+ MVI C,8 ; Size of table (in entries)\r
+RESBP: LDAX D ; Get a HIGH address\r
+ MOV H,A ; Save for later\r
+ INX D ; Advance\r
+ LDAX D ; Get low address\r
+ MOV L,A ; Save for later\r
+ INX D ; Advance\r
+ ORA H ; Is breakpoint enabled?\r
+ JZ NORES ; No, its not\r
+ MVI M,0CFh ; Set up a RST 1 breakpoint\r
+NORES: INX D ; Skip opcode\r
+ DCR C ; Reduce count\r
+ JNZ RESBP ; Do them all\r
+; Restore the user applications registers\r
+ LHLD SP ; Get stack pointer\r
+ SPHL ; Set stack pointer\r
+ LHLD BC ; Get BC\r
+ PUSH H ; Save\r
+ POP B ; And set\r
+ LHLD PSW ; Get PSW\r
+ PUSH H ; Save\r
+ POP PSW ; And set\r
+ LHLD DE ; Get DE\r
+ XCHG ; Set DE\r
+ LHLD HL ; Get HL\r
+ JMP INST ; Execute "faked" instruction\r
+; Trace routine: simulate a breakpoint interrupt\r
+FAKE: PUSH H ; Save HL on stack\r
+ LHLD BUFFER ; Get address to execute\r
+ XTHL ; Restore HL, [SP] = address\r
+ JMP ENTRY ; Display the registers\r
+;\r
+; Display/Change registers\r
+;\r
+REGIST: JNZ CHG1 ; Register name to change is given\r
+; Display registers\r
+ CALL REGDIS ; Display registers\r
+ JMP REST ; And exit\r
+; Set register value\r
+CHG1: MOV B,A ; Save first register name char\r
+ CALL GETCHI ; Get char (in upper case)\r
+ MOV C,A ; Save for later\r
+ JZ OKCH ; End of string\r
+; Drop extra characters incase 'PSW'\r
+CHG2: CALL GETCHR ; Get next\r
+ JNZ CHG2 ; Clean them out\r
+; Get new value for register\r
+OKCH: CALL CALC ; Get new value\r
+ MOV A,B ; Get first char\r
+ CPI 'H' ; Is it HL pair\r
+ JNZ CDE ; No, try next\r
+ SHLD HL ; Set HL value\r
+ JMP REST ; And proceed\r
+CDE: CPI 'D' ; Is it DE pair?\r
+ JNZ CBC ; No, try next\r
+ SHLD DE ; Set DE value\r
+ JMP REST ; And proceed\r
+CBC: CPI 'B' ; Is it BC pair?\r
+ JNZ CSP ; No, try next\r
+ SHLD BC ; Set BC value\r
+ JMP REST ; And proceed\r
+CSP: CPI 'S' ; Is it SP?\r
+ JNZ CP ; No, try next\r
+ SHLD SP ; Set SP value\r
+ JMP REST ; And proceed\r
+CP: CPI 'P' ; Is it PS or PC\r
+ JNZ ERROR ; No, error\r
+ MOV A,C ; Get low character\r
+ CPI 'S' ; Is it PSW?\r
+ JNZ CPC ; No, try next\r
+ SHLD PSW ; Set new PSW\r
+ JMP REST ; And proceed\r
+CPC: CPI 'C' ; Is it PC?\r
+ JNZ ERROR ; No, error\r
+ SHLD PC ; Set new PC\r
+ JMP REST ; And proceed\r
+; Process an ON/OFF operand\r
+ONOFF: CALL SKIP ; Get next char\r
+ CPI 'O' ; Must begin with ON\r
+ JNZ ERROR ; Invalid\r
+ CALL GETCHI ; Get next char\r
+ MVI B,0 ; Assume OFF\r
+ CPI 'F' ; OFF?\r
+ JZ RETON ; Yes, set it\r
+ CPI 'N' ; ON?\r
+ JNZ ERROR ; No, error\r
+ DCR B ; Convert to FF\r
+RETON: MOV A,B ; Save new value\r
+ RET\r
+;\r
+; Turn automatic register display ON or OFF\r
+;\r
+AUTO: CALL ONOFF ; Get ON/OFF value\r
+ STA AFLAG ; Set AUTOREG flag\r
+ JMP REST ; And proceed\r
+;\r
+; Turn SUBROUTINE tracing ON or OFF\r
+;\r
+SUBON: CALL ONOFF ; Get ON/OFF value\r
+ STA SFLAG ; Set SUBTRACE flag\r
+ JMP REST ; And proceed\r
+;\r
+; Set TRACE mode ON or OFF\r
+;\r
+TRACE: CALL ONOFF ; Get ON/OFF value\r
+ STA TFLAG ; Set TRACE flag\r
+ JMP REST ; And proceed\r
+;\r
+; Edit memory contents\r
+;\r
+EDIT: CALL CALC ; Get address\r
+EDIT1: CALL HLOUT ; Display address\r
+ CALL SPACE ; Separator\r
+ MOV A,M ; Get contents\r
+ CALL HPR ; Output\r
+ MVI A,'=' ; Prompt\r
+ CALL OUT ; Output\r
+ PUSH H ; Save address\r
+ CALL INPT ; Get a value\r
+ POP H ; Restore address\r
+ INX H ; Assume advance\r
+ JZ EDIT1 ; Null, advance\r
+ DCX H ; Fix mistake\r
+ DCX H ; Assume backup\r
+ CPI '-' ; Backup?\r
+ JZ EDIT1 ; Yes, backup a byte\r
+ INX H ; Fix mistake\r
+ CPI 27h ; Single quote?\r
+ JNZ EDIT3 ; No, try hex value\r
+; Handle quoted ASCII text\r
+ INX D ; Skip the quote\r
+EDIT2: LDAX D ; Get char\r
+ INX D ; Advance input\r
+ ANA A ; End of loop?\r
+ JZ EDIT1 ; Yes, exit\r
+ MOV M,A ; Save it\r
+ INX H ; Advance output\r
+ JMP EDIT2 ; And proceed\r
+; Handle HEXIDECIMAL values\r
+EDIT3: PUSH H ; Save address\r
+ CALL CALC8 ; Get HEX value\r
+ POP H ; HL = address\r
+ MOV M,A ; Set value\r
+ INX H ; Advance to next\r
+ CALL SKIP ; More operands?\r
+ JNZ EDIT3 ; Get then all\r
+ JMP EDIT1 ; And continue\r
+;\r
+; FIll memory with a value\r
+;\r
+FILL: CALL CALC ; Get starting address\r
+ PUSH H ; Save for later\r
+ CALL CALC ; Get ending address\r
+ PUSH H ; Save for later\r
+ CALL CALC8 ; Get value\r
+ MOV C,A ; C = value\r
+ POP D\r
+ INX D ; DE = End address+1\r
+ POP H ; HL = Starting address\r
+ CALL COMP16 ; Is Start<End ?\r
+ JNC ERROR ; Yes, bad entry\r
+FILL1: MOV M,C ; Save one byte\r
+ INX H ; Advance\r
+ CALL COMP16 ; Test for match\r
+ JC FILL1 ; And proceed\r
+ JMP REST ; Back for next\r
+;\r
+; 16 bit compare of HL to DE\r
+;\r
+COMP16: MOV A,H ; Get HIGH\r
+ CMP D ; Match?\r
+ RNZ ; No, we are done\r
+ MOV A,L ; Get LOW\r
+ CMP E ; Match?\r
+ RET\r
+;\r
+; Copy a block of memory\r
+;\r
+COPY: CALL CALC ; Get SOURCE address\r
+ PUSH H ; Save for later\r
+ CALL CALC ; Get DEST Address\r
+ PUSH H ; Save for later\r
+ CALL CALC ; Get size\r
+ MOV B,H ; BC = Size\r
+ MOV C,L\r
+ POP D ; DE = Dest address\r
+ POP H ; HL = Source\r
+ MOV A,B ; Size is zero?\r
+ ORA C\r
+ JZ REST ; Yes, exit\r
+ CALL COMP16 ; Compare source and destination address\r
+ JC COPY2 ; Dest > Source, jump\r
+ ; Source > Dest\r
+COPY1: MOV A,M ; Get byte from source\r
+ STAX D ; Write to dest\r
+ INX H ; Advance source\r
+ INX D ; Advance dest\r
+ DCX B ; Reduce count\r
+ MOV A,C ; Count is zero ?\r
+ ORA B\r
+ JNZ COPY1 ; No, continue\r
+ JMP REST\r
+ ; Dest > Source\r
+COPY2: DAD B ; Move source and destination address to end\r
+ DCX H ; of block\r
+ XCHG\r
+ DAD B\r
+ DCX H\r
+COPY3: LDAX D ; Get byte from source\r
+ MOV M,A ; Write to dest\r
+ DCX D ; Decrement source address\r
+ DCX H ; Decrement destination address\r
+ DCX B ; Reduce count\r
+ MOV A,C ; Count is zero ?\r
+ ORA B\r
+ JNZ COPY3 ; No, continue\r
+ JMP REST\r
+;\r
+; Display a block of memory\r
+;\r
+MEMRY: CALL CALC ; Get operand\r
+ SUB A ; Get a ZERO\r
+ STA OFLAG ; Clear output flag\r
+ALOOP: CALL HLOUT2 ; Display address (in hex) with 2 spaces\r
+ MVI D,16 ; 16 bytes/line\r
+ PUSH H ; Save address\r
+ALP1: MOV A,M ; Get byte\r
+ CALL HPR ; Output in hex\r
+ CALL SPACE ; Space over\r
+ MOV A,D ; Get count\r
+ CPI 9 ; At boundary?\r
+ CZ SPACE ; Yes, extra space\r
+ MOV A,D ; Get count\r
+ ANI 7 ; Mask for low bits\r
+ CPI 5 ; At boundary?\r
+ CZ SPACE ; Extra space\r
+ INX H ; Advance address\r
+ DCR D ; Reduce count\r
+ JNZ ALP1 ; Do them all\r
+ MVI D,4 ; # separating spaces\r
+AL2: CALL SPACE ; Output a space\r
+ DCR D ; Reduce count\r
+ JNZ AL2 ; And proceed\r
+ POP H\r
+ MVI D,16 ; 16 chars/display\r
+AL3: MOV A,M ; Get data byte\r
+ CALL OUTP ; Display (if printable)\r
+ INX H ; Advance to next\r
+ DCR D ; Reduce count\r
+ JNZ AL3 ; Do them all\r
+ CALL CHKSUS ; Handle output suspension\r
+ JMP ALOOP ; And continue\r
+;\r
+; Perform disassembly to console\r
+;\r
+GODIS: CALL CALC ; Get starting address\r
+ PUSH H ; Save address\r
+ POP D ; Copy to D\r
+ SUB A ; Get a zero\r
+ STA OFLAG ; Clear output flag\r
+VLOOP: CALL DINST ; Display one instruction\r
+ CALL CHKSUS ; Handle output\r
+ JMP VLOOP ; And proceed\r
+;\r
+; Set/display user base address\r
+;\r
+USRBASE: JNZ USRB1 ; Address is given, set it\r
+ CALL PRTMSG ; Output message\r
+ DB "BASE=",0\r
+ LHLD UBASE ; Get address\r
+ CALL HLOUT ; Output\r
+ JMP RECR ; New line & exit\r
+USRB1: CALL CALC ; Get operand\r
+ SHLD UBASE ; Set the address\r
+ JMP REST ; and return\r
+;\r
+; Send out as Intel HEX\r
+;\r
+SNDHEX: CALL CALC ; Get start address\r
+ PUSH H ; Save for later\r
+ CALL CALC ; Get end address\r
+ INX H ; HL = end+1\r
+ POP D ; DE = start\r
+ CALL COMP16 ; Check for Start > End\r
+ JC ERROR ; Bad entry\r
+ MOV A,L ; Compute length\r
+ SUB E\r
+ MOV L,A\r
+ MOV A,H\r
+ SBB D\r
+ MOV H,A\r
+ XCHG ; HL = start, DE = length\r
+SNDHX1: MOV A,D ; Finish ?\r
+ ORA E\r
+ JZ SNDHX3 ; Yes, jump\r
+ MVI B,16 ; 16 bytes per record\r
+ MOV A,D ; Is rest > 16 ?\r
+ ORA A\r
+ JNZ SNDHX2 ; No, jump\r
+ MOV A,E\r
+ CMP B\r
+ JNC SNDHX2 ; No, jump\r
+ MOV B,E ; Yes, B=rest\r
+SNDHX2: CALL SHXRC ; Send out one record\r
+ JMP SNDHX1 ; continue\r
+;\r
+SNDHX3: CALL PRTMSG\r
+ DB ":00000001FF",0Dh,0Ah,0\r
+ JMP REST\r
+;\r
+SHXRC: MVI A,':' ; Start record\r
+ CALL OUT\r
+ MOV A,B ; Length\r
+ MOV C,A ; Init checksum\r
+ CALL HPR ; Output in hex\r
+ MOV A,H ; High byte of address \r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Re-save\r
+ MOV A,H\r
+ CALL HPR ; Output in hex\r
+ MOV A,L ; Low byte of address \r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Re-save\r
+ MOV A,L\r
+ CALL HPR ; Output in hex\r
+ XRA A ; Record type\r
+ CALL HPR\r
+SHXRC1: MOV A,M ; One byte\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Re-save\r
+ MOV A,M\r
+ INX H\r
+ CALL HPR ; Output in hex\r
+ DCX D ; Decrement main counter\r
+ DCR B ; Decrement bytes per record counter\r
+ JNZ SHXRC1\r
+ MOV A,C ; Negate checksum\r
+ CMA\r
+ INR A\r
+ CALL HPR ; Output in hex\r
+ JMP CRLF\r
+;\r
+; Download command\r
+;\r
+LOAD: MVI A,0Fh ; Get default initial state\r
+ JZ LOAD1 ; Address not given...\r
+ CALL CALC ; Get operand value\r
+ SHLD BUFFER+3 ; Save for later calulation\r
+ MVI A,0FFh ; Set new initial state\r
+; Setup the offset calculator\r
+LOAD1: LXI H,0 ; Assume no offset\r
+ STA BUFFER ; Set mode flag\r
+ SHLD BUFFER+1 ; Assume offset is ZERO\r
+; Download the records\r
+LOAD2: CALL DLREC ; Get a record\r
+ JNZ DLBAD ; Report error\r
+ JNC LOAD2 ; Get them all\r
+ JMP DLWAIT ; And back to monitor\r
+; Error in receiving download record\r
+DLBAD: CALL PRTMSG ; Output message\r
+ DB "?Load error"\r
+ DB 0Dh,0Ah,0\r
+; Wait till incoming data stream stops\r
+DLWAIT: MVI C,0 ; Initial count\r
+DLWAIT1: CALL IN ; Test for input\r
+ ANA A ; Any data\r
+ JNZ DLWAIT ; Reset count\r
+ DCR C ; Reduce counter\r
+ JNZ DLWAIT1 ; Keep looking\r
+ JMP REST ; Back to monitor\r
+;\r
+; Download a record from the serial port\r
+;\r
+DLREC: CALL INCHR ; Read a character\r
+ CPI ':' ; Start of record?\r
+ JZ DLINT ; Download INTEL format\r
+ CPI 'S' ; Is it MOTOROLA?\r
+ JNZ DLREC ; No, keep looking\r
+; Download a MOTOROLA HEX format record\r
+DLMOT: CALL INCHR ; Get next character\r
+ CPI '0' ; Header record?\r
+ JZ DLREC ; Yes, skip it\r
+ CPI '9' ; End of file?\r
+ JZ DLEOF ; Yes, report EOF\r
+ CPI '1' ; Type 1 (code) record\r
+ JNZ DLERR ; Report error\r
+ CALL GETBYT ; Get length\r
+ MOV C,A ; Start checksum\r
+ SUI 3 ; Convert for overhead\r
+ MOV B,A ; Save data length\r
+ CALL GETBYT ; Get first byte of address\r
+ MOV H,A ; Set HIGH address\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; And re-save\r
+ CALL GETBYT ; Get next byte of address\r
+ MOV L,A ; Set LOW address\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; And re-save\r
+ CALL SETOFF ; Handle record offsets\r
+DMOT1: CALL GETBYT ; Get a byte of data\r
+ MOV M,A ; Save in memory\r
+ INX H ; Advance\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; And re-save\r
+ DCR B ; Reduce length\r
+ JNZ DMOT1 ; Keep going\r
+ CALL GETBYT ; Get record checksum\r
+ ADD C ; Include calculated checksum\r
+ INR A ; Adjust for test\r
+ ANA A ; Clear carry set Z\r
+ RET\r
+; Download a record in INTEL hex format\r
+DLINT: CALL GETBYT ; Get length\r
+ ANA A ; End of file?\r
+ JZ DLEOF ; Yes, handle it\r
+ MOV C,A ; Begin Checksum\r
+ MOV B,A ; Record length\r
+ CALL GETBYT ; Get HIGH address\r
+ MOV H,A ; Set HIGH address\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Re-save\r
+ CALL GETBYT ; Get LOW address\r
+ MOV L,A ; Set LOW address\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Re-save\r
+ CALL SETOFF ; Handle record offsets\r
+ CALL GETBYT ; Get type byte\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Re-save\r
+DLINT1: CALL GETBYT ; Get data byte\r
+ MOV M,A ; Save in memory\r
+ INX H ; Advance to next\r
+ ADD C ; Include in checksum\r
+ MOV C,A ; Resave checksum\r
+ DCR B ; Reduce count\r
+ JNZ DLINT1 ; Do entire record\r
+ CALL GETBYT ; Get record checksum\r
+ ADD C ; Add to computed checksum\r
+ ANA A ; Clear carry, set Z\r
+ RET\r
+; End of file on download\r
+DLEOF: STC ; Set carry, EOF\r
+ RET\r
+;\r
+; Process record offsets for download records\r
+;\r
+SETOFF: LDA BUFFER ; Get flag\r
+ ANA A ; Test flag\r
+ JNZ SETOF1 ; Special case\r
+; Not first record, adjust for offset & proceed\r
+ XCHG ; DE = address\r
+ LHLD BUFFER+1 ; Get offset\r
+ DAD D ; HL = address + offset\r
+ RET\r
+; First record, set USER BASE & calculate offset (if any)\r
+SETOF1: MVI A,0 ; Get zero (NO CC)\r
+ STA BUFFER ; Clear flag\r
+ SHLD UBASE ; Set user program base\r
+ RP ; No more action\r
+; Calculate record offset to RAM area\r
+ XCHG ; DE = address\r
+ LHLD BUFFER+3 ; Get operand\r
+ MOV A,L ; Subtract\r
+ SUB E ; Record\r
+ MOV L,A ; From\r
+ MOV A,H ; Operand\r
+ SBB D ; To get\r
+ MOV H,A ; Offset\r
+ SHLD BUFFER+1 ; Set new offset\r
+ DAD D ; Get address\r
+ RET\r
+;\r
+; Gets a byte of HEX data from serial port.\r
+;\r
+GETBYT: CALL GETNIB ; Get first nibble\r
+ RLC ; Shift into\r
+ RLC ; Upper nibble\r
+ RLC ; Of result\r
+ RLC ; To make room for lower\r
+ MOV E,A ; Keep high digit\r
+ CALL GETNIB ; Get second digit\r
+ ORA E ; Insert high digit\r
+ RET\r
+; GETS A NIBBLE FROM THE TERMINAL (IN ASCII HEX)\r
+GETNIB: CALL INCHR ; Get a character\r
+ SUI '0' ; Is it < '0'?\r
+ JC GETN1 ; Yes, invalid\r
+ CPI 10 ; 0-9?\r
+ RC ; Yes, its OK\r
+ SUI 7 ; Convert\r
+ CPI 10 ; 9-A?\r
+ JC GETN1 ; Yes, invalid\r
+ CPI 16 ; A-F?\r
+ RC ; Yes, its OK\r
+GETN1: POP D ; Remove GETNIB RET addr\r
+ POP D ; Remove GETBYT RET addr\r
+; Error during download record\r
+DLERR: ORI 0FFh ; Error indicator\r
+ RET\r
+;\r
+; Read an input line from the console\r
+;\r
+INPT: LXI H,BUFFER ; Point to input buffer\r
+INPT1: CALL INCHR ; Get a char\r
+ CPI 1Bh ; ESCAPE?\r
+ JZ RECR ; Back for command\r
+ CPI 0Dh ; Carriage return?\r
+ JZ INPT4 ; Yes, exit\r
+ MOV D,A ; Save for later\r
+; Test for DELETE function\r
+ CPI 7Fh ; Is it delete?\r
+ JZ INPT3 ; Yes, it is\r
+ CPI 08h ; Backspace?\r
+ JZ INPT3 ; Yes, it is\r
+; Insert character in buffer\r
+ MOV A,L ; Get low address\r
+ CPI (BUFFER&255)+30 ; Beyond end?\r
+ MVI A,7 ; Assume error\r
+ JZ INPT2 ; Yes, report error\r
+ MOV A,D ; Get char back\r
+ MOV M,A ; Save in memory\r
+ INX H ; Advance\r
+INPT2: CALL OUT ; Echo it\r
+ JMP INPT1 ; And proceed\r
+; Delete last character from buffer\r
+INPT3: MOV A,L ; Get char\r
+ CPI BUFFER&255 ; At begining\r
+ MVI A,7 ; Assume error\r
+ JZ INPT2 ; Report error\r
+ PUSH H ; Save H\r
+ CALL PRTMSG ; Output message\r
+ DB 8,' ',8,0 ; Wipe away character\r
+ POP H ; Restore H\r
+ DCX H ; Backup\r
+ JMP INPT1 ; And proceed\r
+; Terminate the command\r
+INPT4: MVI M,0 ; Zero terminate\r
+ CALL CRLF ; New line\r
+ LXI D,BUFFER ; Point to input buffer\r
+; Advance to next non-blank in buffer\r
+SKIP: LDAX D ; Get char from buffer\r
+ INX D ; Advance\r
+ CPI ' ' ; Space?\r
+ JZ SKIP ; Yes, keep looking\r
+ DCX D ; Backup to it\r
+ JMP TOCAP ; And convert to upper\r
+;\r
+; Read next character from command & convert to upper case\r
+;\r
+GETCHI: INX D ; Skip next character\r
+GETCHR: LDAX D ; Get char from command line\r
+ ANA A ; End of line?\r
+ RZ ; Yes, return with it\r
+ INX D ; Advance command pointer\r
+;\r
+; Convert character in A to uppercase, set Z if SPACE or EOL\r
+;\r
+TOCAP: CPI 61h ; Lower case?\r
+ JC TOCAP1 ; Yes, its ok\r
+ ANI 5Fh ; Convert to UPPER\r
+TOCAP1: CPI ' ' ; Space\r
+ RZ ; Yes, indicate\r
+ ANA A ; Set 'Z' if EOL\r
+ RET\r
+;\r
+; Get 8 bit HEX operands to command\r
+;\r
+CALC8: CALL CALC ; Get operand\r
+ MOV A,H ; High byte must be zero\r
+ ORA A\r
+ JNZ ERROR ; Bad value\r
+ MOV A,L ; Value also to A\r
+ RET\r
+;\r
+; Get 16 bit HEX operands to command\r
+;\r
+CALC: PUSH B ; Save B-C\r
+ CALL SKIP ; Find start of operand\r
+ LXI H,0 ; Begin with zero value\r
+ MOV C,H ; Clear flag\r
+CALC1: CALL GETCHR ; Get next char\r
+ JZ CALC3 ; End of number\r
+ CALL VALHEX ; Is it valid hex?\r
+ JC ERROR ; No, report error\r
+ DAD H ; HL = HL*2\r
+ DAD H ; HL = HL*4\r
+ DAD H ; HL = HL*8\r
+ DAD H ; HL = HL*16 (Shift over 4 bits)\r
+ SUI '0' ; Convert to ASCII\r
+ CPI 10 ; Decimal number?\r
+ JC CALC2 ; Yes, its ok\r
+ SUI 7 ; Convert to HEX\r
+CALC2: ORA L ; Include in final value\r
+ MOV L,A ; Resave low bute\r
+ MVI C,0FFh ; Set flag & indicate we have char\r
+ JMP CALC1 ; And continue\r
+; End of input string was found\r
+CALC3: MOV A,C ; Get flag\r
+ POP B ; Restore B-C\r
+ ANA A ; Was there any digits?\r
+ JZ ERROR ; No, invalid\r
+ RET\r
+; Test for character in A as valid hex\r
+VALHEX: CPI '0' ; < '0'\r
+ RC ; Too low\r
+ CPI 'G' ; >'F'\r
+ CMC ; Set C state\r
+ RC ; Too high\r
+ CPI 3Ah ; <='9'\r
+ CMC ; Set C state\r
+ RNC ; Yes, its OK\r
+ CPI 'A' ; Set C if < 'A'\r
+ RET\r
+;\r
+; Display the user process registers\r
+;\r
+REGDIS: LHLD BC ; Get saved BC pair\r
+ LXI B,'BC' ; And register names\r
+ CALL OUTPT ; Output\r
+ LHLD DE ; Get saved DE pair\r
+ LXI B,'DE' ; And register names\r
+ CALL OUTPT ; Output\r
+ LHLD HL ; Get saved HL pair\r
+ LXI B,'HL' ; And register names\r
+ CALL OUTPT ; Output\r
+ LHLD SP ; Get saved SP\r
+ LXI B,'SP' ; And register name\r
+ CALL OUTPT ; Output\r
+ LHLD PC ; Get saved PC\r
+ LXI B,'PC' ; And regsiter name\r
+ CALL OUTPT ; Output\r
+ CALL PRTMSG ; Output message\r
+ DB " PSW=",0\r
+ LHLD PSW ; Get saved PSW\r
+ CALL HLOUT2 ; Output value (with two spaces)\r
+ CALL PRTMSG ; Output\r
+ DB " FLAGS=",0\r
+ LHLD PSW-1 ; Get Flags to H\r
+ MVI B,'S' ; 'S' flag\r
+ CALL OUTB ; Display\r
+ MVI B,'Z' ; 'Z' flag\r
+ CALL OUTB ; Display\r
+ MVI B,'K' ; 'K' flag\r
+ CALL OUTB ; Display\r
+ MVI B,'A' ; 'A' flag\r
+ CALL OUTB ; Display\r
+ MVI B,'3' ; 3. bit flag\r
+ CALL OUTB ; Display\r
+ MVI B,'P' ; 'P' flag\r
+ CALL OUTB ; Display\r
+ MVI B,'V' ; 'V' flag\r
+ CALL OUTB ; Display\r
+ MVI B,'C' ; 'C' flag\r
+ CALL OUTB ; Display\r
+ JMP CRLF ; New line & exit\r
+; Display contents of a register pair\r
+OUTPT: MOV A,B ; Get first char of name\r
+ CALL OUT ; Output\r
+ MOV A,C ; Get second char of name\r
+ CALL OUT ; Output\r
+ MVI A,'=' ; Get separator\r
+ CALL OUT ; Output\r
+HLOUT2: CALL HLOUT ; Output value\r
+ CALL SPACE ; Output a space\r
+; Display a space on the console\r
+SPACE: MVI A,' ' ; Get a spave\r
+ JMP OUT ; Display it\r
+; Display an individual flag bit B=title, H[7]=bit\r
+OUTB: DAD H ; Shift H[7] into carry\r
+ MVI A,'-' ; Dash for not set flag\r
+ JNC OUT ; Display dash\r
+ MOV A,B ; Get character\r
+ JMP OUT ; And display\r
+;\r
+; Display an instruction in disassembly format\r
+;\r
+DINST: PUSH D ; Save address\r
+ MOV A,D ; Get high value\r
+ CALL HPR ; Output\r
+ MOV A,E ; Get low address\r
+ CALL HPR ; Output\r
+ CALL SPACE ; Output a space\r
+ CALL LOOK ; Lookup instruction\r
+ ANI 03h ; Save length\r
+ PUSH PSW ; Save length\r
+ PUSH H ; Save table address\r
+ MVI B,4 ; 4 spaces total\r
+ MOV C,A ; Save count\r
+ DCX D ; Backup address\r
+; Display the opcode bytes in HEX\r
+VLP1: INX D ; Advance\r
+ LDAX D ; Get opcode\r
+ CALL HPR ; Output in HEX\r
+ CALL SPACE ; Separator\r
+ DCR B ; Reduce count\r
+ DCR C ; Reduce count of opcodes\r
+ JNZ VLP1 ; Do them all\r
+; Fill in to boundary\r
+VLP2: CALL SPACE ; Space over\r
+ CALL SPACE ; Space over\r
+ CALL SPACE ; Spave over\r
+ DCR B ; Reduce count\r
+ JNZ VLP2 ; Do them all\r
+; DISPLAY ASCII equivalent of opcodes\r
+ POP B ; Restore table address\r
+ POP PSW ; Restore type/length\r
+ POP D ; Restore instruction address\r
+ PUSH D ; Resave\r
+ PUSH PSW ; Resave\r
+ MVI H,8 ; 8 spaces/field\r
+ ANI 0Fh ; Save only length\r
+ MOV L,A ; Save for later\r
+PCHR: LDAX D ; Get byte from opcode\r
+ INX D ; Advance\r
+ CALL OUTP ; Display (if printable)\r
+ DCR H ; Reduce field count\r
+ DCR L ; Reduce opcode count\r
+ JNZ PCHR ; Do them all\r
+; Space over to instruction address\r
+SPLP: CALL SPACE ; Output a space\r
+ DCR H ; Reduce count\r
+ JNZ SPLP ; Do them all\r
+ MVI D,6 ; Field width\r
+VLP3: LDAX B ; Get char from table\r
+ ANA A ; End of string?\r
+ JZ VOUT1 ; Yes, exit\r
+ CALL OUT ; Output it\r
+ INX B ; Advance to next\r
+ DCR D ; reduce count\r
+ CPI ' ' ; end of name?\r
+ JNZ VLP3 ; no, keep going\r
+; Fill in name field with spaces\r
+VOUT: DCR D ; reduce count\r
+ JZ VLP3 ; Keep going\r
+ CALL SPACE ; Output a space\r
+ JMP VOUT ; And proceed\r
+; Output operands for the instruction\r
+VOUT1: POP PSW ; Restore type\r
+ POP D ; Restore instruction address\r
+ DCR A ; Is it type1?\r
+ JZ T1 ; Yes, handle it\r
+; Type 2 - One byte immediate date\r
+T2: PUSH PSW ; Save type\r
+ MVI A,'$' ; Get HEX indicator\r
+ CALL OUT ; Output\r
+ POP PSW ; Restore type\r
+ DCR A ; Type 2?\r
+ JNZ T3 ; No, try next\r
+ INX D ; Advance to data\r
+ LDAX D ; Get data\r
+ CALL HPR ; Output in HEX\r
+; Type 1 - No operand\r
+T1: INX D\r
+ RET\r
+; Type 3 - Two bytes immediate data\r
+T3: INX D ; Skip to low \r
+ INX D ; Skip to high\r
+ LDAX D ; Get HIGH\r
+ CALL HPR ; Output\r
+ DCX D ; Backup to low\r
+ LDAX D ; Get LOW\r
+ CALL HPR ; Output\r
+ INX D ; Advance to high\r
+ INX D\r
+ RET\r
+;\r
+; Look up instruction in table & return TYPE/LENGTH[A], and string[HL]\r
+;\r
+LOOK: PUSH D ; Save DE\r
+ LDAX D ; Get opcode\r
+ MOV B,A ; Save for later\r
+ LXI H,ITABLE ; Point to table\r
+LOOK1: MOV A,B ; Get Opcode\r
+ ANA M ; Mask\r
+ INX H ; Skip mask\r
+ CMP M ; Does it match\r
+ INX H ; Skip opcode\r
+ JZ LOOK3 ; Yes, we found it\r
+; This wasn't it, advance to the next\r
+LOOK2: MOV A,M ; Get byte\r
+ INX H ; Advance to next\r
+ ANA A ; End of string?\r
+ JNZ LOOK2 ; No, keep looking\r
+ JMP LOOK1 ; And continue\r
+; We found the instruction, copy over the text description\r
+LOOK3: MOV C,M ; Save type\r
+ INX H ; Skip type\r
+ LXI D,BUFFER ; Point to text buffer\r
+LOOK4: MOV A,M ; Get char from source\r
+ INX H ; Advance to next\r
+; Insert a RESTART vector number\r
+ CPI 'v' ; Restart vector\r
+ JNZ LOOK5 ; No, its OK\r
+ MOV A,B ; Get opcode\r
+ RRC ; Shift it\r
+ RRC ; Over\r
+ RRC ; To low digit\r
+ ANI 07h ; Remove trash\r
+ ADI '0' ; Convert to digit\r
+ JMP LOOK10 ; And set the character\r
+; Insert a register pair name\r
+LOOK5: CPI 'p' ; Register PAIR?\r
+ JNZ LOOK6 ; No, try next\r
+ MOV A,B ; Get opcode\r
+ RRC ; Shift\r
+ RRC ; Over into\r
+ RRC ; Low digit\r
+ RRC ; For lookup\r
+ ANI 03h ; Save only RP\r
+ PUSH H ; Save HL\r
+ LXI H,RPTAB ; Point to pair table\r
+ JMP LOOK9 ; And proceed\r
+; Insert destination register name\r
+LOOK6: CPI 'd' ; Set destination?\r
+ JNZ LOOK7 ; No, try next\r
+ MOV A,B ; Get opcode\r
+ RRC ; Shift\r
+ RRC ; Into low\r
+ RRC ; digit\r
+ JMP LOOK8 ; And proceed\r
+; Insert source register name\r
+LOOK7: CPI 's' ; Source register?\r
+ JNZ LOOK10 ; No, its OK\r
+ MOV A,B ; Get opcode\r
+; Lookup a general processor register\r
+LOOK8: ANI 07h ; Save only source\r
+ PUSH H ; Save HL\r
+ LXI H,RTAB ; Point to table\r
+; Lookup register in table\r
+LOOK9: ADD L ; Offset to value\r
+ MOV L,A ; Resave address\r
+ MOV A,M ; Get character\r
+ CPI 'S' ; 'SP' register ?\r
+ JNZ LOOK9A ; No, skip\r
+ STAX D ; Save 'S'\r
+ INX D ; Advance to next\r
+ MVI A,'P' ; Character 'P'\r
+LOOK9A: POP H ; Restore HL\r
+; Save character in destination string\r
+LOOK10: STAX D ; Save value\r
+ INX D ; Advance to next\r
+ ANA A ; End of list?\r
+ JNZ LOOK4 ; No, keep copying\r
+; End of LIST\r
+ LXI H,BUFFER ; Point to description\r
+ MOV A,C ; Get length\r
+ POP D ; Restore DE\r
+ RET\r
+;\r
+; Opcode disassembly table: MASK, OPCODE, TYPE/LENGTH, STRINGZ\r
+;\r
+ITABLE: DB 0FFh,0FEh,02h\r
+ DB "CPI ",0\r
+ DB 0FFh,3Ah,03h\r
+ DB "LDA ",0\r
+ DB 0FFh,32h,03h\r
+ DB "STA ",0\r
+ DB 0FFh,2Ah,03h\r
+ DB "LHLD ",0\r
+ DB 0FFh,22h,03h\r
+ DB "SHLD ",0\r
+ DB 0FFh,0F5h,01h\r
+ DB "PUSH PSW",0\r
+ DB 0FFh,0F1h,01h\r
+ DB "POP PSW",0\r
+ DB 0FFh,27h,01h\r
+ DB "DAA",0\r
+ DB 0FFh,76h,01h\r
+ DB "HLT",0\r
+ DB 0FFh,0FBh,01h\r
+ DB "EI",0\r
+ DB 0FFh,0F3h,01h\r
+ DB "DI",0\r
+ DB 0FFh,37h,01h\r
+ DB "STC",0\r
+ DB 0FFh,3Fh,01h\r
+ DB "CMC",0\r
+ DB 0FFh,2Fh,01h\r
+ DB "CMA",0\r
+ DB 0FFh,0EBh,01h\r
+ DB "XCHG",0\r
+ DB 0FFh,0E3h,01h\r
+ DB "XTHL",0\r
+ DB 0FFh,0F9h,01h\r
+ DB "SPHL",0\r
+ DB 0FFh,0E9h,01h\r
+ DB "PCHL",0\r
+ DB 0FFh,0DBh,02h\r
+ DB "IN ",0\r
+ DB 0FFh,0D3h,02h\r
+ DB "OUT ",0\r
+ DB 0FFh,07h,01h\r
+ DB "RLC",0\r
+ DB 0FFh,0Fh,01h\r
+ DB "RRC",0\r
+ DB 0FFh,17h,01h\r
+ DB "RAL",0\r
+ DB 0FFh,1Fh,01h\r
+ DB "RAR",0\r
+ DB 0FFh,0C6h,02h\r
+ DB "ADI ",0\r
+ DB 0FFh,0CEh,02h\r
+ DB "ACI ",0\r
+ DB 0FFh,0D6h,02h\r
+ DB "SUI ",0\r
+ DB 0FFh,0DEh,02h\r
+ DB "SBI ",0\r
+ DB 0FFh,0E6h,02h\r
+ DB "ANI ",0\r
+ DB 0FFh,0F6h,02h\r
+ DB "ORI ",0\r
+ DB 0FFh,0EEh,02h\r
+ DB "XRI ",0\r
+ DB 0FFh,00h,01h\r
+ DB "NOP",0\r
+; 8085 specific instructions\r
+ DB 0FFh,20h,01h\r
+ DB "RIM",0\r
+ DB 0FFh,30h,01h\r
+ DB "SIM",0\r
+; 8085 undocumented instructions\r
+ DB 0FFh,08h,01h\r
+ DB "DSUB B",0\r
+ DB 0FFh,10h,01h\r
+ DB "ARHL",0\r
+ DB 0FFh,18h,01h\r
+ DB "RDEL",0\r
+ DB 0FFh,28h,02h\r
+ DB "LDHI ",0\r
+ DB 0FFh,38h,02h\r
+ DB "LDSI ",0\r
+ DB 0FFh,0CBh,01h\r
+ DB "RSTV",0\r
+ DB 0FFh,0D9h,01h\r
+ DB "SHLX D",0\r
+ DB 0FFh,0DDh,03h\r
+ DB "JNK ",0\r
+ DB 0FFh,0EDh,01h\r
+ DB "LHLX D",0\r
+ DB 0FFh,0FDh,03h\r
+ DB "JK ",0\r
+; Jumps, Calls & Returns\r
+ DB 0FFh,0C3h,0Bh\r
+ DB "JMP ",0\r
+ DB 0FFh,0CAh,43h\r
+ DB "JZ ",0\r
+ DB 0FFh,0C2h,4Bh\r
+ DB "JNZ ",0\r
+ DB 0FFh,0DAh,13h\r
+ DB "JC ",0\r
+ DB 0FFh,0D2h,1Bh\r
+ DB "JNC ",0\r
+ DB 0FFh,0EAh,23h\r
+ DB "JPE ",0\r
+ DB 0FFh,0E2h,2Bh\r
+ DB "JPO ",0\r
+ DB 0FFh,0FAh,83h\r
+ DB "JM ",0\r
+ DB 0FFh,0F2h,8Bh\r
+ DB "JP ",0\r
+ DB 0FFh,0CDh,0Bh\r
+ DB "CALL ",0\r
+ DB 0FFh,0CCh,43h\r
+ DB "CZ ",0\r
+ DB 0FFh,0C4h,4Bh\r
+ DB "CNZ ",0\r
+ DB 0FFh,0DCh,13h\r
+ DB "CC ",0\r
+ DB 0FFh,0D4h,1Bh\r
+ DB "CNC ",0\r
+ DB 0FFh,0ECh,23h\r
+ DB "CPE ",0\r
+ DB 0FFh,0E4h,2Bh\r
+ DB "CPO ",0\r
+ DB 0FFh,0FCh,83h\r
+ DB "CM ",0\r
+ DB 0FFh,0F4h,8Bh\r
+ DB "CP ",0\r
+ DB 0FFh,0C9h,05h\r
+ DB "RET",0\r
+ DB 0FFh,0C8h,45h\r
+ DB "RZ",0\r
+ DB 0FFh,0C0h,4Dh\r
+ DB "RNZ",0\r
+ DB 0FFh,0D8h,15h\r
+ DB "RC",0\r
+ DB 0FFh,0D0h,1Dh\r
+ DB "RNC",0\r
+ DB 0FFh,0E8h,25h\r
+ DB "RPE",0\r
+ DB 0FFh,0E0h,2Dh\r
+ DB "RPO",0\r
+ DB 0FFh,0F8h,85h\r
+ DB "RM",0\r
+ DB 0FFh,0F0h,8Dh\r
+ DB "RP",0\r
+; Register based instructions\r
+ DB 0C0h,40h,01h\r
+ DB "MOV d,s",0\r
+ DB 0C7h,06h,02h\r
+ DB "MVI d,",0\r
+ DB 0F8h,90h,01h\r
+ DB "SUB s",0\r
+ DB 0F8h,98h,01h\r
+ DB "SBB s",0\r
+ DB 0F8h,80h,01h\r
+ DB "ADD s",0\r
+ DB 0F8h,88h,01h\r
+ DB "ADC s",0\r
+ DB 0F8h,0A0h,01h\r
+ DB "ANA s",0\r
+ DB 0F8h,0B0h,01h\r
+ DB "ORA s",0\r
+ DB 0F8h,0A8h,01h\r
+ DB "XRA s",0\r
+ DB 0F8h,0B8h,01h\r
+ DB "CMP s",0\r
+ DB 0C7h,04h,01h\r
+ DB "INR d",0\r
+ DB 0C7h,05h,01h\r
+ DB "DCR d",0\r
+; Register pair instructions\r
+ DB 0CFh,01h,03h\r
+ DB "LXI p,",0\r
+ DB 0EFh,0Ah,01h\r
+ DB "LDAX p",0\r
+ DB 0EFh,02h,01h\r
+ DB "STAX p",0\r
+ DB 0CFh,03h,01h\r
+ DB "INX p",0\r
+ DB 0CFh,0Bh,01h\r
+ DB "DCX p",0\r
+ DB 0CFh,09h,01h\r
+ DB "DAD p",0\r
+ DB 0CFh,0C5h,01h\r
+ DB "PUSH p",0\r
+ DB 0CFh,0C1h,01h\r
+ DB "POP p",0\r
+; Restart instruction\r
+ DB 0C7h,0C7h,01h\r
+ DB "RST v",0\r
+; This entry always matches invalid opcodes\r
+ DB 00h,00h,01h\r
+ DB "DB ",0\r
+; Misc Strings and messages\r
+ON: DB "ON ",0\r
+OFF: DB "OFF",0\r
+AUTMSG: DB "AUTOREG=",0\r
+SUBMSG: DB " SUBTRACE=",0\r
+TRCMSG: DB " TRACE=",0\r
+HTEXT: DB "MON85 Commands:"\r
+ DB 0Dh,0Ah,0\r
+ DB "A ON|OFF!Enable/Disable Automatic register display",0\r
+ DB "B [bp address]!Set/Display breakpoints",0\r
+ DB "C <src> <dest> <size>!Copy memory",0\r
+ DB "D <address>!Display memory in assembly format",0\r
+ DB "E <address>!Edit memory",0\r
+ DB "F <start> <end> <value>!Fill memory",0\r
+ DB "G [address]!Begin/Resume execution",0\r
+ DB "H <start> <end>!Send out memory in Intel HEX format",0\r
+ DB "I <port>!Input from port",0\r
+ DB "L [address]!Load image into memory",0\r
+ DB "M <address>!Display memory in hex dump format",0\r
+ DB "O <port> <data>!Output to port",0\r
+ DB "R [rp value]!Set/Display program registers",0\r
+ DB "S ON|OFF!Enable/Disable Subroutine trace",0\r
+ DB "T ON|OFF!Enable/Disable Trace mode",0\r
+ DB "U [address]!Set/Display program base address",0\r
+ DB 0\r
+;\r
+; Read a character, and wait for it\r
+;\r
+INCHR: CALL IN ; Check for a character\r
+ ANA A ; Is there any data?\r
+ JZ INCHR ; Wait for it\r
+ RET\r
+;\r
+; Display HL in hexidecimal\r
+;\r
+HLOUT: MOV A,H ; Get HIGH byte\r
+ CALL HPR ; Output\r
+ MOV A,L ; Get LOW byte\r
+;\r
+; Display A in hexidecimal\r
+;\r
+HPR: PUSH PSW ; Save low digit\r
+ RRC ; Shift\r
+ RRC ; high\r
+ RRC ; digit\r
+ RRC ; into low\r
+ CALL HOUT ; Display a single digit\r
+ POP PSW ; Restore low digit\r
+HOUT: ANI 0Fh ; Remove high digit\r
+ CPI 10 ; Convert to ASCII\r
+ SBI 2Fh\r
+ DAA\r
+ JMP OUT ; And output it\r
+;\r
+; Display message [PC]\r
+;\r
+PRTMSG: POP H ; Get address\r
+ CALL PRTSTR ; Output message\r
+ PCHL ; And return\r
+;\r
+; Display message [HL]\r
+;\r
+PRTSTR: MOV A,M ; Get byte from message\r
+ INX H ; Advance to next\r
+ ANA A ; End of message?\r
+ RZ ; Yes, exit\r
+ CALL OUT ; Output the character\r
+ JMP PRTSTR ; And proceed\r
+;\r
+; Handle output suspension\r
+;\r
+CHKSUS: CALL CRLF ; New line\r
+ LDA OFLAG ; Is output suspended?\r
+ ANA A ; Test flag\r
+ JNZ CHKS1 ; Yes it is\r
+ CALL IN ; Test for CONTROL-C interrupt\r
+ CPI 1Bh ; ESCAPE?\r
+ JZ REST ; Abort\r
+ CPI ' ' ; SPACE - Suspend command\r
+ RNZ\r
+ STA OFLAG ; Set the flag\r
+; Output is suspended, wait for command\r
+CHKS1: CALL INCHR ; Get char\r
+ CPI ' ' ; One line?\r
+ RZ ; Allow it\r
+ CPI 1Bh ; ESCAPE?\r
+ JZ REST ; Abort\r
+ CPI 0Dh ; Resume?\r
+ JNZ CHKS1 ; Keep going\r
+ SUB A ; Reset flag\r
+ STA OFLAG ; Write it\r
+ RET\r
+; Display a character if its printable\r
+OUTP: CPI ' ' ; < ' '\r
+ JC OUTP1 ; Invalid, exchange it\r
+ CPI 7Fh ; Printable?\r
+ JC OUT ; Ok to display\r
+OUTP1: MVI A,'.' ; Set to DOT to indicate invalid\r
+ JMP OUT ; And display\r
+;\r
+; Write a Line-Feed and Carriage-Return to console\r
+;\r
+CRLF: MVI A,0Dh ; Carriage return\r
+ CALL OUT ; Output\r
+ MVI A,0Ah ; Line-feed\r
+;\r
+; User supplied I/O routines.\r
+;-----------------------------------------------------------\r
+; NOTE: "OUT" must appear first because "CRLF" falls into it.\r
+;\r
+; Write character in A to console (8251 uart)\r
+OUT: PUSH PSW ; Save char\r
+OUT1: IN 9 ; Get 8251 status\r
+ RRC ; Test TX bit\r
+ JNC OUT1 ; Not ready\r
+ POP PSW ; Restore char\r
+ OUT 8 ; Write 8251 data\r
+ RET\r
+; Check for a character from the console (8251 uart)\r
+IN: IN 9 ; Get 8251 status\r
+ ANI 00000010b ; Test for ready\r
+ RZ ; No char\r
+ IN 8 ; Get 8251 data\r
+ RET\r
+;\r
+; Initialize the uart\r
+;\r
+; 8251A initialization, according to datasheet (3x 00h + RESET 040h) \r
+INIT: XRA A ; Insure not setup mode\r
+ OUT 9 ; Write once\r
+ OUT 9 ; Write again (now in operate mode)\r
+ OUT 9 ; Write again (now in operate mode)\r
+ MVI A,01000000b ; Reset\r
+ OUT 9 ; write it\r
+ MVI A,01001110b ; 8 data, 1 stop, x16\r
+ OUT 9 ; Write it\r
+ MVI A,00110111b ; RTS,DTR,Enable RX,TX\r
+ OUT 9 ; Write it\r
+ RET\r