605 lines
8.5 KiB
Plaintext
605 lines
8.5 KiB
Plaintext
; I/O System for 86-DOS.
|
|
|
|
; Assumes a CPU Support card at F0 hex for character I/O,
|
|
; with disk drivers for Tarbell or Cromemco controllers.
|
|
|
|
; Select disk controller here
|
|
TARBELL:EQU 0
|
|
CROMEMCO:EQU 1
|
|
|
|
; For either disk controller, a custom drive table may be defined
|
|
CUSTOM: EQU 0
|
|
|
|
; If Tarbell disk controller, select one-sided or two-sided drives
|
|
; and single or double density controller
|
|
DOUB1SIDE:EQU 0
|
|
DOUB2SIDE:EQU 0
|
|
SNGL1SIDE:EQU 0
|
|
|
|
; If Cromemco disk controller, select drive configuration
|
|
SMALLCRO:EQU 0 ;3 small drives
|
|
COMBCRO:EQU 1 ;2 large drives and 1 small one
|
|
LARGECRO:EQU 0 ;4 large drives
|
|
|
|
WD1791: EQU DOUB1SIDE+DOUB2SIDE
|
|
WD1771: EQU CROMEMCO+SNGL1SIDE
|
|
|
|
IF WD1791
|
|
READCOM:EQU 80H
|
|
WRITECOM:EQU 0A0H
|
|
ENDIF
|
|
|
|
IF WD1771
|
|
READCOM:EQU 88H
|
|
WRITECOM:EQU 0A8H
|
|
ENDIF
|
|
|
|
IF TARBELL
|
|
DONEBIT:EQU 80H
|
|
DISK: EQU 78H
|
|
ENDIF
|
|
|
|
IF CROMEMCO
|
|
DONEBIT:EQU 1
|
|
DISK: EQU 30H
|
|
ENDIF
|
|
|
|
DOSSEG: EQU 80H
|
|
|
|
ORG 0
|
|
PUT 100H
|
|
|
|
BASE: EQU 0F0H
|
|
STAT: EQU BASE+7
|
|
DAV: EQU 2
|
|
TBMT: EQU 1
|
|
DATA: EQU BASE+6
|
|
PSTAT: EQU BASE+0DH
|
|
PDATA: EQU BASE+0CH
|
|
|
|
JMP INIT
|
|
JMP STATUS
|
|
JMP INP
|
|
JMP OUTP
|
|
JMP PRINT
|
|
JMP AUXIN
|
|
JMP AUXOUT
|
|
JMP READ
|
|
JMP WRITE
|
|
JMP RETL ;Flush buffers
|
|
|
|
INIT:
|
|
MOV AX,CS
|
|
MOV DS,AX
|
|
MOV SS,AX
|
|
MOV SP,STACK
|
|
MOV SI,INITTAB
|
|
CALL 0,DOSSEG
|
|
MOV DX,100H
|
|
MOV AH,26 ;Set DMA address
|
|
INT 21H
|
|
MOV BX,DS
|
|
MOV AX,CS
|
|
MOV DS,AX
|
|
MOV DX,FCB
|
|
MOV AH,15
|
|
INT 21H
|
|
OR AL,AL
|
|
JNZ COMERR
|
|
MOV [FCB+33],0
|
|
MOV CX,200H
|
|
MOV AH,39 ;Load file
|
|
INT 21H
|
|
JCXZ COMERR
|
|
CMP AL,1
|
|
JNZ COMERR
|
|
MOV DS,BX
|
|
MOV ES,BX
|
|
MOV SS,BX
|
|
MOV SP,40H
|
|
XOR AX,AX
|
|
PUSH AX
|
|
MOV DX,80H
|
|
MOV AH,26
|
|
INT 21H
|
|
PUSH BX
|
|
MOV AX,100H
|
|
PUSH AX
|
|
RET L
|
|
COMERR:
|
|
MOV DX,BADCOM
|
|
MOV AH,9 ;Print string
|
|
INT 21H
|
|
EI
|
|
STALL: JP STALL
|
|
|
|
BADCOM: DB 13,10,"Bad or missing Command Interpreter",13,10,"$"
|
|
FCB: DB 1,"COMMAND COM"
|
|
DS 24
|
|
|
|
STATUS:
|
|
IN STAT
|
|
AND AL,DAV
|
|
RET L
|
|
|
|
AUXIN:
|
|
INP:
|
|
IN STAT
|
|
AND AL,DAV
|
|
JZ INP
|
|
IN DATA
|
|
AND AL,7FH
|
|
RET L
|
|
|
|
AUXOUT:
|
|
OUTP:
|
|
PUSH AX
|
|
OUTLP:
|
|
IN STAT
|
|
AND AL,TBMT
|
|
JZ OUTLP
|
|
POP AX
|
|
OUT DATA
|
|
RET L
|
|
|
|
PRINT:
|
|
PUSH AX
|
|
PRINLP:
|
|
IN PSTAT
|
|
AND AL,TBMT
|
|
JZ PRINLP
|
|
POP AX
|
|
OUT PDATA
|
|
RET L
|
|
|
|
READ:
|
|
CALL SEEK
|
|
RDLP:
|
|
PUSH CX
|
|
CALL READSECT
|
|
POP CX
|
|
JC ERROR
|
|
INC DH
|
|
ADD SI,128
|
|
LOOP RDLP
|
|
OR AL,AL
|
|
RETL: RET L
|
|
|
|
WRITE:
|
|
CALL SEEK
|
|
WRTLP:
|
|
PUSH CX
|
|
CALL WRITESECT
|
|
POP CX
|
|
JC ERROR
|
|
INC DH
|
|
ADD SI,128
|
|
LOOP WRTLP
|
|
OR AL,AL
|
|
RET L
|
|
|
|
ERROR:
|
|
SEG CS
|
|
MOV B,[DI],-1
|
|
RET L
|
|
|
|
SEEK:
|
|
|
|
; Inputs:
|
|
; AL = Drive number
|
|
; BX = Disk transfer address in DS
|
|
; CX = Number of sectors to transfer
|
|
; DX = Logical record number of transfer
|
|
; Function:
|
|
; Seeks to proper track.
|
|
; Outputs:
|
|
; AH = Drive select byte
|
|
; DL = Track number
|
|
; DH = Sector number
|
|
; SI = Disk transfer address in DS
|
|
; DI = pointer to drive's track counter in CS
|
|
; CX unchanged.
|
|
|
|
MOV SI,BX ; Save transfer address
|
|
CBW
|
|
MOV BX,AX ; Prepare to index on drive number
|
|
SEG CS
|
|
MOV AL,[BX+DRVTAB]
|
|
OUT DISK+4 ; Select drive
|
|
|
|
IF CROMEMCO
|
|
OR AL,80H ;Set auto-wait bit
|
|
ENDIF
|
|
|
|
MOV AH,AL ;Save for later
|
|
XCHG AX,DX
|
|
MOV DL,26 ;26 sectors per track
|
|
|
|
IF CROMEMCO
|
|
TEST DH,10H ;Check if small disk
|
|
JNZ BIGONE
|
|
MOV DL,18 ;18 sectors on small disk track
|
|
BIGONE:
|
|
ENDIF
|
|
|
|
DIV AL,DL ;Compute track and sector
|
|
XCHG AX,DX
|
|
INC DH ;First sector is 1, not zero
|
|
SEG CS
|
|
MOV BL,[BX+TRKPT] ;Get this drive's displacement into track table
|
|
ADD BX,TRKTAB ;BX now points to track counter for this drive
|
|
MOV DI,BX
|
|
MOV AL,DL
|
|
SEG CS
|
|
XCHG AL,[DI] ;Xchange current track with desired track
|
|
OUT DISK+1 ;Inform controller chip of current track
|
|
CMP AL,DL
|
|
JZ ONTRK
|
|
MOV BH,3 ;Seek retry count
|
|
CMP AL,-1 ;Head position known?
|
|
JNZ NOHOME ;If not, home head
|
|
TRYSK:
|
|
CALL HOME
|
|
NOHOME:
|
|
MOV AL,DL
|
|
OUT DISK+3
|
|
MOV AL,1CH
|
|
CALL MOVHEAD
|
|
AND AL,98H
|
|
JZ ONTRK
|
|
DEC BH
|
|
JNZ TRYSK
|
|
STC
|
|
ONTRK:
|
|
RET
|
|
|
|
SETUP:
|
|
|
|
IF CROMEMCO
|
|
TEST AH,10H ;Check for small disk
|
|
JNZ CHKSTP
|
|
CMP DH,18 ;Only 18 sectors/track on small ones
|
|
JA STEP
|
|
CHKSTP:
|
|
ENDIF
|
|
|
|
CMP DH,26 ;Check for overflow onto next track
|
|
JBE PUTSEC
|
|
STEP:
|
|
INC DL
|
|
MOV DH,1
|
|
MOV AL,58H ;Step in with update, no verify
|
|
CALL DCOM
|
|
SEG CS
|
|
INC B,[DI] ;Update track counter
|
|
PUTSEC:
|
|
MOV AL,DH
|
|
OUT DISK+2
|
|
MOV CX,80H
|
|
|
|
IF TARBELL
|
|
IN DISK ;Get head load bit
|
|
ENDIF
|
|
|
|
IF CROMEMCO
|
|
IN DISK+4 ;Get head load bit
|
|
XCHG AL,AH
|
|
OUT DISK+4 ;Turn on auto-wait
|
|
XCHG AL,AH
|
|
ENDIF
|
|
|
|
NOT AL
|
|
AND AL,20H ;Check head load status
|
|
JZ CHKDRV
|
|
MOV AL,4
|
|
CHKDRV:
|
|
; Turn on 15ms head load delay if selecting a different drive
|
|
SEG CS
|
|
CMP AH,[CURDRV]
|
|
SEG CS
|
|
MOV [CURDRV],AH
|
|
JZ RET
|
|
OR AL,4
|
|
RET
|
|
|
|
READSECT:
|
|
CALL SETUP
|
|
JC RET
|
|
MOV BL,10
|
|
RDAGN:
|
|
OR AL,READCOM
|
|
OUT DISK
|
|
PUSH SI
|
|
RLOOP:
|
|
IN DISK+4
|
|
TEST AL,DONEBIT
|
|
|
|
IF TARBELL
|
|
JZ RDONE
|
|
ENDIF
|
|
|
|
IF CROMEMCO
|
|
JNZ RDONE
|
|
ENDIF
|
|
|
|
IN DISK+3
|
|
MOV [SI],AL
|
|
INC SI
|
|
LOOP RLOOP
|
|
RDONE:
|
|
POP SI
|
|
CALL GETSTAT
|
|
AND AL,9CH
|
|
JZ RET
|
|
MOV AL,0
|
|
DEC BL
|
|
JNZ RDAGN
|
|
STC
|
|
RET
|
|
|
|
WRITESECT:
|
|
CALL SETUP
|
|
JC RET
|
|
MOV BL,10
|
|
WRTAGN:
|
|
OR AL,WRITECOM
|
|
OUT DISK
|
|
PUSH SI
|
|
WRLOOP:
|
|
IN DISK+4
|
|
TEST AL,DONEBIT
|
|
|
|
IF TARBELL
|
|
JZ WRDONE
|
|
ENDIF
|
|
|
|
IF CROMEMCO
|
|
JNZ WRDONE
|
|
ENDIF
|
|
|
|
LODB
|
|
OUT DISK+3
|
|
LOOP WRLOOP
|
|
WRDONE:
|
|
POP SI
|
|
CALL GETSTAT
|
|
AND AL,09CH
|
|
JZ RET
|
|
MOV AL,0
|
|
DEC BL
|
|
JNZ WRTAGN
|
|
STC
|
|
RET
|
|
|
|
HOME:
|
|
IF CROMEMCO
|
|
TEST AH,10H ;Check 8" (PerSci) bit
|
|
JNZ RESTORE
|
|
ENDIF
|
|
|
|
MOV BL,3
|
|
TRYHOM:
|
|
MOV AL,0CH
|
|
CALL DCOM
|
|
AND AL,98H
|
|
JZ RET
|
|
MOV AL,58H ;Step in with update
|
|
CALL DCOM
|
|
DEC BL
|
|
JNZ TRYHOM
|
|
RET
|
|
|
|
MOVHEAD:
|
|
IF CROMEMCO
|
|
TEST AH,10H ;Check 8" (PerSci) bit
|
|
JNZ FASTSK
|
|
ENDIF
|
|
|
|
DCOM:
|
|
OUT DISK
|
|
MOV AL,50
|
|
DELAY:
|
|
DEC AL
|
|
JNZ DELAY ;Delay 100 microseconds
|
|
GETSTAT:
|
|
IN DISK+4
|
|
TEST AL,DONEBIT
|
|
|
|
IF TARBELL
|
|
JNZ GETSTAT
|
|
ENDIF
|
|
|
|
IF CROMEMCO
|
|
JZ GETSTAT
|
|
ENDIF
|
|
|
|
IN DISK
|
|
RET
|
|
|
|
IF CROMEMCO
|
|
RESTORE:
|
|
MOV AL,0C4H ;READ ADDRESS command to keep head loaded
|
|
OUT DISK
|
|
MOV AL,77H
|
|
OUT 4
|
|
CHKRES:
|
|
IN 4
|
|
AND AL,40H
|
|
JZ RESDONE
|
|
IN DISK+4
|
|
TEST AL,DONEBIT
|
|
JZ CHKRES
|
|
IN DISK
|
|
JP RESTORE ;Reload head
|
|
RESDONE:
|
|
MOV AL,7FH
|
|
OUT 4
|
|
CALL GETSTAT
|
|
MOV AL,0
|
|
OUT DISK+1 ;Tell 1771 we're now on track 0
|
|
RET
|
|
|
|
FASTSK:
|
|
MOV AL,6FH
|
|
OUT 4
|
|
MOV AL,18H
|
|
CALL DCOM
|
|
SKWAIT:
|
|
IN 4
|
|
TEST AL,40H
|
|
JNZ SKWAIT
|
|
MOV AL,7FH
|
|
OUT 4
|
|
MOV AL,0
|
|
RET
|
|
ENDIF
|
|
|
|
DS 20H
|
|
STACK:
|
|
|
|
LFAT: EQU 300H
|
|
SFAT: EQU 200H
|
|
|
|
CURDRV: DS 1
|
|
|
|
LDRIVE:
|
|
DB 1 ;Records/sector
|
|
DB 4 ;Records/cluster
|
|
DW 52 ;Reserved records
|
|
DB 6 ;FAT size (records)
|
|
DB 2 ;Number of FATs
|
|
DB 8 ;Number of directory records
|
|
DW 482 ;Number of clusters on drive
|
|
|
|
SDRIVE:
|
|
DB 1
|
|
DB 2
|
|
DW 54
|
|
DB 4
|
|
DB 2
|
|
DB 8
|
|
DW 330
|
|
|
|
IF DOUB1SIDE
|
|
DRVTAB: DB 0,10H,20H,30H
|
|
TRKPT: DB 0,1,2,3
|
|
TRKTAB: DB -1,-1,-1,-1
|
|
ENDIF
|
|
|
|
IF DOUB2SIDE
|
|
DRVTAB: DB 0,40H,10H,50H
|
|
TRKPT: DB 0,0,1,1
|
|
TRKTAB: DB -1,-1
|
|
ENDIF
|
|
|
|
IF SNGL1SIDE
|
|
DRVTAB: DB 0F2H,0E2H,0D2H,0C0H
|
|
TRKPT: DB 0,1,2,3
|
|
TRKTAB: DB -1,-1,-1,-1
|
|
ENDIF
|
|
|
|
IF TARBELL
|
|
INITTAB:DB 4 ;Number of drives
|
|
DW LDRIVE
|
|
DW FAT0
|
|
DW LDRIVE
|
|
DW FAT1
|
|
DW LDRIVE
|
|
DW FAT2
|
|
DW LDRIVE
|
|
DW FAT3
|
|
|
|
ORG 0
|
|
FAT0: DS LFAT
|
|
FAT1: DS LFAT
|
|
FAT2: DS LFAT
|
|
FAT3: DS LFAT
|
|
ENDIF
|
|
|
|
; Cromemco drive select byte is derived as follows:
|
|
; Bit 7 = 0
|
|
; Bit 6 = X (unassigned)
|
|
; Bit 5 = 1 (motor on)
|
|
; Bit 4 = 0 for 5", 1 for 8" drives
|
|
; Bit 3 = 1 for drive 3
|
|
; Bit 2 = 1 for drive 2
|
|
; Bit 1 = 1 for drive 1
|
|
; Bit 0 = 1 for drive 0
|
|
|
|
IF LARGECRO
|
|
; Table for four large drives
|
|
DRVTAB: DB 31H,32H,34H,38H
|
|
TRKPT: DB 0,0,1,1
|
|
TRKTAB: DB -1,-1
|
|
INITTAB:DB 4 ;Number of drives
|
|
DW LDRIVE
|
|
DW FAT0
|
|
DW LDRIVE
|
|
DW FAT1
|
|
DW LDRIVE
|
|
DW FAT2
|
|
DW LDRIVE
|
|
DW FAT3
|
|
|
|
ORG 0
|
|
FAT0: DS LFAT
|
|
FAT1: DS LFAT
|
|
FAT2: DS LFAT
|
|
FAT3: DS LFAT
|
|
ENDIF
|
|
|
|
IF COMBCRO
|
|
; Table for two large drives and one small one
|
|
DRVTAB: DB 31H,32H,24H
|
|
TRKPT: DB 0,0,1
|
|
TRKTAB: DB -1,-1
|
|
INITTAB:DB 3 ;Number of drives
|
|
DW LDRIVE
|
|
DW FAT0
|
|
DW LDRIVE
|
|
DW FAT1
|
|
DW SDRIVE
|
|
DW FAT2
|
|
|
|
ORG 0
|
|
FAT0: DS LFAT
|
|
FAT1: DS LFAT
|
|
FAT2: DS SFAT
|
|
ENDIF
|
|
|
|
IF SMALLCRO
|
|
; Table for 3 small drives
|
|
DRVTAB: DB 21H,22H,24H
|
|
TRKPT: DB 0,1,2
|
|
TRKTAB: DB -1,-1,-1
|
|
INITTAB:DB 3
|
|
DW SDRIVE
|
|
DW FAT0
|
|
DW SDRIVE
|
|
DW FAT1
|
|
DW SDRIVE
|
|
DW FAT2
|
|
|
|
ORG 0
|
|
FAT0: DS SFAT
|
|
FAT1: DS SFAT
|
|
FAT2: DS SFAT
|
|
ENDIF
|
|
|
|
IF CUSTOM
|
|
; Table for 2 large drives
|
|
DRVTAB: DB 31H,32H
|
|
TRKPT: DB 0,1
|
|
TRKTAB: DB -1,-1
|
|
|
|
INITTAB:DB 2
|
|
DW LDRIVE
|
|
DW FAT0
|
|
DW LDRIVE
|
|
DW FAT1
|
|
|
|
ORG 0
|
|
FAT0: DS LFAT
|
|
FAT1: DS LFAT
|
|
ENDIF
|
|
|