;*************************************
;                MONITOR EQUATES
;*************************************
;
BRCHR   EQU     1BH     ; CODE FOR BREAK CHARACTER (ESCAPE)
BRTAB   EQU     3FAH    ; LOCATION OF START OF BRANCH TABLE IN ROM
CMD     EQU     025H    ; COMMAND INSTRUCTION  FOR USART  INITIALIZATION
CNCTL   EQU     0EDH    ; CONSOLE (USART) CONTROL PORT
CNIN    EQU     0ECH    ; CONSOLE INPUT PORT
CNOUT   EQU     0ECH    ; CONSOLE OUTPUT PORT
CONST   EQU     0EDH    ; CONSOLE STATUS INPUT PORT
CR      EQU     0DH     ; CODE FOR CARRIAGE RETURN
ESC     EQU     1BH     ; CODE FOR ESCAPE CHARACTER
HCHAR   EQU     0FH     ; MASK TO SELECT LOWER HEX CHAR FROM BYTE
INVRT   EQU     0FFH    ; MASK TO INVERT HALF BYTE FLAG
LF      EQU     0AH     ; CODE FOR LINE FEED
;LSGNON EQU     ---     ; LENGTH OF SIGNON MESSAGE - DEFINED LATER
MODE    EQU     04DH    ; MODE SET FOR USART INITIALIZATION
;MSTAK  EQU     ---     ; START OF MONITOR STACK - DEFINED LATER
;NCMDS  EQU     ---     ; NUMBER OF VALID COMMANDS
NEWLN   EQU     0FH     ; MASK FOR CHECKING MEMORY ADDR DISPLAY
NULL    EQU     0       ; NULL CHAR
PRTYO   EQU     07FH    ; MASK TO CLEAR PARITY BIT FROM CONSOLE CHAR
REGS    EQU     0FFFFH-18      ; START OF REGISTER SAVE AREA
RBR     EQU     2       ; MASK TO TEST RECIEVER STATUS
RSTU    EQU     38H     ; TRANSFER LOCATION FOR RST 7 INSTRUCTION
;RTABS  EQU     ---     ; SIZE OF ENTRY IN RTAB TABLE
TERM    EQU     1BH     ; CODE FOR ICMD TERMINATING CHARACTER (ESCAPE)
TRDY    EQU     1       ; MASK TO TEST TRANSMITTER STATUS
UPPER   EQU     0FFH    ; DENOTES UPPER HALF OF BYTE IN ICMD
TXBE    EQU     04H     ; USART TRANSMITTER BUFFER EMPTY
ONEMS   EQU     131     ; 1 MILLISECOND CONSTANT
;
COC	EQU	0B6H	; 8253 LOAD COUNTER 2 ( BAUD RATE )
BRF	EQU	3584	; 300 BAUD RATE FACTOR
CCP	EQU	0DFH	; 8253 COMMAND PORT
LC2P	EQU	0DEH	; LOAD COUNTER 2 PORT
;
; HIGH SPEED PAPER TAPE PARALLEL INTERFACE J2 80/20
;
PTC     EQU     0EBH    ; READER/PUNCH INTERFACE CONTROL PORT
PTCW    EQU     83H     ; CONTROL WORD
                        ; READER
PTRD    EQU     0E9H    ; DATA
PTRC    EQU     0EAH    ; CONTROL
STR     EQU     10H     ; STEP
PTRS    EQU     0EAH    ; STATUS
PTRR    EQU     01H     ; READY
                        ; PUNCH
PTPD    EQU     0E8H    ; DATA
PTPC    EQU     0EAH    ; CONTROL
STP     EQU     80H     ; STEP
PTPS    EQU     0EAH    ; STATUS
PTPR    EQU     08H     ; READY
;
; DOWN LINE LOADER/READER INTERFACE J3 SBC116 (I/O BASE 0C0H )
;
DLLD    EQU     0CCH    ; DATA
DLLC    EQU     0CDH    ; CONTROL
DLLS    EQU     0CDH    ; STATUS
DLLMW   EQU     0EH     ; MODE WORD
DLLCW   EQU     27H     ; CONTROL WORD
DLLR    EQU     40H     ; RESET 8251
TXRDY   EQU     1       ; TX STATUS
RXRDY   EQU     2       ; RX STATUS
;
;****************************************
;
;                   MONITOR MACROS
;
;****************************************
;
TRUE    MACRO   WHERE   ; BRANCH IF FUCTION RETURNS TRUE (SUCCESS)
        JC      WHERE
        ENDM
;
FALSE   MACRO   WHERE   ; BRANCH IF FUNCTION RETURNS FALSE (FAILURE)
        JNC     WHERE
        ENDM
;
;***********************************************
;
;                 USART INITIALIZATION CODE
;
;***********************************************
;
;       THE USART IS ASSUMED TO COME UP IN THE RESET POSITION (THIS
;       FUNCTION IS TAKEN CARE OF BY THE HARDWARE). THE USART WILL
;       BE INITIALIZED IN THE SAME WAY FOR EITHER A TTY OR CRT
;       INTERFACE. THE FOLLOWING PARAMETERS ARE USED:
;
;       MODE INSTRUCTION
;       ____ ___________
;
;       2 STOP BITS 
;       PARITY DISABLED
;       8 BIT CHARACTERS
;       BAUD RATE FACTOR OF 64
;
;       COMMAND INSTRUCTION
;       ------- -----------
;
;       NO HUNT MODE
;       NOT(RTS) FORCED TO 0
;       RECIEVE ENABLED
;       TRANSMIT ENABLED
;
        MVI     A,MODE
        OUT     CNCTL   ; OUTPUT MODE SET TO USART
        JMP     INUST   ; BRANCH TO COMPLETE USART INITIALIZATION
        NOP             ; FILLER
;
;*****************************************************************
;
;                       RESTART ENTRY POINT
;
;*****************************************************************
;
GO:
        SHLD    LSAVE   ; SAVE HL REGISTERS
        POP     H       ; GET TOP OF STACK ENTRY
        SHLD    PSAVE   ; ASSUME THIS IS LAST P COUNTER
        PUSH    PSW     ; SAVE A,F/F'S
        LXI     H,2     ; SET HL TO 2 SO THAT STACK POINTER SAVED CORRECTLY
        DAD     SP      ; GET STACK POINTER VALUE
        SHLD    SSAVE   ; SAVE USERS'S STACK PONTER
        POP     PSW     ; RESTORE A,F/F'S
        LXI     SP,ASAVE+1      ; NEW VALUE FOR STACK POINTER
        JMP     ADROUT
;
;********************************************
;
;                  PRINT SIGNON MESSAGE
;
;************************************************
;
SOMSG:
        LXI     H,SGNON ; GET ADDRESS OF SIGNON MESSAGE
        MVI     B,LSGNON        ; COUNTER FOR CHARACTERS IN MESSAGE
MSGL:
        MOV     C,M     ; FETCH NEXT CHAR TO C REG
        CALL    CO      ; SEND IT TO THE CONSOLE
        INX     H       ; POINT TO NEXT CHARACTER
        DCR     B       ; DECREMENT BYTE COUNTER
        JNZ     MSGL    ; RETURN FOR NEXT CHARACTER
;
;****************************************
;
;            COMMAND RECOGNIZING ROUTINE
;
;******************************************
;
; FUNCTION: GETCM
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCH,ECHO,ERROR
; DESTROYS: A,B,C,H,L,F/F'S
; DESCRIPTION: GETCM RECIEVES AN INPUT CHARACTER FROM THE USER
;       AND ATTEMPTS TO LOCATE THIS CHARACTER IN ITS COMMAND
;       CHARACTER TABLE. IF SUCCESSFUL, THE ROUTINE
;       CORRESPONDING TO THIS CHARACTER IS SELECTED FROM
;       A TABLE OF COMMAND ROUTINE ADDRESSES, AND CONTROL 
;       IS TRANSFERRED TO THIS ROUTINE. IF THE CHARACTER
;       DOES NOT MATCH ANY ENTRIES, CONTROL IS PASSED TO
;       THE ERROR HANDLER.
;
GETCM:
        LXI     SP,MSTAK        ; ALWAYS WANT TO RESET STACK PTR TO MONITOR
                        ; /STARTING VALUE SO ROUTINES NEEDN'T CLEAN UP
        MVI     C,'.'   ; PROMPT CHARACTER TO C
        CALL    ECHO    ; SEND PROMPT CHARACTER TO USER TERMINAL
        CALL    GETCH   ; GET COMMAND CHARACTER TO A
        CALL    ECHO    ; ECHO CHARACTER TO USER
        MOV     A,C     ; PUT COMMAND CHARACTER INTO ACCUMULATOR
        LXI     B,NCMDS ; C CONTAINS LOOP AND INDEX COUNT
        LXI     H,CTAB  ; HL POINTS INTO COMMAND TABLE
GTC05:
        CMP     M       ; COMPARE TABLE ENTRY AND CHARACTER
        JZ      GTC10   ; BRANCH IF EQUAL - COMMAND RECOGNIZED
        INX     H       ; ELSE, INCREMENT TABLEPOINTER
        DCR     C       ; DECREMENT LOOP COUNT
        JNZ     GTC05   ; BRANCH IF NOT AT TABLE END
        JMP     ERROR   ; ELSE, COMMAND CHARACTER IS ILLEGAL
GTC10:
        LXI     H,CADR  ; IF GOOD COMMAND, LOAD ADDRESS OF TABLE
                        ; /OF COMMAND ROUTINE ADDRESSES
        DAD     B       ; ADD WHAT IS LEFT OF LOOP COUNT
        DAD     B       ; ADD AGAIN - EACH ENTRY IN CADR IS 2 BYTES LONG
        MOV     A,M     ; GET LSB OF ADDRESS OF TABLE ENTRY TO A
        INX     H       ; POINT TO NEXT BYTE IN TABLE
        MOV     H,M     ; GET MSB OF ADDRESS OF TABLE ENTRY TO H
        MOV     L,A     ; PUT LSB OF ADDRESS OF TABLE ENTRY INTO L
        PCHL            ; NEXT INSTRUCTION COMES FROM COMMAND ROUTINE
