mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
860 lines
17 KiB
Plaintext
860 lines
17 KiB
Plaintext
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
|
||
|