; MACRO LIBRARY FOR A ZERO ADDRESS MACHINE ; ***************************************** ; * BEGIN TRACE/DUMP UTILITIES * ; ***************************************** BDOS EQU 0005H ;SYSTEM ENTRY RCHAR EQU 1 ;READ A CHARACTER WCHAR EQU 2 ;WRITE CHARACTER WBUFF EQU 9 ;WRITE BUFFER TRAN EQU 100H ;TRANSIENT PROGRAM AREA DATA EQU 1100H ;DATA AREA CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; DEBUGT SET 0 ;;TRACE DEBUG SET FALSE DEBUGP SET 0 ;;PRINT DEBUG SET FALSE ; PRN MACRO PR ;; PRINT MESSAGE 'PR' AT CONSOLE IF DEBUGP ;;PRINT DEBUG ON? LOCAL PMSG,MSG ;;LOCAL MESSAGE JMP PMSG ;;AROUND MESSAGE MSG: DB CR,LF ;;RETURN CARRIAGE DB '&PR$' ;;LITERAL MESSAGE PMSG: PUSH H ;;SAVE TOP ELEMENT OF STACK LXI D,MSG ;;LOCAL MESSAGE ADDRESS MVI C,WBUFF ;;WRITE BUFFER 'TIL $ CALL BDOS ;;PRINT IT POP H ;;RESTORE TOP OF STACK ENDIF ;;END TEST DEBUGP ENDM ; UGEN MACRO ;; GENERATE UTILITIES FOR TRACE OR DUMP LOCAL PSUB JMP PSUB ;;JUMP PAST SUBROUTINES @CH: ;;WRITE CHARACTER IN REG-A MOV E,A MVI C,WCHAR JMP BDOS ;;RETURN THRU BDOS ;; @NB: ;;WRITE NIBBLE IN REG-A ADI 90H DAA ACI 40H DAA JMP @CH ;;RETURN THRU @CH ;; @HX: ;;WRITE HEX VALUE IN REG-A PUSH PSW ;;SAVE LOW BYTE RRC RRC RRC RRC ANI 0FH ;;MASK HIGH NIBBLE CALL @NB ;;PRINT HIGH NIBBLE POP PSW ANI 0FH JMP @NB ;;PRINT LOW NIBBLE ;; @AD ;;WRITE ADDRESS VALUE IN HL PUSH H ;;SAVE VALUE MVI A,' ' ;;LEADING BLANK CALL @CH ;;AHEAD OF ADDRESS POP H ;;HIGH BYTE TO A MOV A,H PUSH H ;;COPY BACK TO STACK CALL @HX ;;WRITE HIGH BYTE POP H MOV A,L ;;LOW BYTE JMP @HX ;;WRITE LOW BYTE ; @IN: ;;READ HEX VALUE TO HL FROM CONSOLE MVI A,' ' ;;LEADING SPACE CALL @CH ;;TO CONSOLE LXI H,0 ;;STARTING VALUE @IN0: PUSH H ;;SAVE IT FOR CHAR READ MVI C,RCHAR ;;READ CHARACTER FUNCTION CALL BDOS ;;READ TO ACCUMULATOR POP H ;;VALUE BEING BUILT IN HL SUI '0' ;;NORMALIZE TO BINARY CPI 10 ;;DECIMAL? JC @IN1 ;;CARRY IF 0,1,...,9 ;; MAY BE HEXADECIMAL A,...,F SUI 'A'-'0'-10 CPI 16 ;;A THROUGH F? RNC ;;RETURN WITH ASSUMED CR @IN1: ;;IN RANGE, MULTIPLY BY 4 AND ADD REPT 4 DAD H ;;SHIFT 4 ENDM ORA L ;;ADD DIGIT MOV L,A ;;AND REPLACE VALUE JMP @IN0 ;;FOR ANOTHER DIGIT ;; PSUB: UGEN MACRO ;; REDEF TO INCLUDE ONCE ENDM UGEN ;;GENERATE FIRST TIME ENDM ; ***************************************** ; * END OF TRACE/DUMP UTILITIES * ; * BEGIN TRACE(ONLY) UTILITIES * ; ***************************************** TRACE MACRO CODE,MNAME ;; TRACE MACRO GIVEN BY MNAME, ;; AT LOCATION GIVEN BY CODE LOCAL PSUB UGEN ;;GENERATE UTILITIES JMP PSUB @T1: DS 2 ;;TEMP FOR REG-1 @T2: DS 2 ;;TEMP FOR REG-2 ;; @TR: ;;TRACE MACRO CALL ;; BC=CODE ADDRESS, DE=MESSAGE SHLD @T1 ;;STORE TOP REG POP H ;;RETURN ADDRESS XTHL ;;REG-2 TO TOP SHLD @T2 ;;STORE TO TEMP PUSH PSW ;;SAVE FLAGS PUSH B ;;SAVE RET ADDRESS MVI C,WBUFF ;;PRINT BUFFER FUNC CALL BDOS ;;PRINT MACRO NAME POP H ;;CODE ADDRESS CALL @AD ;;PRINTED LHLD @T1 ;;TOP OF STACK CALL @AD ;;PRINTED LHLD @T2 ;;TOP-1 CALL @AD ;;PRINTED POP PSW ;;FLAGS RESTORED POP D ;;RETURN ADDRESS LHLD @T2 ;;TOP-1 PUSH H ;;RESTORED PUSH D ;;RETURN ADDRESS LHLD @T1 ;;TOP OF STACK RET ;; PSUB: ;;PAST SUBROUTINES ;; TRACE MACRO C,M ;; REDEFINED TRACE, USES @TR LOCAL PMSG,MSG JMP PMSG MSG: DB CR,LF ;;CR,LF DB '&M$' ;;MAC NAME PMSG: LXI B,C ;;CODE ADDRESS LXI D,MSG ;;MACRO NAME CALL @TR ;;TO TRACE IT ENDM ;; BACK TO ORIGINAL MACRO LEVEL TRACE CODE,MNAME ENDM ; TRT MACRO F ;; TURN ON FLAG "F" DEBUG&F SET 1 ;;PRINT/TRACE ON ENDM ; TRF MACRO F ;; TURN OFF FLAG "F" DEBUG&F SET 0 ;;TRACE/PRINT OFF ENDM ; ?TR MACRO M ;; CHECK DEBUGT TOGGLE BEFORE TRACE IF DEBUGT TRACE %$,M ENDM ; ***************************************** ; * END TRACE (ONLY) UTILITIES * ; * BEGIN DUMP(ONLY) UTILITIES * ; ***************************************** DMP MACRO VNAME,N ;; DUMP VARIABLE VNAME FOR ;; N ELEMENTS (DOUBLE BYTES) LOCAL PSUB ;;PAST SUBROUTINES UGEN ;;GEN INLINE ROUTINES JMP PSUB ;;PAST LOCAL SUBROUTINES @DM: ;;DUMP UTILITY PROGRAM ;; DE=MSG ADDRESS, C=ELEMENT COUNT ;; HL=BASE ADDRESS TO PRINT PUSH H ;;BASE ADDRESS PUSH B ;;ELEMENT COUNT MVI C,WBUFF ;;WRITE BUFFER FUNC CALL BDOS ;;MESSAGE WRITTEN @DM0: POP B ;;RECALL COUNT POP H ;;RECALL BASE ADDRESS MOV A,C ;;END OF LIST? ORA A RZ ;;RETURN IF SO DCR C ;;DECREMENT COUNT MOV E,M ;;NEXT ITEM (LOW) INX H MOV D,M ;;NEXT ITEM (HIGH) INX H ;;READY FOR NEXT ROUND PUSH H ;;SAVE PRINT ADDRESS PUSH B ;;SAVE COUNT XCHG ;;DATA READY CALL @AD ;;PRINT ITEM VALUE JMP @DM0 ;;FOR ANOTHER VALUE ;; @DT: ;;DUMP TOP OF STACK ONLY PRN <(TOP)=> ;;"(TOP)=" PUSH H CALL @AD ;;VALUE OF HL POP H ;;TOP RESTORED RET ;; PSUB: ;; DMP MACRO ?V,?N ;; REDEFINE DUMP TO USE @DM UTILITY LOCAL PMSG,MSG ;; SPECIAL CASE IF NULL PARAMETERS IF NUL VNAME ;; DUMP THE TOP OF THE STACK ONLY CALL @DT EXITM ENDIF ;; OTHERWISE DUMP VARIABLE NAME JMP PMSG MSG: DB CR,LF ;;CRLF DB '&?V=$' ;;MESSAGE PMSG: ADR ?V ;;HL=ADDRESS ACTIVE SET 0 ;;CLEAR ACTIVE FLAG LXI D,MSG ;;MESSAGE TO PRINT IF NUL ?N ;;USE LENGTH 1 MVI C,1 ELSE MVI C,?N ENDIF CALL @DM ;;TO PERFORM THE DUMP ENDM ;;END OF REDEFINITION DMP VNAME,N ENDM ; ; ***************************************** ; * END DUMP (ONLY) UTILITIES, * ; * BEGIN STACK MACHINE OPCODES * ; ***************************************** ACTIVE SET 0 ;ACTIVE REGISTER FLAG ; SIZ MACRO SIZE ORG TRAN ;;SET TO TRANSIENT AREA ;; CREATE A STACK WHEN "XIT" ENCOUNTERED @STK SET SIZE ;;SAVE FOR DATA AREA LXI SP,STACK ENDM ; SAVE MACRO ;; CHECK TO ENSURE "ENTER" PROPERLY SET UP IF STACK ;;IS IT PRESENT? ENDIF SAVE MACRO ;;REDEFINE AFTER INITIAL REFERENCE IF ACTIVE ;;ELEMENT IN HL PUSH H ;;SAVE IT ENDIF ACTIVE SET 1 ;;SET ACTIVE ENDM SAVE ENDM ; REST MACRO ;; RESTORE THE TOP ELEMENT IF NOT ACTIVE POP H ;;RECALL TO HL ENDIF ACTIVE SET 1 ;;MARK AS ACTIVE ENDM ; CLEAR MACRO ;; CLEAR THE TOP ACTIVE ELEMENT REST ;;ENSURE ACTIVE ACTIVE SET 0 ;;CLEARED ENDM ; DCL MACRO VNAME,SIZE ;; LABEL THE DECLARATION VNAME: IF NUL SIZE DS 2 ;;ONE WORD REQ'D ELSE DS SIZE*2 ;;DOUBLE WORDS ENDM ; LIT MACRO VAL ;; LOAD LITERAL VALUE TO TOP OF STACK SAVE ;;SAVE IF ACTIVE LXI H,VAL ;;LOAD LITERAL ?TR LIT ENDM ; ADR MACRO BASE,INX,CON ;; LOAD ADDRESS OF BASE, INDEXED BY INX, ;; WITH CONSTANT OFFSET GIVEN BY CON SAVE ;;PUSH IF ACTIVE IF NUL INX&CON LXI H,BASE ;;ADDRESS OF BASE EXITM ;;SIMPLE ADDRESS ENDIF ;; MUST BE INX AND/OR CON IF NUL INX LXI H,CON*2 ;;CONSTANT ELSE LHLD INX ;;INDEX TO HL DAD H ;;DOUBLE PRECISION INX IF NOT NUL CON LXI D,CON*2 ;;DOUBLE CONST DAD D ;;ADDED TO INX ENDIF ;;NOT NUL CON ENDIF ;;NUL INX LXI D,BASE ;;READY TO ADD DAD D ;;BASE+INX*2+CON*2 ENDM ; VAL MACRO B,I,C ;; GET VALUE OF B+I+C TO HL ;; CHECK SIMPLE CASE OF B ONLY IF NUL I&C SAVE ;;PUSH IF ACTIVE LHLD B ;;LOAD DIRECTLY ELSE ;; "ADR" PUSHES ACTIVE REGISTERS ADR B,I,C ;;ADDRESS IN HL MOV E,M ;;LOW ORDER BYTE INX H MOV D,M ;;HIGH ORDER BYTE XCHG ;;BACK TO HL ENDIF ?TR VAL ;;TRACE SET? ENDM ; STO MACRO B,I,C ;; STORE THE VALUE OF THE TOP OF STACK ;; LEAVING THE TOP ELEMENT ACTIVE IF NUL I&C REST ;;ACTIVATE STACK SHLD B ;;STORED DIRECTLY TO B ELSE ADR B,I,C POP D ;;VALUE IS IN DE MOV M,E ;;LOW BYTE INX H MOV M,D ;;HIGH BYTE ENDIF CLEAR ;;MARK EMPTY ?TR STO ;;TRACE? ENDM ; SUM MACRO REST ;;RESTORE IF SAVED ;; ADD THE TOP TWO STACK ELEMENTS POP D ;;TOP-1 TO DE DAD D ;;BACK TO HL ?TR SUM ENDM ; DIF MACRO ;; COMPUTE DIFFERENCE BETWEEN TOP ELEMENTS REST ;;RESTORE IF SAVED POP D ;;TOP-1 TO DE MOV A,E ;;TOP-1 LOW BYTE TO A SUB L ;;LOW ORDER DIFFERENCE MOV L,A ;;BACK TO L MOV A,D ;;TOP-1 HIGH BYTE SBB H ;;HIGH ORDER DIFFERENCE MOV H,A ;;BACK TO H ;; CARRY FLAG MAY BE SET UPON RETURN ?TR DIF ENDM ; LSR MACRO LEN ;; LOGICAL SHIFT RIGHT BY LEN REST ;;ACTIVATE STACK REPT LEN ;;GENERATE INLINE XRA A ;;CLEAR CARRY MOV A,H RAR ;;ROTATE WITH HIGH 0 MOV H,A MOV A,L RAR MOV L,A ;;BACK WITH HIGH BIT ENDM ENDM ; GEQ MACRO LAB ;; JUMP TO LAB IF (TOP-1) IS GREATER OR ;; EQUAL TO (TOP) ELEMENT. DIF ;;COMPUTE DIFFERENCE CLEAR ;;CLEAR ACTIVE ?TR GEQ JNC LAB ;;NO CARRY IF GREATER ORA H ;;BOTH BYTES ZERO? JZ LAB ;;ZERO IF EQUAL ;; DROP THROUGH IF NEITHER ENDM ; DUP MACRO ;; DUPLICATE THE TOP ELEMENT IN THE STACK REST ;;ENSURE ACTIVE PUSH H ?TR DUP ENDM ; BRN MACRO ADDR ;; BRANCH TO ADDRESS JMP ADDR ENDM ; XIT MACRO ?TR XIT ;;TRACE ON? JMP 0 ;;RESTART AT 0000 ORG DATA ;;START DATA AREA DS @STK*2 ;;OBTAINED FROM "SIZ" STACK: ENDM ; ; ***************************************** ; * MEMORY MAPPED I/O SECTION * ; ***************************************** ; INPUT VALUES WHICH ARE READ AS IF IN MEMORY ADC0 EQU 1080H ;A-D CONVERTER 0 ADC1 EQU 1082H ;A-D CONVERTER 1 ADC2 EQU 1084H ;A-D CONVERTER 2 ADC3 EQU 1086H ;A-D CONVERTER 3 ; DAC0 EQU 1090H ;D-A CONVERTER 0 DAC1 EQU 1092H ;D-A CONVERTER 1 DAC2 EQU 1094H ;D-A CONVERTER 2 DAC3 EQU 1096H ;D-A CONVERTER 3 ; RWTRACE MACRO MSG,ADR ;; READ OR WRITE TRACE WITH MESSAGE ;; GIVEN BY "MSG" TO/FROM "ADR" PRN ENDM ; RDM MACRO ?C ;; READ A-D CONVERTER NUMBER "?C" SAVE ;;CLEAR THE STACK IF DEBUGP ;;STOP EXECUTION IN DDT RWTRACE ,% ADC&?C UGEN ;;ENSURE @IN IS PRESENT CALL @IN ;;VALUE TO HL SHLD ADC&?C ;;SIMULATE MEMORY INPUT ELSE ;; READ FROM MEMORY MAPPED INPUT ADDRESS LHLD ADC&?C ENDIF ?TR RDM ;;TRACING? ENDM ; WRM MACRO ?C ;; WRITE D-A CONVERTER NUMBER "?C" REST ;;RESTORE STACK IF DEBUGP ;;TRACE THE OUTPUT RWTRACE ,% DAC&?C UGEN ;;INCLUDE SUBROUTINES CALL @AD ;;WRITE THE VALUE ENDIF SHLD DAC&?C ?TR WRM ;;TRACING OUTPUT? CLEAR ;;REMOVE THE VALUE ENDM ; ***************************************** ; * END OF MACRO LIBRARY * ; *****************************************