;
;***********************************************************
;
;                   COMMAND IMPLEMENTING ROUTINES
;
;***********************************************************
;
; FUNCTION: DCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHO,NMOUT,HILO,GETCM,CROUT,GETNM
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: DCMD IMPLEMENTS THE DISPLAY MEMORY (D) COMMAND
;
DCMD:
        MVI     C,2     ; GET TWO NUMBERS FROM INPUT STREAM
        CALL    GETNM
        POP     D       ; ENDING ADDRESS TO DE
        POP     H       ; STARTING ADDRESS TO HL
DCM05:
        CALL    CROUT   ; ECHO CARRIAGE RETURN/LINE FEED
        CALL    ADRD    ; DISPLAY ADDRESS
DCM10:
        MVI     C,' '
        CALL    ECHO    ; USE BLANK AS SEPERATOR
        MOV     A,M     ; GET CONTENTS OF NEXT MEMORY LOCATION
        CALL    NMOUT   ; DISPLAY CONTENTS
        CALL    BREAK   ; SEE IF USER WANTS OUT
        TRUE    EXIT    ; IF SO, BRANCH TO EXIT
        CALL    HILO    ; SEE IF ADDRESS OF DISPLAYED LOCATION IS
                        ; /GREATER THAN OR EQUAL TO ENDING ADDRESS
        TRUE    EXIT    ; EXIT IF NO MORE TO DISPLAY
        INX     H       ; IF MORE TO GO, POINT TO NEXT LOC TO DISPLAY
        MOV     A,L     ; GET LOW ORDER BITS OF NEW ADDRESS
        ANI     NEWLN   ; SEE IF LAST HEX DIGIT OF ADDRESS DENOTES
                        ; /START OF NEW LINE
        JNZ     DCM10   ; NO - NOT AT END OF LINE
        JMP     DCM05   ; YES - START NEW LINE WITH ADDRESS
;
;*************************************************************************
;
; FUNCTION: GCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ERROR,GETHX,RSTTF
; DESTROYS: A,B,C,D,E,H,F/F'S
; DESCRIPTION: GCMD IMPLEMENTS THE BEGIN EXECUTION (G) COMMAND
;
GCMD:
        CALL    GETHX   ; GET ADDRESS (IF PRESENT) FROM INPUT STREAM
        FALSE   GCM05   ; BRANCH IF NO NUMBER PRESENT
        MOV     A,D     ; ELSE, GET TERMINATOR
        CPI     CR      ; SEE IF CARRIAGE RETURN
        JNZ     ERROR   ;  ERROR IF NOT PROPERLY TERMINATED
        LXI     H,PSAVE  ; WANT NUMBER TO REPLACE SAVE PGM COUNTER
        MOV     M,C
        INX     H
        MOV     M,B
        JMP     GCM10
GCM05:
        MOV     A,D     ; IF NO STARTING ADDRESS,MAKE SURE THAT 
        CPI     CR      ; /CARRIAGE RETURN TERMINATED COMMAND
        JNZ     ERROR   ; ERROR IF NOT
GCM10:
        JMP     RSTTF   ; RESTORE REGISTERS AND BEGIN EXECUTION
;
;************************************************************
;
; FUNCTION: ICMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ERROR,ECHO,GETCH,VALDL,VALDG,CNVBN,STHLF,GETNM,CROUT
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: ICMD IMPLEMENTS THE INSERT CODE INTO MEMORY (I) COMMAND.
;
ICMD:
        MVI     C,1
        CALL    GETNM   ; GET SINGLE NUMBER FROM INPUT STREAM
        MVI     A,UPPER
        STA     TEMP    ; TEMP WILL HOLD THE UPPER/LOWER HALF BYTE FLAG
        POP     D       ; ADDRESS OF START TO DE
ICM05:
        CALL    GETCH   ; GET A CHARACTER FROM INPUT STREAM
        CALL    ECHO    ; ECHO IT
        MOV     A,C     ; PUT CHARACTER BACK INTO A
        CPI     TERM    ; SEE IF CHARACTER IS A TERMINATING CHARACTER
        JZ      ICM25   ; IF SO, ALL DONE ENTERING CHARACTERS
        CALL    VALDL   ; ELSE, SEE IF VALID DELIMITER
        TRUE    ICM05   ; IF SO SIMPLY IGNORE THIS CHARACTER
        CALL    VALDG   ; ELSE, CHECK TO SEE IF VALID HEX DIGIT
        FALSE   ICM20   ; IF NOT, BRANCH TO HANDLE ERROR CONDITION
        CALL    CNVBN   ; CONVERT DIGIT TO BINARY
        MOV     C,A     ; MOVE RESULT TO C
        CALL    STHLF   ; STORE IN APPROPIATE HALF WORD
        LDA     TEMP    ; GET HALF BYTE FLAG
        ORA     A       ; SET F/F'S
        JNZ     ICM10   ; BRANCH IF FLAG SET FOR UPPER
        INX     D       ; IF LOWER, INC ADDRESS OF BYTE TO STORE IN
ICM10:
        XRI     INVRT   ; TOGGLE STATE OF FLAG
        STA     TEMP    ; PUT NEW VALUE OF FLAG BACK
        JMP     ICM05   ; PROCESS NEXT DIGIT
ICM20:
        CALL    STHF0   ; ILLEGAL CHARACTER
        JMP     ERROR   ; MAKE SURE ENTIRE BYTE FILLED THEN ERROR
ICM25:
        CALL    STHF0   ; HERE FOR ESCAPE CHARACTER - INPUT IS DONE
        JMP     EXIT
;
;*********************************************************************
;
; FUNTION: MCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCM,HILO,GETNM
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: MCMD IMPLEMENTS THE MOVE DATA IN MEMORY (M) COMMAND
;
MCMD:
        MVI     C,3
        CALL    GETNM   ; GET 3 NUMBERS FROM INPUT STREAM
        POP     B       ; DESTINATION ADDRESS TO BC
        POP     H       ; ENDING ADDRESS TO HL
        POP     D       ; STARTING ADDRESS TO DE
MCM05:
        PUSH    H       ; SAVE ENDING ADDRESS
        MOV     H,D
        MOV     L,E     ; SOURCE ADDRESS TO HL
        MOV     A,M     ; GET SOURCE BYTE
        MOV     H,B     
        MOV     L,C     ; DESTINATION ADDRESS TO HL
        MOV     M,A     ; MOVE BYTE TO DESTINATION
        INX     B       ; INCREMENT DESTINATION ADDRESS
        MOV     A,B
        ORA     C       ; TEST FOR DESTINATION ADDRESS OVERFLOW
        JZ      GETCM   ; IF SO CAN TERMINATE COMMAND
        INX     D       ; INCREMENT SOURCE ADDRESS
        POP     H       ; ELSE, GET BACK ENDING ADDRESS
        CALL    HILO    ; SEE IF ENDING ADDR>=SOURCE ADDR
        FALSE   GETCM   ; IF NOT, COMMAND IS DONE
        JMP     MCM05   ; MOVE ANOTHER BYTE
;
;*********************************************************************
;
; FUNCTION: SCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETHX,GETCM,NMOUT,ECHO
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: SCMD IMPLEMENTS THE SUBSTITUTE INTO MEMORY (S) COMMAND
;
SCMD:
        CALL    GETHX   ; GET A NUMBER, IF PRESENT, FROM INPUT
        PUSH    B
        POP     H       ; GET NUMBER TO HL - DENOTES MEMORY LOCATION
SCM05:
        MOV     A,D     ; GET TERMINATOR
        CPI     ' '     ; SEE IF SPACE
        JZ      SCM10   ; YES - CONTINUE PROCESSING
        CPI     ','     ; ELSE, SEE IF COMMA
        JNZ     GETCM   ; NO - TERMINATE COMMAND
SCM10:
        MOV     A,M     ; GET CONTENTS OF SPECIFIED LOCATION TO A
        CALL    NMOUT   ; DISPLAY CONTENTS ON CONSOLE
        MVI     C,'-'
        CALL    ECHO    ; USE DASH FOR SEPERATOR
        CALL    GETHX   ; GET NEW VALUE FOR MEMORY LOCATION, IF ANY
        FALSE   SCM15   ; IF NO VALUE PRESENT, BRANCH
        MOV     M,C     ; ELSE, STORE LOWER 8 BITS OF NUMBER ENTERED
SCM15:
        INX     H       ; INCREMENT ADDRESS OF MEMORY LOCATION TO VIEW
        JMP     SCM05
;
;*********************************************************************
;
; FUNCTION: XCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCH,ECHHO,REGDS,GETCM,ERROR,RGADR,NMOUT,CROUT,GETHX
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: XCMD IMPLEMENTS THE REGISTER EXAMINE AND CHANGE (X)
;               COMMAND.
;
XCMD:
        CALL    GETCH   ; GET REGISTER IDENTIFIER
        CALL    ECHO    ; ECHO IT
        MOV     A,C
        CPI     CR
        JNZ     XCM05   ; BRANCH IF NOT CARRIAGE RETURN
        CALL    REGDS   ; ELSE, DISPLAY REGISTER CONTENTS
        JMP     GETCM   ; THEN TERMINATE COMMAND
XCM05:
        MOV     C,A     ; GET REGISTER IDENTIFIER TO C
        CALL    RGADR   ; CONVERT IDENTIFIER INTO RTAB TABLE ADDR
        PUSH    B
        POP     H       ; PUT POINTER TO REGISTER ENTRY INTO HL
        MVI     C,' '
        CALL    ECHO    ; ECHO SPACE TO USER
        MOV     A,C
        STA     TEMP    ; PUT SPACE INTO TEMP AS DELIMITER
