;  
;  SET UP ANY CP/M LINE PRINTER FOR SPECIAL COMMANDS
;
; PRSET:   CSECT    
         ORG   256
         LHLD  SPSAV         ; GET THE 'SPSAV' CONTENTS - '0'
         DAD   SP            ; ADD THE (SP) CONTENTS TO (HL)
         SHLD  SPSAV         ; SAVE THE STACK POINTER ADDRESS
         LXI   SP,STACK      ; ASSIGN A NEW STACK POINTER ADDRESS
         JMP   START         ; START THE PROGRAM
;
PRTBLS:  DB    'EPSON   '    ; NAME OF THE DEFAULT PRINT TABLE
         DW    EPSON         ; START ADDRESS OF PRINT TABLE (FOR PATCH)
         DW    ENDEPS        ; END ADDRESS OF PRINT TABLE
PRTABL:  DS    2             ; PRINT TABLE IN USE
;
         DS    30*2          ; SET UP 30 LEVEL STACK AREA
STACK:   EQU   $             ; ESTABLISH NEW STACK
SPSAV:   DW    00            ; CALLER STACK ADDRESS
;
;  STANDARD CP/M EQUATES
;
WARM     EQU   00            ; WARM BOOT RETURN
CLEAR    EQU   26            ; CLEAR SCREEN
CCINP    EQU   01            ; DIRECT CONSOLE INPUT
CCOUT    EQU   02            ; DIRECT CONSOLE OUTPUT
LIST     EQU   05            ; CP/M LIST DEVICE
RBUFF    EQU   10            ; CP/M CONSOLE DEVICE INPUT
PBUFF    EQU   09            ; CP/M CONSOLE DEVICE OUTPUT
BDOS     EQU   05            ; LOCATION OF BDOS
CR       EQU   13            ; CARRIAGE RETURN
LF       EQU   10            ; LINE FEED
ESC      EQU   27            ; 'ESCAPE FUNCTION'
DOLR     EQU   36            ; '$'
PNDSIGN  EQU   25            ; '#"
ZERO     EQU   00            ; '0'
ONE      EQU   01            ; '1'
TWO      EQU   02            ; '2'
THREE    EQU   03            ; '3'
FOUR     EQU   04            ; '4'
SEVEN    EQU   07            ; '7'
EIGHT    EQU   08            ; '8'
SEVEN2   EQU   72            ; '72' DEFAULT NCOLS
UCN      EQU   78            ; 'N'
LCN      EQU  110            ; 'n'
COMMA    EQU   44            ; ','
THIRTY   EQU   48            ; '30H'
BLANK    EQU   32            ; 'SP'
SLASH    EQU   47            ; '/'
TEN      EQU   10            ; '10'
NINER    EQU   99            ; '99'
HUNDRED  EQU  100            ; '100'
SLFLAG   EQU  127            ; '127'
ZEROF    EQU   15            ; B'0000 1111'
FZERO    EQU  240            ; B'1111 0000'
FMAX     EQU  255            ; X'FF'
CCPK     EQU   30            ; '20'
BLANK    EQU   32            ; ' '
F12      EQU   12            ; '12'
F13      EQU   13            ; '13'
F18      EQU   18            ; '18'
F19      EQU   19            ; '19'
F21      EQU   21            ; '21'
;
;   START OF PROGRAM
;
RETRY:   LXI    SP,STACK     ; REINITIALIZE THE STACK POINTER
         MVI    A,ZERO       ; GET A '0' IN (A)
         STA    RBUFFER+1    ; RESET 'RBUFFER' COUNTER
         STA    PBUFFER+1    ; RESET 'PBUFFER' COUNTER
         STA    OBUFFER+1    ; RESET 'OBUFFER' COUNTER
         STA    TEST         ; RESET 'TEST'
         JMP    RETR1
;
START:   EQU    $
         MVI    A,CCPK       ; GET AN INPUT COUNTER
         STA    RBUFFER+1    ; SAVE THE COUNTER
         MOV    B,A          ; GET A COPY
         MVI    A,ZERO       ; GET A '0'
         LXI    H,RBUFFER+2  ; GET THE BUFFER ADDRESS
;
INIT:    MOV    M,A          ; SAVE AT (HL)
         INX    H            ; INCREMENT (HL)
         DCR    B            ; DECREMENT (BC)
         JNZ    INIT         ; LOOP
;
         LHLD   CCP          ; GET THE 'CCP' ADDRESS IN (HL)
         XCHG                ; EXCHANGE (DE) AND (HL) REGISTERS
         LXI    H,RBUFFER+2  ; GET THE INPUT BUFFER ADDRESS
         MVI    B,CCPK       ; SET UP TO COPY
;
COPY:    LDAX   D            ; GET AN INPUT BYTE FROM (DE)
         MOV    M,A          ; SAVE AT (HL)
         INX    D            ; INCREMENT (DE)
         INX    H            ; INCREMENT (HL)
         DCR    B            ; DECREMENT (B)
         JNZ    COPY         ; LOOP
;
;        LXI    D,RBUFFER+1  ; GET THE INPUT ADDRESS
;        CALL   HXTERM       ; WRITE IT OUT IN HEX
;
         LDA    RBUFFER+2    ; GET THE 'CCP' COUNTER
         CPI    ZERO         ; CHECK IF ANYTHING INPUT
         JZ     RETR1        ; SET UP THE MENU
         ADI    ONE          ; SET UP THE LOOP COUNTER
         MOV    B,A          ; GET THE COUNTER IN (B)
         LXI    D,RBUFFER+2  ; GET THE 'OUTPUT' ADDRESS
         LXI    H,RBUFFER+3  ; GET THE 'INPUT' ADDRESS
         MVI    C,ONE        ; INITIALIZE THE (C) REGISTER
