Files
RomWBW/Source/Images/d_fortran/u0/DSKDRV.MAC
2023-06-14 12:45:41 -04:00

860 lines
17 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TITLE DSKDRV - FORTRAN-80 DISK DRIVER
.8080
MAXLUN EQU 10 ;MAX # OF LUN'S ALLOWED
;BDOS FUNCTION CALLS, FCB OFFSETS
BDOS EQU 5 ;CP/M BDOS ENTRY POINT
.RSET EQU 13 ;DISK RESET
.SELCT EQU 14 ;SELECT DISK
.OPEN EQU 15 ;OPEN FILE
.CLOSE EQU 16 ;CLOSE FILE
.DELET EQU 19 ;DELETE FILE
.MAKE EQU 22 ;CREATE FILE
.STDMA EQU 26 ;SET DMA ADDRESS
FCB.FT EQU 9 ;FILE TYPE
FCB.EX EQU 12 ;EXTENT BYTE
FCB.RC EQU 15 ;RECORD COUNT BYTE
FCB.NR EQU 32 ;NEXT RECORD BYTE
FCB.RR EQU 33 ;RANDOM RECORD NUMBER (2.X)
FCBLEN EQU 36 ;FCB SIZE
SECSIZ EQU 128 ;SECTOR SIZE (RECORD LENGTH)
; GLOBAL DEFINITIONS
EXTRN $CPMVN,$CPMRF,$CPMWF,$BL,$BF,$ERR
EXTRN $IOERR,$REC,$UN,$LUNTB,$CLSFL
ENTRY $DSKER,$FLFLG,$MEMRY,DSKDRV
DSEG ;DATA AREA
; I/O ERROR CODE DEFNS
OBOVF EQU 016Q ;OUTPUT BUFFER LIMIT EXCEEDED
IRECER EQU 022Q ;INPUT RECORD TOO LONG
NOFILE EQU 236Q ;FILE NOT FOUND
FULERR EQU 237Q ;DISK FULL
LUNERR EQU 240Q ;LUN TOO LARGE
NOMEM EQU 241Q ;OUT-OF-MEMORY
; I/O MODE DEFN BYTE
MD.ALC EQU 80H ;80H ALLOCATED BUFFER AND FCB
MD.OPN EQU 40H ;40H FILE IS OPEN
MD.OUT EQU 20H ;20H IF OUTPUT
MD.BIN EQU 10H ;10H IF UNFORMATTED I/O
MD.WRT EQU 08H ;08H WRITE-DATA-IN-BUFFER
MD.RND EQU 04H ;04H IF RANDOM I/O
$FLFLG: DS MAXLUN ;I/O MODE BYTE FOR EACH LUN
$FLCNT: DS MAXLUN ;I/O BUFFER INDEX FOR EACH LUN
$FLBUF: DS MAXLUN*2 ;BUFFER LOCATION FOR EACH LUN
$FLFCB: DS MAXLUN*2 ;FCB LOCATION FOR EACH LUN
$DSKER: DS 1 ;STATUS OF LAST I/O
CLSADR: DS 2
$MEMRY: DS 2 ;FOR LOADER TO STORE TOP OF MEM INTO
CSEG ;CODE AREA
FILTXT: DB "FORT",0 ;DEFAULT FILENAME TEXT
FILEXT: DB "DAT",0
PAGE
; I/O DISPATCH TABLE
; LUN'S 6 THRU MAXLUN POINT TO THIS TABLE VIA $LUNTB.
; AN EXPLICIT OPEN VIA CALL OPEN (<FILESPEC>) ALLOW
; OTHER UNITS TO USE THE DISK ALSO...
DSKDRV: DW DSKFRD ;FORMATTED READ
DW DSKFWR ;FORMATTED WRITE
DW DSKURD ;UNFORMATTED READ
DW DSKUWR ;UNFORMATTED WRITE
DW DSKREW ;REWIND
DW $IOERR ;BACKSPACE (NOT SUPPORTED).
DW DSKCLS ;ENDFILE
FNFERR: CALL $ERR
DB NOFILE ;FILE NOT FOUND
DSKFUL: CALL $ERR
DB FULERR ;DISK FULL
LUNOVF: CALL $ERR
DB LUNERR ;LUN TOO LARGE
MEMERR: CALL $ERR
DB NOMEM ;OUT-OF-MEMORY
;------------------------------------------------------
;
; GET MODE BYTE(LUN) FROM $FLFLG
;
GTMODE: LXI H,$FLFLG-1
LDA $UN ;GET UNIT #
MVI D,0
MOV E,A
DAD D ;[HL] POINTS TO FLAG
MOV A,M ;GET FLAG
RET
;------------------------------------------------------
;
; SET DMA TO DATA BUFFER(LUN)
;
SETBUF: PUSH B
PUSH D
CALL GETBUF ;GET BUFFER ADR
MVI C,.STDMA
CALL BDOS
POP D
POP B
RET
;------------------------------------------------------
GETBUF: LDA $UN
ADD A
MOV E,A
MVI D,0
LXI H,$FLBUF-2
DAD D
MOV E,M
INX H
MOV D,M
RET
;------------------------------------------------------
;
; GET DATA.BUFFER.OFFSET(LUN)
;
GTBOFF:
LXI H,$FLCNT-1
LDA $UN
MVI D,0
MOV E,A
DAD D
MOV A,M ;GET OFFSET
RET
;------------------------------------------------------
;
; GET ADR OF FCB(LUN) IN [DE]
;
GTFCB: LXI H,$FLFCB-2
LDA $UN
ADD A
MOV E,A
MVI D,0
DAD D ;POINT TO ADR OF FCB
MOV E,M
INX H
MOV D,M
RET
;------------------------------------------------------
;
; GET READ/WRITE RECORD NUMBER FOR LUN
; ON RETURN:
; [HL] = FCB.RR(LUN) ADR OF RND REC NUM.
; [DE] = $REC 00 OR RND REC NUM.
;
GTREC:
CALL GTFCB
LXI H,FCB.RR
DAD D
XCHG
LHLD $REC
XCHG
RET
;------------------------------------------------------
; ZERO FCB FROM EXTENT BYTE TO END.
;
CLRFCB:
CALL GTFCB
LXI H,FCB.EX
DAD D
LXI B,FCBLEN-FCB.EX
CLRFCL:
MOV M,B
INX H
DCR C
JNZ CLRFCL
RET
;------------------------------------------------------
; COPY BYTES FROM [DE] TO [HL] UNTIL NULL (00).
;
CPYTXT:
MOV M,A ;COPY FROM [DE] TO [HL]
INX H ;UNTIL NULL.
INX D
LDAX D
ORA A
JNZ CPYTXT
RET
PAGE
;------------------------------------------------------
;
; OPNCHK - ASSURE THAT FILE IS OPEN AND BUFFERS ALLOCATED.
; IF NOT THEN:
; 1. ALLOCATE DATA BUFFER AND FCB FROM $MEMRY.
; 2. OPEN FILE WITH NAME OF FORT##.DAT WHERE:
; ## IS LOGICAL-UNIT-NUMBER (LUN) OF FILE.
OPNCHK:
LDA $UN
CPI MAXLUN+1 ;
JNC LUNOVF ;LUN IS TOO LARGE
; ----------------
PUSH B ;SAVE OPEN MODE REQUEST.
CALL GTMODE ;GET FLAG
ORA A ;ALLOCATED BUFFER,FCB?
CP ALCBUF ;NO, GET SPACE AND SET PTRS
; ----------------
POP B ;GET I/O MODE IN [C]
ANI MD.OPN ;WAS OPEN?
CZ OPNFIL ;NO, OPEN FILE.
;------------------------------------------------------
;
; SETREC - SET UP RECORD NUMBER
;
SETREC:
CALL GTREC ;GET CURRENT & LAST RECORD NUMBERS
MOV A,D ;[DE] = $REC
ORA E ;IF RANDOM I/O
JNZ SETRND ;USE VALUE IN $REC
; ----------------
MOV E,M ;..ELSE
INX H ;USE CURRENT RECORD
MOV D,M ;SET BY SEQ READ/WRITE.
PUSH D ;SAVE REC NO.
CALL GTMODE
ANI NOT MD.RND ;SET SEQUENTIAL MODE
MOV M,A
POP D ;RESTORE REC NO.
JMP SETSEQ
; ----------------
SETRND:
CALL GTMODE
ANI MD.WRT ;WRITE-DATA-IN-BUFFER?
CNZ FRCOUT ;YES, FLUSH IT FIRST.
CALL GTMODE
ORI MD.RND ;SET RANDOM MODE
MOV M,A
CALL GTREC ;RESTORE REC NO'S.
DCX D ;ADJUST RANDOM REC NO.
MOV M,E
INX H ;STORE AT FCB.RR FOR NEXT I/O
MOV M,D
INX H
MVI M,0
; ----------------
SETSEQ:
LDA $CPMVN ;CP/M VERSION FLAG
ORA A ;VERSION 1.X ?
RZ ;NO, VERSION 2.X NOTHING ELSE NEEDED.
;------------------------------------------------------
;
; SPLIT RANDOM RECORD INTO EXTENT AND RELATIVE RECORD
; FOR VERSION 1.X
;
SETV1:
MOV A,E
RAL
MOV A,D
RAL
MOV B,A
MOV A,E
ANI X'7F'
MOV C,A
; ----------------
CALL GTFCB ;[DE] = ADR OF FCB(LUN)
LXI H,FCB.EX
DAD D
MOV A,M ;FETCH CURRENT EXTENT
CMP B
JZ SAMEXT ;IF SAME AS REQUESTED EXTENT
;
; CLOSE CURRENT EXTENT, OPEN REQUESTED ONE
;
PUSH B ;EXT/REC
PUSH D ;FCB ADR
LXI H,FCB.NR
DAD D
MVI M,0 ;ZERO THE RECORD NUMBER
LHLD $MEMRY ;GET SCRATCH BUFFER
XCHG ;FROM TOP OF HEAP FOR OPEN/CLOSE
MVI C,.STDMA
CALL BDOS
CALL GTMODE
ANI MD.OUT ;OPEN FOR OUTPUT?
JZ OPNXT ;NO, SKIP THIS CLOSE
POP D
PUSH D ;FCB
MVI C,.CLOSE
CALL BDOS
OPNXT:
POP D ;FCB
POP B ;EXT/REC
PUSH B
PUSH D
LXI H,FCB.EX
DAD D
MOV M,B ;SET NEW EXTENT NUMBER
MVI C,.OPEN
CALL BDOS
INR A
JNZ SKEXT ;IF IT EXISTS
POP D
PUSH D ;FCB
CALL MAKEXT ;CREATE NEW EXTENT
SKEXT:
POP D ;FCB
POP B ;EXT/REC
SAMEXT:
LXI H,FCB.NR
DAD D
MOV M,C ;SET RECORD NUMBER
RET
PAGE
;------------------------------------------------------
; ALLOCATE FCB AND BUFFER FOR UNIT . ALLOCATES UP FROM
; $MEMRY AND STORES PTRS IN TABLE.
ALCBUF: PUSH H
LHLD $MEMRY ;GET CURRENT TOP
XCHG ;IN [DE]
; ----------------
LXI H,-256
DAD SP
MOV A,L
SUB E ;IF MEMTOP-256 < $MEMRY,
MOV A,H ;THEN GIVE OUT-OF-MEMORY
SBB D ;ERROR AND EXIT...
JC MEMERR
; ----------------
LXI H,$FLBUF-2
LDA $UN
ADD A
MVI B,0
MOV C,A ;[BC]= 2*UNIT#
DAD B ;GET ADR OF PTR TO BUFFER
MOV M,E
INX H
MOV M,D ;STORE $MEMRY AS ADR
LXI H,SECSIZ
DAD D ;GET NEW TOP
PUSH H ;SAVE FCB ADR
CALL GTFCB ;GET [HL]=ENTRY+1
POP D
PUSH D ;SAVE FCB ADR
MOV M,D
DCX H
MOV M,E ;STORE ADR OF FCB
LXI H,FCBLEN
DAD D ;GET NEW TOP OF ALLOC
SHLD $MEMRY ;STORE AWAY
; ----------------
POP H ;FCB ADR.
MVI M,0 ;DEFAULT TO CURRENT DISK
INX H
LXI D,FILTXT ;DEFAULT NAME INITIALLY FORT##.DAT
LDAX D
CALL CPYTXT ;MOVE "FORT" TO FCB
LDA $UN
MOV B,A ;SAVE UNIT #
SUI 10 ;CARRY SET IF NOT UNIT 10
SBB A
ADI "1" ;"1" IF 10 ELSE "0"
MOV M,A ;STORE DIGIT 1 OF #
MOV A,B
CPI 10 ;WAS IT 10?
JC SKPSTZ ;NO, DON'T SET ZERO
XRA A
SKPSTZ: ADI "0" ;GET 2ND DIGIT
INX H
MOV M,A
MVI A," "
INX H
MOV M,A
INX H
LXI D,FILEXT-1 ;EXTENSION
CALL CPYTXT ;MOVE "DAT" TO FCB
; ----------------
POP H ;GET PTR TO FLAG
MVI A,MD.ALC ;NOW ALLOCATED.
MOV M,A ;SET FLAG
RET
PAGE
;------------------------------------------------------
;
; OPEN FILE GIVEN BY LUN AND CLEAR BUFFER INDEX.
; ENTRY: [DE] = ADR OF FCB
; EXIT: [HL] = ADR OF MODE BYTE
; [A] = MODE BYTE - ALLOCATED & OPEN.
;
OPNFIL:
PUSH B ;SAVE I/O MODE
CALL GTBOFF ;GET BUFFER.OFFSET(LUN)
MOV M,D ;CLEAR BUFFER INDEX
; ----------------
LHLD $CLSFL
LXI D,CLSALL
MOV A,H
SUB D
JNZ STRADR ;NOT US, STORE ROUTINE ADR
MOV A,L
SUB E
JZ STRCLS ;US, DON'T STORE AGAIN
STRADR: SHLD CLSADR
STRCLS: XCHG
SHLD $CLSFL ;ON EXIT, CLOSE ALL FILES
CALL CLRFCB ;ZERO FCB & RECORD NUMBER.
CALL SETBUF ;SET DMA TO FILE BUFFER.
; ----------------
POP B ;I/O MODE
PUSH B
MOV A,C
ANI MD.OUT
JZ OPNINP ;BRIF OPEN INPUT
;------------------------------------------------------
;
; OPEN NEW FILE FOR OUTPUT OR RANDOM.
;
PUSH D ;SAVE FCB ADR
MVI C,.DELET ;DELETE OLD FILE
CALL BDOS
POP D
PUSH D
CALL MAKEXT ;CREATE NEW FILE.
POP D ;RESTORE FCB ADR
;------------------------------------------------------
;
; OPEN EXISTING FILE FOR INPUT OR RANDOM.
;
OPNINP:
MVI C,.OPEN ;OPEN FILE
CALL BDOS
INR A
JZ FNFERR ;BRIF FILE NOT FOUND (FATAL).
OPNDON:
CALL GTMODE
POP B ;GET I/O MODE.
MOV A,C
ORI MD.ALC+MD.OPN
MOV M,A ;MODE ALLOCATED/OPEN + I/O
RET
;------------------------------------------------------
;
; MAKE NEW FILE OR EXTENT.
;
MAKEXT:
MVI C,.MAKE ;CREATE NEW FILE
CALL BDOS
INR A
JZ DSKFUL ;BRIF DISK FULL ERROR.
RET
PAGE
;------------------------------------------------------
;
; REWIND UNIT #
;
DSKREW: CALL GTMODE
ANI MD.OPN ;FILE OPEN?
CNZ DSKCLS ;YES, CLOSE IT
NOCLOS: XRA A ;GOOD RETURN
RET
;------------------------------------------------------
;
; ENDFILE UNIT #
;
DSKCLS: CALL GTMODE
ADD A ;OPEN?
JP NOCLOS ;NO, DON'T CLOSE
MVI M,MD.ALC ;FLAG CLOSED NOW
ADD A ;OUTPUT FILE?
CM FRCBUF ;YES, DUMP LAST IF NEEDED
CALL GTFCB ;GET ADDR OF FCB
CALL SETBUF ;SET DMA ADR
MVI C,.CLOSE ;CLOSE FILE
CALL BDOS
XRA A ;NEVER AN ERROR
RET
;------------------------------------------------------
;
; CLOSE ALL FILES. CALLED FROM EXIT
;
CLSALL: LXI D,1
CLSAL1: LXI H,$FLFLG-1
DAD D
MOV A,M
ADD A ;SET MINUS IF OPEN
PUSH D ;SAVE UNIT #
MOV A,E
STA $UN ;SET UP FOR OTHERS
CM DSKCLS ;CLOSE FILE IF OPEN
POP D ;GET # BACK
INX D ;BUMP IT
LDA $LUNTB ;GET MAX LUN
CMP E ;DONE ALL?
JNZ CLSAL1 ;NO, DO NEXT
RET ;RETURN
PAGE
;------------------------------------------------------
;
; UNFORMATTED WRITE
;
DSKUWR:
MVI C,MD.OUT+MD.BIN
CALL OPNCHK ;OPEN IF NOT OPEN
LHLD $BF ;GET BUFFER ADR
PUSH H
XCHG
LHLD $BL ;GET LENGTH OF DATA
MVI H,0 ;# OF BYTES
XCHG
DAD D ;PTR TO 1ST TO CLEAR
XRA A
DCR E
DSKWCL:
INR E ;CLEARED REST OF BUFFER?
JM DSKUW1 ;YES, DONE
MOV M,A
INX H
JMP DSKWCL ;CLEAR END OF BUFFER
DSKUW1:
POP D ;GET BUFFER ADR
MVI C,.STDMA ;SET DMA TO BUFFER
CALL BDOS
CALL WRITE ;WRITE RECORD
ORA A ;ERROR?
RZ ;NO, GOOD RETURN
STC
RET
PAGE
;------------------------------------------------------
;
; UNFORMATTED READ
;
DSKURD:
MVI C,MD.BIN
CALL OPNCHK ;OPEN IF NEEDED
LHLD $BF
XCHG
MVI C,.STDMA ;SET DMA TO $BF
CALL BDOS
MVI A,128
STA $BL ;ALWAYS 1 SECTOR
CALL READ ;READ RECORD INTO $BF
ORA A ;EOF OR GOOD
RZ
CPI 2
CMC
RET
;
PAGE
;------------------------------------------------------
;
; FORMATTED WRITE
;
DSKFWR:
MVI C,MD.OUT
CALL OPNCHK ;OPEN FILE IF NEEDED
XRA A
STA $DSKER ;CLEAR COUNT
LDA $BL ;GET # TO WRITE
ORA A
RZ ;IGNORE NULL BUFFERS
LDA $BL
ORA A
JP DSKFW0
CALL $ERR ;WARN USER OF..
DB OBOVF ;OUTPUT BUFFER LIMIT EXCEEDED
MVI A,127 ;AND TRUNCATE TO 127 BYTES.
DSKFW0:
CALL RNDCHK ;IF RND MODE, SET OFFSET TO 0.
LHLD $BF ;GET BUFFER PTR
DSKFW2:
PUSH PSW ;SAVE COUNT
MOV A,M
CALL DSKOUT ;SEND OUT BYTE
INX H ;INCREMENT BUFFER PTR
POP PSW ;RETRIEVE COUNT
DCR A ;DECREMENT COUNT
JNZ DSKFW2 ;ONE MORE TIME
;
DSKWDN: MVI A,15Q
CALL DSKOUT ;PUT OUT <CR>
CALL GTMODE ;MARK MODE BYTE WITH
ORI MD.WRT ;WRITE-DATA-IN-BUFFER.
MOV M,A
LDA $DSKER ;GET $DSKEROR STATUS
ORA A ;ERROR?
RZ ;NO
STC ;YES
RET
;
PAGE
;------------------------------------------------------
;
; FORMATTED READ
;
DSKFRD:
MVI C,0
CALL OPNCHK ;OPEN IF NEEDED
XRA A
STA $BL ;CLEAR LENGTH OF RECORD
STA $DSKER ;CLEAR $DSKEROR
CALL RNDCHK ;IF RND MODE, SET OFFSET TO 0.
DSKFR1:
CALL DSKIN ;GET CHAR
JC DSKRDN ;JUMP IF EOF
CPI 32Q ;CP/M EOF?
JZ DSKEOF ;YES
LHLD $BL
MVI H,0
XCHG
LHLD $BF ;BASE
DAD D ;GET WHERE TO PUT BYTE
MOV M,A ;STORE CHAR
INX D ;BUMP OFFSET
XCHG
SHLD $BL ;UPDATE OFFSET
CPI 15Q ;<CR>?
JZ DSKRDN ;YES, HAVE RECORD
MOV A,L ;GET OFFSET
CPI 128 ;BUFFER FULL?
JC DSKFR1 ;NO, GET NEXT
CALL $ERR ;WARN USER OF..
DB IRECER ;INPUT RECORD TOO LONG.
XRA A
RET
;
DSKRDN: LDA $DSKER ;GET STATUS
ORA A
RZ ;NO ERROR
CPI 2
CMC
RET
DSKEOF: ORA A ;SET CC'S
RET
;
PAGE
;------------------------------------------------------
;
; RESET BUFFER OFFSET IF RANDOM READ OR WRITE
;
RNDCHK:
PUSH PSW
CALL GTMODE
ANI MD.RND
JZ RNDCHX ;DO NOTHING IF SEQUENTIAL MODE.
CALL GTBOFF ;ELSE ZERO BUFFER OFFSET SO..
MVI M,0 ;NEXT READ/WRITE STARTS AT BEGINNING.
RNDCHX:
POP PSW
RET
;------------------------------------------------------
;
; DISK INPUT ROUTINE
;
DSKIN:
CALL GTBOFF ;BUFFER.OFFSET(LUN)
ORA A ;BUFFER EMPTY?
CZ REDBUF ;YES, REFIL
RC ;EOF
DCR M ;DECR. # LEFT
LXI H,$FLBUF-2
DAD D
DAD D ;GET $FLBUF PTR
CMA
ADI 129 ;128-#LEFT=OFFSET
ADD M
MOV E,A
INX H
MVI A,0
ADC M
MOV D,A
LDAX D ;GET CHAR
ORA A
RET
;------------------------------------------------------
;
; READ BUFFER FROM DISK
;
REDBUF: PUSH H
PUSH D
CALL SETBUF
CALL READ ;READ RECORD
STA $DSKER ;STORE STATUS
ORA A
POP D
POP H
MVI A,128 ;FULL BUFFER
MOV M,A ;STORE COUNT
RZ ;IF NO ERROR
STC
RET
;------------------------------------------------------
;
; DISK OUTPUT ROUTINE
;
DSKOUT: PUSH H
PUSH PSW
CALL GTBOFF ;GET BUFFER OFFSET
ORA A ;BUFFER FULL?
CM DMPBUF ;YES, DUMP
INR M
LXI H,$FLBUF-2
DAD D
DAD D ;POINT TO ADR OF BUFFER
ADD M
MOV E,A
INX H
MVI A,0
ADC M
MOV D,A ;POINTS TO FREE
POP PSW ;GET CHAR BACK
STAX D ;STORE CHAR
POP H
RET
;------------------------------------------------------
;
; FORCE FORMATTED BUFFER OUT ON CLOSE
;
FRCBUF: ADD A ;UNFORMATTED I/O?
JM FRCOUT ;YES, FORCE OUT LAST IF NEEDED
MVI A,32Q
CALL DSKOUT ;SET END OF FILE
FRCOUT: CALL GTBOFF ;BUFFER.OFFSET(LUN)
ORA A ;EMPTY?
MVI M,0 ;CLEAR OFFSET
RZ ;YES, DO NOTHING
PUSH PSW ;SAVE OFFSET
CALL GETBUF ;GET BUFFER ADR
POP PSW
MOV L,A
MVI H,0
DAD D ;POINT TO 1ST UNUSED
CHKFIL: ORA A ;SET MINUS IF FULL
JM DMPBF1 ;NOTHING TO FILL
MVI M,0 ;CLEAR BYTE
INX H
INR A ;BUMP OFFSET
JMP CHKFIL
;------------------------------------------------------
;
; DUMP BUFFER TO DISK
;
DMPBF1:
DCX H ;SO THAT DRIVE # ISN'T CLEARED
DMPBUF:
PUSH H
PUSH D
CALL SETBUF
CALL WRITE ;WRITE RECORD
STA $DSKER ;STORE STATUS
CALL GTMODE
ANI NOT MD.WRT ;CLEAR WRITE-DATA BIT
MOV M,A
POP D
POP H
XRA A
MOV M,A ;CLEAR BUFFER OFFSET
RET
;------------------------------------------------------
;
; READ RECORD/WRITE RECORD PRIMITIVES
;
READ: CALL GTFCB ;GET ADDR OF FCB
LDA $CPMRF ;CP/M 1.X OR 2.X
MOV C,A ;RANDOM READ FUNCTION
JMP IOCALL
WRITE: CALL GTFCB ;GET ADDR OF FCB
LDA $CPMWF ;CP/M 1.X OR 2.X
MOV C,A ;RANDOM WRITE FUNCTION
IOCALL: CALL BDOS ;DO APPROPRIATE FUNCTION
PUSH PSW ;SAVE ERROR RESULT
CALL GTREC ;POINT TO RECORD NUMBER
INR M ;UPDATE SEQUENTIAL
JNZ POPART ; RECORD NUMBER
INX H
INR M
POPART: POP PSW ;RESTORE ERROR
RET
PAGE
;------------------------------------------------------
;
; CALL OPEN(UNIT #,FILENAME,DRIVE #)
;
ENTRY OPEN
EXT $IOINIT
OPEN: LDA $LUNTB ;GET MAX LUN
DCR A
CMP M ;OUT OF RANGE?
JC LUNOVF ;YES, LUN TOO LARGE.
MOV A,M ;FETCH LUN
STA $UN ;SET IT UP
PUSH D ;SAVE REGISTERS
PUSH B ;SAVE FILPTR
CALL $IOINIT ;INITIALIZE IF NOT ALREADY DONE
CALL GTMODE
ORA A ;ALLOCATED?
CP ALCBUF ;NO, ALLOCATE
POP B
CALL GTFCB
XCHG
POP D ;[DE]=NAME PTR
LDAX B ;GET DRIVE #
MOV M,A ;STORE DRIVE #
MVI B,11 ;COPY FILE NAME TO FCB
FILLOP: LDAX D
ORA A ;ZERO BYTE?
JZ FILLEN ;YES, LEAVE REST AS BEFORE
INX D
INX H
MOV M,A
DCR B ;FINISHED MOVING NAME?
JNZ FILLOP ;NO, DO REST
FILLEN: LDA $UN ;GET UNIT #
ADD A ;*2 FOR TABLE INDEX
MVI D,0
MOV E,A
LXI H,$LUNTB ;INDEX INTO LUN TABLE
DAD D
LXI B,DSKDRV ;REPLACE CURRENT LUNTB ENTRY
MOV M,B ; WITH ADDRESS OF DISK DRIVER
DCX H ; DISPATCH ADDRESS
MOV M,C
RET
END