XCM10:
        LDA     TEMP    ; GET TERMINATOR
        CPI     ' '     ; SEE IF BLANK
        JZ      XCM15   ; YES - GO CHECK POINTER INTO TABLE
        CPI     ','     ; NO - SEE IF COMMA
        JNZ     GETCM   ; NO - MUST BE CARRIAGE RETURN TO END COMMAND
XCM15:
        MOV     A,M
        ORA     A       ; SET F/F'S
        JZ      EXIT    ; BRANCH IF AT END OF TABLE
        PUSH    H       ; PUT POINTER ON STACK
        MOV     E,M     
        MVI     D,HIGH(REGS)    ; FETCH ADDRESS OF SAVE LOCATION FROM
        INX     H               ; /TABLE
        MOV     B,M     ; FETCH LENGTH FLAG FROM TABLE
        PUSH    D       ; SAVE ADDRESS OF SAVE LOCATION
        PUSH    D
        POP     H       ; MOVE ADDRESS TO HL
        PUSH    B       ; SAVE LENGTH FLAG
        MOV     A,M     ; GET 8 BITS OF REGISTER FROM SAVE LOCATION
        CALL    NMOUT   ; DISPLAY IT
        POP     PSW     ; GET BACK LENGTH FLAG
        PUSH    PSW     ; SAVE IT AGAIN
        ORA     A       ; SET F/F'S
        JZ      XCM20   ; IF 8 BIT REGISTER, NOTHING MORE TO DISPLAY
        DCX     H       ; ELSE, FOR 16 BIT REGISTER, GET LOWER 8 BITS
        MOV     A,M
        CALL    NMOUT   ; DISPLAY THEM
XCM20:
        MVI     C,'-'
        CALL    ECHO    ; USE DASH AS SEPERATOR
        CALL    GETHX   ; SEE IF THERE IS A VALUE TO PUT INTO REGISTER
        FALSE   XCM30   ; NO - GO CHECK FOR NEXT REGISTER
        MOV     A,D
        STA     TEMP    ; ELSE, SAVE THE TERMINATOR FOR NOW
        POP     PSW     ; GET BACK LENGTH FLAG
        POP     H       ; PUT ADDRESS OF SAVE LOCATION INTO HL
        ORA     A       ; SET F/F'S
        JZ      XCM25   ; IF 8 BIT REGISTER, BRANCH
        MOV     M,B     ; SAVE UPPER 8 BITS
        DCX     H       ; POINT TO SAVE LOCATION FOR LOWER 8 BITS
XCM25:
        MOV     M,C     ; STORE ALL OF 8 BIT OR LOWER 1/2 OF 16 BIT REG
XCM27:
        LXI     D,RTABS ; SIZE OF ENTRY IN RTAB TABLE
        POP     H       ; POINTER INTO REGISTER TABLE RTAB
        DAD     D       ; ADD ENTRY SIZE TO POINTER
        JMP     XCM10   ; DO NEXT REGISTER
XCM30:
        MOV     A,D     ; GET TERMINATOR
        STA     TEMP    ; SAVE IN MEMORY
        POP     D       ; CLEAR STACK OF LENGTH FLAG AND ADDRESS
        POP     D       ; /OF SAVE LOCATION
        JMP     XCM27   ; GO INCREMENT REGISTER TABLE POINTER
;
;***********************************************************************
;
;                UTILITY ROUTINES
;
;***********************************************************************
;
; FUNCTION: ADRD
; INPUTS: HL - ADDRESS TO BE DISPLAYED
; OUTPUTS: NONE
; CALLS: NMOUT
; DESTROYS: A
; DESCRIPTION: ADRD OUTPUTS TO THE CONSOLE THE ADDRESS
;              CONTAINED IN THE H,L REGISTERS.
;
ADRD:
        MOV     A,H     ; DISPLAY FIRST HALF OF ADDRESS
        CALL    NMOUT
        MOV     A,L     ; DISPLAY SECOND HALF OF ADDRESS
        CALL    NMOUT   
        RET             ; RETURN TO CALLING ROUTINE
;
;***********************************************************************
;
; FUNCTION: ADROUT
; INPUTS: USER REGISTERS ON THE STACK 
; OUTPUTS: NOTHING
; CALLS: ECHO,ADRD
; DESTROYS:A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: ADROUT SAVES THE USER REGISTERS AND OUTPUTS TO THE
;              CONSOLE THE USER P COUNTER AFTER A RST 1 INSTRUCTION.
;
ADROUT:
        PUSH    PSW     ; SAVE A AND FLAGS
        PUSH    B       ; SAVE B AND C
        PUSH    D       ; SAVE D AND E
        MVI     C,'#'
        CALL    ECHO    ; OUTPUT '#'
        LHLD    PSAVE   ; LOAD USER P COUNTER
        CALL    ADRD    ; DISPLAY ADDRESS
        JMP     EXIT    ; GET NEW COMMAND
;
;*************************************************************
;
; FUNCTION: BREAK
; INPUTS: NONE
; OUTPUTS: CARRY - 1 IF ESCAPE CHARACTER INPUT
;                - 0 IF ANY OTHER CHARACTER OR NO CHARACTER PENDING
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: BREAK IS USED TO SENSE AN ESCAPE CHARACTER FROM
;              THE USER. IF NO CHARACTER IS PENDING, OR IF THE
;              PENDING CHARACTER IS NOT THE ESCAPE, THEN A FAILURE
;              RETURN (CARRY=0) IS TAKEN. IN THIS CASE, THE
;              PENDING CHARACTER (IF ANY) IS LOST. IF THE PENDING 
;              CHARACTER IS AN ESCAPE CHARACTER, BREAK TAKES A SUCCESS
;              RETURN (CARRY=1).
;
BREAK:
        IN      CONST   ; GET CONSOLE STATUS
        ANI     RBR     ; SEE IF CHARACTER PENDING
        JZ      FRET    ; NO - TAKE FAILURE RETURN
        IN      CNIN    ; YES - PICK UP CHARACTER
        ANI     PRTYO   ; STRIP OF PARITY BIT
        CPI     BRCHR   ; SEE IF BREAK CHARACTER
        JZ      SRET    ; YES - SUCCESS RETURN
        JMP     FRET    ; NO - FAILURE RETURN - CHARACTER LOST
;
;******************************************************************
;
; FUNCTION CI
; INPUTS: NONE
; OUTPUTS: A - CHARACTER FROM CONSOLE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: CI WAITS UNTIL A CHARACTER HAS BEEN ENTERED AT THE
;              CONSOLE AND THEN RETURNS THE CHARACTER, VIA THE A
;              REGISTER, TO THE CALLING ROUTINE. THIS ROUTINE
;              IS CALLED BY THE USER VIA A JUMP TABLE IN RAM.
;
CI:
        IN      CONST   ; GET STATUS OF CONSOLE
        ANI     RBR     ; CHECK FOR RECEIVER BUFFER READY
        JZ      CI      ; NOT YET - WAIT
        IN      CNIN    ; READY SO GET CHARACTER
        RET
;
;*******************************************************
;
; FUNCTION: CNVBN
; INPUTS: C - ASCII CHARACTER '0'-'9' OR 'A'-'F'
; OUTPUTS: A - 0 TO F HEX
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: CNVBN CONVERTS THE ASCII REPRESENTATION OF A HEX
;              CHARACTER INTO ITS CORRESPONDIG BINARY VALUE. CNVBN
;              DOES NOT CHECK THE VALIDITY OF ITS INPUT.
;
CNVBN:
        MOV     A,C
        SUI     '0'     ; SUBTRACT CODE FOR '0' FROM ARGUMENT
        CPI     10      ; WANT TO TEST FOR RESULT OF 0 TO 9
        RM              ; IF SO, THEN ALL DONE
        SUI     7       ; ELSE, RESULT BETWEEN 17 AND 23 DECIMAL
        RET             ; SO RETURN AFTER SUBTRACTING BIAS OF 7
;
;**********************************************************
;
; FUNCTION: CO
; INPUTS; C - CHARACTER TO OUTPUT TO CONSOLE
; OUTPUTS: C - CHARACTER OUTPUT TO CONSOLE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: CO WAITS UNTIL THE THE CONSOLE IS READY TO ACCEPT
;              A CHARACTER AND THEN SENDS THE INPUT ARGUMENT
;              TO THE CONSOLE.
;
CO:
        IN      CONST   ; GET STATUS OF CONSOLE
        ANI     TRDY    ; SEE IF TRANSMITTER READY
        JZ      CO      ; NO - WAIT
        MOV     A,C     ; ELSE, MOVE CHARACTER TO A REGISTER FOR OUTPUT
        OUT     CNOUT   ; SEND TO CONSOLE
        RET
;
;*******************************************************
;
; FUNCTION: CROUT
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHO
; DESTROYS: A,B,C,F/F'S
; DESCRIPTION: CROUT SENDS A CARRIAGE RETURN (AND THENCE A LINE
;              FEED) TO THE CONSOLE
;
CROUT:
        MVI     C,CR
        CALL    ECHO    ; OUTPUT CARRIAGE RETURN TO USER TERMINAL
        RET
;
;*******************************************************
;
; FUNCTION: ECHO
; INPUTS: C - CHARACTER TO ECHO TO TERMINAL
; OUTPUTS: C - CHARACTER ECHOED TO TERMINAL
; CALLS: CO
; DESTROYS: A,B,F/F'S
; DESCRIPTION: ECHO TAKES A SINGLE CHARACTER AS INPUT AND, VIA
;              THE MONITOR, SENDS THAT CHARACTER TO THE USER
;              TERMINAL. A CARRIAGE RETURN IS ECHOED AS CARRIAGE
;              RETURN/ LINE FEED, AND AN ESCAPE CHARACTER IS ECHOED
;              AS $
;
ECHO:
        MOV     B,C     ; SAVE ARGUMENT
        MVI     A,ESC
        CMP     B       ; SEE IF ECHOING AN ESCAPE CHARACTER
        JNZ     ECH05   ; NO - BRANCH
        MVI     C,'$'   ; YES - ECHO AS $
