;************* THIS IS FILE NSCPM48.ASM ****************
;
;THIS PROGRAM IS THE INTERFACE FROM NORTHSTAR
;BASIC (SPECIAL VERSION AT 800H) RELEASE 4
;TO CPM V1.4, V2.0, AND CDOS V1.07.  11/20/78
;
;       REV 1   4/8/79   GOT IT TO WORK WITH MINOR LIMITATIONS
;       REV 2   4/14/79  -CREATE FULLY IMPLEMENTED WITH BLOCK SIZE
;                        -FIXED DIRECTORY LIST BUG
;                        -WILL CLOSE UP TO 8 OPEN FILES VERSUS 4 (BUG)
;                        -ADDED PUNCH DEVICE AS DEV #2 IN BASIC
;       REV 3   5/10/79  -MODIFIED CREATE ROUTINE TO NOT CAUSE BDOS
;                         ERROR WHEN CREATING A FILE WHOSE SIZE IS
;                         LARGER THAN CPM
;                        -RETURN DISK NUMBER WHEN DIRECTORY ENTRY NOT FOUND (BUG)
;                        -DISK/DIRECTORY FULL MESSAGE ON CONSOLE WHEN CREATING
;                         SINCE NS BASIC WON'T ERROR WITH THIS INTERFACE.
;                         JUMP TO WARM BOOT AFTER MESSAGE DISPLAYED.
;                        -ADD VERIFY AFTER WRITE & ERROR MESSAGE JUMP TO JUMP
;                         TABLE SINCE BASIC INSERTS A JUMP ADDRESS AT INIT
;                        -INIT TO JUMP TO WBOOT SINCE BASIC MODIFIES ANYWAY
;       REV 4   5/28/79  -FIXED MEMSET TO ERROR IF SET IN CPM AREA
;                        -ZEROES OUT A REG IN FCB0 ROUTINE (BUG)
;                        -PATCHES BASIC TO REMOVE LIMIT ON 350 BLOCK SIZE
;                        -AUTO PATCH OF LINE LENGTH=132
;                        -AUTO PATCH OF DELETE ECHO CHAR TO BACKSPACE (CTL-H)
;       REV 5   6/10/79  -MODIFIED SRCHMOR SUBROUTINE FOR CDOS COMPATIBLITY.
;                         DOES NOT AFFECT REV 4.
;                        -REVISED COMMENTS ON CDOS PATCH AND COMPATIBILITY
;       REV 6   9/27/79  -ADDED VARIABLES TO ALLOW CHANGE IN STARTING MEMORY
;                         ADDRESS FROM STD CPM TO TRS80 CPM
;       REV 7   10/29/79 -CORRECTED CLOSE WHEN WRITING A TYPE 3 BLOCK.
;                        -RESTORED NEXT RECORD WHEN CROSSING EXTENTS FOR CDOS.
;                        -CORRECTED TYPO FOR ONE OF THE CDOS PATCHES.
;       REV 8   11/20/79 -MADE INTERFACE COMPATIBLE WITH CPM V2.0.
;                        -INCREASED MAXIMUM FILE SIZE TO 4096 256-BYTE BLOCKS
;                         FOR 8" QUAD DENSITY. (1 MEGABYTE FILE SIZE)
;                        -PUT . IN FRONT OF FILE TYPE WHEN CATALOGING.
;
;THIS INTERFACE WILL WORK WITH CPM OR ANY OF ITS
;DERIVATIVES, E.G., IMDOS, CDOS (V1.07 OR LATER), ETC
;
;NOTE:  CDOS V1.07 MUST BE PATCHED IN 4 PLACES; THIS IS INDICATED BY THE [[ ]]
;       IN THE REMARKS.
;
;
;       *****************************************
;       *                                       *
;       * YOU MUST MOVE BASIC TO JUST ABOVE THIS*
;       * INTERFACE.  USE THE BASIC MOVER IN    *
;       * THE NORTHSTAR USERS GROUP (REL 4)     *
;       *                                       *
;       * BASIC MOVER PARAMETERS: STD   TRS80   *
;       *                                       *
;       *       BASIC START ADDR: 800   4A00    *
;       *       ROM ADDRESS:     E800   E800    *
;       *       DOS START ADDR:    F6   42F6    *
;       *       END OF MEMORY ADDR: XXXX        *
;       *               X=DON'T CARE            *
;       *****************************************
;
;****************************************************************************
;
;       RELEASE 4 INCOMPATIBILITIES (THRU REV 4):
;
;               1. RND(-1) WILL NOT GENERATE RANDOM NUMBERS
;
;       SOFTWARE NOTES:
;
;               1. STORAGE ALLOWED FOR ONLY 10 OPEN FILES
;               2. DO NOT HAVE FILES WITH THE SAME NAME WITH A SINGLE
;                       CHARACTER TYPE.  IF MORE THAN ONE, FUNCTIONS WILL
;                       OPERATE ON 1ST ENTRY FOUND IN DIRECTORY
;                       (EXCLUDING SAVE, NSAVE, LOAD, APPEND)
;               3. WHEN CREATING A FILE AND THE DISK OR DIRECTORY IS FULL,
;                       THE MESSAGE 'DISK/DIR FULL' IS DISPLAYED ON THE CONSOLE
;                       NOT THE NORTH STAR ERROR MESSAGE.  THIS INTERFACE
;                       IMPLEMENTATION DOES NOT ALLOW ERROR TRAPPING OF DISK
;                       FULL WHEN CREATING.  IT DOES NOT STOP EITHER.
;                       JUMPS TO WARM BOOT AFTER PRINTING MESSAGE.
;               4. WILL NOT ALLOW MEMSET INTO CPM AREA.  GIVES ARGUMENT ERROR
;                       IF ATTEMPTED.  WHEN BASIC IS BOOTED, MEMSET AT 809H IS
;                       AUTOMATICALLY SET TO THE MAX RAM UP TO BDOS-1 IN CPM.
;
;
;***************************************************************************
;
;----------------------------------------------------
;FCB AND NORTHSTAR DISK PARAMETERS FORMAT
;
;  FIELD        POSITION        DESCRIPTION
;
;    ET             0           ENTRY TYPE
;    FN            1-8          FILE NAME
;    FT            9-11         FILE TYPE
;    EX             12          FILE EXTENT (0-15)
;                 13-14         NOT USED
;    RC             15          RECORD COUNT (0-128)
;    DM           16-31         DISK MAP (16 1K BLKS)
;    NR             32          NEXT RECORD
;    DA           33-34         NS DISK ADDRESS
;    BL           35-36         NUMBER OF 256-BYTE BLOCKS
;    TY             37          NS FILE TYPE
;    PB             38          NO. OF BASIC PROGRAM BLKS
;                 39-40         FILE PARAMETERS, NOT USED
;    DN             41          DRIVE NUMBER FILE IS ON
;-------------------------------------------------------
;
;******CONDITIONAL ASSEMBLIES ******
;
TRUE    EQU     -1
FALSE   EQU     NOT TRUE
;
;
;***** EQUATES *****
;
ADDRZ   EQU     0               ;FIRST ADDRESS OF MEMORY
                               ;(STD CPM=0; TRS80 CPM=4200H)