;
COPY1:   MOV    A,M          ; GET AN INPUT SAMPLE
         INX    H            ; INCREMENT (HL)
         DCR    B            ; DECREMENT THE COUNTER
         JZ     COPY2        ; MOVED ALL BYTES OF DATA
         CPI    BLANK        ; IS IT BLANK
         JZ     COPY1        ; DON'T COPY
         STAX   D            ; SAVE AT (DE)
         INX    D            ; INCREMENT (DE)
         INR    C            ; INCREMENT THE COUNTER
         JMP    COPY1        ; LOOP UNTIL DONE
;
COPY2    EQU    $
         MVI    A,PNDSIGN    ; GET A '#'
         STAX   D            ; SAVE AT (DE)
         INX    D            ; INCREMENT (DE)
         MVI    A,DOLR       ; GET A '$'
         STAX   D            ; SAVE AT (DE)
         INX    D            ; INCREMENT (DE)
         MOV    A,C          ; GET THE COUNTER
         ADI    TWO          ; SET UP COUNTERS
         STA    RBUFFER+1    ; SAVE
;
;        LXI    D,RBUFFER+1  ; GET THE MOVED DATA
;        CALL   HXTERM       ; ECHO IN HEX
;
         JMP    GOMESG
;
RETR1:   EQU    $
         LXI    D,CLRSCN     ; CLEAR THE SCREEN
         CALL   WRTERM       ; DO IT
;
         LXI    D,OPTIONS    ; LIST THE OPTIONS
         CALL   WRTERM       ; DO IT
;
         LXI    D,PROMPT     ; ISSUE THE 'PROMPT' MESSAGE
         CALL   WRTERM       ; DO IT - NOTE NO 'CRLF'
;
         LXI    D,RBUFFER    ; GET THE BUFFER LOCATION
         CALL   RDTERM       ; READ OPTIONS FROM THE KEYBOARD
;
GOMESG:  EQU    $
         LXI    D,MESG       ; OUTPUT THE READ MESSAGE
         CALL   WRTERM       ; DO IT
;
         LXI    D,RBUFFER+2  ; GET THE INPUT BUFFER LOCATION
         CALL   WRTERM       ; ECHO THE INPUT PARAMETERS
;
         LXI    D,CRLF       ; FINISH WRITE WITH CR LF
         CALL   WRTERM       ; DO IT
;
         LXI    B,PBUFFER+2  ; GET THE OUTPUT BUFFER LOCATION
         LXI    D,RBUFFER+2  ; GET THE INPUT BUFFER LOCATION
         CALL   PARSE        ; SEPARATE THE INPUT INSTRUCTIONS
;
;        LXI    D,PBUFFER+1  ; GET THE PBUFFER ADDRESS
;        CALL   HXTERM       ; ECHO THE INPUT PARAMETERS IN HEX
;
         LHLD   PRTBLS+8     ; GET THE PRINTER TABLE ADDRESS
         SHLD   PRTABL       ; SAVE
;
         CALL   FIXTABL      ; ENTER THE OPTIONAL COMMANDS INTO THE TABLE
;
         LXI    B,OBUFFER+2  ; GET THE OUTPUT BUFFER LOCATION
         LXI    D,PBUFFER+2  ; GET THE INPUT BUFFER LOCATION
         CALL   PRCMND       ; PUT THE PRINTER COMMANDS INTO A BUFFER
;
         LXI    D,PMESG      ; GET THE PRINTER MESSAGE
         CALL   WRTERM       ; DO IT
;
         LXI    D,OBUFFER+1  ; GET THE OUTPUT BUFFER ADDRESS
         CALL   HXTERM       ; ECHO THE OUTPUT PARAMETERS IN HEX
;
         LDA    OBUFFER+1    ; GET THE 'OBUFFER' COUNTER
         MOV    C,A          ; PUT IN (C)
         LXI    D,OBUFFER+2  ; GET THE OUTPUT BUFFER ADDRESS AGAIN
         CALL   PRINT        ; SET UP THE PRINTER
;
         LDA    TEST         ; GET THE 'TEST' OPTION
         CPI    ZERO         ; STILL ZERO ??
         JZ     RTNCPM       ; YES - ALLDONE
;
         LDA    RBUFFER+1    ; GET THE 'RBUFFER' COUNTER
         MOV    C,A          ; PUT IN (C)
         LXI    D,RBUFFER+2  ; GET THE INPUT PARAMETER LOCATION
         CALL   PRINT        ; PRINT IT
;
         MVI    A,EIGHT      ; TEMP 'NLINES'
         STA    NLINES       ; SAVE
         MVI    A,SEVEN2     ; TEMP 'NCOLS'
         STA    NCOLS        ; SAVE
;
         LDA    NLINES       ; GET NUMBER OF LINES FOR 1 INCH
         MOV    B,A          ; GET A COPY IN (B)
         LDA    NCOLS        ; GET NUMBER OF COLUMNS TO PRINT
         MOV    C,A          ; GET A COPY IN (C)
         LXI    D,PSTRING    ; GET THE AREA TO BE PRINTED