ECH05:
        CALL    CO      ; DO OUTPUT THROUGH MONITOR
        MVI     A,CR
        CMP     B       ; SEE IF ECHOING A CARRIAGE RETURN
        JNZ     ECH10   ; NO - NO NEED FOR SPECIAL ACTION
        MVI     C,LF    ; YES - WANT TO ECHO A LINE FEED, TOO
        CALL    CO
ECH10:
        MOV     C,B     ; RESTORE ARGUMENT
        RET
;
;***********************************************************************
;
; FUNCTION: ERROR
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHO,CROUT,GETCM
; DESTROYS: A,B,C,F/F'S
; DESCRIPTION: ERROR PRINTS THE ERROR CHARACTER (CURRENTLY AN ASTERISK)
;              ON THE CONSOLE, FOLLOWED BY A CARRIAGE RETURN-LINE FEED,
;              AND THEN RETURNS CONTROL TO THE COMMAND RECOGNISER.
;
ERROR:
        MVI     C,'#'
        CALL    ECHO    ; SEND # TO CONSOLE
EXIT:
        CALL    CROUT   ; SKIP TO BEGINING OF NEXT LINE
        JMP     GETCM   ; TRY AGAIN FOR ANOTHER COMMAND
;
;***********************************************************************
;
; FUNCTION: FRET
; INPUTS: NONE
; OUTPUTS: CARRY - ALWAYS 0
; CALLS: NOTHING
; DESTROYS: CARRY
; DESCRIPTION: FRET IS JUMPED TO BY ANY ROUTINE THAT WISHES TO
;              INDICATE FAILURE ON RETURN. FRET SETS THE CARRY
;              FALSE, DENOTING FAILURE, AND THEN RETURNS TO THE
;              CALLER OF THE ROUTINE INVOKING FRET
;
FRET: 
        STC             ; FIRST SET CARRY TRUE
        CMC             ; THEN COMPLIMENT IT TO MAKE IT FALSE
        RET             ; RETURN APPROPRIATELY
;
;***********************************************************************
;
; FUNCTION: GETCH
; INPUTS: NONE
; OUTPUTS: C - NEXT CHARACTER IN INPUT STREAM
; CALLS: CI
; DESTROYS: A,C,F/F'S
; DESCRIPTION: GETCH RETURNS THE NEXT CHARACTER IN THE INPUT STREAM
;              TO THE CALLING PROGRAM
;
GETCH:
        CALL    CI      ; GET CHARACTER FROM TERMINAL
        ANI     PRTYO   ; TURN OFF PARITY BIT IN CASE SET BY CONSOLE
        MOV     C,A     ; PUT VALUE IN C REGISTER FOR RETURN
        RET
;
;***********************************************************************
;
; FUNCTION: GETHX
; INPUTS: NONE
; OUTPUTS: BC - 16 BIT INTEGER
;          D - CHARACTER WHICH TERMINATED THE INTEGER
;          CARRY - 1 IF FIRST CHARACTER NOT DELIMITER
;                - 0 IF FIRST CHARACTER IS DELIMITER
; CALLS: GETCH,ECHO,VALDL,VALDG,CNVBN,ERROR
; DESTROYS: A,B,C,D,E,F/F'S
; DESCRIPTION: GETHX ACCEPTS A STRING OF HEX DIGITS FROM THE INPUT
;              STREAM AND RETURNS THEIR VALUE AS A 16 BIT BINARY
;              INTEGER. IF MORE THAN 4 HEX DIGITS ARE ENTERED,
;              ONLY THE LAST 4 ARE USED. THE NUMBER TERMINATES WHEN 
;              A VALID DELIMITER IS ENCOUNTERED. THE DELIMITER IS
;              ALSO RETURNED AS AN OUTPUT OF THE FUNCTION. ILLEGAL
;              CHARACTERS (NOT HEX CHARACTERS OR DELIMITERS) CAUSE AN
;              ERROR INDICATION. IF THE FIRST (VALID) CHARACTER
;              ENCONTERED IN THE INPUT STREAM IS NOT A DELIMITER,
;              GETHX WILL RETURN WITH THE CARRY BIT SET TO 1;
;              OTHERWISE, THE CARRY BIT IS SET TO 0 AND THE CONTENTS 
;              OF BC ARE UNDEFINED.
;
GETHX:
        PUSH    H       ; SAVE HL
        LXI     H,0     ; INITIALISE RESULT
        MVI     E,0     ; INITIALISE DIGIT FLAG TO FALSE
GHX05: 
        CALL    GETCH   ; GET A CHARACTER
        CALL    ECHO    ; ECHO THE CHARACTER
        CALL    VALDL   ; SEE IF DELIMITER
        FALSE   GHX10   ; NO - BRANCH
        MOV     D,C     ; YES - ALL DONE, BUT WANT TO RETURN DELIMITER
        PUSH    H
        POP     B       ; MOVE RESULT TO BC
        POP     H       ; RESTORE HL
        MOV     A,E     ; GET FLAG
        ORA     A       ; SET F/F'S
        JNZ     SRET    ; IF FLAG NON-0, A NUMBER HAS BEEN FOUND
        JZ      FRET    ; ELSE, DELIMITER WAS FIRST CHARACTER
GHX10:
        CALL    VALDG   ; IF NOT DELIMITER, SEE IF DIGIT
        FALSE   ERROR   ; ERROR IF NOT A VALID DIGIT, EITHER
        CALL    CNVBN   ; CONVERT DIGIT TO ITS BINARY VALUE
        MVI     E,0FFH  ; SET DIGIT FLAG NON-0
        DAD     H       ; *2
        DAD     H       ; *4
        DAD     H       ; *8
        DAD     H       ; *16
        MVI     B,0     ; CLEAR UPPER 8 BITS OF BC PAIR
        MOV     C,A     ; BINARY VALUE OF CHARACTER INTO C
        DAD     B       ; ADD THIS VALUE TO PARTIAL RESULT
        JMP     GHX05   ; GET NEXT CHARACTER
;
;***********************************************************************
;
; FUNCTION: GETNM
; INPUTS: C - COUNT OF NUMBERS TO FIND IN INPUT STREAM
; OUTPUTS: TOP OF STACK - NUMBERS FOUND IN REVERSE ORDER (LAST ON TOP
;                         OF STACK)
; CALLS: GETHX,HILO,ERROR
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: GETNM FINDS A SPECIFIED COUNT OF NUMBERS , BETWEEN 1
;              AND 3, INCLUSIVE, IN THE INPUT
;              STREAM AND RETURNS THEIR VALUES ON THE STACK. IF 2
;              OR MORE NUMBERS ARE REQUESTED, THEN THE FIRST MUST BE
;              LESS THAN OR EQUAL TO THE SECOND, OR THE FIRST AND
;              SECOND NUMBERS WILL BE SET EQUAL. THE LAST NUMBER
;              REQUESTED MUST BE TERMINATED BY A CARRIAGE RETURN
;              OR AN ERROR INDICATION WILL RESULT.
;
GETNM:  
        MVI     L,3     ; PUT MAXIMUM ARGUMENT COUNT INTO L
        MOV     A,C     ; GET THE ACTUAL ARGUMENT COUNT
        ANI     3       ; FORCE TO MAXIMUM OF 3
        RZ              ; IF 0,DON'T BOTHER TO DO ANYTHING
        MOV     H,A     ; ELSE, PUT ACTUAL COUNT INTO H
GNM05:
        CALL    GETHX   ; GET A NUMBER FROM INPUT STREAM
        FALSE   ERROR   ; ERROR IF NOT THERE - TOO FEW NUMBERS
        PUSH    B       ; ELSE, SAVE NUMBER ON STACK
        DCR     L       ; DECREMENT MAXIMUM ARGUMENT COUNT
        DCR     H       ; DECREMENT ACTUAL ARGUMENT COUNT
        JZ      GNM10   ; BRANCH IF NO MORE NUMBERS WANTED
        MOV     A,D     ; ELSE, GET NUMBER TERMINATOR TO A
        CPI     CR      ; SEE IF CARRIAGE RETURN
        JZ      ERROR   ; ERROR IF SO - TOO FEW NUMBERS
        JMP     GNM05   ; ELSE, PROCESS NEXT NUMBER
GNM10:
        MOV     A,D     ; WHEN COUNT 0, CHECK LAST TERMINATOR
        CPI     CR
        JNZ     ERROR   ; ERROR IF NOT CARRIAGE RETURN
        LXI     B,0FFFFH        ; HL GETS LARGEST NUMBER
        MOV     A,L     ; GET WHAT'S LEFT OF MAXIMUM ARG COUNT
        ORA     A       ; CHECK FOR 0
        JZ      GNM20   ; IF YES, THREE NUMBERS WERE INPUT
GNM15:
        PUSH    B       ; IF NOT, FILL REMAINING ARGUMENTS WITH 0FFFFH
        DCR     L
        JNZ     GNM15
GNM20:
        POP     B       ; GET THE THREE ARGUMENTS OUT
        POP     D
        POP     H
        CALL    HILO    ; SEE IF FIRST >= SECOND
        FALSE   GNM25   ; NO - BRANCH
        MOV     D,H
        MOV     E,L     ; YES - MAKE SECOND EQUAL TO THE FIRST
GNM25:
        XTHL            ; PUT FIRST ON STACK - GET RETURN ADDR
        PUSH    D       ; PUT SECOND ON STACK
        PUSH    B       ; PUT THIRD ON STACK
        PUSH    H       ; PUT RETURN ADDRESS ON STACK
GNM30:
        DCR     A       ; DECREMENT RESIDUAL COUNT
        RM              ; IF NEGATIVE, PROPER RESULTS ON STACK
        POP     H       ; ELSE, GET RETURN ADDR
        XTHL            ; REPLACE TOP RESULT WITH RETURN ADDR
        JMP     GNM30   ; TRY AGAIN
