;               DVRPATCH.ASM ver 1.0
;             by Keith Petersen, W8SDZ
;                 (revised 3/14/81)
;
;This program moves alternate console and list
;drivers into high memory and then patches CP/M
;to use them instead of the regular CBIOS routines.
;The patches will remain intact until the next
;cold boot.
;
;Why this is useful: if your console and/or list
;drivers are too long to fit into your CBIOS, this
;program can be used to patch them in after CP/M is
;booted.  Another use might be when some special
;drivers are temporarily needed, such as allowing
;a modem port to be patched in so it is the console
;or the list device.
;
;------------------------------------------------
;Change the following equate to an area in your high
;memory where the alternate console and list drivers
;may be located without interference to or from CP/M.
;
DEST    EQU     0FB80H  ;RUNNING LOCATION OF CODE
;
;------------------------------------------------
;
;Define I/O ports and status bits
;
CRTS    EQU     20H     ;CRT STATUS PORT
CRTD    EQU     21H     ;CRT DATA PORT
CRTRDY  EQU     04H     ;CRT TRANS. BUF. EMPTY
KBDS    EQU     0EH     ;KBD STATUS PORT
KBDD    EQU     0CH     ;KBD DATA PORT
KBDRDY  EQU     01H     ;KBD RECEIVE DATA AVAIL.
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,4              ;READY TO ADD 4
       DAD     D                ;HL = CONSTAT + 1
;
       MVI     M,CSTAT AND 0FFH ;PATCH LSB OF JMP ADRS
       INX     H
       MVI     M,CSTAT SHR 8    ;PATCH MSB JMP ADRS
;
       INX     H
       INX     H                ;HL = CONIN + 1
       MVI     M,CONIN AND 0FFH ;PATCH LSB OF JMP ADRS
       INX     H
       MVI     M,CONIN SHR 8    ;PATCH MSB JMP ADRS
;
       INX     H
       INX     H                ;HL = CONOUT + 1
       MVI     M,CONOUT AND 0FFH ;MODIFY LSB JMP ADRS
       INX     H
       MVI     M,CONOUT SHR 8   ;MODIFY MSB JMP ADRS
;
       INX     H
       INX     H                ;HL = LISTOUT + 1
       MVI     M,LISOUT AND 0FFH ;MODIFY LSB JMP ADRS
       INX     H
       MVI     M,LISOUT 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 CONSOLE and LIST '
       DB      'drivers 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 console status routine
CSTAT   EQU     $+OFFSET
       IN      KBDS    ;GET KEYBOARD STATUS
       ANI     KBDRDY  ;CHARACTER WAITING?
       MVI     A,0
       RZ              ;NO, RETURN WITH 0
       CMA             ;ELSE MAKE IT 0FFH
       RET
;
;This is the new console input routine
CONIN   EQU     $+OFFSET
       IN      KBDS    ;GET KEYBOARD STATUS
       ANI     KBDRDY  ;CHARACTER WAITING?
       JZ      CONIN   ;NO, LOOP AND WAIT
       IN      KBDD    ;GET CHARACTER
       ANI     7FH     ;STRIP PARITY
       JZ      CONIN   ;IGNORE NULLS
       RET
;
;This is the new console output routine
CONOUT  EQU     $+OFFSET
       IN      CRTS    ;GET CRT STATUS
       ANI     CRTRDY  ;READY FOR CHARACTER?
       JZ      CONOUT  ;NO, LOOP AND WAIT
       MOV     A,C     ;GET CHARACTER
       ANI     7FH     ;STRIP PARITY
       RZ              ;IGNORE NULLS
       CPI     7FH     ;RUBOUT?
       RZ              ;YES, IGNORE IT
       OUT     CRTD    ;ELSE SEND TO CRT
       RET
;
;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
;
PEND    EQU     $+OFFSET ;END OF RELOCATED CODE
;
       END