;
NXTLIN:  PUSH   D            ; SAVE (DE)
         PUSH   B            ; SAVE (BC)
         CALL   PRINT        ; PRINT A LINE
         POP    B            ; RESTORE (BC)
         POP    D            ; RESTORE (DE)
         INX    D            ; INCREMENT A PRINT POSITION
         DCR    B            ; DECREMENT THE LINE COUNTER
         JNZ    NXTLIN       ; PRINT NEXT LINE
;
         LXI    D,ACCMSG     ; GET THE ACCEPTANCE MESSAGE
         CALL   WRTERM       ; DO IT
;
NXTL:    CALL   TERMIN       ; GET A CHARACTER FROM THE KEYBOARD
         CPI    ZERO         ; HAS ANYTHING BEEN ENTERED
         JZ     NXTL         ; LOOP UNTIL ANYTHING ENTERED
         CPI    UCN          ; CHECK RETURN CODE
         JZ     RETRY        ; TRY AGAIN
         CPI    LCN          ; CHECK THE RETURN CODE
         JZ     RETRY        ; TRY AGAIN
         JMP    RTNCPM       ; RETURN TO CALLER
;
RTNCPM:  EQU    $
         LXI    D,RMESG      ; ECHO THE 'RETURN' MESSAGE
         CALL   WRTERM       ; DO IT
         LHLD   SPSAV        ; GET THE STACK POINTER ADDRESS
         SPHL                ; EXCHANGE (SP) AND (HL) REGISTERS
         JMP    WARM         ; RETURN TO CP/M
;
;  ADD THE OPTIONAL COMMANDS TO THE PRINT TABLE
;
FIXTABL: LHLD   PRTABL       ; GET THE ADDRESS OF THE PRINT TABLE
         MVI    D,ZERO       ; GET A ZERO IN (D)
         MVI    E,EIGHT      ; GET A '8' IN (E)
         DAD    D            ; ADD (DE) TO (HL)
;
         LDA    N12          ; GET THE F12 CONTENTS
         CALL   MOVDAT       ; SAVE
         LDA    N13          ; GET THE F13 CONTENTS
         CALL   MOVDAT       ; SAVE
         LDA    N18          ; GET THE F18 CONTENTS
         CALL   MOVDAT       ; SAVE
         LDA    N19          ; GET THE F19 CONTENTS
         CALL   MOVDAT       ; SAVE
         LDA    N21          ; GET THE F19 CONTENTS
         CALL   MOVDAT       ; SAVE
         RET
;
MOVDAT:  MOV    E,M          ; GET THE BYTE AT (HL)
         INX    H            ; INCREMENT (HL)
         MOV    D,M          ; GET THE BYTE AT (HL)
         INX    H            ; INCREMENT (HL)
         XCHG                ; EXCHANGE (DE) AND (HL)
         MOV    M,A          ; STORE AT (HL)
         XCHG                ; EXCHANGE (DE) AND (HL) AGAIN
         RET                 ; RETURN TO CALLER
;
;  CREATE THE OUTPUT BUFFER WITH PRINTER COMMANDS
;
PRCMND:  PUSH   H            ; SAVE (HL) CONTENTS
         PUSH   D            ; SAVE (DE) CONTENTS (INPUT)
         XCHG                ; GET THE (DE) ADDRESS IN (HL)
PRL1:    EQU    $
         MOV    A,M          ; GET AN INPUT VALUE
         INX    H            ; INCREMENT (HL)
         PUSH   H            ; SAVE (HL) CONTENTS
         PUSH   B            ; SAVE (BC) CONTENTS
         CPI    FMAX         ; CHECK IF LAST VALUE
         JZ     PRL9         ; ALL DONE
         CPI    NINER        ; CHECK FOR 'TEST' FUNCTION
         JZ     PRL7         ; TEST REQUESTED
         LHLD   PRTABL       ; GET THE PRINTER TABLE
         MOV    B,A          ; SAVE THE INPUT VALUE
;
PRL2:    EQU    $
         MOV    A,M          ; GET THE 'OP' CODE
         CPI    FMAX         ; CHECK IF LAST VALUE
         JZ     PRL8         ; REQUESTED VALUE NOT FOUND
         CMP    B            ; CHECK AGAINST REQUESTED NUMBER
         JZ     PRL3         ; (A) = (B)
         INX    H            ; INCREMENT (HL)
         MVI    D,ZERO       ; GET A '0' IN D
         MOV    E,M          ; GET THE JUMP COUNTER
         DAD    D            ; ADD (DE) TO (HL)
         JMP    PRL2         ; LOOP
;
PRL3:    EQU    $
         INX    H            ; INCREMENT (HL)
         MOV    D,M          ; GET THE LENGTH OF PR SEQUENCE
         INX    H            ; INCREMENT (HL) AGAIN
         LDA    OBUFFER+1    ; GET THE OUTPUT BYTE COUNTER
         ADD    D            ; ADD OUTPUT LENGTH
         STA    OBUFFER+1    ; SAVE
         DCR    D            ; DECREMENT THE COUNTER
         MVI    A,ESC        ; GET THE ESCAPE FUNCTION
         POP    B            ; GET OUTPUT ARRAY ADDRESS
         STAX   B            ; SAVE AT (BC)
         INX    B            ; INCREMENT THE (BC) ADDRESS
;
PRL4:    EQU    $
         MOV    A,M          ; GET AN INPUT SAMPLE
         STAX   B            ; SAVE AT (BC)
         INX    B            ; INCREMENT THE (BC) ADDRESS
         INX    H            ; INCREMENT THE (HL) ADDRESS
         DCR    D            ; DECREMENT THE COUNTER
         JNZ    PRL4         ; LOOP UNTIL DONE