;
;*********************************************************************
;
; FUNCTION: HILO
; INPUTS: DE - 16 BIT INTEGER
;         HL - 16 BIT INTEGER
; OUTPUTS: CARRY - 0 IF HL<DE
;                - 1 IF HL>=DE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: HILO COMPARES THE 2 16 BIT INTEGERS IN HL AND DE. THE
;              INTEGERS ARE TREATED AS UNSIGNED NUMBERS. THE CARRY
;              BIT IS SET ACCORDING TO THE RESULT OF THE COMPARISON.;
HILO:
        PUSH    B       ; SAVE BC
        MOV     B,A     ; SAVE A REGISTER
        INX     H       ; INCREMENT HL BY 1
        MOV     A,H     ; WANT TO TEST FOR 0 RESULT AFTER
        ORA     L       ; /INCREMENTING
        DCX     H       ; RESTORE HL
        STC             ; SET CARRY
        JZ      HIL05   ; IF SO, CARRY IS SET PROPERLY
        MOV     A,L     ; IF NOT, MOVE L TO A
        SUB     E       ; SUBTRACT E
        MOV     A,H     ; MOVE H TO A
        SBB     D       ; SUBTRACT D WITH BORROW
        CMC             ; COMPLIMENT CARRY FOR CORRECT CARRY BIT VALUE
HIL05:
        MOV     A,B     ; RESTORE A
        POP     B       ; RESTORE BC
        RET             ; EXIT
;
;*********************************************************************
;
; FUNCTION: INUST
; INPUTS: NONE
; OUTPUTS: NOTHING
; CALLS: NOTHING
; DESTROYS: A,HH,L,SP
; DESCRIPTION: INUST OUTPUTS TO THE USART THE COMMAND WORD
;              AND INITIALIZES THE STACK POINTER.
;
INUST:
        MVI     A,CMD
        OUT     CNCTL   ; OUTPUT COMMAND WORD TO USART
;
	MVI	A,COC	; SET UP 8253 ( BAUD RATE )
	OUT	CCP
	MVI	A,LOW(BRF)
	OUT	LC2P
	MVI	A,HIGH(BRF)
	OUT	LC2P
;
        MVI     A,PTCW  ; SET UP PARALLEL I/O FOR HIGH SPEED PAPER TAPE
        OUT     PTC
;
        LXI     H,MSTAK-44      ; LOAD POINTER TO STACK
        SHLD    SSAVE   ; INITIALIZE USER STACK POINTER
;
        LXI     SP,MSTAK        ; INITIALIZE MONITOR STACK
        JMP     SOMSG   ; GO TO PRINT SIGNON MESSAGE
;
;*********************************************************************
;
; FUNCTION: NMOUT
; INPUTS: A - 8 BIT INTEGER
; OUTPUTS: NONE
; CALLS: ECHO,PRVAL
; DESTROYS: A,B,C,F/F'S
; DESCRIPTION: NMOUT CONVERTS THE 8 BIT, UNSIGNED INTEGER IN THE
;              A REGISTER INTO 2 ASCII CHARACTERS. THHE ASCII CHARACTERS
;              ARE THE ONES REPRESENTING THE 8 BITS. THESE TWO
;              CHRACTERS ARE SENT TO THE CONSOLE AT THE CURRENT PRINT
;              POSITION OF THE CONSOLE.
;
NMOUT:
        PUSH    PSW     ; SAVE ARGUMENT
        RRC
        RRC
        RRC
        RRC             ; GET UPPER 4 BITS TO LOW 4 BIT POSITIONS
        CALL    PRVAL   ; CONVERT LOWER 4 BITS TO ASCII
        CALL    ECHO    ; SEND TO TERMINAL
        POP     PSW     ; GET BACK ARGUMENT
        CALL    PRVAL
        CALL    ECHO
        RET
;
;*********************************************************************
;
; FUNCTION: PRVAL
; INPUTS: A - INTEGER, RANGE 0 TO F
; OUTPUTS: A - ASCII CHARACTER
; CALLS: NOTHING
; DESTROYS: NOTHING
; DESCRIPTION: PRVAL CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO
;              THE CORRESPONDING ASCII CHARACTERS, 0-9,A-F. PRVAL
;              DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT.
;
PRVAL:
        ANI     HCHAR   ; MASK OUT UPPER 4 BITS - WANT 1 HEX CHAR
        ADI     90H     ; SET UP A SO THAT A-F CAUSE A CARRY
        DAA             ; ADJUST CONTENTS OF A REGISTER
        ACI     40H     ; ADD IN CARRY AND ADJUST UPPER 4 BITS
        DAA             ; ADJUST CONTENTS OF A REGISTER AGAIN
        MOV     C,A     ; MOVE ASCII CHARACTER TO C
        RET             ; ALL DONE
;
;*********************************************************************
;
; FUNCTION: REGDS
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHHO,NMOUT,ERROR,CROUT
; DESTROYS: A,B,C,D,E,HH,L,F/F'S
; DESCRIPTION: REGDS DISPLAYS THE CONTENTS OF THE REGISTER SAVE
;              LOCATIONS, IN FORMATTED FORM, ON THE CONSOLE. THE
;              DISPLAY IS DRIVEN FROM A TABLE, RTAB, WHICH CONTAINS
;              THE REGISTER'S PRINT SYMBOL, SAVE LOCATION ADDRESS,
;              AND LENGTH (8 OR 16 BITS).
;
REGDS:
        LXI     H,RTAB  ; LOAD HL WITH ADDRESS OF START OF TABLE
REG05:
        MOV     C,M     ; GET PRINT SYMBOL OF REGISTER
        MOV     A,C
        ORA     A       ; TEST FOR 0 - END OF TABLE
        JNZ     REG10   ; IF NOT END, BRANCH
        CALL    CROUT   ; ELSE, CARRIAGE RETURN/LINE FEED TO END
        RET             ; /DISPLAY
REG10:
        CALL    ECHO    ; ECHO CHARACTER
        MVI     C,'='
        CALL    ECHO    ; OUTPUT EQUALS SIGN, I.E. A=
        INX     H       ; POINT TO START OF SAVE LOCATION ADDRESS
        MOV     E,M     ; GET LSB OF SAVE LOCATION ADDRESS TO E
        MVI     D,HIGH(REGS)    ; PUT MSB OF SAVE LOC ADDRESS INTO D
        INX     H       ; POINT TO LENGTH FLAG
        LDAX    D       ; GET CONTENTS OF SAVE ADDRESS
        CALL    NMOUT   ; DISPLAY ON CONSOLE
        MOV     A,M     ; GET LENGTH FLAG
        ORA     A       ; SET SIGN F/F
        JZ      REG15   ; IF 0, REGISTER IS 8 BITS
        DCX     D       ; ELSE, 16 BIT REGISTER SO MORE TO DISPLAY
        LDAX    D       ; GET LOWER 8 BITS
        CALL    NMOUT   ; DISPLAY THEM
REG15:
        MVI     C,' '
        CALL    ECHO    ; OUTPUT BLANK CHARACTER
        INX     H       ; POINT TO START OF NEXT TABLE ENTRY
        JMP     REG05   ; DO NEXT REGISTER
;
;*********************************************************************
;
; FUNCTION: RGADR
; INPUTS: C - CHARACTER DENOTING REGISTER
; OUTPUTS: BC - ADDRESS OF ENTRY IN RTAB CORRESPONDING TO REGISTER
; CALLS: ERROR
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: RGADR TAKES A SINGLE CHARACTER AS INPUT . THIS CHARACTER
;              DENOTES A REGISTER. RGADR SEARCHES THE TABLE RTAB
;              FOR A MATCH ON THE INPUT ARGUMENT. IF ONE OCCURS,
;              RGADR RETURNS THE ADDRESS OF THE ADDRESS OF THE
;              SAVE LOCATION CORRESPONDING TO THE REGISTER.
;              THIS ADDRESS POINTS INTO RTAB. IF NO MATCH OCCURS, THEN
;              THE REGISTER IDENTIFIER IS ILLEGAL AND CONTROL IS
;              PASSED TO THE ERROR ROUTINE.
;
RGADR:
        LXI     H,RTAB  ; HL GETS ADDRES OF TABLE START
        LXI     D,RTABS ; DE GET SIZE OF A TABLE ENTRY     
RGA05:
        MOV     A,M     ; GET REGISTER IDENTIFIER
        ORA     A       ; CHECK FOR TABLE END (IDENTIFIER IS 0)
        JZ      ERROR   ; IF AT END OF TABLE, ARGUMENT IS ILLEGAL
        CMP     C       ; ELSE, COMPARE TABLE ENTRY AND ARGUMENT
        JZ      RGA10   ; IF EQUAL, WE'VE FOUND WHAT WERE LOOKING FOR
        DAD     D       ; ELSE, INCREMENT TABLE POINTER TO NEXT ENTRY
        JMP     RGA05   ; TRY AGAIN
RGA10:
        INX     H       ; IF A MATCH, INCREMENT TABLE POINTER TO
        MOV     B,H     ; /SAVE LOCATION ADDRESS
        MOV     C,L     ; RETURN THIS VALUE
        RET
;
;*********************************************************************
;
; FUNCTION: RSTTF
; INPUTS: NONE 
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: RSTTF RESTORES ALL CPU REGISTER, FLIP/FLOPS, STACK
;              POINTER AND PROGRAM COUNTER FROM THEIR RESPECTIVE
;              SAVE LOCATIONS IN MEMORY. THE ROUTINE THEN TRANSFERS 
;              CONTROL TO THE LOCATION SPECIFIED BY THE PROGRAM
;              COUNTER (I.E. THE RESTORED VALUE). THE ROUTINE
;              EXITS WITH THE INTERRUPTS ENABLED.
;
RSTTF:
        DI              ; DISABLE INTERRUPTS WHILE RESTORING THINGS
        LXI     SP,MSTAK        ; SET MONITOR STACK POINTER TO START
                        ; /OF STACK
        POP     D       ; START ALSO END OF REGISTER SAVE AREA
        POP     B
        POP     PSW
        LHLD    SSAVE   ; RESTORE USER STACK POINTER
        SPHL
        LHLD    PSAVE   
        PUSH    H       ; PUT USER RETURN ADDRESS ON USER STACK
        LHLD    LSAVE   ; RESTORE HL REGISTERS
        EI              ; ENABLE INTERRUPTS NOW
        RET             ; JUMP TO RESTORED PC LOCATION
