You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

860 lines
17 KiB

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