; ; **************************** ; ; Z-80 TRACER ; ; **************************** ; ; THIS PROGRAM USES THE TRACER ; PROGRAM WRITTEN BY ARTHUR W. CLINE ; AND PUBLISHED IN DR. DOBB'S JOURNAL ; VOLUME 3,ISSUE 3,MAR 1978 ; ; VERSION 1.1 25 OCTOBER 81 ; ; THIS IS A STAND ALONE TRACER FOR ; 8080/Z80 PROGRAMS TO BE EXECUTED ; ON A Z80 COMPUTER. AS WRITTEN IT ; DUMPS THE CONTENTS OF THE REGISTERS ; PRIOR TO EXECUTING AN OP-CODE. IT ; THEN CALCULATES THE NEXT OP-CODE ; LOCATION AND PLACES A RESTART THERE. ; THE TARGET PROGRAM AND TRACER MUST ; BE IN R/W MEMORY SINCE THEY ARE ; MODIFIED DURING EXECUTION. ; ; TRANSLATED TO TDL MNEMONICS AND ; MADE INTO A STAND ALONE PROGRAM ; BY ; CHARLES THOMAS ; 416 GREENWOOD DR. ; CLINTON, TN. ; 37716 ; .RADIX 16 .PABS .XSYM ; ;=========================== ; HARDWARE DEPENDANT EQUATES ;=========================== ; ;CONSOLE OUTPUT ROUTINE. ;DATA IS PASSED IN THE 'A' REG ;THE 'HL','DE',AND 'BC' REGISTERS ;MUST BE PRESERVED BY THE CALLED ;ROUTINE. ; COUT = 0D006H ; ;KEYBOARD STATUS PORT ; CSTAT = 0D5H ; ;KEYBOARD DATA PORT ; CDATA = 0D4H ; ;MASK FOR READY BIT FOR ;KEYBOARD STATUS. ;THE PROGRAM EXPECTS THE RDY BIT ;TO BE HIGH WHEN DATA IS AVAILABLE. ;IF YOUR RDY BIT IS TRUE LOW YOU MUST ;CHANGE THE 'CTEST' SUBROUTINE. ; RDYMSK = 80H ;BIT 8 ; .LOC 8000H ; ;SET UP RESTART VECTORS AND ;INSTALL RESTART IN TARGET ;PROGRAM. ; INIT: LXI SP,STACK + 20 LXI H,MSG1 ;TRACE @ CALL MSGOUT CALL ADDIN ;GET ADDRESS MOV A,M ;GET B1 STA B1 MVI M,0F7 ;PUT IN RST6 INX H ;GET B2 MOV A,M STA B2 LXI H,PREDMP SHLD 31 ;RESTART VECTOR MVI A,0C3 STA 30 ;PUT IN JUMP LXI H,MSG2 CALL MSGOUT ;START TARGET @ CALL ADDIN ;GET ADDRESS PCHL ;GO RUN IT ; ; SUBROUTINE VECTORED TO BY RESTART. ; IT SAVES THE STACK POINTER AND THE ; REGISTER CONTENTS. ; PREDMP: SSPD ST1+1 ;SAVE FOR TRACER SSPD RET2+1 ;SAVE FOR TARGET SHLD RET1+1 ;SAVE HL POP H ;GET RETURN ADDR DCX H ;ADJUST IT LXI SP,WSTAK PUSH H ;PUT RETURN ON IT RET1: LXI H,0 ;RESTORE HL PUSH PSW ;SAVE REGS PUSH B PUSH D PUSH H PUSH X LHLD RET2+1 PUSH H ;SAVE SP EXAF PUSH PSW EXAF EXX PUSH B PUSH D PUSH H EXX PUSH Y JMP DUMP ;USER DISPLAY ROUTINE ; ; SUBROUTINE TO RESTORE REGISTERS ; AND REENTER TARGET PROGRAM. ; REENT: LXI SP,SAVHL POP H ;RESTORE REGS POP D POP B POP PSW RET2: LXI SP,0 ;RESTORE TARGET STACK RET ;BACK TO TARGET PRGM ; ;===================== ; MAIN TRACER PROGRAM. ;===================== ; ;TRACER RESTORES OPCODE ;AT THE BREAKPOINT,CALCULATES ;THE NEXT OP-CODE TO BE EXECUTED ;THEN RESTORES THE REGISTERS AND ;REENTERS THE TARGET PROGRAM. ; START: MVI D,0F7 ;RESTART OP-CODE LHLD B2 ;DISPLACED OP-CODE ST1: LXI SP,0 ;TARGET SP MOV A,H ;FIRST BYTE (B1) MOV E,A ; E = B1 CPI 76 ;HALT INST? JZ AHALT ;EXIT ===> CPI 0FD ;INDEX TYPE? JZ IX CPI 0DD JZ IX CPI 0CB JZ TWOBT CPI 0E9 JZ PCHL CPI 0ED JZ EDCODE ; ; TEST FOR RETURN TYPE INSTR. ; LXI B,0A LXI H,ONE CCIR XRA A CMP C JNZ RETTST ; ; TEST FOR THREE BYTE LOADS ; MOV A,E LXI B,9 CCIR XRA A CMP C JNZ THRBT ; ; TEST FOR TWO BYTE LOADS ; MOV A,E LXI B,13 CCIR XRA A CMP C JNZ TWOBT ; ;TEST FOR THREE BYTE CALLS AND JMPS ; MOV A,E LXI B,13 CCIR XRA A CMP C JNZ CALLTST ; ; TEST FOR RESTARTS ; MOV A,E LXI B,7 CCIR XRA A CMP C JNZ RST ; ; TEST FOR RELATIVE JUMPS ; MOV A,E LXI B,7 CCIR XRA A CMP C JNZ JRTST JMPR ONEBT ; ; TEST FOR DD/FD/ED __ XX XX INSTR. ; EDCODE: MOV A,L ;A = B2 LXI B,0C LXI H,DDFD4 CCIR XRA A CMP C JRNZ FRBT JMPR TWOBT ; ;TEST FOR DD/FD __ XX INSTR ; IX: MOV A,L ;A = B2 LXI B,19 LXI H,DDFD3 CCIR XRA A CMP C JRNZ THRBT ; ; TEST FOR DD/FD __ INSTR ; MOV A,E LXI B,0C CCIR XRA A CMP C JRNZ TWOBT ; ; FOLLOWING ROUTINES: ; 1) RESTORE DISPLACED OP-CODE ; 2) EXIT WITH HL ->NXT OP-CODE ; ENTER WITH RESTART ADDR+1 ON STACK ; AND E REG =DISPLACED BYTE (B1). ; FRBT: POP H ;LOC OF RESTART + 1 DCX H ;PT TO RESTART PUSH H ;SET UP RETURN MOV A,E ;RESTORE DISPLACED CODE MOV M,A INX H ;HL -> NEXT OP-CODE INX H INX H INX H JMPR RT1 ; THRBT: POP H DCX H PUSH H MOV A,E MOV M,A INX H JMPR TW1 ; TWOBT: POP H DCX H PUSH H MOV A,E MOV M,A TW1: INX H INX H JMPR RT1 ; ONEBT: POP H DCX H PUSH H MOV A,E MOV M,A INX H JMPR RT1 ; CALL: POP H DCX H PUSH H MOV A,E MOV M,A ;RESTORE OP-CODE INX H ;GET CALL ADDR. MOV E,M INX H MOV D,M XCHG ;HL->NXT OP-CODE MOV A,M MVI M,0F7 ;INSTALL RST JMPR RT2 ; JR: POP H DCX H PUSH H MOV A,E MOV M,A ;RESTORE OP-CODE INX H MOV A,M ;RELATIVE OFFSET CMP B JM JR1 ;J IF NEG OFFSET INX H ADD L ;CALC NXT ADDR. JMPR JR2 ; JR1: CMP L MOV B,A MOV A,L SUB B ;CALC NXT ADDR. JR2: MOV L,A ;HL->NXT OP-CODE JMPR RT1 ; ;ON A RESTART THE PROGRAM EXPECTS A ;JUMP INSTRUCTION. THE ROUTINE GETS ;THE ADDRESS OF THE JUMP AND PUTS IT ;IN THE HL REG. ; RST: POP H DCX H PUSH H MOV A,E ;RESTORE OP-CODE MOV M,A XRI 0C7 ;WHICH RESTART? INR A ;RST ADDR + 1 MOV L,A MVI H,0 ;HL = RESTART + 1 SPHL POP H ;HL->NXT OP-CODE JMPR RT1 ; PCHL: POP H DCX H PUSH H MOV A,E MOV M,A ;RESTORE OP-CODE LHLD SAVHL ;GET HL JMPR RT1 ; RET: POP H DCX H PUSH H MOV A,E MOV M,A ;RESTORE OP-CODE POP H ;GET PAST RENTRY PT. POP H ;HL->RETURN ON STACK RT1: MOV A,M ;NXT OP-CODE MOV M,D ;PUT IN RESTART RT2: STA B1 ;SAVE OP-CODE JMPR END ;GO EXIT ; ; TEST CONDITIONAL RELATIVE JUMPS ; TO DETERMINE NEXT OP-CODE TO BE ; EXECUTED. ; ROUTINE INSTALLS THE OP-CODE IN ; ITSELF AND RESTORES PSW. IT THEN ; EXECUTES THE OPCODE TO DETERMINE ; THE CONDITIONAL RESULT. ; JRTST: MOV A,E LXI SP,SAVPSW STA JRT1 ;PUT OP-CODE IN! POP PSW ;TARGET PSW JRT1: JMPR JT1 ;TEST DONE HERE! LSPD ST1+1 ;<- IF NO JMP JMPR TWOBT ; JT1: LSPD ST1+1 ;<- IF JMP JMPR JR ;CALC REL JMP ; ; CONDITIONAL CALL TEST ; PROGRAM STORES CONDITIONAL CALL ; IN ITSELF AND TESTS THE RESULT. ; CALLTST:MOV A,E LXI SP,SAVPSW STA CALL1 ;PUT IN OPCODE POP PSW ;TARGET PSW LXI SP,0FFFF;OUT OF THE WAY CALL1: CALL CALL3 ;TEST HERE! CALL2: LSPD ST1+1 ;<-IF NO CALL JMP THRBT ; CALL3: LSPD ST1+1 ;<-IF CALL JMP CALL ; ; CONDITIONAL RETURN TEST ; INSTALLS CONDITIONAL RETURN ; THEN EXECUTES IT TO OBSERVE ; THE RESULT. ; RETTST: MOV A,E ;B1 LXI SP,SAVPSW STA RE1 ;PUT IN OPCODE POP PSW ;TARGET PSW LXI SP,DSPL ;SP -> RE2 RE1: RET ;TEST HERE! LSPD ST1+1 ;<-IF NO RETURN JMP ONEBT ; RE2: LSPD ST1+1 ;<-IF RETURN JMP RET ; DSPL: .WORD RE2 ;RET ADDR FOR TEST ; END: INX H ;SECOND BYTE OF OP-CODE MOV A,M STA B2 ;SAVE IT JMP REENT ;GO REENTER TARGET PRGM ; ;====================== ; REGISTER DUMP ROUTINE ;====================== ;ROUTINE TO DISPLAY CONTENTS OF ;REGISTERS TO THE DISPLAY DEVICE ; DUMP: LXI SP,STACK LXI H,SAVRST+1 LXI D,RLABEL MVI C,0DH ;FIELDS TO DISP. ..A: CALL REGOUT ;PRINT A FIELD DCR C JRNZ ..A ;LOOP TILL DONE CALL CTEST ;CK KEYBD JZ START ;Z=NO KEY CPI 1BH ;PAUSE CHAR? JNZ START ;NZ=NO LXI H,PROMPT CALL MSGOUT ..B: CALL CTEST JRZ ..B ;Z=NOT YET CPI 1BH JZ START ANI 0DF ;EITHER 'X' CPI 'X' JZ RESTORE ;COMMAND MODE JMPR ..B ; ;OUTPUT REGISTER LABEL AND ;CONTENTS. ; REGOUT: XCHG CALL MSGOUT ;PRNT LABEL XCHG CALL HXOUT ;SEND A BYTE DCX H CALL HXOUT DCX H RET ; MSGOUT: MOV B,M ;MSG LENGTH ..A: INX H ;GET CHAR MOV A,M CALL COUT ;PRINT IT DCR B JRNZ ..A ;NZ=NOT DONE INX H RET ; ;OUTPUT (HL) IN ASCII ; HXOUT: MOV A,M RAR ;LOWER NIBBLE RAR RAR RAR CALL BINAS ;CONVERT MOV A,M BINAS: ANI 0FH ADI 30H CPI 3AH JRC ..A ADI 07H ..A: CALL COUT RET ; ;KEYBOARD INPUT ROUTINE. ;RETURNS WITH: ; Z=1 NO KEY PUSHED ; Z=0 KEY PUSHED (DATA IN 'A' REG) ; CTEST: IN CSTAT ;KEY PUSHED? ANI RDYMSK ;CK RDY BIT RZ ;Z=NO KEY IN CDATA ;GET DATA ANI 7F ;MASK PARITY RET ; ;INPUT A HEX ADDRESS. ;RETURNS WITH ADDRESS ;IN HL REG. ; ADDIN: LXI H,0 ;START WITH 0 ..A: CALL CTEST ;KEY? JRZ ..A CPI 0D ;DONE? RZ ;Z=YES MOV B,A ;SAVE CHAR CPI 61 ;LOWER CASE? JRC ..B ;C = NO SUI 20 ;REMOVE BIAS ..B: SUI '0' ;ASCII BIAS JRC ..A ;C=NOT HEX CPI 17 JRNC ..A ;NC= NOT HEX CPI 10 JRZ ..A ;Z= NOT HEX JRC ..C ;C= < 'A' SUI 7 ;MORE BIAS ..C: DAD H ;SHIFT OVER DAD H DAD H DAD H ORA L ;PUT IN CHAR MOV L,A MOV A,B ;GET ORIGINAL CALL COUT ;ECHO IT JMPR ..A ;MORE DIGITS ; ;FLAG HALT AND GO TO COMMAND MODE ; AHALT: LXI H,HLTMSG CALL MSGOUT ;PRINT IT ; ;RESTORE TARGET PROGRAM ; RESTORE:LDA B1 ;DISPLACED OP-CODE LHLD SAVRST ;RESTART LOC. MOV M,A ;FIX IT JMP INIT ;TO COMMAND MODE ; ;=========================== ; LOOK UP TABLES FOR VARIOUS ; OP-CODES. ;=========================== ; TABLE: ONE: .BYTE 0C0,0C8,0D0,0D8 .BYTE 0E0,0E8,0F0,0F8 .BYTE 0C9,0 ; THRLDS: .BYTE 01,11,21,31 .BYTE 22,2A,32,3A .BYTE 0 ; TBYTE: .BYTE 06,0E,16,1E .BYTE 26,2E,36,3E .BYTE 0D3,0DB,0C6,0CE .BYTE 0D6,0DE,0E6,0EE .BYTE 0F6,0FE,0 ; JMPCAL: .BYTE 0C2,0CA,0D2,0DA .BYTE 0E2,0EA,0F2,0FA .BYTE 0C3,0C4,0CC,0D4 .BYTE 0DC,0E4,0EC,0F4 .BYTE 0FC,0CD,0 ; RSTS: .BYTE 0CF,0D7,0DF,0E7 .BYTE 0EF,0F7,0 ; JRS: .BYTE 10,18,20,28 .BYTE 30,38,0 ; DDFD3: .BYTE 34,35,70,71 .BYTE 72,73,74,75 .BYTE 77,46,4E,56 .BYTE 5E,66,6E,7E .BYTE 86,8E,96,9E .BYTE 0A6,0AE,0B6,0BE .BYTE 0 ; DDFD2: .BYTE 09,19,23,29 .BYTE 2B,39,0E1,0E3 .BYTE 0E5,0E9,0F9,0 ; DDFD4: .BYTE 21,22,2A,36 .BYTE 43,4B,53,5B .BYTE 73,7B,0CB,0 ; ;LABELS FOR REGISTER DISPLAY ; RLABEL: .ASCII [5][0D][0A]'PC=' .ASCII [4]' AF=' .ASCII [4]' BC=' .ASCII [4]' DE=' .ASCII [4]' HL=' .ASCII [4]' IX=' .ASCII [4]' SP=' .ASCII [0D][0D][0A]" AF'" .ASCII [4]" BC'" .ASCII [4]" DE'" .ASCII [4]" HL'" .ASCII [4]" IY=" .ASCII [4]" B1=" MSG1: .ASCII [13][0D][0A]"START TRACE AT-> " MSG2: .ASCII [13][0D][0A]"START TARGET AT> " PROMPT: .ASCII [0A] [0D][0A]" TRACE >" HLTMSG: .ASCII [0C] [0D][0A]"HALTED !!!" ; ;=============================== ;TEMPORARY STORAGE FOR DISPLACED ;BYTES FROM TARGET PROGRAM. ;=============================== ; B2: .BYTE 0 ;FIRST BYTE B1: .BYTE 0 ;SECOND BYTE ; ;==================================== ;STORAGE FOR TARGET PROGRAM REGISTERS ;==================================== ; SAVY: .WORD 0 ;Y REG SAVHLP: .WORD 0 ;HL' REG SAVDEP: .WORD 0 ;DE' REG SAVBCP: .WORD 0 ;BC' REG SAVAFP: .WORD 0 ;PSW' REG SAVSP: .WORD 0 ;SP SAVX: .WORD 0 ;X REG SAVHL: .WORD 0 ;HL REG SAVDE: .WORD 0 ;DE REG SAVBC: .WORD 0 ;BC REG SAVPSW: .WORD 0 ;AF REG SAVRST: .WORD 0 ;LOC OF RST WSTAK: .BLKB 20H ;ROOM FOR STACK STACK: .BLKB 20H ;LOCAL STACK ; .END INIT