;
;*********************************************************************
;
; FUNCTION: SRET
; INPUTS: NONE
; OUTPUTS: CARRY = 1
; DESTROYS: CARRY
; DESCRIPTION: SRET IS JUMPED TO BY ROUTINES WISHING TO RETURN SUCCESS.
;              SRET SETS THE CARRY TRUE AND THEN RETURNS TO THE
;              CALLER OF THE ROUTINE INVOKING SRET.
;
SRET:
        STC             ; SET CARRY TRUE
        RET             ; RETURN APPROPRIATELY
;
;*********************************************************************
;
; FUNTION: STHF0
; INPUTS: DE - 16 BIT ADDRESS OF BYTE TO BE STORED INTO
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: A,B,C,H,L,F/F'S
; DESCRIPTION: STHF0 CHECKS THE HALF BYTE FLAG IN TEMP TO SEE IF
;              IT IS SET TO LOWER. IF SO, STHF0 STORES A 0 TO
;              PAD OUT THE LOWER HALF OF THE ADDRESSED BYTE;
;              OTHERWISE, THE ROUTINE TAKES NO ACTION.
;
STHF0:
        LDA     TEMP    ; GET HALF BYTE FLAG
        ORA     A       ; SET F/F'S
        RNZ             ; IF SET TO UPPER, DON'T DO ANYTHING
        MVI     C,0     ; ELSE, WANT TO STORE THE VALUE 0
        CALL    STHLF   ; DO IT
        RET
;
;*********************************************************************
;
; FUNCTION: STHLF
; INPUTS: C - 4 BIT VALUE TO BE STORED IN HALF BYTE
;         DE - 16 BIT ADDRESS OF BYTE TO BE STORED INTO
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: A,B,C,H,L,F/F'S
; DESCRIPTION: STHLF TAKES THE 4 BIT VALUE IN C AND STORES IT IN
;              HALF OF THE BYTE ADDRESSED BY REGISTERS DE. THE
;              HALF BYTE USED (EITHER UPPER OR LOWER) IS DENOTED
;              BY THE VALUE OF THE FLAG IN TEMP. STHLF ASSUMES
;              THAT THIS FLAG HAS BEEN PREVIOUSLY SET
;              (NOMINALLY BY ICMD).
;
STHLF:
        PUSH    D
        POP     H       ; MOVE ADDRESS OF BYTE INTO HL
        MOV     A,C     ; GET VALUE
        ANI     0FH     ; FORCE TO 4 BIT LENGTH
        MOV     C,A     ; PUT VALUE BACK
        LDA     TEMP    ; GET HALF BYTE FLAG
        ORA     A       ; CHECK FOR LOWER HALF
        JNZ     STH05   ; BRANCH IF NOT
        MOV     A,M     ; ELSE, GET BYTE
        ANI     0F0H    ; CLEAR LOWER 4 BITS
        ORA     C       ; OR IN VALUE
        MOV     M,A     ; PUT BYTE BACK
        RET
STH05:
        MOV     A,M     ; IF UPPER HALF, GET BYTE
        ANI     0FH     ; CLEAR UPPER 4 BITS
        MOV     B,A     ; SAVE BYTE IN B
        MOV     A,C     ; GET VALUE
        RRC
        RRC
        RRC
        RRC             ; ALIGN TO UPPER 4 BITS
        ORA     B       ; OR IN ORIGINAL LOWER 4 BITS
        MOV     M,A     ; PUT NEW CONFIGURATION BACK
        RET
;
;*********************************************************************
;
; FUNCTION: VALDG
; INPUTS: C - ASCII CHARACTER
; OUTPUTS: CARRY - 1 IF CHARACTER REPRESENTS VALID HEX DIGIT
;                - 0 OTHERWISE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DECRIPTION: VALDG RETURNS SUCCESS IF ITS INPUT ARGUMENT IS
;             AN ASCII CHARACTER REPRESENTING A VALID HEX DIGIT
;             (0-9,A-F), AND FAILURE OTHERWISE.
;
VALDG:
        MOV     A,C
        CPI     '0'     ; TEST CHARACTER AGAINST '0'
        JM      FRET    ; IF ASCII CODE LESS, CANNOT BE VALID DIGIT
        CPI     '9'     ; ELSE, SEE IF IN RANGE '0'-'9'
        JM      SRET    ; CODE BETWEEN '0' AND '9'
        JZ      SRET    ; CODE EQUAL '9'
        CPI     'A'     ; NOT A DIGIT - TRY FOR A LETTER
        JM      FRET    ; NO - CODE BETWEEN '9' AND 'A'
        CPI     'G'
        JP      FRET    ; NO - CODE GREATER THAN 'F'
        JMP     SRET    ; OKAY - CODE IS 'A' TO 'F', INCLUSIVE
;
;**********************************************************************
;
; FUNCTION: VALDL
; INPUTS: C - CHARACTER
; OUTPUTS: CARRY - 1 IF INPUT ARGUMENT VALID DELIMITER
;                - 0 OTHERWISE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: VALDL RETURNS SUCCESS IF ITS INPUT ARGUMENT IS A VALID
;              DELIMITER CHARACTER (SPACE, COMMA, CARRIAGE RETURN) AND
;              FAILURE OTHERWISE.
;
VALDL:
        MOV     A,C
        CPI     ','     ; CHECK FOR COMMA
        JZ      SRET
        CPI     CR      ; CHECK FOR CARRIAGE RETURN
        JZ      SRET
        CPI     ' '     ; CHECK FOR SPACE
        JZ      SRET
        JMP     FRET    ; ERROR IF NONE OF THE ABOVE
;
;*********************************************************************
;
;                        MONITOR TABLES
;
;*********************************************************************
;
SGNON:
        DB      CR,LF,'80/10 MON.KT',CR,LF
;
LSGNON          EQU     $-SGNON ; LENGTH OF SIGNON MESSAGE
;
CADR:                   ; TABLE OF ADDRESSES OF COMMAND ROUTINES
        DW      0       ; DUMMY
        DW      XCMD
        DW      SCMD
        DW      MCMD
        DW      ICMD
        DW      GCMD
        DW      DCMD
        DW      RCMD
        DW      WCMD
        DW      LCMD
;
CTAB:                   ; TABLE OF VALID COMMAND CHARACTERS
        DB      'L'
        DB      'W'
        DB      'R'
        DB      'D'
        DB      'G'
        DB      'I'
        DB      'M'
        DB      'S'
        DB      'X'
NCMDS   EQU     $-CTAB  ; NUMBER OF VALID COMMANDS
;
RTAB:                   ; TABLE OF REGISTER INFORMATION
        DB      'A'     ; REGISTER IDENTIFIER
        DB      ASAVE AND 0FFH  ; ADDRESS OF REGISTER SAVE LOCATION
        DB      0       ; LENGTH FLAG 0=8 BITS, 1=16 BITS
RTABS   EQU     $-RTAB  ; SIZE OF AN ENTRY IN THIS TABLE
        DB      'B'
        DB      BSAVE AND 0FFH
        DB      0
        DB      'C'
        DB      CSAVE AND 0FFH
        DB      0
        DB      'D'
        DB      DSAVE AND 0FFH
        DB      0
        DB      'E'
        DB      ESAVE AND 0FFH
        DB      0
        DB      'F'
        DB      FSAVE AND 0FFH
        DB      0
        DB      'H'
        DB      HSAVE AND 0FFH
        DB      0
        DB      'L'
        DB      LSAVE AND 0FFH
        DB      0
        DB      'M'
        DB      HSAVE AND 0FFH
        DB      1
        DB      'P'
        DB      PSAVE+1 AND 0FFH
        DB      1
        DB      'S'
        DB      SSAVE+1 AND 0FFH
        DB      1
        DB      0       ; END OF TABLE MARKERS
        DB      0
;
        ORG     BRTAB
;
        JMP     CO      ; BRANCH TABLE FOR USER ACCESSIBLE ROUTINES
        JMP     CI
        JMP     RI
        JMP     PO
;
;********************************************************************
;
; FUNCTION: RCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCH,ECHO,CO RICH,BYTE
; DESTROYS: A,B,C,D,E,H,L,F/F`S
; DESCRIPTION: RCMD IMPLIMENTS THE READ HEXADECIMAL TAPE (R)
;              COMMAND
;
RCMD:
        CALL    GETCH   ; GET CARRIAGE RETURN CHARACTER
        CALL    ECHO    ; ECHO IT
        MOV     A,C     ; MOVE IT TO A REGISTER
        CPI     CR      ; SEE IF CARRIAGE RETURN
        JNZ     ERROR   ; ERROR IF NOT PROPERLY TERMINATED
RCM05:
        CALL    RICH    ; READ CHARACTER FROM TAPE
        CPI     ':'     ; SEE IF RECORD MARK
        JNZ     RCM05   ; TRY AGAIN IF NOT MARK
        XRA     A       ; ZERO A REGISTER
        MOV     D,A     ; INITIALISE D FOR HOLDING THE CHECKSUM
        CALL    BYTE    ; READ TWO CHARACTERS FROM TAPE
        JZ      GETCM   ; IF ZERO RECORD LENGTH, ALL DONE
        MOV     E,A     ; OTHERWISE, PUT THE RECORD LENGTH IN E
        CALL    BYTE    ; GET MSB OF LOAD ADDRESS
        MOV     H,A     ; MOVE TO H
        CALL    BYTE    ; GET LSB OF LOAD ADDRESS
        MOV     L,A     ; MOVE TO L
        CALL    BYTE    ; GET RECORD TYPE
        MOV     C,E     ; MOVE RECORD LENGTH TO C
RCM10:
        CALL    BYTE    ; READ DATA FROM TAPE
        MOV     M,A     ; PUT DATA INTO MEMORY
        INX     H       ; INCREMENT HL FOR NEXT LOCATION
        DCR     E       ; DECREMENT RECORD LENGTH
        JNZ     RCM10   ; LOOP UNTIL DONE
        CALL    BYTE    ; READ CHECKSUM FROM TAPE
        JNZ     ERROR   ; CHECKSUM ERROR IF NOT ZERO
        JMP     RCM05   ; GET ANOTHER RECORD
;
;********************************************************************
;
; FUNCTION: WCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETNM,LEAD,PO,PBYTE,PADR,PEOL,PEOF
; DESTROYS: A,B,C,D,E,H,L,F/F`S
; DESCRIPTION: WCMD IMPLEMENTS THE WRITE HEXADECIMAL TAPE (W)
;              COMMAND.
;
WCMD:
        MVI     C,2
        CALL    GETNM   ; GET 2 NUMBERS FROM INPUT STREAM
        CALL    LEAD    ; PUNCH 60 NULL CHARACTERS FOR TAPE LEADER
        POP     D       ; ENDING ADDRESS TO DE
        POP     H       ; STARTING ADDRESS TO HL