;
         POP    H            ; RESTORE INPUT ADDRESS
         JMP    PRL1         ; LOOK FOR NEXT INPUT VALUE
;
PRL7:    STA    TEST         ; ACTIVE THE TEST FUNCTION FLAG
         POP    B            ; RESTORE (BC)
         POP    H            ; RESTORE (HL)
         JMP    PRL1         ; CONTINUE
;
PRL8:    EQU    $
         LXI    D,ERRMSG2    ; GET THE RROR MESSAGE
         CALL   WRTERM       ; DO IT
         JMP    RETRY
;
PRL9:    EQU    $
         POP    B            ; RESTORE (BC)
         MVI    A,CR         ; GET A <CR>
         STAX   B            ; SAVE AT (BC)
         INX    B            ; INCREMENT (BC)
         MVI    A,LF         ; GET A LINE FEED
         STAX   B            ; SAVE AT (BC)
         INX    B            ; INCREMENT (BC)
         MVI    A,DOLR       ; GET A '$' SIGN
         STAX   B            ; STORE AT (BC)
         INX    B            ; INCREMENT (BC)
         LDA    OBUFFER+1    ; GET THE OUTPUT COUNTER
         ADI    FOUR         ; INCREMENT (A) BY 4
         STA    OBUFFER+1    ; SAVE
         POP    H            ; RESTORE (HL)
         POP    D            ; RESTORE (DE) CONTENTS
         POP    H            ; RESTORE (HL) CONTENTS
         RET                 ; RETURN TO CALLER
;
;  READ A SINGLE CHARACTER FROM THE CONSOLE
;
TERMIN:  PUSH   H            ; SAVE (HL) CONTENTS
         PUSH   B            ; SAVE (BC) CONTENTS
         MVI    C,CCINP      ; GET THE BDOS FUNCTION
         CALL   BDOS         ; GO TO THE FUNCTION (RETURN IN (A))
         POP    B            ; RESTORE (BC) CONTENTS
         POP    H            ; RESTORE (HL) CONTENTS
         RET
;
;  OUTPUT A SINGLE CHARACTER TO THE SCREEN
;
COUT:    PUSH   H            ; SAVE (HL) CONTENTS
         PUSH   B            ; SAVE (BC) CONTENTS
         MVI    C,CCOUT      ; SET THE BDOS FUNCTION
         CALL   BDOS         ; GO TO THE FUNCTION
         POP    B            ; RESTORE (BC) CONTENTS
         POP    H            ; RESTORE (HL) CONTENTS
         RET                 ; RETURN TO CALLER
;
;  READ DATA FROM THER TERMINAL KEYBOARD
;
RDTERM:  PUSH   H            ; SAVE (HL) CONTENTS
         PUSH   B            ; SAVE (BC) CONTENTS
         MVI    C,RBUFF      ; SET THE BDOS FUNCTION
         CALL   BDOS         ; GO TO THE FUNCTION
;
         LXI    H,RBUFFER+1  ; GET THE BUFFER LOCATION +1 (LENGTH)
         MOV    A,M          ; GET THE CONTENTS IN (A)
         CPI    ZERO         ; CHECK IF ANYTHING INPUT
         JZ     NOINP        ; <CR> ONLY FROM USER
FIND:    INX    H            ; INCREMENT (HL)
         DCR    A            ; DECREMENT (A)
         JNZ    FIND         ; DECREMENT TO END OF COUNTER
NOINP:   INX    H            ; INCREMENT (HL) ONCE MORE
         MVI    A,PNDSIGN    ; GET A '#' IN (A)
         MOV    M,A          ; STORE AT (HL) ADDRESS
         INX    H            ; INCREMENT (HL) AGAIN
         MVI    A,DOLR       ; GET A '$' IN (A)
         MOV    M,A          ; STORE AT (HL)
;
         POP    B            ; RESTORE (BC) CONTENTS
         POP    H            ; RESTORE (HL) CONTENTS
         RET                 ; RETURN TO CALLER
;
;   OUTPUT HEXIDECIMAL DATA TO THE TERMINAL SCREEN
;
HXTERM:   XCHG               ; GET THE (DE) ADDRESS IN (HL)
          MOV   B,M          ; GET THE COUNTER IN (B)
HXLOOP:   MOV   A,M          ; GET A HEX BYTE OF DATA
          ANI   FZERO        ; SAVE THE HIGH ORDER BITS ONLY
          RRC                ; ROTATE RIGHT ONE BIT
          RRC                ; ROTATE RIGHT ONE BIT
          RRC                ; ROTATE RIGHT ONE BIT
          RRC                ; ROTATE RIGHT ONE BIT
          CALL  LOOKUP       ; CONVERT THE BYTE TO ASCII
;         ADI   THIRTY       ; ASCII-IZE THE BYTE
          MOV   E,A          ; GET THE BYTE OF DATA IN (E)
          MOV   A,M          ; GET THE HEX BYTE OF DATA AGAIN
          ANI   ZEROF        ; SAVE THE LOW ORDER BITS ONLY
          CALL  LOOKUP       ; CONVERT THE BYTE TO ASCII
