; 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 INB DISK ;Get head load bit ENDIF IF CROMEMCO INB DISK+4 ;Get head load bit XCHG AL,AH OUTB 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 seek speed 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 seek speed bit JNZ FASTSK ENDIF DCOM: OUT DISK MOV AL,50 DELAY: DEC AL ;Delay 10 microseconds JNZ DELAY 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 = 1 if fast seek (PerSci) ; 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 without fast seek 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