TITLE   'Z80-ASSEMBLER TO CP/M LINKAGES'
;
;       EQUATE TABLE
;
CR      EQU     13
LF      EQU     10
ENTRY   EQU     5               ;FDOS ENTRY
BOOT    EQU     0               ;WARM START
SETDMA  EQU     26              ;CP/M FUNCTION NUMBER
OPNFIL  EQU     15              ;OPEN FILE
CLSFIL  EQU     16              ;CLOSE FILE
DELFIL  EQU     19              ;DELETE FILE
MAKFIL  EQU     22              ;CREATE FILE
RDNR    EQU     20              ;READ NEXT RECORD
WRNR    EQU     21              ;WRITE NEXT RECORD
PRBUF   EQU     9               ;PRINT STRING
DFCB    EQU     5CH             ;CP/M DEFAULT FCB
DEFBUF  EQU     80H             ;CP/M DEFAULT I/O ADDR
PASSNO  EQU     1B03H           ;CURRENT PASS NO.
;
GETCON  EQU     0F009H          ;MONITOR CONSOLE INPUT
PUTCON  EQU     0F00CH          ;MONITOR CONSOLE OUTPUT
CTLZ    EQU     1AH             ;^Z = EOF MARK
;
;
       ORG     102H
       JP      CONIN
       JP      CONOUT
       JP      LSTO
       JP      RDRIN
       JP      PCHO
       JP      MEMCHK
       JP      BOOT
;
       ORG     2400H           ;PUT ABOVE SYMBOL TABLE
;
SRCFCB  DEFB    0               ;FCB STARTS WITH 0
SRCFN   DEFM    '        '      ;RESERVE 8 CHARS FOR FILE NAME
       DEFM    'Z80'           ;USE EXTENSION OF Z80
       DEFS    21              ;21 BYTES FOR CP/M
SRCPTR  DEFS    2               ;FOR CHARACTER POINTER
SRCOPN  DEFM    'C'             ;DECLARE CLOSED
;
LSTFCB  DEFB    0               ;LISTING FILE SETUP
LSTFN   DEFM    '        '
       DEFM    'PRN'           ;PRINT FILE
       DEFS    21
LSTPTR  DEFS    2
LSTOPN  DEFM    'C'
;
HEXFCB  DEFB    0               ;SAME FOR HEX FILE
HEXFN   DEFM    '        '
       DEFM    'HEX'
       DEFS    21
HEXPTR  DEFS    2
HEXOPN  DEFM    'C'
;
MEMCHK  LD A, 0FFH              ;MAX MEM = 23FFH
       LD B, 23H
       RET
;
CONOUT  PUSH    BC              ;NO REGISTERS MAY BE DESTROYED
       PUSH    DE
       PUSH    HL
OUT4    LD A,C
       CALL    PUTCON
;
GENRET  POP     HL              ;GENERAL RETURN FOR ALL SUBR'S
       POP     DE
       POP     BC
       RET
;
;
OPNOUT  PUSH    DE              ;OPEN (DE) FCB FOR OUTPUT
       LD C, DELFIL            ;FIRST DELETE CURRENT
       CALL    ENTRY
       POP     DE
       LD C, MAKFIL            ;THEN RE-CREATE
       JP      ENTRY
;
CONIN   PUSH    BC              ;CONSOLE INP IS ONLY COMMON
       PUSH    DE              ; POINT FOR ALL PASSES SO DO
       PUSH    HL              ; SETUP HERE
;
       LD A, (SRCOPN)          ;IS SRC OPEN?
       CP 'O'
       CALL NZ, CPYFCB         ;IF NOT, CREATE FCB'S
       LD HL, (NXTPAS)         ;POINT TO PASS SEQUENCE
       LD A, (HL)              ;GET NEXT PASS NUMBER
       INC HL                  ;UPDATE POINTER
       LD (NXTPAS), HL         ;SAVE POINTER
       PUSH    AF