;         ADI   THIRTY       ; ASCII IZE THE BYTE
          MOV   D,A          ; SAVE (A) IN (D)
          PUSH  B            ; SAVE (BC) 
          PUSH  H            ; SAVE (HL)
          PUSH  D            ; SAVE (DE)
          CALL  COUT         ; GO TO THE FUNCTION
          POP   D            ; RESTORE (DE)
          MOV   E,D          ; GET THE BYTE OF DATA IN (E)
          CALL  COUT         ; GO TO THE FUNCTION
          MVI   E,BLANK      ; INSERT A BLANK        
          CALL  COUT         ; GO TO THE FUNCTION
          POP   H            ; RESTORE (HL)
          POP   B            ; RESTORE (BC)
          INX   H            ; INCRMENT (HL)
          DCR   B            ; DECREMENT THE COUNTER
          JNZ   HXLOOP       ; LOOP TO END OF COUNTER
          LXI   D,CRLF       ; CARRIAGE RETURN - LINE FEED
          CALL  WRTERM       ; DO IT
          RET                ; RETURN TO CALLER
; 
;   CONVERT A HEXIDECIMAL BYTE TO AN ASCII BYTE FOR PRINTING
;
LOOKUP:   PUSH  H            ; SAVE (HL)
          LXI   H,TABLE      ; GET THE CONVERSION TABLE
          CPI   ZERO         ; DOES (A) CONTAIN A ZERO
          JZ    LOOK2        ; YES
LOOK1:    INX   H            ; INCREMENT (HL)
          DCR   A            ; DECREMENT (A)
          JNZ   LOOK1        ; LOOP UNTIL (A) = 0
LOOK2:    MOV   A,M          ; GET THE TABLE CONTENTS IN (A)
          POP   H            ; RESTORE (HL)
          RET
;
;   PARSE THE INPUT ARRAY TO FORM THE OUTPUT ARRAY
;
PARSE:    PUSH H             ; SAVE (HL) CONTENTS
          PUSH D             ; SAVE (DE) CONTENTS (INPUT)
          XCHG               ; GET THE (DE) ADDRESS IN (HL)
          MVI  D,ZERO        ; ZERO (DE)
          MVI  E,ZERO        ; ZERO (DE)
          MVI  A,ZERO        ; GET A '0'
          STA  AUXCOD        ; INITIALIZE THE AUXCOD FLAG
;
LOOP1:    MOV  A,M           ; GET THE BYTE AT (HL) INTO A
          CPI  PNDSIGN       ; IS IT A '#' IN (A)
          JZ   RTRN1         ; NO DATA  
          CPI  BLANK         ; IS IT A BLANK IN (A)
          JZ   INCRIN        ; YES, INCREMENT THE INPUT POINTER
          CPI  COMMA         ; IS IT A COMMA IN (A) 
          JZ   ERR2          ; YES, NO DATA                       
          CPI  SLASH         ; IS IT A SLASH (/) IN (A)
          JZ   AUXNUM1       ; YES - SETUP TO PROCESS
          SBI  THIRTY        ; ASCII TO BINARY CONVERSION
          MOV  D,A           ; SAVE IN (DE)
          INX  H             ; INCREMENT (HL)
;
          MOV  A,M           ; GET THE BYTE AT (HL) INTO A
          CPI  PNDSIGN       ; IS IT A '#' IN (A)
          JZ   USEIT         ; ALL DONE
          CPI  BLANK         ; IS IT A BLANK IN (A)
          JZ   ERR3          ; YES, IMBEDDED BLANKS NOT PERMITTED
          CPI  COMMA         ; IS IT A COMMA IN (A) 
          JZ   USEIT         ; YES, CONVERT PREVIOUS DATA TO HEX
          CPI  SLASH         ; IT IT A SLASH IN (A)
          JZ   AUXNUM2       ; YES, SET UP TO PROCESS
          SBI  THIRTY        ; ASCII TO BINARY CONVERSION
          MOV  E,A           ; SAVE IN (DE)
          INX  H             ; INCREMENT (HL)
;
          MOV  A,M           ; GET THE BYTE AT (HL) INTO A
          CPI  PNDSIGN       ; IS IT A '#' IN (A)
          JZ   CONVERT       ; CONVERT THE NUMBER IN (DE)
          CPI  BLANK         ; IS IT A BLANK IN (A)
          JZ   ERR3          ; YES, IMBEDDED BLANKS NOT PERMITTED
          CPI  COMMA         ; IT IT A COMMA IN (A)
          JZ   CONVERT       ; CONVERT THE NUMBER IN (DE)
          CPI  SLASH         ; IS IT A SLASH IN (A)
          JZ   AUXNUM3       ; YES - SET UP TO PROCESS
          SBI  THIRTY        ; ASCII TO BINARY CONVERSION
          PUSH B             ; SAVE (BC)
          MOV  B,D           ; GET FIRST BYTE OF ASCII NUMBER
          MOV  D,E           ; GET SECOND BYTE OF ASCII NUMBER
          MOV  E,A           ; GET THIRD BYTE OF ASCII NUMBER
          SUB  A             ; ZERO (A)
;
CONV0:    ADI  HUNDRED       ; ADD '100' TO (A)
          DCR  B             ; DECREMENT (B)
          JNZ  CONV0         ; GO AROUND AGAIN
;
          MOV  B,A           ; SAVE AT (B)
          CALL HEXCON        ; CONVERT THE NUMBER AT (DE)
          ADD  B             ; ADD THE NUMBER AT (B)
          POP  B             ; RESTORE (BC)
          INX  H             ; INCREMENT (HL)
          JMP  CONV2         ; SPECIAL CONVERSION HAS BEEN DONE
;
USEIT:    MOV  E,D           ; SET UP (DE) AS A 16 BIT NUMBER
          MVI  D,ZERO        ; GET A '0' IN D
          JMP  CONVERT       ; CONVERT THE NUMBER IN (DE)