IFBASE  EQU     ADDRZ+100H
BASIC   EQU     IFBASE+700H
WBOOT   EQU     ADDRZ
BDOS    EQU     ADDRZ+5
;
;*** CPM SYSTEM CALL EQUATES ***
;
PRINT   EQU     9
SEARCH  EQU     17
NEXT    EQU     18
;
;*** BIOS JUMP TABLE RELATIVE ADDRESSES (RELATIVE TO WARM BOOT @ ADDR 6,7) ***
;
CONST   EQU     3
CONIN   EQU     6
CONOT   EQU     9
LIST    EQU     0CH
PUNCH   EQU     0FH
;
CTLC    EQU     3
CTLS    EQU     13H             ;FREEZE SCREEN KEY
;
PRNTNO  EQU     1               ;NS DEVICE NUMBER FOR PRINTER; CALLS CPM LIST
PNCHNO  EQU     2               ;NS DEVICE NUMBER FOR PUNCH
;
NOFCBS  EQU     10
FCBSIZ  EQU     42              ;NO. OF BYTES IN EXTENDED FCB
CR      EQU     0DH
LF      EQU     0AH
ERRMSG  EQU     0               ;DUMMY ADDRESS
ARGERR  EQU     BASIC+197H      ;ENTRY POINT TO BASIC FOR 'ARGUMENT ERROR'
;
;*** NORTH STAR BASIC PARAMETERS ***
;
MEMEND  EQU     9               ;BASIC OFFSET FOR END OF MEMORY
PGMPTR  EQU     BASIC+2BB9H     ;NS BASIC PROGRAM POINTER
;
;*** THE FOLLOWING EQUATES ARE FOR DETERMINING WHICH DISK FUNCTION IS
;       CALLING DLOOK.  THEY ARE THE LEAST SIGNIFICANT ADDRESS BYTE FOR EACH
;       FUNCTION. ***
;
TY3ADR  EQU     42H             ;OPEN TYPE 3 FILE
LDADR   EQU     7CH             ;LOAD OR APPEND
DESADR  EQU     0C4H            ;DESTROY
FLADR   EQU     0F7H            ;FILE
CRADR   EQU     98H             ;CREATE
NSADR   EQU     0BBH            ;NSAVE
NSCR2   EQU     6               ;NSAVE OR CREATE FOR THE 2ND TIME
DESDWR  EQU     0D3H            ;DESTROY FILE
SAVADR  EQU     41H             ;SAVE
;
;**************************************************************************
;
;**** PATCHES TO BASIC MEMSET ROUTINE ****
;
       ORG     BASIC+519H
;
       XCHG                    ;PUT MEMSET ADDR IN DE
       LHLD    BDOS+1          ;GET BEGINNING OF CPM ADDR
       JMP     MEMSET
MEMSETR EQU     $               ;PATCH IN INTERFACE JUMPS TO HERE
;
;**** PATCH BASIC TO REMOVE 350 BLOCK SIZE LIMIT ****
;
       ORG     BASIC+05F6H
;
       LXI     H,-4096         ;SHOULD SUFFICE FOR 8" QD
;
;**** PATCH BASIC TO ECHO BACKSPACE (CTL-H) ON DELETE ****
;
       ORG     BASIC+17H
;
       DB      8
;
;**** PATCH BASIC TO LINE LENGTH=132 ****
;
       ORG     BASIC+0EH
;
       DB      132
;
;
;***************************************************************************
;
       ORG     IFBASE