;
       CP 'Q'                  ;QUIT ?
       CALL Z  FLUSH           ;YES, FLUSH BUFFERS
       POP     AF
       PUSH    AF
;
       CP '1'                  ;PASS 1?
       JR Z,   PASS1
       CP '2'                  ;PASS 2?
       JP Z,   PASS2
       CP '3'                  ;PASS 3?
       JP Z,   PASS3
       CP '4'                  ;PASS 4 USES CONSOLE OUTPUT
       JR Z,   PASS1
INPRET  POP     AF              ;IF NONE OF ABOVE, EXIT
       JR      GENRET
;
NXTPAS  DEFW    SEQNO           ;SEQUENCE # POINTER
SEQNO   DEFM    '1423Q'         ;DEFAULT SEQUENCE
CPYFCB  LD HL, DFCB+9           ;POINT TO FILE EXTENSION
       LD DE, SEQNO+2          ;POINT TO PASS 2 FLAG
       LD A, 'N'               ;IF N, SKIP PASS
       CP (HL)                 ;SKIP IT?
       JR NZ   DOIT            ;NO, DO LISTING
       LD (DE), A              ;SKIP IT
DOIT    INC HL                  ;POINT TO HEX SWITCH
       INC DE                  ;POINT TO PASS 3 FLAG
       CP (HL)                 ;SKIP IT?
       JR NZ   COPYIT          ;NO, DO HEX FILE
       LD (DE), A              ;DON'T DO IT
COPYIT  LD BC, 8H               ;SETUP FOR LDIR
;
       LD DE, SRCFN            ;DESTINATION
       PUSH    BC
       CALL    MOVFCB
;
       LD DE, LSTFN
       POP     BC
       PUSH    BC
       CALL    MOVFCB
;
       LD DE, HEXFN
       POP     BC
;
MOVFCB  LD HL, DFCB+1           ;FILE NAME STARTS IN POS 1
       LDIR
       RET
;
PASS1   XOR A                   ;MAKE SURE OPEN FIRST
       LD (SRCFCB+12), A       ; EXTENT
       LD DE,  SRCFCB
       LD C, OPNFIL
       CALL    ENTRY
       CP 0FFH                 ;SUCESSFUL?
       JR Z,   NOSRC           ; NO, LET US KNOW
       LD A, 'O'               ; DECLARE OPEN
       LD (SRCOPN), A
       XOR A                   ;FIRST RECORD IS #0
       LD (SRCFCB+32), A
       LD HL, SRCBUF+1024
       LD (SRCPTR), HL
       JR      INPRET
;
NOSRC   LD DE, NFMSG            ;NO FILE MESSAGE
ERROUT  LD C, PRBUF             ;PRINT STRING FUNCTION
       CALL    ENTRY
       CALL    GETCON          ;WAIT FOR KEYSTROKE TO EXIT
       JP      BOOT
;
NFMSG   DEFB    CR
       DEFB    LF
       DEFM    'NO SOURCE FILE FOUND'
       DEFB    CR
       DEFB    LF
       DEFM    '$'
;
PASS2   LD A, (HEXOPN)          ;HEX FILE OPEN FROM PREV?
       CP 'O'
       CALL Z, FLUSH           ;YES, FLUSH AND CLOSE
;
       LD DE, LSTFCB           ;OPEN LISTING FILE
       CALL    OPNOUT
       CP 0FFH                 ;SUCESSFUL?
       JR Z,   DSKERR          ;NO, ERROR MSG
       LD A, 'O'
       LD (LSTOPN),A           ;DECLARE OPEN
       XOR A                   ;START WITH RECORD 0
       LD (LSTFCB+32), A
       LD HL, LSTBUF           ;DECLARE EMPTY
       LD (LSTPTR), HL
       JR      PASS1           ;GO OPEN SRC
;
DSKERR  LD DE, ERRMSG
       JR      ERROUT          ;GOTO ERROR OUTPUT RTN