;
AUXNUM1:  EQU  $
          JMP  ERR4          ; ISSUE AN ERROR MESSAGE
;
AUXNUM2:  EQU  $
          STA  AUXCOD        ; SAVE THE SLASH AS A FLAG
          JMP  USEIT         ; AUX NUMBER COMING
;
AUXNUM3:  EQU  $
          STA  AUXCOD        ; SAVE THE SLASH AS A FLAG
          JMP  CONVERT       ; WAS A TWO DIGIT NUMBER
;
CONVERT:  CALL HEXCON        ; CONVERT TO HEX 
CONV2:    MOV  D,A           ; SAVE (A) AT (D)
          LDA  AUXCOD        ; GET THE AUXCOD
          CPI  ZERO          ; IS IT A '0'  
          JZ   CONTINU       ; NO AUXCOD SAVED
          CPI  SLASH         ; IS IT A SLASH
          JZ   CON1          ; CONDITION AUXCOD
          CPI  F12           ; IS IT A '12'
          JZ   CON12         ; YES
          CPI  F13           ; IS IT A '13'
          JZ   CON13         ; YES
          CPI  F18           ; IS IT A '18'
          JZ   CON18         ; YES
          CPI  F19           ; IS IT A '19'
          JZ   CON19         ; YES
          CPI  F21           ; IS IT A '21'
          JZ   CON21         ; YES
          JMP  ERR5          ; NON OF THE ABOVE - ISSUE AN ERROR
;
CON1:     MOV  A,D           ; GET THE 'OP' CODE
          STA  AUXCOD        ; SAVE THE FUNCTION NUMBER
          JMP  CONTINU       ; WAIT FOR THE NEXT TIME AROUND
;
CON12:    MOV  A,D           ; GET THE AMOUNT
          STA  N12           ; SAVE
          JMP  CONV3         ; CONTINUE
;
CON13:    MOV  A,D           ; GET THE AMOUNT
          STA  N13           ; SAVE
          JMP  CONV3         ; CONTINUE
;
CON18:    MOV  A,D           ; GET THE AMOUNT
          STA  N18           ; SAVE
          JMP  CONV3         ; CONTINUE
;
CON19:    MOV  A,D           ; GET THE AMOUNT
          STA  N19           ; SAVE
          JMP  CONV3         ; CONTINUE
;
CON21:    MOV  A,D           ; GET THE AMOUNT
          STA  N21           ; SAVE
          JMP  CONV3         ; CONTINUE
;
CONV3:    MVI  A,ZERO        ; GET A '0'
          STA  AUXCOD        ; RESET 'AUXCOD'
          INX  H             ; INCREMENT (HL)
          JMP  LOOP1         ; GO AROUND AGAIN
;
CONTINU:  MOV  A,D           ; GET THE NUMBER FROM (D)
          STAX B             ; SAVE (A) AT (BC)
          INX  B             ; INCREMENT (BC)
          MVI  D,ZERO        ; ZERO (D)
          MVI  E,ZERO        ; ZERO (E)
;
          LDA  PBUFFER+1     ; GET THE COUNTER BYTE
          INR  A             ; ADD '1' TO (A)
          STA  PBUFFER+1     ; SAVE            
;
CONV1:    MOV  A,M           ; GET (A) AGAIN             
          CPI  PNDSIGN       ; IS IT A '#' IN (A)
          JZ   RTRN1         ; ALL DONE
          CPI  BLANK         ; IS IT A BLANK IN (A)
          JZ   INCRIN        ; YES, NO IMBEDDED BLANKS PERMITTED
          CPI  COMMA         ; IS IT A COMMA IN (A) 
          JZ   INCRIN        ; YES, CONVERT PREVIOUS DATA TO HEX
          CPI  SLASH         ; IS IT A SLASH IN (A)
          JZ   AUXNUM4       ; YES, SET UP TO PROCESS 
          JMP  LOOP1         ; CONTINUE
;
INCRIN:   INX  H             ; INCREMENT (HL) BY '1'
          JMP  LOOP1         ; GO AROUND AGAIN
;
AUXNUM4:  INX  H             ; INCREMENT (HL) BY '1'
          JMP  LOOP1         ; GO AROUND AGAIN
;
RTRN1:    MVI  A,FMAX        ; GET A X'FF' IN (A)
          STAX B             ; SAVE IN (BC)
          INX  B             ; INCREMENT (BC) BY '1'
          LDA  PBUFFER+1     ; GET THE COUNTER BYTE
          INR  A             ; ADD '1' TO (A)
          INR  A             ; ADD '1' TO (A) AGAIN
          STA  PBUFFER+1     ; SAVE
          POP  D             ; RESTORE THE (DE) REGISTER
          POP  H             ; RESTORE THE (HL) REGISTER
          RET                ; RETURN TO CALLER
;
HEXCON:   SUB  A             ; ZERO (A)
          ORA  D             ; CHECK THE CONTENTS OF (D) AND (A)
          JZ   DZERO         ; (D) CONTAINED A ZERO
          SUB  A             ; ZERO (A)
;
CHKD:     ADI  TEN           ; ADD '10' TO (A)
          DCR  D             ; DECREMENT (D) BY '1'
          JZ   DZERO         ; TERMINATE IF NOW < 0
          JMP  CHKD          ; LOOP FOR MORE '10' FACTORS
DZERO:    ADD  E             ; ADD (E) TO (A) FOR ENTIRE NUMBER
          RET