WCM05:
        MOV     A,L     ; MOVE L TO A
        ADI     16      ; INCREMENT THE LSB OF STARTING ADDRESS BY 16
        MOV     C,A     ; MOVE RESULT TO C
        MOV     A,H     ; MOVE H TO A
        ACI     0       ; ADD CARRY IN FROM PREVIOUS OPERATION
        MOV     B,A     ; SAVE RESULT IN B
        MOV     A,E     ; NOW MOVE LSB OF ENDING ADDRESS TO A
        SUB     C       ; SUBTRACT LSB OF STARTING ADDRESS
        MOV     C,A     ; SAVE IN C
        MOV     A,D     ; NOW GET MSB OF STARTING ADDRESS IN A
        SBB     B       ; SUBTRACT MSB OF STARTING ADDRESS
        JC      WCM10   ; BRANCH IF THE RECORD LENGTH IS NOT 16
        MVI     A,16    ; OTHERWISE SET A TO RECORD LENGTH OF 16
        JMP     WCM15   ; NOW BRANCH TO PUNCH THE RECORD
WCM10:
        MOV     A,C     ; THIS IS THE LAST RECORD
        ADI     17      ; SO SET A TO REMAINING DATA LENGTH
WCM15:
        ORA     A       ; CHECK FOR RECORD LENGTH OF ZERO
        JZ      WCM25   ; IF IT IS, ALL DONE
        PUSH    D       ; OTHERWISE, SAVE ENDING ADDRESS
        MOV     E,A     ; PUT RECORD LENGTH IN E
        MVI     D,0     ; INITIALISE D FOR HOLDING CHECKSUM
        MVI     C,':'
        CALL    PO      ; PUNCH RECORD MARK CHARACTER
        MOV     A,E     ; PUT RECORD LENGTH IN A
        CALL    PBYTE   ; PUNCH RECORD LENGTH
        CALL    PADR    ; PUNCH STARTING ADDRESS
        XRA     A       ; ZERO A
        CALL    PBYTE   ; PUNCH RECORD TYPE
WCM20:
        MOV     A,M     ; GET DATA TO BE PUNCHED FROM MEMORY
        CALL    PBYTE   ; PUNCH IT
        INX     H       ; INCREMENT MEMORY ADDRESS
        DCR     E       ; DECREMENT LENGTH COUNT
        JNZ     WCM20   ; LOOP UNTIL ALL DATA PUNCHED
        XRA     A
        SUB     D       ; PUNCH CHECKSUM
        CALL    PBYTE
        POP     D       ; RESTORE ENDING ADDRESS
        CALL    PEOL    ; PUNCH CARRIAGE RETURN LINE FEED
        JMP     WCM05
WCM25:
        CALL    PEOF    ; PUNCH END OF FILE RECORD
        JMP     EXIT    ; ALL DONE
;
;********************************************************************
;
; FUNCTION: LCMD
; CALLS: INIT,INPUT,ASCHEX
; DESCRIPTION: LCMD IMPLEMENTS THE DOWNLINE LOADER/READER (L)
;              COMMAND
;
LCMD:
        CALL    INIT    ; SET UP 8251 USED FOR SERIAL LINK TO MDS
                        ; ONLY WHWEN COMMAND IS USED
LCM05:  CALL    INPUT   ; MOVE TO BEGINING OF HEX RECORD
        CPI     ':'
        JNZ     LCM05
        CALL    ASCHEX  ; GET RECODRD LENGTH
        JZ      EXIT
        MOV     E,A
        CALL    ASCHEX  ; GET MSB OF LOAD ADDRESS
        MOV     H,A
        CALL    ASCHEX  ; GET LSB OF LOAD ADDRESS
        MOV     L,A
        CALL    ASCHEX  ; GET RECORD TYPE AND IGNORE
LCM10:  CALL    ASCHEX  ; GET DATA
        MOV     M,A
        INX     H
        DCR     E
        JNZ     LCM10
        JMP     LCM05
;
;*********************************************************************
;
; FUNCTION: INIT
; DESCRIPTION: INIT INITIALIZES THE 8251 USED FOR THE SERIAL
;              DATA LINK TO THE MDS
;
INIT:
        MVI     A,0
        OUT     DLLC
        OUT     DLLC
        OUT     DLLC
        MVI     A,DLLR
        OUT     DLLC    ; THIS SEQUENCE RESETS THE 8251 FROM ANY UNKNOWN
                        ; STATE
        MVI     A,DLLMW
        OUT     DLLC    ; SET MODE
        MVI     A,DLLCW
        OUT     DLLC    ; SET COMMAND
        RET
;
;********************************************************************
;
; FUNCTION: ASCHEX
; OUTPUTS: A - 8 BIT VALUE REPRESENTED BY TWO ASCII DIGITS
; CALLS: HEXBIN
; DESCRIPTION: HEXBIN READS TWO ASCII DIGITS FROM THE DOWNLINE
;              LINK AND OUTPUTS THEIR CONVERTED VALUE IN THE A REG.
;
ASCHEX:
        CALL    HEXBIN  ; GET FIRST DIGIT
        RLC
        RLC
        RLC
        RLC             ; MOVE TO UPPER 4 BITS OF BYTE
        MOV     B,A     ; TEMP SAVE OF A
        CALL    HEXBIN  ; GET SECOND DIGIT
        ORA     B       ; ADD IN TOP 4 BITS
        RET
;
;**********************************************************************
;
; FUNCTION: HEXBIN
; OUTPUTS: A - 4 BIT VALUE OF CONVERTED HEX DIGIT
; CALLS: INPUT
; DESCRIPTION: HEXBIN READS A ASCII HEX DIGIT FROM THE DOWNLINE LINK
;              AND CONVERTS IT TO BINARY LOWER 4 BITS OF A REG.
;              THE VALIDITY OF THE DIGIT IS NOT CHECKED AS THIS IS
;              DONE IN THE MDS.
;
HEXBIN:
        CALL    INPUT   ; GET A DIGIT
        SUI     '0'
        CPI     10
        RM              ; THAT WAS A NUMBER
        SUI     7
        RET             ; THAT WAS A - F
;
;********************************************************************
;
; FUNCTION: INPUT
; CALLS: OUTP,INP
; OUTPUTS: A - CHAR
; DESCRIPTION: INPUT READS A CHAR FROM DOWNLINE LINK
;
INPUT:
        MVI     C,0
        CALL    OUTP    ; TELL THE OTHER END READY FOR A CHAR
        CALL    INP     ; REPLY
        RET
;
;*******************************************************************
;
; FUNCTION: OUTP
; INPUT: CHAR IN C REG TO BE SENT TO MDS
; DESCRIPTION: OUTP SENDS CHAR TO MDS VIA DOWNLINE LINK
;
OUTP:
        IN      DLLS
        ANI     TXRDY
        JZ      OUTP
        MOV     A,C
        OUT     DLLD    ; SEND CHAR
        RET
;
;********************************************************************
;
; FUNCTION: INP
; OUTPUT: CHAR IN A REG RECEIVED FROM MDS
; DESCRIPTION: INP RECEIVES A CHAR FROM MDS VIA DOWNLINE LINK
;
INP:
        IN      DLLS
        ANI     RXRDY
        JZ      INP
        IN      DLLD    ; RECEIVE CHAR
        RET
;
;*******************************************************************
;
; FUNCTION: EOLOUT
; CALLS: OUTPUT
; DESCRIPTION: EOLOUT USER CALLABLE ROUTINE ( NOT USED IN MONITOR)
;              SENDS END OF LINE SEQUENCE TO DOWNLINE LINK
;
EOLOUT:
        MVI     C,CR
        CALL    OUTPUT
        MVI     C,LF
        CALL    OUTPUT
        RET
;
;*********************************************************************
;
; FUNCTION: EOFOUT
; CALLS: OUTPUT
; DESCRIPTION: EOFOUT USER CALLABLE ROUTINE ( NOT USED IN MONITOR)
;              SENDS EOF SEQUENCE TO MDS VIA DOWNLINE LINK
;              20 NULLS SENT
;
EOFOUT:
        MVI     B,20
EOF05:  MVI     C,NULL
        CALL    OUTPUT
        DCR     B
        JNZ     EOF05
        RET
;
;**********************************************************************
;
; FUNCTION: OUTPUT
; CALLS: INP,OUTP
; INPUT: C - REG CHAR TO OUTPUT
; DESCRIPTION: OUTPUT USER CALLABLE ROUTINE ( NOT USED IN MONITOR)
;              SENDS A CHAR TO MDS VIA DOWNLINE LINK
;
OUTPUT:
        CALL    INP     ; IS THE OTHER END READY
        CALL    OUTP    ; SEND CHAR
        RET