;
ERRMSG  DEFB    CR
       DEFB    LF
       DEFM    'DISK ERROR, ASSEMBLY ABORTED'
       DEFB    CR
       DEFB    LF
       DEFM    '$'
;
PASS3   LD A, (LSTOPN)          ;LIST STILL OPEN?
       CP 'O'
       CALL Z, FLUSH           ;YES, FLUSH AND CLOSE
       LD DE, HEXFCB
       CALL    OPNOUT          ;OPEN HEX FILE FOR OUTPUT
       CP 0FFH                 ;SUCESS?
       JR Z,   DSKERR          ;NO, ABORT
;
       LD A, 'O'
       LD (HEXOPN),A           ;DECLARE OPEN
       XOR A
       LD (HEXFCB+32), A
       LD HL, HEXBUF           ;DECLARE EMPTY
       LD (HEXPTR), HL
       JP      PASS1           ;GO OPEN SRC
;
FLUSH   LD A, (HEXOPN)          ;HEX FILE OPEN?
       CP 'O'                  ; IF O, YES
       JR Z,   HEXFL
;
       LD A, (LSTOPN)          ;LIST FILE OPEN?
       CP 'O'                  ; IF O, YES
       RET NZ                  ; NO OPEN OUTPUT FILES, EXIT
;
       LD DE, LSTBUF           ;DE POINTS TO START
       LD HL, (LSTPTR)         ;HL POINTS TO CURRENT CHAR
       LD BC, LSTFCB           ;NEED FCB PTR FOR CP/M
       JR      MTBUF
;
HEXFL   LD DE, HEXBUF           ;COMMENTS AS FOR LST FILE
       LD HL, (HEXPTR)
       LD BC, HEXFCB
;
MTBUF   LD A, L                 ;FIND IF ON RECORD BOUNDARY
       AND 127
       JR Z,   MTBUF2          ;IF Z, YES
       LD (HL), CTLZ           ;PUT ^Z AS EOF MARK
;
MTBUF2  PUSH    BC              ;SAVE FCB PTR
       OR A                    ;CLEAR CARRY
       SBC HL, DE              ;CALC # BYTES IN BUFFER
       JR NZ,  AREREC          ;IF NZ, ARE RECORDS TO WRITE
       POP BC                  ;ELSE EXIT
       RET
;
AREREC  LD B, 7                 ;B = SHIFT COUNTER
DIV128  SRL H                   ; BYTES/128 = # RECORDS
       RR  L
       DJNZ    DIV128          ;LOOP TIL DONE
;
       LD B, L                 ;B = # RECORDS
       OR A                    ;FIND IF EVEN RECORD AGAIN
       JR Z,   EVNREC
;
       INC B                   ;DON'T WANT TO LOSE PARTIAL
EVNREC  EX DE, HL               ;HL = BUFFER POINTER
       POP     DE              ;DE = FCB POINTER
;
       CALL    FLBUF           ;WRITE BUFFER TO DISK
       LD C, CLSFIL            ;CLOSE FUNCTION
       PUSH    DE
       CALL    ENTRY
       POP     DE
       LD HL, 35               ;(DE+35) = FILE OPEN FLAG
       ADD HL, DE
       EX DE, HL
       LD (HL), 'C'            ;DECLARE CLOSED
       RET
;
FLBUF   PUSH    BC              ;B=#RECS, C=CHAR
       PUSH    HL              ;HL=BUFFER POINTER
       PUSH    DE              ;DE=FCB PTR
;
       EX DE, HL               ;DE NOW = BUFFER PTR
       LD C, SETDMA
       CALL    ENTRY           ;DMA NOW = BUFFER
;
       POP     DE              ;GET FCB PTR BACK
       PUSH    DE
       LD C, WRNR              ;WRITE NEXT REC FUNCTION
       CALL    ENTRY
;
       OR A                    ;SET FLAGS
       JP NZ,  DSKERR