;
ERR1:     LXI  D,ERRMSG1     ; GET ERROR MESSAGE '1'
          CALL WRTERM        ; INDICATE THE ERROR
          JMP  WAIT          ; CONTINUE          
;
ERR2:     LXI  D,ERRMSG2     ; GET ERROR MESSAGE '2'
          CALL WRTERM        ; INDICATE THE ERROR
          JMP  WAIT          ; CONTINUE          
;
ERR3:     LXI  D,ERRMSG3     ; GET ERROR MESSAGE '3'
          CALL WRTERM        ; INDICATE THE ERROR
          JMP  WAIT          ; CONTINUE           
;
ERR4:     LXI  D,ERRMSG4     ; GET ERROR MESSAGE '4'
          CALL WRTERM        ; INDICATE THE ERROR
          JMP  WAIT          ; CONTINUE      
;
ERR5:     LXI  D,ERRMSG5     ; GET ERROR MESSAGE '5'
          CALL WRTERM        ; INDICATE THE ERROR
          JMP  WAIT          ; CONTINUE          
;
;  NOTIFY THE USER OF AN ERROR AND WAIT ON REPLY
;
WAIT:     LXI  D,WAITMSG     ; ISSUE THE WAIT MESSAGE
          CALL WRTERM        ; DO IT
WAITR:    CALL TERMIN        ; GET THE REPLY
          CPI  ZERO          ; IS IT A'ZERO'
          JZ   WAITR         ; LOOP UNTIL SOMETHING ENTERED
          CPI  CR            ; IS IT A <CR>
          JZ   RETRY         ; GO AROUND AGAIN
          JMP  RTNCPM        ; RETURN TO CALLER 
;
;  WRITE DATA TO THE TERMINAL SCREEN
;
WRTERM:  PUSH   H            ; SAVE (HL) CONTENTS
         PUSH   B            ; SAVE (BC) CONTENTS
         MVI    C,PBUFF      ; SET THE BDOS FUNCTION
         CALL   BDOS         ; GO TO THE FUNCTION
         POP    B            ; RESTORE (BC) CONTENTS
         POP    H            ; RESTORE (HL) CONTENTS
         RET                 ; RETURN TO CALLER
;
;  WRITE DATA TO THE LINE PRINTER
;
PRINT:   PUSH   H            ; SAVE (HL) CONTENTS
         XCHG                ; EXCHANGE (DE) AND (HL) REGISTERS
LOOP:    MOV    A,M          ; GET A BYTE FROM (HL) IN (A)
         CPI    DOLR         ; IS A '$' IN (A)
         JZ     ENDPRT       ; ALL DONE
         MOV    E,A          ; PUT THE BYTE IN THE (E) REGISTER
         PUSH   B            ; SAVE (BC)
         PUSH   H            ; SAVE (HL)
         CALL   BDLIST       ; DO IT
         POP    H            ; RESTORE (HL)
         POP    B            ; RESTORE (BC)
         INX    H            ; INCREMENT (HL)
         DCR    C            ; DECREMENT COLUMN COUNTER
         JNZ    LOOP         ; LOOP UNTIL END OF INPUT - '$'
;
         LXI    H,CRLF       ; GET THE 'CRLF' FUNCTION
         MVI    C,THREE      ; GET A NEW COUNTER IN 'C'
         JMP    LOOP         ; OUTPUT THE 'CRLF' FUNCTION
;
ENDPRT:  POP    H            ; RESTORE (HL) TO ENTRY
         RET                 ; RETURN TO CALLER
;
BDLIST:  MVI    C,LIST       ; SET THE BDOS FUNCTION
         JMP    BDOS         ; RETURN TO CALLER
;
;  STORAGE AREAS
;
TABLE:   DB     '0','1','2','3','4','5','6','7'
         DB     '8','9','A','B','C','D','E','F'
CCP:     DW     128
TEMP:    DS     4
RBUFFER: DB     40
         DB     00
         DS     40
         DB     '$'
PBUFFER: DB     40
         DB     00
         DS     40
         DB     '#'
OBUFFER: DB     40
         DB     00
         DS     40
         DB     '%'
;
N12:     DB     0            ; n/72 LINES/IN.
N13:     DB     0            ; n/216 LINES/IN.
N18:     DB     0            ; LEFT MARGIN
N19:     DB     0            ; FORM LENGTH 
N21:     DB     0            ; FOREIGN CHAR SET
TEST:    DB     0            ; TEST MODE
AUXCOD:  DB     0            ; AUX NUMBER COMING
NLINES:  DB     0            ; NUMBER OF LINES TO PRINT
NCOLS:   DB     0            ; NUMBER OF COLUMNS TO PRINT
;
PSTRING: DB     'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
         DB     'abcdefghijklmnopqrstuvwxyz'
         DB     '0123456789!@#%^&*()[]{}<>-=+_|\":;,.?/'
         DB     'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
         DB     'abcdefghijklmnopqrstuvwxyz'
;
CLRSCN:  DB     CLEAR,CR,LF,LF,DOLR        ; CLEAR THE SCREEN
MESG:    DB     CR,LF,'Data read from the keyboard is: >>> ',DOLR
PMESG:   DB     CR,LF,'Printer setup parameters are: >>> ',DOLR
RMESG:   DB     CR,LF,'RETURN TO CP/M',CR,LF,DOLR
PROMPT:  DB     CR,LF,'ENTER PRINTER OPTIONS: >>> ',DOLR
ERRMSG1: DB     CR,LF,'Error Message One   - <CR> to try Again'
         DB     ' or ^C To Terminate.',CR,LF,DOLR
