forked from MirrorRepos/RomWBW
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
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
|
|
|