;
       POP     DE
       POP     HL
       POP     BC
;
       DEC B
       RET Z                   ;IF Z, ALL RECORDS WRITTEN
;
       LD A, L
       ADD A, 128              ;UPDATE DATA POINTER
       LD L, A
       JR NC,  FLBUF
       INC H
       JR      FLBUF
;
PCHO    PUSH    BC
       PUSH    DE
       PUSH    HL
       LD HL, (HEXPTR)         ;BUFFER POINTER
       LD A,H                  ;GET HIGH ORDER
       CP 34H                  ;FULL?
       JR Z,   DMPHEX          ;IF Z, BUFFER FULL
;
HEXCHR  LD (HL),C
       INC HL                  ;NOT FULL, JUST STORE CHAR
       LD (HEXPTR), HL
       JP      GENRET
;
DMPHEX  PUSH    BC              ;SAVE CHAR
       LD B, 8                 ;8 RECORD BUFFER
       LD HL, HEXBUF           ;SETUP FOR FLBUF
       LD DE, HEXFCB
       CALL    FLBUF
;
       POP     BC              ;GET CHAR BACK
       LD HL,  HEXBUF          ;START AT BEGINNING AGAIN
       JR      HEXCHR
;
LSTO    PUSH    BC
       PUSH    DE
       PUSH    HL
       LD A,(PASSNO)           ;GET CURRENT PASS
       CP 4                    ;IS IT PASS 4 ?
       JP Z,   OUT4            ;IF YES, OUTPUT TO CONSOLE
       LD HL, (LSTPTR)         ;NO, OUTPUT TO .PRN
       LD A, H
       CP 30H                  ;FULL?
       JR Z,   DMPLST          ;YES, FLUSH
;
LSTCHR  LD (HL), C              ;STORE CHAR IN I/O BUFFER
       INC HL                  ;UPDATE POINTER
       LD (LSTPTR), HL
       JP      GENRET
;
DMPLST  PUSH    BC
       LD B, 8                 ;BUFFER = 8 RECORDS
       LD HL, LSTBUF           ;START AT BEGINNING
       LD DE, LSTFCB           ;FCB FOR CP/M
       CALL    FLBUF
;
       POP     BC              ;GET THIS OUTPUT CHAR BACK
       LD HL, LSTBUF           ;RESTART AT BEGINNING
       JR      LSTCHR
;
RDRIN   PUSH    BC
       PUSH    DE
       PUSH    HL
       LD HL, (SRCPTR)         ;GET SRC POINTER
       LD A, H
       CP 2CH                  ;PAST END?
       JR Z,   SRCRD           ;YES, GO GET MORE
;
NXTCHR  LD A, (HL)              ;GET CHAR
       INC HL
       LD (SRCPTR), HL         ;SAVE POINTER
       JP      GENRET
;
SRCRD   LD BC, 0880H            ;B=#RECS, C=BYTES/REC
       LD DE, SRCBUF           ;DESTINATION
;
NXTREC  PUSH    DE
       PUSH    BC
       LD C, SETDMA
       CALL    ENTRY
;
       LD DE, SRCFCB
       LD C, RDNR              ;READ NEXT RECORD
       CALL    ENTRY
;
       POP     BC
       POP     DE
       CP 1                    ;1 MEANS FILE DONE
       JR Z,   SRCDON
;
       LD A, E                 ;UPDATE DESTINATION
       ADD A, C
       LD E, A
       JR NC,  DOK
       INC D
DOK     DEC B                   ;DONE 8 RECORDS?
       JR NZ,  NXTREC          ;NO, CONTINUE
;
SRCDON  LD HL, SRCBUF           ;START AT BEGINNING
       JR      NXTCHR
;
;
       ORG     2800H           ;I/O BUFFERS
SRCBUF  DEFS    1024
LSTBUF  DEFS    1024
HEXBUF  DEFS    1024
;
       END