;
;**** JUMP TABLE; MATCHES NORTHSTAR DOS ****
;
       JMP     BSINIT
       JMP     COUT            ;BEGINNING OF EQUIV NS DOS JUMP TABLE
       JMP     CIN
       JMP     INIT
       JMP     CONTC
       JMP     ERRMSG          ;BASIC ERROR MESSAGE; BASIC CHANGES AT INIT
       JMP     DLOOK
       JMP     DWRIT
       JMP     DCOM
       JMP     DLIST
       JMP     WBOOT
RWCHK:  DB      0               ;VERIFY; PUT HERE FOR TABLE INTEGRITY
       JMP     ERRMSG          ;BASIC ERROR MESSAGE; BASIC CHANGES AT INIT
;
;**** CHECK FOR MEMSET ****
;
MEMSET: DCX     H               ;ONE LESS
       XRA     A               ;CLEAR CARRY
       MOV     A,L
       SBB     E               ;MEMSET ADDR-MAX CPM MEM ADDR
       MOV     A,H
       SBB     D
       XCHG                    ;HL=MEMSET ADDR
       JC      ARGERR          ;JUMP TO BASIC'S ARGUMENT ERROR
       JMP     MEMSETR
;
;**** SET UP BASIC END OF MEMORY ****
;
BSINIT: LHLD    BDOS+1
       DCX     H               ;ONE LESS
       SHLD    BASIC+MEMEND
       JMP     BASIC
;
;**** CONSOLE OUT INTERFACE ****
;
COUT:   PUSH    B
       PUSH    D
       PUSH    H
       ORA     A               ;A=0 FOR CONSOLE?
       CZ      CONIT
       CPI     PRNTNO          ;SHALL WE SEND TO LIST DEVICE?
       CZ      LISTIT
       CPI     PNCHNO          ;PUNCH DEVICE NUMBER?
       CZ      PNCHIT
       CPI     PNCHNO+1
       CNC     CONIT           ;DEFAULT TO CONSOLE FOR ALL OTHER DEVICES
       MOV     C,B
       CALL    CBIOS
       POP     H
       POP     D
       POP     B
       MOV     A,B
       RET
;
CONIT:  MVI     E,CONOT         ;CONSOLE OUT FOR DEV #0
       RET
LISTIT: MVI     E,LIST
       RET
PNCHIT: MVI     E,PUNCH
       RET
;
;**** CONSOLE IN INTERFACE ****
;
CIN:    PUSH    B
       PUSH    D
       PUSH    H
       MVI     E,CONIN         ;CONSOLE IN FOR ALL DEV #'S
       CALL    CBIOS
       POP     H
       POP     D
       POP     B
       RET
;
;**** CONTROL-C INTERFACE ****
;
CONTC:  MVI     E,CONST
       CALL    CBIOS
       CPI     0FFH
       RNZ
       MVI     E,CONIN
       CALL    CBIOS
       CPI     CTLS            ;FREEZE THE SCREEN?
       CZ      CIN
       CPI     CTLC
       RET
;
CBIOS:  MVI     D,0
CBIOS2: LHLD    WBOOT+1
       DAD     D
       PCHL
;
;**** INITIALIZATION INTERFACE ****
;
INIT:   RET
;
;
;**** DIRECTORY LOOK UP INTERFACE ****
;
;       INPUT:  A=DISK NO.  HL=NAME IN RAM
;       OUTPUT: A=DISK NO.
;               CARRY=1 IF FAILURE & HL=1ST FREE DISK ADDR
;               CARRY=0 IF SUCCESS & HL=8TH BYTE OF DOS ENTRY IN RAM
;
DLOOK:  STA     DISKNO          ;SAVE DR#
       POP     D               ;GET RETURN ADDRESS
       PUSH    D               ;SAVE IT FOR LATER
       MVI     A,NSCR2         ;2ND NSAVE OR CREATE?
       CMP     E
       JZ      FOOLIT          ;FOOLIT; SAY OK
       PUSH    H               ;SAVE NS NAME PTR
       XRA     A
       STA     EXTENT          ;ZERO EXTENT
       CALL    FCB0            ;ZERO FCB AREA
       POP     H               ;RESTORE NS NAME PTR
       MVI     A,80H           ;FOOL NS BASIC; MAX PGM SIZE=32K
       STA     NSPARMS+5       ;SAVE IT
       LXI     D,FCB+1         ;POINT TO NAME LOC
       MVI     B,8             ;NAME CHARS
NEXTC:  MOV     A,M
       CPI     0DH             ;PUT IN SPACES IF CR
       JZ      SPACES
       CPI     ' '
       JZ      SPACES
       CPI     ','
       JZ      DRVNO
       STAX    D
       INX     H
       INX     D
       DCR     B
       JNZ     NEXTC
       MOV     A,M
       CPI     ','
       JNZ     SEL
DRVNO:  INX     H
       MOV     A,M
       CPI     '4'             ;IF DRIVE #>=4 THEN ERROR
       JNC     ERROR
       CPI     '1'             ;IF DRIVE #<0 THEN ERROR
       JC      ERROR
       ANI     3
       STA     DISKNO
       XRA     A
       CMP     B
       JZ      SEL
SPACES: MVI     A,20H
       STAX    D
       INX     D
       DCR     B
       JNZ     SPACES          ;ENOUGH SPACES?
