TITLE '6800 EMULATOR (8080A-BASED)' PAGE 60 $-PRINT ; ; THIS IS DESIGNED TO RUN UNDER THE CP/M DISK OPERATING SYSTEM ; AND WILL EXECUTE CODE FOR THE 6800 MICROPROCESSOR. SINCE IT ; IS AN EMULATOR, THE SPEED IS MARKEDLY REDUCED. THE EMULATOR ; ALLOWS THE TRACE (T), UNTRACE(U), AND EXAMINE (X) MODES ; SIMILAR TO CP/M'S DDT. IT IS PLANNED TO ADD OTHER DDT ; TO THIS PROGRAM AS TIME PROGRESSES. THIS PROGRAM WILL ASK ; AN OFFSET SO THE 6800 CODE CAN BE RUN WITHOUT INTERFERING WITH ; EITHER CP/M OR THE EMULATOR. WARNING MESSAGES WILL BE PROVIDED ; IF AN ATTEMPT IS MADE TO LOAD THE 6800 PROGRAM SO IT INTERFERS ; WITH EITHER CP/M OR THE EMULATOR. ; ; *** EQUATES *** ; INH: EQU 0 ;INHERENT ADDRESSING MODE REL: EQU 1 ;RELATIVE IMM: EQU 2 ;IMMEDIATE DIR: EQU 3 ;DIRECT IND: EQU 4 ;INDEXED EXT: EQU 5 ;EXTENDED ; FCB: EQU 5CH ;CP/M FILE CONTROL BLOCK MACLIB MACRO ;INCLUDE OUR GENERAL-PURPOSE LIBRARY ORG 100H ;STARTING PLACE FOR CPM $+PRINT JMP EMUL ;GO TO START OF PROGRAM ILEG1: JMP NOGOOD ; ILEG2: JMP NOGOOD ; THESE ARE FOR USER INSTRUCTIONS ILEG3: JMP NOGOOD ; ILEG4: JMP NOGOOD ; ; *** THE FOLLOWING AREA REPRESENTS THE REGISTERS OF THE ; MOTOROLA M6800 MICROPROCESSOR *** ; ACCA: DB 0 ;ACCUMULATOR A ACCB: DB 0 ;ACCUMULATOR B IXRG: DW 0 ;INDEX REGISTER SPTR: DW 0 ;6800 STACK POINTER PCTR: DW 0 ;6800 PROGRAM COUNTER ; ; FOLLOWING ARE CONDITION CODE REGISTERS ; CARY: DB 0 ;CARRY FLAG OFLW: DB 0 ;ARTH. OVERFLOW ZERO: DB 0 ;ZERO FLAG NEGA: DB 0 ;NEGATIVE IMSK: DB -1 ;INTERRUPT MASK (DISABLED) HCRY: DB 0 ;HALF-CARRY FLAG ; ; *** END OF M6800 REGISTERS *** $-PRINT EMUL: LXI SP,STACK ;SET UP STACK LHLD 6 ;CDOS CALL LOCATION LXI D,-900H ;DOWN FOR BASE OF CP/M DAD D ;ADD TO BASE(CPM-900H)= SHLD CBASE ;CBASE FILL OFFSET,TRFLAG ;ZERO REGISTERS LXI H,TOP ;SET INITIAL OFFSET TO ZERO SHLD OFFSET ;SAVE IT! MVI A,1 ;INITIALIZE PASS COUNTER STA COUNT DISKIO ?DRIVE ;GET CURRENTLY LOGGED DRIVE NO STA NEWDRV ;ALSO SAVE IN NEW DRIVE NO LDA 81H ;CONSOLE INPUT ALREADY HERE ? ORA A JZ SIGNON ;BUFFER EMPTY, INPUT FROM CONSOLE LDA 80H ;GET NO OF CHAR INPUT ORI 80H ;ADD 128 MOV L,A ;TO L XRA A ;ZERO MOV H,A ;HL CONTAINS ADDR OF END OF BUFFER ZBFF: INR L JZ START ;REMAINDER OF BUFFER ZEROED MOV M,A JMP ZBFF ;LOOP SIGNON: PRINT PRINT <'COPYRIGHT 1980 BY R. B. KOLBLY',CR,LF> JMP MAIN ;NO FILE, GO TO MAIN LOOP NEWIN: PRINT MVI A,0FFH ;SET SWITCH TO RETURN HERE AGAIN STA INFLAG LXI SP,STACK ;RESET STACK POINTER XRA A STA VALFLG ;RESET VALIDATION ERROR FLAG FILL 80H,0FFH ;ZERO INPUT BUFFER INPUT 80H ;READ FILE NAME ; ; SELECT DISK DRIVE AND SET UP FILE CONTROL BLOCK ; START: FILL FCB,FCB+32 ;ZERO FILE CONTROL BLOCK MATCH 82H,'A:' ;DRIVE A JZ ADISK MATCH 82H,'B:' ;DRIVE B JZ BDISK JMP FILNAM ;NO DRIVE SPECIFIED ADISK: XRA A STA NEWDRV ;SELECT DRIVE A JMP DOWN BDISK: MVI A,1 STA NEWDRV ;SELECT DRIVE B DOWN: MOVE 82H,80H,40H ;SHIFT BUFFER DOWN TWO BYTES JMP FILNAM MAIN: PRINT ;PROMPT CHARACTER CALL ZBUFF ;ZERO OUT BUFFER INPUT BUFFER,32 ;GET COMMAND STRING LXI H,BUFFER+2 ;POINT TO FIRST CHARACTER IN BUFFER MOV A,M ;GET IT TO ACCUMULATOR CPI 'T' ;IS IT TRACE? JZ TRACE ;DO IT CPI 'U' ;UNTRACE (INVISIBLE TRACE) JZ UNTRA CPI 'X' ;EXAMINE/CHANGE REGISTERS JZ EXAM CPI 'I' ;SET UP FILE CONTROL BLOCK JZ NEWIN CPI 'R' ;READ FILE INTO MEMORY JÚ BIAS CPÉ 'G§ ;GÏ TÏ ADDRESS AND EXECUTE JZ GOTO CPI 'D' ;DUMP PROGRAM MEMORY JZ DUMP CPI 'S' ;SET MEMORY VALUE JZ SETM CPI 'V' ;SET INTERRUPT VECTORS JZ VECTS JMP ERROR ;INVALID COMMAND, GET NEXT ; UNTRA: MVI A,0 ;SET TRACE OFF JMP TRACE+2 TRACE: MVI A,-1 ;SET TRACE FLAG ON STA TRFLAG ;SAVE FOR FUTURE REFERENCE CALL CRLF DECIN BUFFER+3 ;DO A DECIMAL CONVERSION JC TRAC2 ;ERROR, DO ONE TRACE STA COUNT ;SET COUNT PASS ORA A ;IS IT ZERO? JNZ TRAC2 ;NOT ZERO,CONTINUE INR A ;MAKE IT ONE! STA COUNT TRAC2: CALL STEP ;DO THE NEXT PROGRAM STEP LDA COUNT ;GET PASS COUNTER DCR A ;DROP ONE PASS STA COUNT ;SAVE THE COUNT JNZ TRAC2 ;LOOP UNTIL DONE ENDTR: MVI A,1 ;SET UP FOR NEXT PASS STA COUNT ;SAVE FOR NEXT TIME JMP MAIN ;BACK AGAIN ; ; FILL IN FCB FOR NAMED FILE ; SETUP: FILNAM: FILFCB FCB,82H ;FILL IN FCB NAME FROM INPUT BUFFER JC ERROR ;ERROR IN FILE NAME LXI H,TOP ;START AT TOP OF PROGRAM SHLD FPNTR ;SET FILE(MEMORY) POINTER SELDR: LDA NEWDRV ;SELECT NEW DRIVE MOV E,A DISKIO LOGIN DISKIO OPEN,FCB ;OPEN FILE CPI 255 ;CHECK FILE PRESENT JZ ERROR ;EXIT IF ERROR RDFILE: DISKIO READ,FCB ;READ A BLOCK ORA A ;ZERO INDICATES SUCESSFUL READ JNZ MAIN ;1 INDICATES EOF CALL BUFMOV ;DO BUFFER MOVE TO WERE USED JMP RDFILE ;BACK FOR NEXT BLOCK ; BUFMOV: LHLD FPNTR ;GET MEMORY POINTER XCHG ;PUT IN DE LXI H,80H ;GET DISK BUFFER LXI B,80H ;LENGTH TO MOVE MOVE LHLD FPNTR ;GET BACK MEMORY POINTER LXI D,80H DAD D ;UP COUNT SHLD FPNTR ;SAVE FOR LATER XCHG ;TO THE DE REGISTER LHLD CBASE ;MAXIMUM BUFFER VALUE CPHL ;COMPARE(LOGICAL SUBTRACT) RM ;IF DE DISKIO CLOSE,FCB ;CLOSE THE FILE JMP MAIN ; STEP: LDA TRFLAG ;GET PRINT FLAG ORA A ;SET FLAGS CNZ DSPLY ;IF ZERO, DON'T DISPLAY CALL BREAK ;CHECK IF STOP ORA A ;SET FLAGS JNZ ENDTR ;A KEY HAS BEEN HIT! STEPX: LHLD OFFSET ;GET OFFSET VALUE XCHG ;TO [DE] REGISTER LHLD PCTR ;GET PROGRAM COUNTER DAD D ;CALCULATE LOCATION SHLD POINT ;ACTUAL MEMORY POINTER MOV A,M ;GET INSTRUCTION STA TEMPA ;SAVE FOR FUTURE USE CALL SMODE ;SET ADDRESSING MODE JMP DSPCH ;NOW DO THE CODE ; ; FROM HERE WE WILL FAKE A NOP FOR NOW ; NOGOOD: MVI A,-1 ;SET NOGOOD FLAG STA GDFLG LHLD PCTR ;GET PROGRAM COUNTER INX H ;DONE UP IT ONE! SHLD PCTR ;AND RESTORE CALL INRPT ;CHECK FOR INTERRUPTS RET ;ALL DONE WITH STEP ; ; THIS ROUTINE CHECKS FOR VARIOUS INTERRUPTS OR RESTART ; INRPT: CALL BREAK ;SEE IF KEYBOARD INPUT ORA A JZ INRP1 ;NOBODY, SEE IF PENDING CHARIN ;GET CHARACTER CPI 'R' JZ DORST ;RESET PROCESSOR CPI 'N' JZ DONMI ;NON-MASKABLE INTERRUPT CPI 'I' JZ DOIRQ ;INTERRUPT REQUEST RET ;INVALID COMMAND, RETURN INRP1: LDA IPEND ;GET PENDING INTERRUPT FLAG ORA A RZ ;NONE PENDING, RETURN LDA IMSK ;OTHERWISE, GET INT. MASK ORA A ;TEST IT RNZ ;IF NOT ZERO, RETURN STA IPEND ;CLEAR PENDING FLAG CMA STA IMSK ;DISABLE INTERRUPTS CALL SVALL ;SAVE REGISTERS LHLD WAIV ;GET VECTOR SHLD PCTR ;INTO PROGRAM COUNTER PRINT <'*INTERRUPT*',CR,LF> RET DONMI: CALL SVALL ;SAVE ALL REGISTERS MVI A,-1 STA IMSK ;DISABLE FURTHER INTERRUPTS LHLD NMIV ;POINTER TO ROUTINE SHLD PCTR ;INTO PROGRAM COUNTER PRINT <'*NMI*',CR,LF> RET DORST: FILL ACCA,HCRY ;ZERO ALL REGISTERS MVI A,-1 ;DENY ANY INTERRUPTS STA IMSK LHLD RESTV ;GET RESTART ADDRESS SHLD PCTR ;AND RETURN PRINT <'*RESET*',CR,LF> RET DOIRQ: LDA IMSK ;GET MASK... ORA A ;...AND TEST JZ DOIR1 ;OKAY FOR INTERRUPT STA IPEND ;IF NOT,SET PENDING FLAG RET DOIR1: LDA TEMPA ;GET LAST INSTRUCTION CPI 3EH ;WAS IT A WAIT [WAI]? CNZ SVALL ;IF NOT SAVE REGISTERS MVI A,-1 ;DISABLE INTERRUPT STA IMSK LHLD WAIV ;GET INTERRUPT ROUTINE... SHLD PCTR ;...TO PROGRAM COUNTER PRINT <'*INTERRUPT*',CR,LF> RET ; COMMAND DISPATCHER ; DSPCH: LDA TEMPA ;GET OPCODE MVI H,0 ;ZERO H REG MOV L,A ;DE NOW HAS OPCODE DAD H ;DOUBLE IT XCHG ;TO THE DE REGISTER LXI H,OPTAB DAD D ;HL HAS ROUTINE ADDRESS MOV E,M ;GET LOW ORDER BYTE INX H MOV D,M ;DE NOW HAS ROUTINE ADDRESS XCHG ;TO HL REGISTER PCHL ;GO THERE!!! ; ; OPERATION CODE DISPATCH TABLE ; OPTAB: DW O0,O1,O2,O3,O4,O5,O6,O7,O8,O9,OA,OB DW OC,OD,OE,OF,O10,O11,O12,O13,O14,O15 DW O16,O17,O18,O19,O1A,O1B,O1C,O1D,O1E DW O1F,O20,O21,O22,O23,O24,O25,O26,O27 DW O28,O29,O2A,O2B,O2C,O2D,O2E,O2F,O30 DW O31,O32,O33,O34,O35,O36,O37,O38,O39 DW O3A,O3B,O3C,O3D,O3E,O3F,O40,O41,O42 DW O43,O44,O45,O46,O47,O48,O49,O4A,O4B DW O4C,O4D,O4E,O4F,O50,O51,O52,O53,O54 DW O55,O56,O57,O58,O59,O5A,O5B,O5C,O5D DW O5E,O5F,O60,O61,O62,O63,O64,O65,O66 DW O67,O68,O69,O6A,O6B,O6C,O6D,O6E,O6F DW O70,O71,O72,O73,O74,O75,O76,O77,O78 DW O79,O7A,O7B,O7C,O7D,O7E,O7F,O80,O81 DW O82,O83,O84,O85,O86,O87,O88,O89,O8A DW O8B,O8C,O8D,O8E,O8F,O90,O91,O92,O93 DW O94,O95,O96,O97,O98,O99,O9A,O9B,O9C DW O9D,O9E,O9F,OA0,OA1,OA2,OA3,OA4,OA5 DW OA6,OA7,OA8,OA9,OAA,OAB,OAC,OAD,OAE DW OAF,OB0,OB1,OB2,OB3,OB4,OB5,OB6,OB7 DW OB8,OB9,OBA,OBB,OBC,OBD,OBE,OBF,OC0 DW OC1,OC2,OC3,OC4,OC5,OC6,OC7,OC8,OC9 DW OCA,OCB,OCC,OCD,OCE,OCF,OD0,OD1,OD2 DW OD3,OD4,OD5,OD6,OD7,OD8,OD9,ODA,ODB DW ODB,ODD,ODE,ODF,OE0,OE1,OE2,OE3,OE4 DW OE5,OE6,OE7,OE8,OE9,OEA,OEB,OEC,OED DW OEE,OEF,OF0,OF1,OF2,OF3,OF4,OF5,OF6 DW OF7,OF8,OF9,OFA,OFB,OFC,OFD,OFE,OFF ; ; PROGRAMS TO EXECUTE M6800 OPCODES - CALLED FROM DSPCH - ; NO GARANTEES ON REGISTERS ON EXIT... ; O0: LHLD OFFSET ;THIS IS OUR BREAKPOINT CODE XCHG LHLD PCTR ;PROGRAM COUNTER DAD D ;ACTUAL MEMORY LOCATION LDA OCODE ;CODE THAT WAS ORIGINALLY THERE MOV M,A ;PUT IT BACK! JMP MAIN ;TO THE COMMAND LOOP ; O1: JMP GOOD ;EFFECTIVE NOP ; O2: JMP ILEG1 ;USER DEFINED TRAP O3: JMP ILEG2 O4: JMP ILEG3 O5: JMP ILEG4 ; O6: CALL TAP ;[TAP] CC REGS <- ACCA JMP GOOD TAP: LXI H,CARY LXI B,100H LDA ACCA ;ACCUM VALUE MOV C,A ;TEMPORARY STORE TAP1: ANA B ;MASK REGISTER BIT MVI A,0 JZ TAP2 CMA TAP2: MOV M,A ;SET APPROPRIATE REGISTER MOV A,B ;GET MASK RAL ;ROTATE IT CPI 40H ;DONE? RZ ;YES, GO BACK MOV B,A ;PUT MASK BACK MOV A,C ;GET CCR INX H ;LOOK AT NEXT JMP TAP1 ;DO MORE! ; O7: CALL TPA ;[TPA] ACCA <- CC REGISTERS STA ACCA ;PUT THEM AWAY JMP GOOD TPA: LXI H,CARY ;THIS TRANSFERS CCR TO ACC A LXI B,100H TPA1: MOV A,M ;GET FLAG ANA B ;MASK ORA C ;OR WITH C MOV C,A ;AND IN C REG MOV A,B RAL ;ROTATE MASK BIT CPI 40H ;DONE JZ TPA2 MOV B,A INX H ;NEXT FLAG JMP TPA1 TPA2: MOV A,C ;GET FINAL VALUE ORI 0C0H ;SET MSB'S HIGH RET ; O8: LHLD IXRG ;THIS INCREMENTS INDEX REGISTER INX H ; SHLD IXRG O8X: MOV H,A ;NOW WE WILL CHECK FOR ZERO ORA L MVI A,0 JNZ $+4 ;JUMP OVER IF NOT ZERO CMA ;MAKE 0FFH IF ZERO STA ZERO ;SET ZERO FLAG JMP GOOD ;DO PC ; O9: LHLD IXRG ;DECREMENT INDEX REGISTER DCX H SHLD IXRG JMP O8X ;DO ZERO FLAG AND PC ; OA: MVI A,0 ;CLEAR OVERFLOW FLAG STA OFLW JMP GOOD OB: MVI A,-1 ;SET OVERFLOW FLAG STA OFLW JMP GOOD OC: MVI A,0 ;CLEAR CARRY FLAG STA CARY JMP GOOD OD: MVI A,-1 ;SET CARRY FLAG STA CARY JMP GOOD OE: XRA A ;CLEAR INTERRUPT MASK STA IMSK JMP GOOD OF: MVI A,-1 ;SET INTERRUPT MASK STA IMSK JMP GOOD O10: LDA ACCA ;[SBA] ACCA <- (ACCA)-(ACCB) MOV B,A LDA ACCB ;GET THE 'B' ACCUMULATOR MOV C,A ;SAVE SBB B ;SUBTRACT... STA ACCA ;AND INTO 'A' ACCUMULATOR O10A: MVI A,0 ;THIS IS A RESET FLAG VALUE PUSH PSW ;AND SAVE JNZ $+4 ;FIRST WE SET THE ZERO FLAG CMA STA ZERO POP PSW PUSH PSW JP $+4 ;IF NOT ZERO,JUMP AROUND CMA ;MAKE 0FFH IF ZERO STA NEGA ;NEGATIVE FLAG POP PSW ;GET FLAGS AND 0 BACK PUSH PSW ;BACK ON STACK JNC $+4 ;WILL SET/RESET CARRY CMA STA CARY ;SET THE CARRY FLAG POP PSW ;...REQUIRED FOR STACK BALANCE CALL SUBTS ;TEST FOR OVERFLOW ON SUB. JMP GOOD ;DONE O11: LDA ACCB ;THIS IS [CBA] MOV B,A LDA ACCA ;GET 'A' ACCUM MOV C,A SUB B ;SUBTRACT JMP O10A ;SAME FROM HERE ON OUT! ; O12: LHLD OFFSET ;THIS IS OUR SECOND BREAKPOINT XCHG LHLD PCTR ;GET PROGRAM COUNTER DAD D LDA OCODE1 ;ORIGINAL PROGRAM... MOV M,A ;...IS PUT BACK JMP MAIN ;AND TO COMMAND LOOP O13: O14: O15: O18: O1A: O1C: O1D: O1E: O1F: JMP NOGOOD ; O16: LDA ACCA ;[TAB] ACCB <-- (ACCA) ORA A ;SET FLAGS STA ACCB O16A: MVI A,0 STA OFLW ;RESET OVERFLOW FLAG PUSH PSW JNZ $+4 CMA ;SET ZERO FLAG STA ZERO POP PSW JP $+4 ;SET MINUS FLAG CMA STA NEGA JMP GOOD O17: LDA ACCB ;[TBA] ACCA <-- (ACCB) ORA A ;SET FLAGS STA ACCA JMP O16A ;FROM HERE SAME AS [TAB] O19: LDA CARY ;[DAA] DECIMAL ADJUST ACCUM RAL ;WILL SET CARRY FLAG LDA ACCA ; DAA STA ACCA ;RESTORE CALL DOFLAG ;SET ALL APPROPRIATE FLAGS JMP GOOD O1B: LDA ACCA ;[ABA] MOV C,A LDA ACCB MOV B,A ADD C STA ACCA ;HERE GO THE RESULTS PUSH PSW ;SAVE RESULTS CALL ADDTS ;TEST FOR OVERFLOW POP PSW CALL DOFLAG ;SET N,Z,C CALL HFCRY ;SET HALF-CARRY FLAG JMP GOOD ; ; HERE ARE THE BRANCH INSTRUCTIONS... ; O20: ;BRANCH ALWAYS... BRA: LHLD PCTR XCHG LHLD OFFSET DAD D INX H ;POINT AT OFFSET MOV A,M ;RECOVER VALUE INX H ;FOR PROPER VALUE MOV E,A MVI D,0 ;GET OFFSET IN DE REGISTER ORA A ;SET FLAGS JP O20A ;IF PLUS, WE ARE OKAY... CMA ;COMPLIMENT MOV E,A ;PUT IN DE INX D ;MAKE 2'S COMPLIMENT NOP!NOP!NOP!NOP!NOP! NOP!NOP! ;FOR PATCHES IF NEEDED CALL NEGDE ;NEGATE--- O20A: LHLD PCTR ;PROGRAM COUNTER DAD D ;NEW REGISTER VALUE SHLD PCTR ;WE GOT IT JMP GOOD ;DO THE REST O21: JMP NOGOOD ;BAD OPCODE O22: CALL HITST ;[BHI] BRANCH IF HIGHER O22A: JNC GOOD ;TEST NOT MET JMP BRA ;BRANCH O23: CALL LSTST ;[BLS] BRANCH IF LOWER OR SAME JMP O22A O24: CALL CCTST ;[BCC] BRANCH IF CARRY CLEAR JMP O22A ; O25: CALL CSTST ;[BCS] BRANCH IF CARRY SET JMP O22A O26: CALL NETST ;[BNE] BRANCH IF NOT EQUAL JMP O22A O27: CALL EQTST ;[BEQ] BRANCH IF EQUAL JMP O22A O28: CALL VCTST ;[BVC] BRANCH IF OVERFLOW CLEAR JMP O22A O29: CALL VSTST ;[BVS] BRANCH IF OVERFLOW SET JMP O22A O2A: CALL PLTST ;[BPL] BRANCH IF PLUS JMP O22A O2B: CALL MITST ;[BMI] BRANCH IF MINUS JMP O22A O2C: CALL GETST ;[BGE] BRANCH IF GREATER THAN.. JMP O22A ;OR EQUAL TO ZERO O2D: CALL LTTST ;[BLT] BRANCH IF LESS THAN ZERO JMP O22A O2E: CALL GTTST ;[BGT] BRANCH IF GREATER THAN ZERO JMP O22A O2F: CALL LETST ;[BLE] BRANCH IF LESS THAN OR EQUAL JMP O22A ; TO ZERO ; ; BOOLIAN TEST ROUTINES...RETURN WITH CARRY SET IF TEST TRUE ; CCTST: LDA CARY ;CARRY CLEAR CMA RAL RET CSTST: LDA CARY ;CARRY SET RAL RET EQTST: LDA ZERO ;EQUAL RAL RET NETST: LDA ZERO ;NOT EQUAL CMA RAL RET MITST: LDA NEGA ;MINUS RAL RET PLTST: LDA NEGA ;PLUS CMA RAL RET VCTST: LDA OFLW ;OVERFLOW CLEAR CMA RAL RET VSTST: LDA OFLW ;OVERFLOW SET RAL RET GETST: LDA NEGA ;GREATER THAN OR EQUAL MOV B,A LDA OFLW XRA B STC RZ ;CONDITION MET CMC ;SET CARRY TO ZERO RET GTTST: CALL GETST ;GREATER THAN ZERO RNC ;CONDITION NOT MET LDA ZERO CMA RAL RET HITST: LDA CARY ;HIGHER ORA A RNZ LDA ZERO CMA RAL RET LTTST: LDA NEGA ;LESS THAN ZERO CMA MOV B,A LDA OFLW XRA B STC RZ ;CONDITION MET CMC RET LETST: LDA ZERO ;LESS THAN OR EQUAL TO ZERO RAL RC ;ZERO, SO RETURN JMP LTTST LSTST: LDA CARY ;LOWER OR SAME RAL RC LDA ZERO RAL RET $+PRINT O30: LHLD SPTR ;[TSX] IX <- (SP)+1 INX H SHLD IXRG JMP GOOD O31: LHLD SPTR ;[INS] ICREMENT STACK POINTER INX H SHLD SPTR JMP GOOD O32: CALL PULIT ;[PULA] STA ACCA JMP GOOD O33: CALL PULIT ;[PULB] STA ACCB JMP GOOD O34: LHLD SPTR ;[DES] DECREMENT STACK POINTER DCX H SHLD SPTR JMP GOOD O35: LHLD IXRG ;[TXS] SP <- (IX)-0001 DCX H SHLD SPTR JMP GOOD O36: LDA ACCA ;[PSH A] O36A: CALL PSHIT JMP GOOD O37: LDA ACCB ;[PSH B] JMP O36A O38: O3A: O3C: O3D: JMP NOGOOD ; STACK OPS SUBROUTINES...DATA TRANSFERED BY 'A' PULIT: LHLD SPTR ;CURRENT STACK POINTER INX H SHLD SPTR ;UP COUNT XCHG LHLD OFFSET DAD D MOV A,M ;GET ACTUAL DATA RET PSHIT: LHLD SPTR ;STACK POINTER DCX H SHLD SPTR INX H ;GET CORRECT VALUE XCHG LHLD OFFSET DAD D MOV M,A ;STORE REGISTER ON STACK RET O39: CALL PULIT ;[RTS] RETURN FROM SUBROUTINE MOV B,A CALL PULIT MOV L,A MOV B,H SHLD PCTR ;LOAD PROGRAM COUNTER JMP GOOD O3B: CALL PULIT ;[RTI] RETURN FROM INTERRUPT CALL TAP ;SET CONDITION CODE REGISTERS CALL PULIT STA ACCB CALL PULIT STA ACCA CALL PULIT MOV B,A CALL PULIT MOV L,A MOV H,B SHLD IXRG ;RESTORED INDEX REGISTER CALL PULIT MOV B,A CALL PULIT MOV L,A MOV H,B SHLD PCTR ;RESTORED PROGRAM COUNTER JMP GOOD SVALL: LHLD PCTR ;THIS ROUTINE SAVES ALL 6800 REGS INX H ;NEXT OPERATION SHLD PCTR PUSH H MOV A,L CALL PSHIT POP H MOV A,H CALL PSHIT ;PROGRAM COUNTER NOW ON STACK LHLD IXRG ;GET INDEX REGISTER PUSH H MOV A,L CALL PSHIT POP H MOV A,H CALL PSHIT ;INDEX REGISTER IS NOW STACKED LDA ACCA CALL PSHIT ;STACK ACCUMULATOR A LDA ACCB CALL PSHIT ;ACCUM B CALL TPA ;TRANSFER CONDITION CODES TO 'A' CALL PSHIT ;AND ON TO STACK RET O3E: CALL SVALL ;[WAI] STACK AND WAIT FOR INTERRUPT LDA IMSK ;SEE IF INTERRUPT ALLOWED ORA A JNZ O3EA ;NOT ENABLED, WE ARE IN TROUBLE! LDA IPEND ;SEE IF... ORA A ;...AN INTERRUPT IS PENDING JZ O3EC ;NONE ARE WAITING STA IMSK ;DISABLE FURTHER INTERRUPTS CMA STA IPEND ;CLEAR PENDING FLAG LHLD WAIV ;GET ADDRESS... SHLD PCTR ;...TO PROGRAM COUNTER RET O3EA: PRINT <'*WAITING FOR RESET OR NMI*',CR,LF> O3EB: CHARIN ;GET KEYBOARD INPUT CPI 'N' ;NON-MASKABLE JZ DONMI CPI 'R' ;RESET? JZ DORST JMP O3EB ;NOTHING ELSE ALLOWED, LOOP! O3EC: PRINT <'*WAITING FOR INTERRUPT*',CR,LF> O3ED: CHARIN ;READ KEYBOARD CPI 'I' JZ DOIR1 ;DO REGULAR INTERRUPT CPI 'R' JZ DORST ;THESE ARE ALSO ALLOWED CPI 'N' JZ DONMI JMP O3ED ;LOOP UNTIL WE SEE WHAT WE LIKE! O3F: CALL SVALL ;[SWI] SOFTWARE INTERRUPT LHLD SWIV ;GET VECTOR SHLD PCTR ;MAKE PROGRAM COUNTER MVI A,-1 ;MASK INTERRUPTS STA IMSK RET O40: LXI H,ACCA ;[NEG] TWO'S COMPLIMENT REGISTER JMP O70A O50: LXI H,ACCB JMP O70A O60: CALL INDXV ;GET INDEXED ADDRESS VECTOR JMP O70A O70: CALL EXTV ;EXTENDED ADDRESS VECTOR O70A: MOV A,M ;GET VALUE CMA INR A ;MAKE 2'S COMPLIMENT MOV M,A ;AND PUT IT BACK PUSH PSW ;SAVE RESULTS CALL DOFLAG ;SET N,Z, C FLAGS POP PSW CPI 80H ;SEE IF OVERFLW CONDITION MVI A,0 JNZ $+4 ;NOT 80H, NO OVERFLOW CMA STA OFLW JMP GOOD O41: O51: O61: O71: O42: O52: O62: O72: JMP NOGOOD ; ; THIS ROUTINE IS USED FOR INSTRUCTIONS >7FH. IT RETURNS THE ; ACCUMULATOR POINTER (A OR B) IN THE DE REGISTER AND THE ; OPERAND VECTOR IN THE HL REGISTER ; ADPTR: CALL AMODE ;GET POINTER TO MEMORY VALUE LDA TEMPA ANI 40H ;MASK BIT FOR ACCUMULATOR JZ $+7 ;IF ZERO, WE NEED ACCA LXI D,ACCB ;POINT TO ACCB RET ;HL ALREADY HAS MEMORY POINTER LXI D,ACCA ;ACCUMULATOR A (ACCA) RET AMODE: LDA TEMPA ;GET OPCODE ANI 30H ;MASK ALL BUT BITS 4 & 5 RAR!RAR!RAR ;DIVIDE BY EIGHT LXI H,ADRTB ;POINT TO ADDRESSING TABLE MOV E,A MVI D,0 ;DE HAS OFFSET DAD D ;GET POINTER TO SUBROUTINE MOV E,M INX H MOV D,M XCHG ;ROUTINE TO HL REGISTER PCHL ;AND GO! ADRTB: DW IMMV ;IMMEDIATE MODE DW DIRV ;DIRECT MODE(PAGE 0) DW INDXV ;INDEXED MODE DW EXTV ;EXTENDED (TWO BYTES) IMMV: LHLD OFFSET ;GET OFFSET VALUE XCHG ;AND PUT IN DE LHLD PCTR ;AND PROGRAM COUNTER INX H ;POINT AT NEXT BYTE DAD D ;HL NOW POINTS AT IMMEDIATE RET ;VALUE DIRV: LHLD OFFSET ;DIRECT (PAGE 0) ADDRESSING XCHG LHLD PCTR ;AND GET PROGRAM COUNTER INX H DAD D ;NOW LOOKING AT PAGE 0 ADDRESS MOV E,M ;AND TO DE REGISTER MVI D,0 ;ZERO MOST SIG. BYTE LHLD OFFSET ;GET OFFSET VALUE DAD D ;MAKE HL ACT. MEM. VECTOR RET ;WITH PAGE 0 ADDRESS IN HL INDXV: LHLD PCTR ;COMPUTE MEM VECTOR FOR INDEXED ADDR XCHG LHLD OFFSET DAD D INX H ;POINT AT OFFSET BYTE MOV E,M MVI D,0 ;DE NOW HAS OFFSET LHLD IXRG ;GET INDEX REGISTER DAD D XCHG LHLD OFFSET DAD D RET ;NOW POINTING AT NEW VECTOR EXTV: LHLD PCTR ;THIS GETS MEMORY VECTOR XCHG ;FOR EXTENDED ADDRESSING LHLD OFFSET DAD D INX H ;HIGH ORDER BYTE MOV D,M INX H ;LOW ORDER BYTE MOV E,M LHLD OFFSET ;GET OFFSET VALUE DAD D ;HL NOW HAS MEM VECTOR RET O43: LXI H,ACCA ;[COM] COMPLIMENT JMP O73A O53: LXI H,ACCB JMP O73A O63: CALL INDXV ;INDEXED POINTER JMP O73A O73: CALL EXTV O73A: MOV A,M CMA MOV M,A PUSH PSW ANI 80H MVI A,0 STA OFLW ;RESET OVERFLOW JZ $+4 CMA STA NEGA ;SET NEGATIVE FLAG POP PSW ORA A MVI A,0 JNZ $+4 CMA STA ZERO ;ZERO FLAG MVI A,-1 STA CARY ;SET CARRY JMP GOOD O44: LXI H,ACCA ;[LSR] LOGICAL SHIFT RIGHT JMP O74A O54: LXI H,ACCB ; JMP O74A O64: CALL INDXV JMP O74A O74: CALL EXTV O74A: MOV A,M ;GET VALUE STC!CMC ;CLEAR CARRY FLAG RAR MOV M,A PUSH PSW MVI A,0 JNC $+4 CMA STA CARY ;DO CARRY FLAG POP PSW MVI A,0 JNZ $+4 CMA STA ZERO ;ZERO AS APPROPRIATE LDA CARY MOV B,A LDA NEGA XRA B ;TEST FOR SAME STA OFLW ;INTO OVERFLOW FLAG MVI A,0 STA NEGA ;RESET NEGATIVE FLAG JMP GOOD O45: O55: O65: O75: JMP NOGOOD O46: LXI H,ACCA ;[ROR] ROTATE RIGHT JMP O76A O56: LXI H,ACCB JMP O76A O66: CALL INDXV JMP O76A O76: CALL EXTV O76A: MOV A,M RAR MOV M,A ;STORE RESULTS PUSH PSW MVI A,0 JNC $+4 CMA STA CARY ;CARRY FLAG POP PSW PUSH PSW ORA A MVI A,0 JNZ $+4 CMA STA ZERO ;ZERO FLAG LDA CARY MOV B,A LDA NEGA XRA B STA OFLW ;OVERFLOW FLAG POP PSW ANI 80H ;MASK FOR MSB MVI A,0 JNZ $+4 CMA STA NEGA ;MINUS FLAG JMP GOOD O47: LXI H,ACCA ;[ASR] ARITHMETIC SHIFT RIGHT JMP O77A O57: LXI H,ACCB JMP O77A O67: CALL INDXV JMP O77A O77: CALL EXTV O77A: MOV A,M RLC ;PUT BIT 7 IN CARRY MOV A,M ;GET ORIGNAL VALUE RAR ;ROTATE WITH BIT 7 HELD MOV M,A PUSH PSW MVI A,0 JNC $+4 CMA STA CARY ;CARRY FLAG LDA NEGA MOV B,A LDA CARY XRA B STA OFLW ;OVERFLW POP PSW PUSH PSW ORA A MVI A,0 JNZ $+4 CMA STA ZERO ;ZERO POP PSW ANI 80H MVI A,0 JNZ $+4 CMA STA NEGA ;MINUS JMP GOOD O48: LXI H,ACCA ;[ASL] ARITHMETIC SHIFT LEFT JMP O78A O58: LXI H,ACCB JMP O78A O68: CALL INDXV JMP O78A O78: CALL EXTV O78A: STC!CMC ;RESET CARRY MOV A,M RAL MOV M,A PUSH PSW MVI A,0 JNC $+4 CMA STA CARY ;CARRY FLAG MOV B,A LDA NEGA XRA B STA OFLW ;OVERFLOW POP PSW PUSH PSW ORA A MVI A,0 JNZ $+4 CMA STA ZERO ;ZERO POP PSW ANI 80H MVI A,0 JZ $+4 CMA STA NEGA ;MINUS FLAG JMP GOOD O49: LXI H,ACCA ;[ROL] ROTATE LEFT JMP O79A O59: LXI H,ACCB JMP O79A O69: CALL INDXV JMP O79A O79: CALL EXTV O79A: MOV A,M RAL MOV M,A PUSH PSW MVI A,0 JNC $+4 CMA STA CARY ;CARRY MOV B,A LDA NEGA XRA B STA OFLW ;OVERFLOW POP PSW ORA A MVI A,0 JNZ $+4 CMA STA ZERO ;ZERO FLAG MVI A,0 JP $+4 CMA STA NEGA ;MINUS JMP GOOD O4A: LXI H,ACCA ;[DEC] ACCX <- (ACCX)-01 JMP O7AA ; M <- (M)-01 O5A: LXI H,ACCB JMP O7AA O6A: CALL INDXV JMP O7AA O7A: CALL EXTV O7AA: MOV A,M DCR A ;DECREMENT VALUE MOV M,A PUSH PSW INR A ;RECOVER ORIGINAL VALUE CPI 80H ;IF 80H... MVI A,0 JNZ $+4 CMA STA OFLW ;OVERFLOW SET IF 80H POP PSW ORA A ;SET FLAGS MVI A,0 PUSH PSW JNZ $+4 CMA STA ZERO ;SET ZERO FLAG POP PSW JP $+4 CMA STA NEGA ;MINUS JMP GOOD O4B: O5B: O6B: O7B: JMP NOGOOD O4C: LXI H,ACCA ;[INC] ACCX <- (ACCX)+01 INCREMENT JMP O7CA O5C: LXI H,ACCB JMP O7CA O6C: CALL INDXV JMP O7CA O7C: CALL EXTV O7CA: MOV A,M INR A MOV M,A CPI 80H ;SEE OF 2'S COMP.OVERFLOW PUSH PSW MVI A,0 JNZ $+4 CMA STA OFLW ;IF IT WAS 7F, OVERFLOW POP PSW ORA A ;SET FLAGS MVI A,0 PUSH PSW JNZ $+4 CMA STA ZERO ;STORE ZERO FLAG POP PSW JP $+4 CMA STA NEGA ;MINUS JMP GOOD O4D: LXI H,ACCA ;[TST] TEST FOR ZERO OR MINUS JMP O7DA O5D: LXI H,ACCB JMP O7DA O6D: CALL INDXV JMP O7DA O7D: CALL EXTV O7DA: MOV A,M ORA A MVI A,0 STA OFLW ;RESET OVERFLOW FLAG STA CARY ;RESET CARRY PUSH PSW JNZ $+4 CMA STA ZERO ;ZERO FLAG POP PSW JP $+4 CMA STA NEGA ;MINUS JMP GOOD O4E: O5E: JMP NOGOOD O6E: CALL INDXV ;[JMP] JUMP XCHG ;PUT MEM VECTOR IN DE LHLD OFFSET ;BIAS VALUE XCHG CALL NEGDE DAD D ;HL NOW HAS ACTUAL MEM VECTOR DCX H ;DECREMENT DCX H SHLD PCTR ;PUT IN PROGRAM COUNTER JMP GOOD O7E: CALL EXTV O7EA: XCHG ;PUT ACTUAL MEM IN DE LHLD OFFSET ;GET OFFSET VALUE XCHG ;NOW OFFSET IN DE, POINTER IN HL CALL NEGDE ; DAD D ;HL = HL-OFFSET DCX H ;WE MUST DECREMENT DCX H DCX H SHLD PCTR ;SET PROGRAM COUNTER JMP GOOD O4F: LXI H,ACCA ;[CLR] CLEAR JMP O7FA O5F: LXI H,ACCB JMP O7FA O6F: CALL INDXV JMP O7FA O7F: CALL EXTV O7FA: MVI A,0 MOV M,A ;CLEAR INDICATED REGISTER STA NEGA ;RESET MINUS STA OFLW ;RESET OVERFLOW STA CARY ;RESET CARRY CMA STA ZERO ;SET ZERO JMP GOOD O80: O90: OA0: OB0: OC0: OD0: OE0: OF0: CALL ADPTR ;[SUB] ACCX <- (ACCX) - (M) MOV B,M ;MEMORY VALUE XCHG MOV C,M ;ACCUMULATOR VALUE SAVE ;SAVE OUR REGISTERS MOV A,C SUB B MOV M,A ;PUT RESULTS BACK CALL DOFLAG ;SET FLAGS RESTORE ;GET REGISTERS BACK CALL SUBTS ;TEST AND SET OVERFLOW JMP GOOD O81: O91: OA1: OB1: OC1: OD1: OE1: OF1: CALL ADPTR ;[CMP] (ACCX) - (M) MOV B,M ;ACCUMULATOR VALUE XCHG MOV C,M ;MEMORY VALUE MOV A,C SUB B SAVE ;SAVE REGISTERS CALL DOFLAG RESTORE CALL SUBTS ;SET V FLAG JMP GOOD O82: O92: OA2: OB2: OC2: OD2: OE2: OF2: CALL ADPTR ;[SBC] ACCX <- (ACCX)-(M)-(C) STC!CMC ;CLEAR CARRY FLAG LDA CARY ;GET CARRY FROM 6800 INR A ;UP ONE (C WILL SET IF A=0FFH) MOV C,M ;GET ACCUMULATOR VALUE XCHG MOV B,M ;GET MEMORY VALUE MOV A,C SBB B ;DO SUBTRACTION MOV M,A ;RESULTS SAVE CALL DOFLAG ;SET C,Z,N FLAGS RESTORE CALL SUBTS ;DO OVERFLOW JMP GOOD O83: O93: OA3: OB3: OC3: OD3: OE3: OF3: JMP NOGOOD ;INVALID OPCODES O84: O94: OA4: OB4: OC4: OD4: OE4: OF4: CALL ADPTR ;[AND] ACCX <- (ACCX) AND (M) LDAX D ;ACCUMULATOR TO 8080A ACCUM ANA M ;COMPARE WITH MEMORY STAX D ;RESULTS TO ACCUM OF4A: MVI A,0 ;SET ACCUM TO ZERO PUSH PSW ;SAVE FLAGS JNZ $+4 ; CMA STA ZERO ;SET ZERO FLAG POP PSW ;RECOVER JP $+4 CMA STA NEGA ;MINUS MVI A,0 STA OFLW ;CLEAR OVERFLOW FLAG JMP GOOD O85: O95: OA5: OB5: OC5: OD5: OE5: OF5: CALL ADPTR ;[BIT] (ACCX) AND (M) LDAX D ;ACCUM VALUE TO 'A' REG ANA M ;SET FLAGS JMP OF4A ;FROM HERE SAME AS [AND] O86: O96: OA6: OB6: OC6: OD6: OE6: OF6: CALL ADPTR ;[LDA] ACCX <- (M) MOV A,M STAX D ;PUT IN ACCUMULATOR ORA A ;SET FLAGS JMP OF4A ;AND STORE AS APPROPRIATE O87: OC7: JMP NOGOOD ;CAN'T STORE IMMEDIATE! O97: OA7: OB7: OD7: OE7: OF7: CALL ADPTR ;[STA] M <- (ACCX) LDAX D ;GET ACCUM VALUE MOV M,A ;STORE IT! ORA A JMP OF4A ;AND DO THE FLAGS O88: O98: OA8: OB8: OC8: OD8: OE8: OF8: CALL ADPTR ;[EOR] ACCX <- (ACCX) XOR (M) LDAX D XRA M ;EXCLUSIVE OR STAX D ;BACK IN REGISTER JMP OF4A O89: O99: OA9: OB9: OC9: OD9: OE9: OF9: CALL ADPTR ;[ADC] ACCX <- (ACCX)+(M)+(C) STC!CMC ;CLEAR CARRY LDA CARY ;GET SIMULATOR CARRY INR A ;CARRY IS NOW SET LDAX D ;GET ACCUM VALUE MOV C,A ;INTO C FOR TEMP MOV B,M ;GET VALUE ADC M ;DO ADD OF9A: STAX D ;AND RESTORE TO REG SAVE CALL DOFLAG ;SET N,Z,C FLAGS RESTORE CALL ADDTS ;DO OVERFLOW FLAG JMP GOOD O8A: O9A: OAA: OBA: OCA: ODA: OEA: OFA: CALL ADPTR ;[ORA] ACCX <- (ACCX)OR(M) LDAX D ;GET ACCX VALUE ORA M STAX D ;PUT BACK IN ACCX JMP OF4A ;DO BOOLIAN FLAGS O8B: O9B: OAB: OBB: OCB: ODB: OEB: OFB: CALL ADPTR ;[ADD] ACCX <- (ACCX)+(M) LDAX D ;GET REGISTER DATA MOV C,A MOV B,M ;GET MEMORY VALUE ADD B JMP OF9A ;STORE AND SET FLAGS O8C: CALL ADPTR ;[CPX #] COMPARE INDEX REGISTERS PUSH H LHLD PCTR ;WE HAVE TO FAKE THE PROGRAM COUNTER.. INX H ;..AS THIS IS A THREE-BYTE IMMEDIATE.. SHLD PCTR ;...INSTRUCTION!!! POP H O8CA: MOV D,M ;GET MSB OF IMMEDIATE INSTRUCTION INX H MOV E,M ;AND LSB...(DE NOW HAS M INSTRUCTION) LHLD IXRG ;GET INDEX REGISTER VALUE CPHL ;SUBTRACT DE FROM HL SAVE MVI A,0 PUSH PSW JNZ $+4 CMA STA ZERO ;DO ZERO FLAG POP PSW JP $+4 CMA STA NEGA ;MINUS RESTORE ;GET REGISTERS BACK MOV B,D ;SET UP FOR... MOV C,H ;...SUB OVERFLOW TEST CALL SUBTS ;AND TEST AND SET OVERFLOW FLAG JMP GOOD O9C: OAC: OBC: CALL ADPTR ;[CPX] COMPARE INDEX REG WITH MEMORY JMP O8CA ;SAME AS REST FROM HERE! OCC: ODC: OEC: OFC: JMP NOGOOD STKIT: LHLD PCTR ;THIS STACKS THE RETURN ADDRESS INX H INX H ;CALCULATE RETURN ADDRESS MOV A,L CALL PSHIT ;PUSH LSB ON STACK MOV A,H CALL PSHIT ;AND PUSH MSB... RET O8D: CALL STKIT ;[BSR] BRANCH TO SUBROUTINE JMP BRA ;AND DO BRANCH! O9D: JMP NOGOOD OAD: CALL STKIT ;[JSR INDEXED] JUMP TO SUBROUTINE CALL INDXV ;GET INDEXED VECTOR XCHG ;PUT IN DE OADA: LHLD OFFSET ;GET OUR ACTUAL MEM OFSET XCHG ;DE HAS OFFSET,HL HAS MEM VECTOR CALL NEGDE DAD D ;HL NOW HAS PROGRAM TO JUMP TO DCX H DCX H ;THIS IS SO THE 'GOOD'ROUTINE WILL SHLD PCTR ;END UP WITH CORRECT PROGRAM COUNTER JMP GOOD OBD: LHLD PCTR ;[JSR] JUMP TO SUBROUTINE INX H ;INCREMENT STACK POINTER SHLD PCTR ;FAKE FOR STKIT! CALL STKIT LHLD PCTR ; DCX H ;BACK TO ORIGINAL VALUE SHLD PCTR CALL EXTV ;GET EXTENDED DCX H ;WE WILL GO DOWN THREE BYTES JMP OADA OCD: ODD: OED: OFD: JMP NOGOOD O8E: CALL ADPTR ;[LDS #] LOAD STACK POINTER IMM PUSH H LHLD PCTR INX H ;FAKE UP THE PROGRAM COUNTER SHLD PCTR POP H ;GET MEMORY VECTOR BACK O8EA: MOV D,M INX H MOV E,M XCHG ;NEW STACK POINTER NOW IN [HL] SHLD SPTR O8EB: MOV H,A ORA A MVI A,0 JP $+4 CMA STA NEGA ;SET MINUS FLAG MOV H,A ORA L ;SEE IF BOTH ZERO MVI A,0 JNZ $+4 CMA STA ZERO ;SET ZERO FLAG MVI A,0 ;ALWAYS RESET OVERFLOW STA OFLW JMP GOOD O9E: OAE: OBE: CALL ADPTR ;[LDS] LOAD STACK POINTER JMP O8EA OCE: CALL ADPTR ;[LDX #] LOAD INDEX REGISTER IMMEDIATE PUSH H LHLD PCTR INX H ;AGAIN, FAKE PC FOR THREE-BYTE IMM SHLD PCTR POP H OCEA: MOV D,M ;HIGH ORDER BYTE INX H MOV E,M ;LOW ORDER BYTE XCHG ;PUT NEW INDEX REG IN [HL] SHLD IXRG ;SET VALUE OF INDEX REGISTER JMP O8EB ;GO SET FLAGS ODE: OEE: OFE: CALL ADPTR ;[LDX] LOAD INDEX REGISTER JMP OCEA ;SAVE AS ABOVE WITHOUT SP MODS O8F: OCF: JMP NOGOOD ;CAN'T STORE IMMEDIATE! O9F: OAF: OBF: CALL ADPTR ;[STS] STORE STACK POINTER XCHG ;POINTER IN [DE] LHLD SPTR ;GET STACK POINTER OBFA: XCHG ;STACK POINTER IN [DE] MOV M,D ;STORE HIGH ORDER BYTE INX H MOV M,E ;...AND LOW ORDER BYTE XCHG ;STACK POINTER NOW IN [HL] JMP O8EB ;AND GO DO THE FLAGS ODF: OEF: OFF: CALL ADPTR ;[STX] STORE INDEX REGISTER XCHG ;ADDRESS TO STORE IN [DE] LHLD IXRG ;GET THE INDEX REGISTER JMP OBFA ;AND THE SAME AS [STS] FROM HERE! ; *** END OF M6800 EMULATION CODE *** DOFLAG: MVI A,0 ;THIS SETS N,Z,C FLAGS PUSH PSW JNZ $+4 CMA STA ZERO ;SET ZERO FLAG POP PSW PUSH PSW JNC $+4 CMA STA CARY ;SET CARRY FLAG POP PSW JP $+4 CMA STA NEGA ;SET NEGATIVE RET HFCRY: PUSH PSW ;SAVE RESULTS PUSH B ;AND FACTORS MOV A,C ANI 0FH ;GET RID OF MSBS MOV C,A ;PUT BACK MOV A,B ;GET OTHR ANI 0FH ADD C ANI 10H ;TEST FOR CARRY MVI A,0 JZ $+4 CMA STA HCRY POP B ;RESTORE ORIGINALS POP PSW ;AND RESULTS RET ; ; PROGRAM TO TEST FOR TWO'S COMPLIMENT OVERFLOW ; ASSUMES OPERANDS ARE IN B AND C REGISTERS, SETS ; OVERFLOW FLAG IF CONDITION TRUE - FROM R.GOSLINE ; ADDTS: PUSH B ;THIS IS FOR AN ADDITION MOV A,B ADD C ;DO ADDITION JMP OVCHK ;DO OVERFLOW CHECK SUBTS: PUSH B ;SUBTRACTION TEST MOV A,B CMA ;COMPLIMENT FOR SUBTRACTION MOV B,A ;BACK TO B REGISTER CMA ;GET ORIGINAL VALUE BACK SUB C ;SUBTRACT!!! OVCHK: PUSH PSW ;SAVE RESULTS XRA B MOV B,A POP PSW XRA C ;EXCLUSIVE OR WITH EVERYONE ANA B ;MASK MVI A,-1 JM $+4 ;LEAVE IT IF OVERFLOW CMA ;SET TO ZERO IF NO OVERFLOW STA OFLW ;SET FLAG POP B ;RESTORE ORIGINAL VALUES RET ; GOOD: MVI A,0 ;SET FLAG FOR GOOD OPER STA GDFLG ;SAVE IT LHLD PCTR ;GET PROGRAM COUNTER LDA MODE ;GET ADDRESSING MODE CPI INH JZ GOOD1 ;IF INHERENT, UP COUNT ONE CPI REL ;TEST FOR RELATIVE JZ GOOD2 ;STEP BY TWO CPI IND JZ GOOD2 CPI EXT JZ GOOD3 CPI IMM JZ GOOD2 CPI DIR JZ GOOD2 JMP GOOD1 ;IF NOT FOUND, DO ONE STEP GOOD3: INX H GOOD2: INX H GOOD1: INX H ;DO ONE COUNT SHLD PCTR ;RETURN NEW PC VALUE CALL INRPT ;SEE IF INTERRUPT PENDING RET $-PRINT ; SUBROUTINE TO SET ADDRESSING MODE ; SMODE: CPI 08DH ;THIS IS AN ODD-BALL! JZ SBSR ;BRANCH TO SUBROUTINE ANI 0F0H ;GET MSB... RRC!RRC!RRC!RRC ; ...AND SHIFT TO LSB LXI H,ATAB ;POINT TO TABLE MVI D,0 ;ZERO DE REGISTER MOV E,A ; DAD D ;POINT AT CORRECT ADDRESSING MOV A,M ;GET IT! STA MODE ;AND SAVE... RET SBSR: MVI A,REL ;THIS IS RELATIVE MODE STA MODE RET ; ATAB: DB INH,INH,REL,INH DB INH,INH,IND,EXT DB IMM,DIR,IND,EXT DB IMM,DIR,IND,EXT ; BIAS: CALL CRLF PRINT <'STARTING ADDRESS OF 6800 PROGRAM? '> CALL GHXW JC ERROR ; INPUT ERROR XCHG ;PUT IT IN DE CALL NEGDE ;WE WILL SUBTRACT IT LXI H,TOP ;ACTUAL ADDRESS OF PROGRAM DAD D ;ADD TO ACUAL ADDRESS SHLD OFFSET ;WE WILL NEED THIS BUNCHES!! GOTO: JMP MAIN ; ; SET MEMORY VALUES ; SETM: INX H ;POINT AT NUMBER INPUT HEXIN ;CONVERT JC ERROR SET1: CALL CRLF ;DOWN ONE LINE CALL THXW ;TYPE VALUE CALL SPACE PUSH H ;SAVE... PUSH D ;...DE & HL XCHG LHLD OFFSET ;GET BIAS VALUE DAD D ;HL NOW HAS LOCATION MOV A,M ;GET VALUE CALL THXB ;DISPLAY CALL SPACE PUSH H CALL GHXB ;GET NEW VALUE POP H JC SET2 ;IF NOT VALID,SEE WHY MOV M,A ;PUT IN VALUE POP D POP H ;RECOVER REGISTERS INX H JMP SET1 ;DO NEXT LOCATION SET2: POP D POP H ;RESTORE FOR BALANCE PUSH H ;AND BACK ON STACK LXI H,BUFFER+1 MOV A,M ;GET THE OFFENDER ORA A ;SEE IF ZERO POP H ;RESTORE MEMORY POINTER JZ SET2-4 ;DO NEXT LOCATION PUSH H ;SAVE AGAIN LXI H,BUFFER+2 MOV A,M POP H ;AND RECOVER POINTER CPI '.' ;PERIOD JZ MAIN ;ALL DONE CPI '-' ;MINUS SIGN JNZ ERROR DCX H ;DO LAST LOCATION JMP SET1 ; ; ROUTINE TO DUMP A BLOCK OF MEMORY TO CONSOLE ; DUMP: LXI H,BUFFER+1 MOV A,M ;LENGTH OF BUFFER CPI 1 ;ANY ADDITIONAL PARAMETERS? JZ DUMP0 ;JUST A 'D' ENTERED INSTR BUFFER+3,29,',' JC DUMP2 ;IF COMMA, THERE ARE TWO DUMP1: HEXIN BUFFER+3 JC ERROR SHLD STRTD ;STORE STARTING ADDRESS DUMPX: LXI D,0FFH ; DAD D ;ADD TO STARTING ADDRESS SHLD STOPD ;HERE WE WILL STOP JMP DMPIT ;NOW DO THE BIT DUMP0: LHLD STRTD JMP DUMPX DUMP2: DCX H ;BACK UP ONE MVI M,0 ;REPLACE COMMA WITH 00H INX H ;POINT AT SECOND PARAMETER HEXIN ;CONVERT JC ERROR SHLD STOPD ;ENDING ADDRESS HEXIN BUFFER+3 JC ERROR SHLD STRTD ;WE NOW HAVE STARTING ADDRESS DMPIT: LHLD STOPD ;GET END ADDRESS XCHG ;SAVE IN [DE] REGISTER LHLD STRTD ;GET FIRST ADDRESS ; ; FROM ADDRESS IN HL, TO ADDRESS IN DE ; CALL NEGDE ;NEGATE DE FOR END CHECK DMRET: CALL CRLF ;RETURN CARRIAGE CALL STOP ;LOOK FOR A STOP CALL THXW ;TYPE VECTOR ADDRESS DMN1: CALL SPACE DMNXT: CALL SPACE ;SPACE PUSH H ;SAVE REGISTERS PUSH D XCHG LHLD OFFSET ;GET OFFSET VALUE DAD D ;ADD TO MEMORY POINTER MOV A,M ;GET DATA CALL THXB ; AND DISPLAY POP D ;RESTORE REGISTERS POP H CALL LAST1 ;SEE IF DONE MOV A,L ;CHECK FOR MOD 8 ANI 0FH CPI 8 ; ADDRESS JZ DMN1 ;SPACE IF MOD 8 CPI 0 ;CHECK FOR END OF LINE JZ DMN2 ;NEW LINE IF MOD 16 JMP DMNXT ; CONTINUE IF NOT ; LAST: PUSH H DAD D ;ADD TO -END JC LAST0 ;IF CARRY,DONE! POP H INX H ;SET UP FOR NEXT LOCATION RET LAST0: POP H ;RESTORE POINTER INX H ;SAVE FOR NEXT TIME! SHLD STRTD JMP MAIN ;BACK TO COMMAND LOOP ; LAST1: PUSH H ;SAVE MEM VECTOR DAD D ; ADD NEGATIVE END ADDRESS JC LAST2 ;DONE IF CARRY POP H ;RESTORE VECTOR INX H ;BUMP AND RET ; EXIT ; LAST2: POP H LAST3: INX H MOV A,L ANI 0FH JZ DMN2 CALL SPACE CALL SPACE CALL SPACE CPI 9 JNC LAST3 CPI 8 JNC LAST4 JMP LAST3 LAST4 CALL SPACE JMP LAST3 ; DMN2: DCX H MOV A,L ANI 0F0H MOV L,A CALL SPACE DMN3: CALL SPACE DMN4: PUSH H PUSH D XCHG ;SAVE FOR ADD LHLD OFFSET ;GET BIAS VECTOR DAD D ;ADD TO POINTER MOV A,M ;GET MEMORY VALUE POP D ;GET BACK... POP H ;...REGISTERS CPI 020H ;LESS THAN SPACE? JC DMN5 ;DO A PERIOD CPI 07FH ;MORE THAN DEL? JNC DMN5 ;SEND A PERIOD JMP DMN7 ;OTHERWISE, SEND CHAR DMN5: MVI A,02EH ;SET UP ASCII PERIOD DMN7: CALL TYPE CALL LAST MOV A,L ANI 0FH CPI 8 JZ DMN3 CPI 0 JZ DMRET JMP DMN4 ; ; STOP DRIVER A SPACE WILL STOP THINGS A RETURN WILL ; GET THINGS GOING AGAIN AND AN ESCAPE WILL RETURN ; YOU TO THE COMMAND LOOP ; STOP: PUSH H PUSH D CHARSTAT ;CONSOLE STATUS ORA A ;CHECK FLAGS JZ STOP4 ;NOT READY STOP1: CHARIN ;GET THE CHARACTER ANI 7FH ;STRIP ANY PARITY CPI 1BH ;IF ESCAPE, ALL DONE JNZ STOPX ;NO,CHECK SOME MORE MVI A,0C2H STA ST1 ;STORE FLAG JMP MAIN ;EXIT WHOLE ROUTINE STOPX: CPI 0DH ;SEE IF RETURN JZ STOP3 CPI 20H ;SPACE BAR? JZ STOP2 JMP STOP1 ;LOOP UNTIL VALID COMMAND STOP2: MVI A,0CAH STA ST1 JMP STOPGO STOP3: MVI A,0C2H STA ST1 JMP STOPGO STOP4: LDA ST1 ;GET GO/NO WORD CPI 0CAH ;CHECK IF SPACE BAR JZ STOP1 STOPGO: POP D ;RESTORE... POP H ;...REGISTERS RET ; ; *** ROUTINE TO EXAMINE OR CHANGE 6800 INTERRUPT VECTORS *** ; VECTS: LXI H,BUFFER+3 ;CHECK NEXT CHAR AFTER 'V' MOV A,M CPI 'R' JZ CRSTV ;CHANGE RESTART VECTOR CPI 'W' JZ CWAIV ;CHANGE WAIT VECTOR CPI 'N' JZ CNMIV ;CHANGE NON-MASKABLE INT. CPI 'I' JZ CSWIV ;SOFTWARE INTERRUPT VECTOR ; ; IF WE ARE HERE, WE JUST WANT TO DISPLAY VECTORS ; CALL PRSTV ; CALL PNMIV CALL PWAIV CALL PSWIV JMP MAIN ;ALL DONE, RETURN CRSTV: CALL PRSTV ;PRINT VALUE OF RESTART LXI H,RESTV PUSH H ;SAVE ON STACK! JMP CHGD1 ;GET NEW VALUE CWAIV: CALL PWAIV ;DISPLAY OLD WAIT VECTOR LXI H,WAIV PUSH H JMP CHGD1 ;GET NEW VALUE CNMIV: CALL PNMIV ;SHOW THE NON-MASKABLE LXI H,NMIV PUSH H JMP CHGD1 ;DO IT! CSWIV: CALL PSWIV ;AND HERE IS SWI LXI H,SWIV PUSH H JMP CHGD1 ;AND REPLACE ; ROUTINES TO PRINT HEADER AND VALUE OF INTERRUPT VECTORS PRSTV: PRINT LHLD RESTV CALL THXW RET PNMIV: PRINT LHLD NMIV CALL THXW ;TYPE ACTUAL VALUE RET PWAIV: PRINT LHLD WAIV ;GET CURRENT VALUE CALL THXW RET PSWIV: PRINT LHLD SWIV CALL THXW RET ; ; *** ROUTINE TO EXAMINE 6800 REGISTERS *** ; EXAM: LXI H,BUFFER+3 ;LOOK AT NEXT CHARACTER MOV A,M ;GET IT CPI 'C' ;CARRY FLAG? JZ CCRY ;CHANGE CARRY FLAG CPI 'V' ;OVERFLOW? JZ COFLW CPI 'Z' ;ZERO FLAG? JZ CZERO CPI 'N' ;NEGATIVE FLAG JZ CNEG CPI 'I' ;INTERRUPT MASK? JZ CINTP CPI 'H' ;HALF-CARRY FLAG JZ CHALF ; ; NOW WE WILL CHECK FOR REGISTER CHANGES ; CPI 'A' ;ACCUMULATOR A? JZ CHGA CPI 'B' ;ACCUMULATOR B? JZ CHGB CPI 'X' ;INDEX REGISTER? JZ CHGI CPI 'S' ;STACK POINTER? JZ CHGSP CPI 'P' ;PROGRAM COUNTER? JZ CHGPC ; ; IF WE GET HERE, WE JUST WANT TO DISPLAY THE REGISTERS ; ALL: CALL DSPLY ;DISPLAY THEM! PRINT ;DO A CRLF JMP MAIN ;GO BACK TO MAIN COMMAND LOOP ; ; THESE ARE THE ROUTINES TO INDIVIDUALLY CHANGE REGISTERS ; CCRY: PRINT LXI H,CARY ;POINT TO CARRY FLAG JMP CFLAG ;DO FLAG CHANGE COFLW: PRINT LXI H,OFLW ;SET UP FOR OVERFLOW JMP CFLAG CZERO: PRINT LXI H,ZERO ;AIM AT THE ZERO FLAG JMP CFLAG CNEG: PRINT LXI H,NEGA ;READY FOR NEGATIVE FLAG JMP CFLAG CINTP: PRINT LXI H,IMSK ;INTERRUPT MASK JMP CFLAG CHALF: PRINT LXI H,HCRY ;SHOOT FOR HALF-CARRY FLAG JMP CFLAG CHGA: PRINT LXI H,ACCA ;ACCUMULATOR A JMP CHGSG ;SINGLE BYTE REGISTER CHANGE CHGB: PRINT LXI H,ACCB ;YOU SHOULD KNOW WHY BY NOW! JMP CHGSG CHGI: PRINT LXI H,IXRG ;THIS IS THE INDEX REGISTER JMP CHGDB ;DOUBLE REGISTER CHANGE CHGSP: PRINT LXI H,SPTR ;STACK POINTER JMP CHGDB CHGPC: PRINT LXI H,PCTR ;GET PROGRAM COUNTER JMP CHGDB ; CFLAG: PUSH H ;SAVE REGISTERS MOV A,M ;GET THE CHARACTER ANI 01H ; CONVERT... ADI 30H ; ...TO ASCII CHAROUT ;TO CONSOLE CALL SPACE ;SPACE TO CONSOLE CHARIN ;GET CHAR FROM CONSOLE CPI 0DH ;SEE IF CR POP H ;RESTORE POINTER JZ MAIN ;NO CHANGE ANI 01H ;GET JUST FIRST BIT JZ $+5 ;IF ZERO,DEPOSIT IT XRA A ;CLEAR ACCUMULATOR CMA ;SET TO 0FFH MOV M,A ;DEPOSIT JMP MAIN ;NOW WE ARE DONE ; CHGSG: PUSH H ;SAVE POINTER MOV A,M ;GET VALUE CALL THXB ;TYPE ON CONSOLE CALL SPACE ;SKIP OVER ONE CALL GHXB ;GET NEW VALUE JC EXIT ;ERROR IN INPUT(OR NONE) POP H ;GET POINTER BACK MOV M,A ;REPLACE WITH NEW VALUE JMP MAIN ;ALL DONE EXIT: POP H ;BALANCE STACK JMP ERROR ;NOW RETURN ; CHGDB: PUSH H ;AGAIN,SAVE THE POINTER MOV E,M ;GET LOW BYTE INX H ;POINT TO HIGH BYTE MOV D,M ;GET IT XCHG ;PUT IN HL CALL THXW ;TO CONSOLE CHGD1: CALL SPACE ;AND SPACE CALL GHXW ;GET HEX WORD JC EXIT ;ERROR IN HEX INPUT(OR NONE) XCHG ;SAVE FOR MOVE POP H ;GET BACK POINTER MOV M,E ;LOW ORDER BYTE INX H ;BUMP POINTER MOV M,D ;HIGH BYTE JMP MAIN ;ALL THROUGH ; ; *** ROUTINE TO DISPLAY ALL 6800 REGISTERS *** ; DSPLY: CALL CRLF CALL PFLAG ;DISPLAY THE CONDITION CODES SAVE ;SAVE REGISTER ENVIORNMENT PRINT <' A='> ;HEADER HEXOUT ACCA ;ACCUMULATOR A PRINT <' B='> ; HEXOUT ACCB ;ACCUMULATOR B TO CONSOLE PRINT <' IX='> ; LHLD IXRG ;GET INDEX REGISTER CALL THXW ;PRINT IT ON CONSOLE PRINT <' SP='> ;LET'S DO THE STACK POINTER LHLD SPTR ;GET THE VALUE CALL THXW ;TYPE IT! PRINT <' PC='> ;LAST REGISTER (PROGRAM COUNTER) LHLD PCTR ;GET THE PROGRAM COUNTER CALL THXW ;...AND SEND IT TO CONSOLE PRINT <' *='> ;VALUE OF MEMORY POINTER LHLD OFFSET ;GET OFFSET VALUE XCHG ;AND IN DE PAIR LHLD PCTR ;COUNTER DAD D ;COMPUTE ACTUAL ADDRESS MOV A,M ;GET VALUE OF INSTRUCTION CALL THXB ;TYPE VALUE LDA GDFLG ;SEE IF GOOD CODE! ORA A ;SET FLAGS JZ DSPL1 ;OK, EXIT MVI A,'?' ;MARK INVALID OPCODE CALL TYPE DSPL1: RESTORE ;GET REGISTERS BACK RET ;ALL DONE!!! ; ; UTILITY ROUTINES ; BREAK: SAVE CHARSTAT ;CHECK KEYBOARD RESTORE RET ;RETURN(A=0 FOR NOT READY) ; (A=FF FOR CHAR PRESSED) ; ; ...TYPE A CHARACTER IN 'A' REGISTER ON CONSOLE... ; TYPE: SAVE ;PRESERVE ALL REGISTERS CHAROUT ;TO CONSOLE THROUGH CP/M RESTORE ;GET EM BACK RET ; ; PRINT ERROR MESSAGE ; ERROR: CALL CRLF MVI A,'?' CHAROUT JMP MAIN ; FILL BUFFER WITH ZERO ; ZBUFF: FILL BUFFER,BUFFER+32 RET ; ; GET HEX BYTE TO A REGISTER ; GHXB: CALL ZBUFF ;ZERO OUT INPUT BUFFER INPUT BUFFER,4 ;MAX OF 2 CHAR GHEX: LDA BUFFER+1 ;LOOK AT COUNT ORA A ;SET FLAGS JNZ GHEX1 ;NOT ZERO, DO CONVERSION STC ;SET CARRY FOR ERROR FLAG RET ;RETURN WITH CARRY SET FOR ERROR GHEX1: HEXIN BUFFER+2 ;DO CONVERSION RET ;ALL DONE ; ; GET HEX WORD TO [HL] REGISTER ; GHXW: CALL ZBUFF ;ZERO BUFFER INPUT BUFFER,6 ;GET FOUR CHARACTERS JMP GHEX ;SAME AS ABOVE ; THXB: SAVE HEXOUT ;TYPE HEX IN 'A' RESTORE RET ; ; GENERAL-PURPOSE ROUTINE TO TYPE HL IN HEX ON CONSOLE ; THXW: SAVE MOV A,H ;MOST SIGNIFICANT BYTE PUSH H ;SAVE REGISTERS HEXOUT ;TO CONSOLE POP H MOV A,L ;LEAST SIGNIFICANT BYTE HEXOUT ;AND SHOW IT RESTORE RET SPACE: SAVE MVI A,' ' ;LOAD A SPACE... CHAROUT ;AND TYPE IT! RESTORE RET ; CRLF: SAVE MVI A,0DH ;CARRIAGE RETURN CHAROUT MVI A,0AH ;LINE FEED CHAROUT RESTORE RET ; ; ROUTINE TO NEGATE THE DE REGISTER ; ; CALLING SEQUENCE ... ; ; ... ;VALUE IN DE ; CALL NEGDE ;NEGATE DE ; ... ;RETURN HERE WITH DE= -DE ; NEGDE: PUSH PSW ;SAVE PSW MOV A,D ;FETCH D CMA ;COMPELEMENT MOV D,A ;AND RESTORE MOV A,E ;FETCH E CMA ; COMPLEMENT MOV E,A ; AND RESTORE INX D ;ADD ONE TO D POP PSW ;RESTORE PSW RET ;AND EXIT ; ; THIS ROUTINE DISPLAYS THE CONDITION CODE REGISTERS ; PFLAG: SAVE ;SAVE REGISTERS PRINT <'C='> ;CARRY FLAG LXI H,CARY CALL CONV PRINT <' V='> ;OVERFLOW FLAG LXI H,OFLW CALL CONV ;DISPLAY IT! PRINT <' Z='> ;ZERO FLAG LXI H,ZERO CALL CONV ;CONVERT & DISPLAY PRINT <' N='> ;NEGATIVE FLAG LXI H,NEGA CALL CONV ;TO THE CONSOLE PRINT <' I='> ;INTERRUPT MASK LXI H,IMSK CALL CONV ;SEND IT! PRINT <' H='> ;HALF-CARRY FLAG... LXI H,HCRY CALL CONV ;...TO CONSOLE! RESTORE ;GET REGISTERS BACK RET ;DONE WITH REGISTERS ; CONV: MOV A,M ;GET VALUE ANI 01H ;MASK FIRST BIT ADI 30H ;MAKE IT AN ASCII '0' OR '1' CHAROUT ;SEND TO CONSOLE RET ; ; *** TEMPORARY STORAGE REGISTERS (MUST BE IN RAM) ; OFFSET: DS 2 ;OFFSET FOR 6800 PROGRAM TEMPA: DS 1 ;TEMPORARY STORAGE FOR CODE MODE: DS 1 ;ADDRESSING MODE FLAGS POINT: DS 2 ;PHYSICAL MEMORY POINTER FPNTR: DS 2 ;POINTER FOR FILE LOAD NEWDRV: DS 1 ;DRIVE FOR FILE BEING EMULATED INFLAG: DS 1 ;INPUT FLAG VALFLG: DS 1 CBASE: DS 2 ;BASE OF CP/M CCP STRTD: DS 2 ;START OF DUMP DISPLAY STOPD: DS 2 ;END OF DUMP DISPLAY ST1 DS 1 ;PAUSE FLAG OCODE: DS 1 ;BREAKPOINT CODE STORAGE OCODE1: DS 1 ;SECOND BREAKPOINT BKADD1: DS 2 ;ADDRESS OF FIRST BREAKPOINT BKADD2: DS 2 ;SECOND BREAKPOINT LOCATION GDFLG: DS 1 ;0=GOOD OPCODE,1= INVALID IPEND: DS 1 ;INTERRUPT PENDING IF = 1 WAIV: DS 2 ;INTERRUPT WAIT VECTOR SWIV: DS 2 ;SOFTWARE INTERRUPT VECTOR RESTV: DS 2 ;RESTART VECTOR NMIV: DS 2 ;NON-MASKABLE INTERRUPT VECTOR TRFLAG: DS 1 ;0 = DO NOT DISPLAY TRACE COUNT: DS 1 ;PASS COUNTER BUFFER: DS 32 ;KEYBOARD INPUT BUFFER DS 128 ;SAVE LOTS FOR STACK STACK: EQU $ TOP: EQU STACK+1 ;FIRST FREE BYTE FOR PROGRAM END