;
;********************************************************************
;
; FUNCTION: BYTE
; INPUTS: D - CURRENT VALUE OF CHECKSUM
; OUTPUTS: A - HEXADECIMAL CHARACTER
;          D - UPDATED VALUE OF CHECKSUM
; CALLS: RICH,CNVBN
; DESTROYS: A,B,C,D,F/F`
; DESCRIPTION: BYTE READS 2 ASCII CHARACTERS FROM THE TAPE READER
;              AND CONVERTS THE CHARACTERS TO ONE HEXADECIMAL CHARACTER.
;              THE A REGISTER CONTAINS THE FINAL CHARACTER AND THE
;              D REGISTER CONTAINS THE UPDTATED VALUE OF
;              THE CHECKSUM.
BYTE:
        PUSH    B       ; SAVE BC
        CALL    RICH    ; READ ASCII CHARACTER FROM TAPE
        MOV     C,A
        CALL    CNVBN   ; CONVERT CHARACTER TO HEXADECIMAL
        RLC             ; POSITION VALUE INTO UPPER 4 BITS
        RLC
        RLC
        RLC
        MOV     B,A     ; SAVE RESULTS IN B
        CALL    RICH    ; GET ANOTHER CHARACTER FROM TAPE
        MOV     C,A
        CALL    CNVBN   ; CONVERT IT
        ORA     B       ; OR IN THE UPPER 4 BITS
        MOV     C,A     ; SAVE
        ADD     D       ; INCREMENT CHECKSUM
        MOV     D,A
        MOV     A,C     ; RESTORE HEX DATA TO A REGISTER
        POP     B       ; RESTORE BC
        RET
;
;********************************************************************
;
; FUNCTION: DELAY
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: F/F`S
; DESCRIPTION: DELAY PROVIDES A PROGRAMED DELAY OF 1 MILLISECOND
;              FOR TAPE READER OPERATION.
;
DELAY:
        PUSH    B       ; SAVE BC REGISTERS
        MVI     B,ONEMS ; LOAD 1 MILLISECOND CONSTANT
DEL1:
        DCR     B       ; DECREMENT INNER COUNTER
        JNZ     DEL1    ; JUMP IF NOT DONE
        POP     B       ; RESTORE BC REGISTERS
        RET             ; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
; FUNCTION: LEAD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: PO
; DESTROYS: B,C,F/F`S
; DESCRIPTION:LEAD OUTPUTS 60 NULL CHARACTERS TO PAPER TAPE TO FORM A
;             LEADER.
;
LEAD:
        MVI     B,60    ; LOAD B WITH A COUNT OF 60
LE05:
        MVI     C,0
        CALL    PO      ; PUNCH NULL CHARACTER
        DCR     B       ; DECREMENT COUNT
        JNZ     LE05    ; DO IT AGAIN IF NOT DONE
        RET
;
;********************************************************************
;
; FUNCTION: PADR
; INPUTS: HL - ADDRESS TO BE PUNCHED
; OUTPUTS: NONE
; CALLS: PBYTE
; DESTROYS: A
; DESCRIPTION: PADR PUNCHES THE ADDRESS CONTAINED IN THE H,L REGISTERS.
;
PADR:
        MOV     A,H     ; PUNCH FIRST HALF OF ADDRESS
        CALL    PBYTE
        MOV     A,L     ; PUNCH SECOND HALF OF ADDRESS
        CALL    PBYTE
        RET             ; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
; FUNCTION: PBYTE
; INPUTS: A - CHARACTER TO BE PUNCHED
;         D - CURRENT VALUE OF CHECKSUM
; OUTPUTS: D - UPDATED VALUE OF CHECKSUM
; CALLS: PRVAL,PO
; DESTROYS: A,F/F`S
; DESCRIPTION: PBYTE CONVERTS THE HEXADECIMAL VALUE IN THE A REGISTER
;              INTO TWO ASCII CHARACTERS AND PUNCHES THESE CHARACTERS
;              ON PAPER TAPE. THE CHECKSUM CONTAINED IN D IS UPDATED.
;
PBYTE:
        PUSH    PSW     ; SAVE A,F/F`S
        RRC             ; POSITION UPPER 4 BITS INTO LOWER 4 BITS
        RRC
        RRC
        RRC
        CALL    PRVAL   ; CONVERT UPPER 4 BITS JUST ROTATED TO ASCII
        CALL    PO      ; PUNCH CHARACTER
        POP     PSW     ; RESTORE A,F/F`S
        PUSH    PSW     ; SAVE A AGAIN
        CALL    PRVAL   ; CONVERT LOWER 4 BITS TO ASCII CHARACTER
        CALL    PO      ; PUNCH CHARACTER
        POP     PSW     ; RESTORE A
        ADD     D       ; ADD VALUE TO CHECKSUM
        MOV     D,A     ; UPDATE D REGISTER WITH NEW CHECKSUM
        RET             ; RETURN TO CALLING ROUTINE
;
;*********************************************************************
;
; FUNCTION: PEOF
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: PO,PBYTE,PADR,LEAD
; DESTROYS: A,C,D,H,L,F/F`S
; DESCRIPTION: PEOF PUNCHES THE END OF FILE RECORD CONSISTING OF A RECORD
;              MARK,A LOAD ADDRESS OF 0, THE RECORD TYPE, AND THE
;              RECORD CHECKSUM.
;
PEOF:
        MVI     C,':'
        CALL    PO      ; PUNCH RECORD MARK
        XRA     A       ; ZERO CHECKSUM
        MOV     D,A     ; SAVE IN D REGISTER
        CALL    PBYTE   ; PUNCH RECORD LENGTH
        LXI     H,0     ; LOAD HL WITH ZERO ADDRESS
        CALL    PADR    ; PUNCH IT
        MVI     A,1     ; LOAD A WITH RECORD TYPE
        CALL    PBYTE   ; PUNCH IT
        XRA     A       ; ZERO A
        SUB     D       ; COMPUTE CHECKSUM
        CALL    PBYTE   ; PUNCH IT
        CALL    LEAD    ; PUNCH TRAILER
        RET
;
;********************************************************************
;
; FUNCTION: PEOL
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: PO
; DESTROYS: C
; DESCRIPTION: PEOL PUNCHES A CARRIAGE RETURN AND LINE FEED ONTO
;              PAPER TAPE.
;
PEOL:
        MVI     C,CR
        CALL    PO      ; PUNCH CARRIAGE RETURN CHARACTER
        MVI     C,LF
        CALL    PO      ; PUNCH LINE FEED CHARACTER
        RET
;
;********************************************************************
;
; FUNCTION: PO
; INPUTS: C - CHARACTER TO BE PUNCHED
; OUTPUTS: NONE
; CALLS: CO
; DESTROYS: NOTHING
; DESCRIPTION: PO PUNCHES THE CHARACTER SUPPLIED IN THE C REGISTER
;
PO:
        IN      PTPS    ; TEST PUNCH STATUS
        ANI     PTPR
        JNZ     PO
        MOV     A,C     ; READY
        NOP
        OUT     PTPD    ; OUTPUT IT
        MVI     A,STP   ; STEP AND PUNCH
        OUT     PTPC
        MVI     A,0
        OUT     PTPC
        RET
;
;********************************************************************
;
; FUNCTION: RICH
; INPUTS: NONE
; OUTPUTS: A - ZERO,CARRY - 1 IF END OF FILE
;          A - CHARACTER, CARRY - 0 IF VALID CHARACTER
;
RICH:
        CALL    RI      ; READ A CHARACTER FROM TAPE
        JC      ERROR   ; JUMP IF READER TIMEOUT ERROR
        ANI     PRTYO   ; REMOVE PARITY BIT
        RET             ; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
; FUNCTION: RI
; INPUTS: NONE
; OUTPUTS: A - ZERO, CARRY - 1 IF END OF FILE
;          A - CHARACTER, CARRY - 0 IF VALID CHARACTER
; CALLS: DELAY
; DESTROYS: A,F/F`S
; DESCRIPTION: RI READS A CHARACTER FROM THE TAPE READER.
;
RI:
        PUSH    B       ; SAVE BC
        MVI     A,STR   ; STEP READER
        OUT     PTRC
        MVI     A,0
        OUT     PTRC
        MVI     B,250   ; INTIALIZE TIMER FOR 250MS
RI10:
        IN      PTRS    ; INPUT READER STATUS
        CMA
        ANI     PTRR    ; CHECK FOR READER READY
        JNZ     RI15    ; YES - DATA IS READY
        CALL    DELAY   ; DELAY 1 MS.
        DCR     B       ; DECREMENT TIMER
        JNZ     RI10    ; JUMP IF TIMER NOT EXPIRED
        XRA     A       ; ZERO A
        STC             ; SET CARRY INDICATING EOF
        POP     B       ; RESTORE BC
        RET             ; RETURN TO CALLING ROUTINE
RI15:
        IN      PTRD    ; INPUT DATA CHARACTER
        CMA
        ORA     A       ; CLEAR CARRY
        POP     B       ; RESTORE BC
        RET             ; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
COPYRT:
        DB      '(C) 1976 INTEL CORP'
;
;********************************************************************
;
        ORG     REGS    ; ORG TO REGISTER SAVE - STACK GOES IN HERE
;
MSTAK           EQU     $       ; START OF MONITOR STACK
ESAVE:          DB      0       ; E REGISTER SAVE LOCATION
DSAVE:          DB      0       ; D REGISTER SAVE LOCATION
CSAVE:          DB      0       ; C REGISTER SAVE LOCATION
BSAVE:          DB      0       ; B REGISTER SAVE LOCATION
FSAVE:          DB      0       ; FLAGS SAVE LOCATION
ASAVE:          DB      0       ; A REGISTER SAVE LOCATION
LSAVE:          DB      0       ; L REGISTER SAVE LOCATION
HSAVE:          DB      0       ; H REGISTER SAVE LOCATION
PSAVE:          DW      0       ; PGM COUNTER SAVE LOCATION
SSAVE:          DW      0       ; USER STACK POINTER SAVE LOCATION
TEMP:           DB      0       ; TEMPORY MONITOR CELL
;
        END