SEL:    CALL    SELECT          ;SET UP DEFAULT BUFFER @ 80H
       CALL    SETBUF0
OPEN:   MVI     A,'?'           ;AMBIGUOUS FILE TYPE
       STA     FCB+9           ;SAVE IN FCB
       LXI     H,2020H         ;BLANKS FOR NO AMBUGUITY
       SHLD    FCB+10
       POP     H               ;GET RETURN ADR
       PUSH    H               ;SAVE IT AGAIN
       MOV     A,L
       CPI     TY3ADR          ;OPEN TYPE<>2 CALLING?
       JZ      OPEN3
       CPI     CRADR           ;CREATE CALLING?
       JZ      OPEN0
       CPI     FLADR           ;FILE CALLING?
       JZ      OPEN0
       CPI     DESADR          ;DESTROY CALLING?
       JZ      OPEN0
       MVI     A,2             ;TYPE 2 ONLY FOR SAVE, NSAVE, LOAD, APPEND
       STA     FILTYP
       ADI     30H
       STA     FCB+9           ;REMOVE AMBIGUITY
       XRA     A
       STA     OLD1
       LXI     H,FCBBAS
       LXI     B,NOFCBS*FCBSIZ ;ZERO TYPE 3 FCBS
       CALL    MOVEIT
       JMP     OPEN0
OPEN3:  MVI     A,3             ;SAVE TYPE=3 FOR OPEN
       STA     FILTYP
       CALL    SETTYP3         ;SET UP FCB FOR TYPE <>2 OPEN
OPEN0:  CALL    OPENIT          ;OPEN FILE; FIND THE SAME
       CPI     0FFH            ;CHECK FOR NO ENTRY
       JZ      WRTYP2          ;TEST FOR SAVE BEFORE ERROR
       MVI     C,17            ;GET FIRST DIRECTORY ENTRY
       CALL    READ2
       LXI     H,ADDRZ+80H+9   ;[[[[ LXI D,9 ]]]]
                               ;GET FILE TYPE FROM DIRECTORY (1ST ONE FOUND)
       CALL    DIRENT          ;[[[[ DAD D   NOP   NOP ]]]]
       MOV     A,M
       LXI     D,9             ;REMOVE AMBIGUITY; SAVE TYPE IN DIR
       CALL    ADD16
       SUI     30H
       LXI     D,37            ;SAVE TYPE IN NS PARMS
       CALL    ADD16
       POP     H               ;GET RETURN ADDR
       PUSH    H
       MOV     A,L
       CPI     DESADR          ;DESTROY?
       JZ      DESTROY
       CPI     TY3ADR          ;OPEN TYPE <>2?
       JNZ     FOOLIT          ;FOR SAVE, FILE, LOAD, APPEND, CREATE, NSAVE
BLKS:   LHLD    CURFCB          ;HL=PTR TO CURRENT FCB
       LXI     D,15            ;MOVE PTR TO REC CNT IN FCB
       DAD     D
       MOV     A,M             ;GET REC CNT IN FCB
       STA     RECCNT          ;SAVE IT
       CPI     80H             ;REC CNT = 128 BLKS?
       CZ      SRCHMOR         ;FIND ALL EXTENTS IF IT IS
       LDA     EXTENT          ;GET CURRENT EXTENT
       MVI     H,0             ;COMPUTE EQUIV NS BLKS; * 64
       MOV     L,A
       DAD     H
       DAD     H
       DAD     H
       DAD     H
       DAD     H
       DAD     H               ;HL=# EXTENTS * # 256 BLKS PER EXTENT
       LDA     RECCNT          ;GET REC CNT
       RAR                     ;DIVIDE BY 2
       JNC     BLKS1
       INR     A               ;ROUND UP
