;               LSTPATCH.ASM ver 1.0
;             by Keith Petersen, W8SDZ
;                 (revised 12/29/84)
;
;This program moves an alternate list driver into high
;memory and then patches CP/M to use it instead of the
;regular CBIOS list routine.  The patch will remain
;intact until the next cold boot.
;
;Why this is useful: if your list driver is too long
;to fit into your CBIOS or the list STAT routine is
;not implemented, this program can be used to patch it
;in after CP/M is booted.  Another use would be if
;a temporary list driver is needed for an otherwise
;unimplemented port.
;
;------------------------------------------------
;Change the following equate to an area in your high
;memory where the alternate list driver may be located
;without interference to or from CP/M.
;
DEST    EQU     0FB80H          ;running location of code
;
;------------------------------------------------
;
;Define I/O ports and status bits
;
LISTS   EQU     02H             ;list status port
LISTD   EQU     03H             ;list data port
LISRDY  EQU     80H             ;list trans. buf. empty
;
CR      EQU     0DH             ;carriage return
LF      EQU     0AH             ;line feed
NULL    EQU     00H             ;null character
BDOS    EQU     0005H           ;BDOS entry adrs
;
       ORG     100H
;
;Move the console and list drivers up to high ram
;
MOVEUP: LXI     B,PEND-START+1      ;number of bytes to move
       LXI     H,DEST+PEND-START+1 ;end of moved code
       LXI     D,SOURCE+PEND-START ;end of source code
;
MVLP:   LDAX    D               ;get byte
       DCX     H               ;bump pointers
       MOV     M,A             ;new home
       DCX     D
       DCX     B               ;bump byte count
       MOV     A,B             ;check if zero
       ORA     C
       JNZ     MVLP            ;if not, do some more
;
;now patch cp/m to use the new drivers
       LHLD    1               ;get CP/M jump table adrs
       LXI     D,13            ;ready to add 13
       DAD     D               ;HL = LISTOUT + 1
;
       MVI     M,LISOUT AND 0FFH ;modify LSB jmp adrs
       INX     H
       MVI     M,LISOUT SHR 8    ;modify MSB jmp adrs
       LXI     D,29              ;ready to add 29
       DAD     D                 ;hl = lststat + 1
       MVI     M,LSTSTAT AND 0FFH ;modify LSB jmp adrs
       INX     H
       MVI     M,LSTSTAT SHR 8    ;modify MSB jmp adrs
;
;Print message saying what has been done, then exit to CP/M
       LXI     D,MSG           ;point to message
       MVI     C,9             ;bdos print string function
       JMP     BDOS            ;print msg then return to CCP
;
MSG:    DB      '++Alternate LIST driver now patched++',CR,LF,'$'
;
SOURCE  EQU     $               ;boundary memory marker
;
OFFSET  EQU     DEST-SOURCE     ;reloc amount
;-----------------------------------------------;
;       The following code gets moved           ;
;       to high RAM located at "DEST"           ;
;-----------------------------------------------;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
;xx   C A U T I O N :  if modifying anything    xx
;xx     in this program from here on:           xx
;xx     A-L-L  labels must be of the form:      xx
;xx     LABEL   EQU     $+OFFSET                xx
;xx     in order that the relocation to high    xx
;xx     RAM work successfully.  Forgetting to   xx
;xx     specify '$+OFFSET' will cause the pro-  xx
;xx     gram to JMP into whatever is currently  xx
;xx     in low memory, with unpredictable       xx
;xx     results.  Be careful....                xx
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
;
START   EQU     $+OFFSET
;
;This is the new list output routine
LISOUT  EQU     $+OFFSET
       IN      LISTS           ;get list status
       ANI     LISRDY          ;ready for character?
       JZ      LISOUT          ;no, loop and wait
       MOV     A,C             ;get character
       ANI     7FH             ;strip parity
       OUT     LISTD           ;send to printer
       CPI     LF              ;was it a line feed?
       RNZ                     ;no, return
;
;Send null to printer to allow time for carriage to return
       MVI     C,NULL          ;get a null
       CALL    LISOUT          ;send it to printer
       MVI     C,LF            ;restore line feed
       RET
;
;This is the new list status routine
LSTSTAT EQU     $+OFFSET
       IN      LISTS           ;get list status
       ANI     LISRDY          ;ready for character?
       MVI     A,0
       RZ                      ;no, return with 0
       CMA                     ;else make it 0ffh
       RET
;
PEND    EQU     $+OFFSET        ;end of relocated code
;
       END