ERRMSG2: DB     CR,LF,'Error Message Two   - <CR> to try Again.'
         DB     ' or ^C To Terminate.',CR,LF,DOLR
ERRMSG3: DB     CR,LF,'Error Message Three - <CR> to try Again.'
         DB     ' or ^C To Terminate.',CR,LF,DOLR
ERRMSG4: DB     CR,LF,'Error Message Four  - <CR> to try Again.'
         DB     ' or ^C To Terminate.',CR,LF,DOLR
ERRMSG5: DB     CR,LF,'Error Message Five  - <CR> to try Again.'
         DB     ' or ^C To Terminate.',CR,LF,DOLR
WAITMSG: DB     CR,LF,'Enter Error Action: >> ',DOLR
ACCMSG:  DB     CR,LF,'Are these parameters acceptable ??' 
         DB     '  <CR> to accept, "N" to try agian.',CR,LF,DOLR
CRLF:    DB     CR,LF,DOLR
;
OPTIONS: EQU    $  
         DB     'The following options are available for a CP/M printer'
         DB     CR,LF
         DB     'Enter Your Choices - COMMA Separated then <CR>'
         DB     CR,LF,LF
         DB     'General Parameters:',CR,LF
         DB     '    0.  PRINTER TYPE               '
         DB     '    1.  RESET             ',CR,LF
         DB     'Line Style: - Choose One',CR,LF
         DB     '    2.  ENLARGED -  5.0 Char/In.   '
         DB     '    5.  ELITE    - 12.0 Char/In.',CR,LF
         DB     '    3.  COND/ENL -  8.5 Char/In.   '
         DB     '    6.  CONDENSE - 17.0 Char/In.',CR,LF
         DB     '    4.  PICA     - 10.0 Char/In.',CR,LF
         DB     'Line Spacing: - Choose One',CR,LF
         DB     '    7.  2 Lines/In.                '
         DB     '   12.  n/72  -  9/72  = 8 Lines/In.',CR,LF
         DB     '    8.  3 Lines/In.                '
         DB     '        n = 0 >> 85                 ',CR,LF
         DB     '    9.  4 Lines/In.                '      
         DB     '   13.  n/216 - 27/216 = 8 Lines/In.',CR,LF
         DB     '   10.  6 Lines/In.                '
         DB     '        n = 0 >> 255               ',CR,LF
         DB     '   11.  8 Lines/In.                '
         DB     '        Input as 12/n or 13/n      ',CR,LF
         DB     'Miscellaneous Options: - Choose as required.',CR,LF
         DB     '   14.  Emphasized Print     OR    '
         DB     '   15.  Double Strike              ',CR,LF
         DB     '   16.  Superscript          OR    '
         DB     '   17.  Subscript                  ',CR,LF
         DB     '   18.  Left Margin  0 >> 78       '
         DB     '   19.  Form Length  1 >> 127      ',CR,LF
         DB     '   20.  Alternate Character Set    '
         DB     '   21.  Inter Character Set 0 >> 10',CR,LF
         DB     'Invoke Test Option: - 99',CR,LF,DOLR
;
K1       EQU    02
K2       EQU    03
K3       EQU    04
K6       EQU    17
;
EPSON:   DB     00H,K6,'EPSON '        ; NAME OF PRINTER
         DW     EPSF12                 ; ADDRESS OF F12 FUNCTION
         DW     EPSF13                 ; ADDRESS OF F13 FUNCTION
         DW     EPSF18                 ; ADDRESS OF F18 FUNCTION
         DW     EPSF19                 ; ADDRESS OF F19 FUNCTION
         DW     EPSF21                 ; ADDRESS OF F21 FUNCTION
         DB     01H,K1,'@'             ; RESET
         DB     02H,K2,'W',01          ; ENLARGED PRINT
         DB     03H,K2,15,14           ; COND/ENL PRINT        
         DB     04H,K1,'P'             ; PICA PRINT
         DB     05H,K1,'M'             ; ELITE PRINT
         DB     06H,K1,15              ; CONDENSED PRINT
         DB     07H,K2,'A',36          ; 2 LINES/IN
         DB     08H,K2,'A',27          ; 3 LINES/IN
         DB     09H,K2,'A',24          ; 4 LINES/IN
         DB     0AH,K1,'2'             ; 6 LINES/IN
         DB     0BH,K1,'0'             ; 8 LINES/IN
         DB     0CH,K2,'A'             ; n/72 LINES/IN
EPSF12:  DB     00
         DB     0DH,K2,'3'             ; n/216 LINES IN
EPSF13:  DB     00
         DB     0EH,K1,'E'             ; EMPHASIZED PRINT
         DB     0FH,K1,'G'             ; DOUBLE STRIKE PRINT
         DB     10H,K2,'S',00          ; SUPERSCRIPT
         DB     11H,K2,'S',01          ; SUBSCRIPT
         DB     12H,K2,'l'             ; LEFT MARGIN
EPSF18:  DB     00
         DB     13H,K2,'C'             ; FORM LENGTH 
EPSF19:  DB     00
         DB     14H,K1,'4'             ; ALT CHAR SET
         DB     15H,K2,'5'             ; INTERNATIONAL CHAR SET
EPSF21:  DB     00
         DB     16H,K2,00,00           ; NOT SPECIFIED
         DB     17H,K2,00,00           ; NOT SPECIFIED
         DB     18H,K2,00,00           ; NOT SPECIFIED
         DB     0FFH                   ; EOF
ENDEPS:  EQU    $
;
         END