BLKS1:  ANI     7FH
       MOV     E,A             ;DE=# 256 REC COUNT
       XRA     A
       MOV     D,A             ;D=0
       DAD     D               ;HL=ALLOCATED NS BLKS=(#EXT*256BLKS/EXT)+#256 REC CNT IN LAST EXT
       PUSH    H               ;SAVE IT
BLKS2:  LXI     D,36
       LHLD    CURFCB
       DAD     D               ;PTR TO NS BLKS IN FCB
       POP     D               ;DE=ALLOCATED NS BLKS
       MOV     M,D             ;SAVE BLKS IN FCB
       DCX     H               ;MOVE PTR BACK
       MOV     M,E
       DCX     H               ;MOVE PTR TO NS PARAMETERS IN FCB
       DCX     H
BLKS3:  LDA     DISKNO          ;A=CURRENT DISK NO.
       ORA     A               ;ZERO CARRY FOR NS RETURN
       RET
;
;**** INTERFACE TO NORTHSTAR DCOM ROUTINES ****
;
;       INPUT:  A=NO OF BLOCKS  B=COMMAND (0=WR, 1=RD, 2=VERIFY)
;               C=DISK NO.      DE=STARTING RAM ADDRESS
;               HL=STARTING DISK ADDRESS
;       OUTPUT: CARRY=1 MEANS ARGUMENTS ILLEGAL
;
DCOM:   STA     BLKCNT          ;SAVE # BLKS
       SHLD    DISKADR         ;SAVE NS DISK ADR
       LXI     H,-80H
       DAD     D
       SHLD    BUFADR          ;SAVE BUFFER ADR-128
       MOV     A,B
       STA     WR              ;SAVE WRITE OR READ
       MOV     A,C
       STA     DISKNO          ;SAVE DR#
SEL1:   CALL    SELECT
       LDA     FILTYP
       CPI     2               ;SKIP OFFSET CALC, IF TYPE 2
       JZ      WRRD
RECNUM: CALL    FNDFCB
       LXI     D,33
       DAD     D               ;HL=PTR TO NS BASE DISK ADR
       MOV     E,M
       INX     H
       MOV     D,M             ;DE=BASE DISK ADR
       LHLD    DISKADR         ;HL=CURRENT, DE=BASE
       MOV     A,L             ;CURRENT-BASE
       SUB     E
       MOV     L,A
       MOV     A,H
       SBB     D
       MOV     H,A             ;HL=ADDR OFFSET
       DAD     H               ;* 2
       MOV     A,L
       ANI     7FH             ;A=# 128 BYTE BLKS
       DAD     H               ;H=EXTENT
       MOV     B,H             ;TEMP STORE; B=EXTENT
       CALL    ADD16X          ;PT TO NEXT REC & SAVE IT IN NEXT RECORD
       STA     DEVNXT          ;SAVE NEXT REC FOR LATER
       LXI     D,-20           ;EXTENT ADDR WRT PTR
       DAD     D               ;PTR TO EXTENT IN FCB
       MOV     A,B             ;A=EXT #
       STA     EXTENT          ;SAVE IT
       CMP     M               ;SAME ONE?
       CNZ     CLSOPN          ;IF NOT CALL CLOSE/OPEN SUBR
WRRD:   LDA     WR
       ORA     A
       JZ      WRITE
       CPI     1
       JNZ     ERROR1
READ:   LDA     BLKCNT
       ORA     A
       RZ                      ;CY=0 FOR BASIC RETURN
       DCR     A
       STA     BLKCNT
       CALL    SETBUF          ;GET 1ST 128-BYTE BLK
       CALL    READIT
       CALL    EOF
       CALL    SETBUF          ;GET 2ND 128-BYTE BLK
       CALL    READIT          ;TO EQUAL 1 256-BYTE BLK
       CALL    EOF
       JMP     READ
;
WRITE:  LHLD    BLKCNT          ;GET BLOCK COUNT
       XRA     A               ;CHECK FOR LAST ONE
       CMP     L
       JNZ     WRITE1
       CMP     H
       JZ      CLOSE
WRITE1: DCX     H
       SHLD    BLKCNT          ;SAVE FOR NEXT TIME
       CALL    SETBUF
       CALL    WRITEIT
       CALL    SETBUF
       CALL    WRITEIT
       JMP     WRITE
;
;****DESTROY A FILE ****
;
DESTROY:CALL    DELIT
       JMP     BLKS3
;
FOOLIT: LXI     H,80H           ;FOOL NSBASIC; MAX PROGRAM SIZE=32K
       PUSH    H               ;SAVE IT BLKS2
       JMP     BLKS2
;
WRTYP2: POP     H               ;GET RETURN ADDR
       PUSH    H               ;SAVE IT FOR RETURN
       MOV     A,L             ;CHECK FOR LSA MATCH
       CPI     CRADR           ;CREATE
       CZ      CRFLAG          ;SET CREATE FLAG
       CPI     NSADR           ;NSAVE
       MVI     A,2             ;ALWAYS NSAVE TYPE 2
       CZ      NSAVE
ERROR:  LXI     H,0             ;FOOL NS BASIC; NEXT DISK ADDR=0
       LDA     DISKNO          ;DISK NUMBER FOR ERROR RETURN
ERROR1: STC                     ;CY=1 FOR FILE NOT FOUND ERROR
       RET
;
NSAVE:  STA     NSPARMS+4       ;SAVE FILE TYPE IN NS DIRECTORY
CRNSAV: ADI     30H             ;CONVERT TO ASCII FOR CPM
       STA     FCB+9           ;SAVE IN FCB
       CALL    DELIT           ;DELETE, MAKE, THEN OPEN FOR NSAVE & CREATE
MAKEIT: CALL    SETBUF0
       MVI     C,22
       CALL    READ2
       CPI     255             ;JUMP IF DIRECTORY FULL
       JZ      DSKFUL
OPENIT: CALL    SETBUF0
       MVI     C,15
       JMP     READ2
;
CRFLAG: MVI     A,1
       STA     FUNFL           ;SET UP DWRIT FUNCTION FLAG
       RET
;
;**** INTERFACE TO DIRECTORY LIST ROUTINE ****
;       INPUT:   A=DISK NUMBER      L=DEVICE NUMBER
;
DLIST:  PUSH    H
       STA     DISKNO
       CALL    SELECT
       POP     H
       MOV     A,L
       STA     DEVNXT
       CALL    RESET
       CALL    SETBUF0
       CALL    FCB0            ;ZERO FCB AREA
       LXI     H,FCB           ;NAME & TYPE = AMBIGUOUS (??????)
       MVI     B,11            ;NUMBER OF CHARS IN NAME & TYPE
       MVI     A,'?'
DLIST0: INX     H
       MOV     M,A
       DCR     B
       JNZ     DLIST0
       CALL    CRLF            ;PRINT CR AND LF
       MVI     C,SEARCH        ;FIND FIRST ENTRY
       CALL    DNEXT0
       CALL    DIRNT           ;[[[[ NOP   NOP   NOP ]]]
                               ;WHICH ONE OF 4; POINT TO IT IN BUFFER
       CALL    PRNTIT          ;PRINT OUT DIRECTORY ENTRY
DLIST1: CALL    DNEXT           ;GET ALL OTHERS
       CALL    DIRNT           ;[[[[ NOP   NOP   NOP ]]]]
                               ;WHICH ONE OF 4; POINT TO IT IN BUFFER
       CALL    PRNTIT          ;PRINT OUT
       JMP     DLIST1          ;GET MORE
;
PRNTIT: LXI     D,12            ;PT TO FILE EXTENT
       DAD     D
       XRA     A
       CMP     M
       RNZ                     ;DON'T PRINT EXTENTS >0
       LDA     DISKNO          ;PRINT DRIVE NUMBER
       ADI     40H             ;CONVERT TO A,B,C,D,ETC
       MOV     B,A
       CALL    DPRNT
       MVI     B,':'
       CALL    DPRNT
       LXI     B,-12           ;MOVE POINTER BACK TO BEGINNING
       DAD     B
       MVI     D,8             ;PRINT NAME
       CALL    DLIST3
       MVI     B,'.'           ;PRINT . BEFORE TYPE
       CALL    DPRNT
       MVI     D,3             ;PRINT TYPE
       CALL    DLIST3
       MVI     C,6
SPCIT:  CALL    DPRNT0          ;PRINT 6 SPACES
       DCR     C
       JNZ     SPCIT
       LDA     ACROSS
       DCR     A               ;PRINT 3 ACROSS?
       STA     ACROSS
       CZ      CRLF            ;START NEW LINE
       RET
;
DNEXT:  MVI     C,NEXT
DNEXT0: LXI     D,FCB
       CALL    BDOS
       CPI     0FFH
       RNZ
       CALL    CRLF            ;MAKE DISPLAY PRETTY
       POP     H               ;CLEAR OUT STACK
       RET                     ;EXIT DIRECTORY LIST ROUTINE
;
DLIST3: INX     H               ;PRINT NO. OF BYTES SPECIFIED IN D
       MOV     B,M
       CALL    DPRNT
       DCR     D
       JNZ     DLIST3
       RET;
;
CRLF:   MVI     B,CR            ;PRINT CR & LF
       CALL    DPRNT
       MVI     B,LF
       CALL    DPRNT
RESET:  MVI     A,3
       STA     ACROSS          ;RESET NUMBER ACROSS SCREEN
       RET
;
DPRNT0: MVI     B,' '           ;PRINT SPACE
DPRNT:  LDA     DEVNXT          ;PRINT ON SELECTED DEVICE
       JMP     COUT
;
;
;***** SELECT A DRIVE *****
;
SELECT: LDA     DISKNO
       DCR     A
       MVI     C,14
       MOV     E,A
       JMP     BDOS
;
;*** FIND AN EXISTING TYPE 3 FCB IF POSSIBLE ***
;
SETTYP3:MVI     B,NOFCBS        ;B=# OPEN TYPE 3 FILES
       LXI     H,FCBBAS        ;HL=FCBBAS
RT0:    SHLD    CURFCB          ;SAVE IT IN CURRENT FCB
       PUSH    H               ;SAVE IT FOR LATER
       MVI     C,8             ;8 CHARS IN FILE NAME
       LXI     D,FCB           ;SET UP FCB FOR COMPARISON
RT1:    INX     D               ;MOVE PTR TO 1ST CHAR IN NAME
       INX     H               ;DITTO
       LDAX    D               ;FILE NAME MATCH (8 CHARS) & DRIVE #
       CMP     M
       JNZ     NXTBLK
       DCR     C
       JNZ     RT1
       LXI     D,33            ;PTR OFFSET TO DRIVE # IN FCB
       DAD     D               ;MOVE PTR TO DRIVE #
       LDA     DISKNO          ;GET CURRENT DRIVE #
       CMP     M               ;SAME ONE?
       JNZ     NXTBLK          ;MOVE ON IF NOT
       LXI     D,-29           ;PT TO FCB EXTENT
       DAD     D
       XRA
A
       MOV     M,A             ;ZERO OUT EXTENT IN FCB BEFORE OPENING
       POP     B               ;CLEAR OUT STACK
       RET

NXTBLK: POP     H
       LXI     D,FCBSIZ
       DAD     D
       DCR     B
       JNZ     RT0
NEW1:   LDA     OLD1            ;NO MATCH; MAKE NEW ONE
       CPI     NOFCBS          ;NO MORE FCB SPACE?
       CZ      FCBTOP
       INR     A
       STA     OLD1
       LXI     D,FCBSIZ
       LXI     H,FCBBAS-FCBSIZ
NXTBLK1:DAD     D               ;SET UP PTR IN HL
       DCR     A               ;MOVE FCBBAS UNTIL END FOUND
       JNZ     NXTBLK1
       SHLD    CURFCB
       MVI     B,FCBSIZ
       LXI     D,FCB           ;MOVE FCB TO FCB AREA
MOVIT:  LDAX    D
       MOV     M,A
       INX     H
       INX     D
       DCR     B
       JNZ     MOVIT
       LDA     OLD1
       DCR     A
       RLC                     ;4K INCREMENTS
       RLC
       RLC
       RLC
       LXI     D,34
       CALL    ADD16           ;ADD OFFSET FOR NS HI ORDER ADDR
       LXI     D,7             ;PTR OFFSET TO DR # IN FCB
       DAD     D               ;MOVE PTR
       LDA     DISKNO          ;GET CURRENT DR #
       MOV     M,A             ;SAVE IT IN FCB
       RET
;
FCBTOP: XRA     A
       RET
;
;*** SEARCH FOR ALL EXTENTS ***
;
SRCHMOR:LHLD    CURFCB          ;SEARCH FOR ALL EXTENTS
       LXI     D,12            ;PT TO EXTENT
       DAD     D
       MVI     C,18            ;SEARCH FOR NEXT DIR ENTRY
SRCH0:  PUSH    H               ;SAVE PTR TO EXTENT
       LDA     EXTENT          ;GET EXTENT
       INR     A               ;A=EXT+1
       MOV     M,A             ;NEW EXT=EXT+1
       CALL    READ2
       LXI     H,ADDRZ+80H+15  ;[[[[ LXI D,0FH ]]]]
                               ;PT TO REC CNT IN DEFAULT FCB
       CALL    DIRENT          ;[[[[ DAD D   NOP   NOP ]]]]
                               ;PT TO PARAMETER IN DIRECTORY
       LDA     EXTENT          ;INCREMENT EXTENT
       INR     A
       STA     EXTENT          ;SAVE NEW EXTENT
       MOV     A,M
       STA     RECCNT          ;SAVE LAST RECORD COUNT
       CPI     80H             ;IS EXTENT FULL?
       MVI     C,18            ;SEARCH FOR NEXT DIR ENTRY
       POP     H
       JZ      SRCH0           ;GET ANOTHER EXTENT IF IT IS
SRCH1:  XRA     A               ;ZERO EXTENT IN FCB
       MOV     M,A
       RET
;
                               ;[[[[ SUBROUTINE NOT USED BY CDOS VERSION ]]]]
DIRNT:  LXI     H,ADDRZ+80H     ;SET UP POINTER TO BUFFER
DIRENT: ANI     3               ;A=LOC OF DIR ENTRY IN BUFFER (0-3)
       RRC ! RRC ! RRC         ;MULT BY 32
       ADD     L
       MOV     L,A             ;HL=PTR DESIRED DIRECTORY ENTRY
       RET
;
;*** READ A TYPE 2 OR 3 BLOCK ***
;
READIT: MVI     C,20
READ2:  LHLD    CURFCB
       XCHG
GOBDOS: JMP     BDOS
;
;
;*** FIND AN EXISTING FCB USING NS PARAMETERS FROM BASIC ***
;
FNDFCB: LXI     B,FCBSIZ
       LDA     DISKADR+1       ;A=CURRENT HI BYTE DISK ADR
       MOV     E,A             ;E=CURRENT ADR
       LXI     H,FCBBAS+34
       MOV     A,M             ;A=BASE
       ADI     0FH             ;16 * 256 BLKS OF 256 BYTE EACH, MAX
       CMP     E
       JNC     FNDFCB1         ;IF CUR (E)<=BASE+0FH (A), THEN 0-FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;1000-1FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;2000-2FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;3000-3FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;4000-4FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;5000-5FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;6000-6FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;7000-7FFF
       CALL    ADRCK
       JNC     FNDFCB1         ;8000-8FFF
       DAD     B               ;9000-9FFF
;
FNDFCB1:LXI     D,-34
       DAD     D               ;HL=PTR TO FCB IN FCB AREA
       SHLD    CURFCB
       RET
;
ADRCK:  DAD     B
       MOV     A,M
       ADI     0FH
       CMP     E
       RET
;
;*** WRITE TO DISK ***
;
WRITEIT:MVI     C,21
       CALL    READ2
       ORA     A               ;WRITE IS OK IF A=0
       RZ
DSKFUL:                         ;IF DIRECTORY FULL, DISK FULL OR FILE
       POP     H               ;EXTENSION ERROR, GIVE INVALID ARGUMENT ERROR
       STC                     ;CY=1 FOR BASIC ERROR RETURN
       RET
;
;*** SET UP DMA ADDRESS ***
;
SETBUF: LDA     FUNFL           ;ARE WE CREATING?
       ORA     A
       JNZ     SETBUF0         ;SKIP INCREMENTING BUFFER IF WE ARE
       LHLD    BUFADR
       LXI     D,80H
       DAD     D
       SHLD    BUFADR
       XCHG
       JMP     SETBUF1
SETBUF0:LXI     D,ADDRZ+80H     ;SET UP DEFAULT BUFFER
SETBUF1:MVI     C,26
       JMP     BDOS
;
;*** DIRECTORY WRITE INTERFACE ***
;       INPUT: HL=POINTER TO NS PARAMETERS
;
;       THIS ROUTINE IS ONLY USED FOR CREATE COMMAND TO GET FILE TYPE FROM
;       NORTH STAR DISK PARAMETERS AND TO RESERVE DISK SPACE FOR THE FILE.
;       A DUMMY FILE IS CREATED BY WRITING OUT WHATEVER IS IN RAM FROM ADDRZ+
;       80H TO ADDRZ+0FFH
;
DWRIT:  LDA     FUNFL           ;CHECK IF CREATE; RETURN IF NOT
       ORA     A
       RZ
       XRA     A
       STA     FCB+32          ;NEXT RECORD =0; CAUSED BY NS BASIC
       LHLD    NSPARMS+2       ;GET BLOCK SIZE
       SHLD    BLKCNT          ;SAVE IT FOR WRITING
       LDA     NSPARMS+4       ;GET TYPE
       CALL    CRNSAV          ;PUT TYPE IN FCB AND MAKE FILE
       CALL    WRITE           ;SAVE DUMMY FILE
       JC      NOSPAC          ;PRINT DISK FULL ERROR SINCE BASIC WON'T
       XRA     A
       STA     FUNFL           ;FUNCTION FLAG=0
       RET
;
NOSPAC: MVI     C,PRINT         ;DISK OR DIRECTORY FULL MESSAGE ON CONSOLE
       LXI     D,EMSG
       CALL    BDOS
       JMP     WBOOT           ;EXIT BASIC TO CPM AFTER ERROR MESSAGE
;
;
;*** CLOSE, OPEN, AND MAKE A DIRECTORY ENTRY ***
;
CLSOPN: CALL    CLOSE0          ;CLOSE CURRENT EXTENT
       LDA     EXTENT
       LXI     D,12
       CALL    ADD16
       CALL    OPENIT          ;OPEN NEW EXTENT
       CPI     0FFH
       CZ      MAKEIT          ;IF NO EXTENT,MAKE ONE
       LDA     DEVNXT          ;GET NEXT REC
ADD16X: LXI     D,32
ADD16:  LHLD    CURFCB          ;MOVE PTR WRT TO OFFSET IN DE
       DAD     D
       MOV     M,A
       RET
;
;*** PROCESS END OF FILE ***
;
EOF:    CPI     1               ;ALL BLKS READ?
       RC                      ;RETURN IF <1
       CPI     2               ;GIVE INVALID ARGUMENT ERROR
       JZ      ERROR1          ;IF READING UNWRITTEN RA DATA
       POP     H               ;CLEAR OUT RETURN
QUIT:   ORA     A               ;CY=0 FOR BASIC RETURN
       RET
;
;*** CLOSE A FILE ***
;
CLOSE:  LDA     FILTYP          ;CHECK FOR TYPE 3
       CPI     3               ;SPEED PROCESSING IF TYPE 3
       JNZ     CLOSE0          ;OTHERWISE CLOSE EVERY TIME
       LDA     FUNFL           ;CHECK IF CREATE
       ORA     A
       JNZ     CLOSE0
       LHLD    PGMPTR          ;GET CURRENT PROGRAM PTR
       CALL    BLANKS          ;IGNORE BLANKS
       CPI     '8'             ;FILE #>=8?
       JNC     QUIT            ;QUIT IF NOT LEGAL FILE #
       CPI     '0'             ;FILE#<0?
       JC      QUIT            ;QUIT IF NOT A LEGAL FILE #
       CALL    BLANKS          ;IGNORE BLANKS
       CPI     23H             ;# DELIMITER?
       JNZ     QUIT            ;QUIT IF NOT
       CALL    BLANKS          ;IGNORE BLANKS
       CPI     98H             ;CLOSE TOKEN?
       JNZ     QUIT            ;QUIT IF NOT
CLOSE0: CALL    SETBUF0
       MVI     C,16
       CALL    READ2
       ORA     A               ;CY=0 FOR BASIC RETURN
       RET
;
BLANKS: DCX     H
       MOV     A,M
       CPI     20H             ;IS IT A BLANK?
       JZ      BLANKS          ;SKIP IF IT IS
       RET
;
;*** DELETE A FILE ***
;
DELIT:  CALL    SETBUF0
       MVI     C,19
       JMP     READ2
;
;*** ZERO DEFAULT FCB ***
;
FCB0:   LXI     H,FCB           ;PT TO FCB
       SHLD    CURFCB          ;SAVE CURRENT FILE CONTROL BLOCK
       LXI     B,FCBSIZ
       XRA     A               ;A=0
MOVEIT: MOV     M,A             ;ZERO FCB
       INX     H
       DCX     B
       CMP     C
       JNZ     MOVEIT
       CMP     B
       JNZ     MOVEIT
       RET
;
;*** DISK/DIRECTORY FULL ERROR MESSAGE ***
;
EMSG:   DB      'DISK/DIR FULL',CR,LF,'$'
;
;***** BUFFER AREA *****
;
DISKNO: DB      1
DEVNXT: DS      1               ;TEMP SAVE FOR DEV # OR NEXT REC
CURFCB: DS      2
DISKADR:DS      2
WR:     DS      1
BLKCNT: DW      0
BUFADR: DS      2
RECCNT  DS      1
EXTENT: DS      1
FUNFL:  DB      0
FILTYP: DS      1
OLD1:   DB      0
ACROSS: DB      3
FCB:    DS      33
NSPARMS:DS      8

FCBBAS: DS      FCBSIZ
FCBBAS1:DS      FCBSIZ
FCBBAS2:DS      FCBSIZ
FCBBAS3:DS      FCBSIZ
FCBBAS4:DS      FCBSIZ
FCBBAS5:DS      FCBSIZ
FCBBAS6:DS      FCBSIZ
FCBBAS7:DS      FCBSIZ
FCBBAS8:DS      FCBSIZ
FCBBAS9:DS      FCBSIZ
;
       END     IFBASE