; taken from a clone bios ; and fixed to link with Turbo Pascal ; ROM CALLS ROMREAD equ 2 ROMWRITE equ 3 ROMFORMAT equ 5 ; 765 commands RECAL equ 7 SENSEINT equ 8 SPECIFY equ 3 SENSESTAT equ 4 READ equ 6 WRITE equ 5 FORMAT equ 13 ; 0dh SEEK equ 15 entry macro x pad =BANNER - $ + x - 0E000h if pad LT 0 .err %out 'No room for ENTRY point' endif if pad GT 0 db pad DUP(0FFh) endif endm ; RRETF macro x ; tasm complained about retf ifb db 0CBh else db 0CAh dw x endif endm ; LF equ 0Ah CR equ 0Dh ; wreg86 struc wax dw ? wbx dw ? wcx dw ? wdx dw ? wbp dw ? wsi dw ? wdi dw ? wdseg dw ? weseg dw ? wflags dw ? ends breg86 struc bal db ? bah db ? bbl db ? bbh db ? bcl db ? bch db ? bdl db ? bdh db ? ends DSKPARMS struc dmode1 db ?;11001111B dmode2 db ?;2 clktic db ?;25h bytesec db ?;2 lstsec db ?;8 gaplen db ?;2Ah datalen db ?;0ffh ; if not 80h gplenfmt db ?;50h fmtchr db ?;0f6h hdsett db ?;19h mtrstrt db ?;4 ends ; problem : the ROM bios routines do not allow easy access to some features ; of the disk controller ; 1) The ROM does not support single density, since setup codes for 765 ; are ; hard coded in rom. ; 2) Setting the AT HiDensity drive in low density, 96 tpi mode is a ; pain ; Hence the following TASM source file can replace the usual ROM call ; ; procedure inter13( VAR REGS : registers; VAR DISKTABLE : diskparms) .MODEL TPASCAL .DATA EXTRN DOUBLESTEP : WORD ; set externally by pascal program EXTRN SINGLEDENSITY : WORD; ENDS .CODE DISKIO PROC FAR REGS:DWORD, DISKTABLE : DWORD ; must preserve DS and BP PUBLIC DISKIO LES SI,REGS ; get the registers mov bx, es:[si.wbx] mov cx, es:[si.wcx] test cs:DBLSTEP, 1 ; ch has track number, so could double here jz DONT add ch,ch DONT: mov ax, es:[si.wax] mov dx, es:[si.wdx] mov di, es:[si.weseg] mov es, di ; use di as scratch STI ; PUSH BP ; macros do this one ; PUSH SI ; don't care ; PUSH DI PUSH DS PUSH ES PUSH BX MOV DI,AX ; Request type in DI, for index LES SI, DISKTABLE ;load pointer to disk params ; Get disk scratch ram area MOV AX,40h MOV DS,AX ASSUME DS:0040h MOV AX,word ptr es:[SI.GAPLEN] ; Get (Gap Length, DTL) in AX PUSH AX ; ...save it MOV AX,word ptr es:[SI.BYTESEC] ; Get (Bytes/sector,EOT) in AX PUSH AX ; ...save it XCHG CL,DH XCHG DL,CL PUSH DX ; Push (Head,Drive) swapped PUSH CX PUSH DI ; got to save BP, since variables are reference off it MOV AX,BP ; save the old BP before resetting MOV BP,SP ; Mark bottom of stack frame PUSH AX ; now can push the old BP ifdef SLOW_FLOPPY CALL FD_SPD ; ...execute request lo speed else CALL FD_XQT ; ...execute at current speed endif MOV AH,ES:[SI.CLKTIC] ; Get new motor count MOV DS:40h,AH ; ...and save it MOV AH,DS:41h ; Get completion status CMP AH,1 ; ...check for write protect CMC ; ...was write protect error POP BP ; last pushed POP BX POP CX POP DX POP BX ; Clean POP BX ; ...up POP BX ; ...stack POP ES POP DS ; turbo macro does not save ds automatically ; POP DI ; POP SI ; POP BP ; macro does this one les si, REGS ; mov es:[si.wax],ax ; save the result pushf ; how else to do this? pop ax and ax, 1 ; just get the carry flag mov es:[si.wflags],ax ret ;RETF 2 ; DISKIO ENDP SERVICE PROC NEAR ; service routines for the above FD_XQT: MOV AL, byte ptr [BP+1] ; Get floppy service number OR AL,AL JZ FD_RST ; ...reset, AH=0 DEC AL JZ FD_XQ3 ; ...read status, AH=1 CMP Byte ptr [BP+2],3 ; For track number above 3? JA FD_XQ1 ; ...yes CMP AL,ROMFORMAT ;5 ; Service within range? JBE FD_XQ2 ; ...yes FD_XQ1: MOV Byte ptr DS:41h,1 ; Say write protect error RET FD_XQ2: JMP FD_001 ; Execute legal service FD_XQ3: MOV AL,DS:41h ; Return NEC status byte RET FD_RST: MOV DX,3F2h ; Reset the floppy disk system CLI AND Byte ptr DS:3Fh,0Fh ; Clear "write in progress" MOV AL,DS:3Fh ; ...find out busy drives MOV CL,4 SHL AL,CL TEST AL,20h JNZ FD_RS1 ; Drive #1 active TEST AL,40h JNZ FD_RS2 ; Drive #2 active TEST AL,80h JZ FD_RS0 ; Drive #3 idle FD_RS3: INC AL FD_RS2: INC AL FD_RS1: INC AL FD_RS0: MOV Byte ptr DS:3Eh,0 ; All drives need recalibrate MOV Byte ptr DS:41h,0 ; ...no completion status OR AL,8 ; Interrupt ON in command word OUT DX,AL ; ...send word to controller OR AL,4 ; "Reset" in command word OUT DX,AL ; ...send word to controller STI CALL NC_BSY ; Wait for completion CALL NC_STS ; ...read result block MOV AL,DS:42h CMP AL,0C0h ; Did the reset work JZ FD_RS4 ; ...yes MOV Byte ptr DS:41h,20h ; Else set controller error JMP SHORT FD_RS5 ; ...return FD_RS4: MOV AL,SPECIFY ;3 ; Specify command to NEC CALL NEC765 ; ...send it MOV AL,ES:[SI.dmode1] ; First byte in param block CALL NEC765 ; ...send it MOV AL,ES:[SI.dmode2] ; Secnd byte in param block CALL NEC765 ; ...send it FD_RS5: RET NECFUN DB 003h,000h,0E6h,0C5h,0E6h,04Dh ; NEC function table lookup NECDMA DB 000h,000h,046h,04Ah,042h,04Ah ; DMA modes for 8237 NECWRT DB 000h,000h,000h,080h,000h,080h ; Write flag table lookup NECDRV DB 1,2,4,8 ; Drive number table lookup NECERR DB 80h,20h,10h,4,2,1 ; Error code table lookup NECSTS DB 04h,10h,08h,04h,03h,02h,20h ; Disk status table lookup ; single density versions SNECFUN DB 003h,000h,0A6h,085h,0A6h,00Dh ; NEC function table lookup FD_001: CLI ; Normal (non-reset) commands MOV Byte ptr DS:41h,0 ; ...reset status MOV AL,[BP+1] ; Get command word XOR AH,AH MOV DI,AX ; Save copy, zero-extended OUT 0Ch,AL ; ...diddle LSB/MSB flip-flop MOV AL,CS:[DI+NECDMA] ; Fetch DMA mode OUT 0Bh,AL ; ...send it to IC8237 MOV AX,[BP+0Ch] ; Get segment address MOV CL,4 ; ...convert ROL AX,CL ; ...to bytes MOV CH,AL ; Copy the wrap around AND CH,0Fh ; ...mask out not wrapped, CH AND AL,0F0h ; ...mask out wrapped, AL ADD AX,[BP+0Ah] ; Add offset to AX ADC CH,0 ; ...do carry if set MOV DX,AX ; Now save lo 16 bits of addr. OUT 4,AL ; ...send lowest 8 bits " " MOV AL,AH OUT 4,AL ; ...send next 8 bits " " MOV AL,CH OUT 81h,AL ; Send hi bits to DMA page reg MOV AH,[BP+0] XOR AL,AL SHR AX,1 ; Sector cnt * 128 MOV CL,[BP+6] ; Track count SHL AX,CL ; * sector count DEC AX ; - 1 OUT 5,AL ; Send 1/2 of the word count XCHG AL,AH OUT 5,AL ; Send 2/2 of the word count XCHG AL,AH ADD AX,DX ; Compute final address JNB FD_002 ; ...ok STI MOV Byte ptr DS:41h,9h ; Else wrapped around page reg JMP FD_011 FD_002: MOV AL,2 ; Disable floppy disk dma OUT 0Ah,AL MOV Byte ptr DS:40h,0FFh ; Set large motor timeout MOV BL,[BP+2] ; ...get drive number XOR BH,BH MOV AL,CS:[BX+NECDRV] ; Table lookup bit position MOV CH,AL ; ...save mask MOV CL,4 SHL AL,CL ; Shift mask into place OR AL,BL ; ...or in drive select OR AL,0Ch ; ...or in DMA and NO RESET MOV DX,3F2h OUT DX,AL ; Send to floppy control port STI MOV AL,CS:[DI+NECWRT] ; Table lookup for write flag OR DS:3Fh,AL ; ...set write flag if active OR AL,AL JNS FD_003 ; ...skip if non-write MOV AH,ES:[SI.mtrstrt] ; Motor start from param blk OR AH,AH JZ FD_003 ; ...none specified TEST CH,DS:3Fh ; Was this drive motor running? JNZ FD_003 ; ...skip if so CALL FD_WT1 ; Else delay for motor start FD_003: OR DS:3Fh,CH ; Show this motor is running TEST CH,DS:3Eh ; Drive recalibration needed? JNZ FD_004 ; ...no, skip OR DS:3Eh,CH ; Else show recalibrated MOV AL,RECAL ;7 ; Send RECAL command CALL NEC765 ; ...to NEC 765 chip MOV AL,BL CALL NEC765 ; ...drive number CALL NC_BSY ; Wait for completion of RECAL CALL NEC_04 ; ...dummy call to RET FD_004: MOV AL,SEEK ;0Fh ; Request a seek CALL NEC765 ; ...from the NEC 765 MOV AL,BL CALL NEC765 ; Drive number MOV AL,[BP+3] CALL NEC765 ; Cylinder number CALL NC_BSY ; ...wait for completion CALL NC_STS ; ...read results MOV AL,ES:[SI.hdsett] ; Get head settle time OR AL,AL ; ...none specified? JZ FD_005 ; ...if none, skip FD_STL: MOV CX,226h ; Delay time for head settle FD_STZ: LOOP FD_STZ ; ...timed wait DEC AL ; ...delay in millisec JNZ FD_STL ; ...wait some more ; the density flag is set as part of the command sent to the 765 ; so easiest just to change pointers to table FD_005: test cs:DENSITYFLAG,1 MOV AL,CS:[DI+NECFUN] ; Translate user service, then jnz RESUME MOV AL,CS:[DI+SNECFUN] ; Translate user service, then RESUME: CALL NEC765 ; ...and send as NEC func MOV AL,[BP+4] ; AND AL,1 SHL AL,1 SHL AL,1 OR AL,BL CALL NEC765 CMP Byte ptr [BP+1],ROMFORMAT ;5 ; Is this a format request? JNZ FD_006 ; ...skip if not MOV AL,[BP+6] ; Else use user bytes/sector CALL NEC765 MOV AL,[BP+7] ; ... user EOT CALL NEC765 MOV AL,ES:[SI.gplenfmt] ; Disk table format gap length CALL NEC765 MOV AL,ES:[SI.fmtchr] ; Disk table format fill byte CALL NEC765 JMP SHORT FD_008 FD_006: MOV CX,7 ; Else lookup bytes * 512/sec MOV DI,3 ; ...from disk table FD_007: MOV AL,[BP+DI] ; AL has bytes/sector * 512 CALL NEC765 INC DI ; ...get next item for table LOOP FD_007 ; ...also (EOT,GAP,DTL...) FD_008: CALL NC_BSY ; Wait on floppy i/o completion CALL NC_ST1 ; ...get NEC status MOV AL,DS:42h ; ...into AL AND AL,0C0h ; Isolate errors JZ FD_012 ; ...no errors CMP AL,40h ; Test direction bit JZ FD_ERR MOV Byte ptr DS:41h,20h ; Set if bad controller JMP SHORT FD_012 ; ...return error FD_ERR: MOV AL,DS:43h ; Read return code from block MOV CX,6 ; ...number of error types XOR BX,BX ; Start at error type 0 FD_009: TEST AL,CS:[BX+NECERR] ; Has error type BX occured? JNZ FD_010 ; ...yes INC BX ; Else try next error type LOOP FD_009 ; ...until done FD_010: MOV AL,CS:[BX+NECSTS] ; Translate error code again MOV DS:41h,AL ; ...store it as disk status FD_012: MOV AL,DS:45h ; Get bytes read CMP AL,[BP+3] ; ...compare with requested MOV AL,DS:47h ; Read sectors requested JZ FD_013 ; ...return if all read MOV AL,[BP+7] ; Else read sectors requested INC AL ; ...add one for luck FD_013: SUB AL,[BP+5] ; Subtract stectors read RET FD_011: MOV AL,0 ; Show no sectors read RET NC_BSY: STI ; Wait for operatin to finish XOR CX,CX ; ...zero lo orderdelay MOV AL,2 ; Load hi order delay NC_BS1: TEST Byte ptr DS:3Eh,80h ; Has interrupt set the flag? CLC ; ...hack to slow CPU JNZ NC_BS2 ; ...yes LOOP NC_BS1 ; Else back for more DEC AL JNZ NC_BS1 MOV Byte ptr DS:41h,80h ; Time-out, say it completed POP AX XOR AL,AL ; ...return time out code STC ; ...error status RET NC_BS2: AND Byte ptr DS:3Eh,7Fh ; Mask off completion status RET ; ...return carry clear NC_RDY: PUSH CX ; Wait for NEC ready for comand XOR CX,CX MOV DX,3F4h ; ...NEC status port NC_RD1: IN AL,DX ; Read status of NEC 765 chip OR AL,AL JS NC_RD2 ; ...able to accept command LOOP NC_RD1 MOV Byte ptr DS:41h,80h ; Else show timeout error JMP SHORT NC_RD3 NC_RD2: TEST AL,40h ; Test the direction bit JNZ NC_RD4 MOV Byte ptr DS:41h,20h ; ...clear iff controller err NC_RD3: POP CX STC RET NC_RD4: INC DX ; Load NEC data port IN AL,DX ; ...read it PUSH AX MOV CX,0Ah ; Short delay NC_RD5: LOOP NC_RD5 DEC DX ; Load NEC status port IN AL,DX ; ...read status TEST AL,10h ; ...set Z flag if done CLC ; ...return success POP AX POP CX RET ; does this work on 8 mhz v20 ????? FD_WT1: PUSH CX ; Millisecond delay in AH FD_WT2: XOR CX,CX FD_WT3: LOOP FD_WT3 DEC AH JNZ FD_WT2 POP CX RET ifdef SLOW_FLOPPY ; Run floppy at SLOWEST speed FD_SPD: IN AL,61h ; Toggle speed on Floppy Disk PUSH AX ; ...save old clock rate AND AL,0F3h ; ...load slowest clock rate OUT 61h,AL ; ...slow down to 4.77 mHz CALL FD_XQT ; Execute the i/o request POP AX ; ...restore old clock rate OUT 61h,AL ; ...from saved clock byte RET FD_SPD ENDP endif ; ENTRY 0EF57h ; Disk interrupt entry NC_STS: MOV AL,8 ; Send a "Request status" CALL NEC765 ; ...to the NEC 765 chip NC_ST1: PUSH BX ; Alternate entry point PUSH CX MOV CX,7 XOR BX,BX NC_ST2: CALL NC_RDY ; Wait for NEC 765 ready JB NC_ST3 ; ...NEC 765 error MOV [BX+42h],AL ; Save status in BIOS block JZ NC_ST4 ; ...NEC 765 ready INC BX ; Count more LOOP NC_ST2 MOV Byte ptr DS:41h,20h ; NEC 765 controller error NC_ST3: STC ; Set error condition POP CX POP BX POP AX XOR AL,AL RET NC_ST4: POP CX ; Successful return POP BX RET NEC765: PUSH CX ; Send control to NEC 765 chip PUSH DX PUSH AX XOR CX,CX MOV DX,3F4h ; Load NEC 765 status port NEC_01: IN AL,DX ; Read NEC 765 status OR AL,AL JS NEC_02 ; ...done LOOP NEC_01 MOV Byte ptr DS:41h,80h ; Set time out status JMP SHORT NEC_05 NEC_02: TEST AL,40h ; Check data direction JZ NEC_03 MOV Byte ptr DS:41h,20h ; ...NEC 765 is gimped JMP SHORT NEC_05 NEC_03: INC DX ; Load NEC 765 data port POP AX OUT DX,AL ; ...write user's parameter CLC POP DX POP CX NEC_04: RET NEC_05: POP AX ; Common error return POP DX POP CX POP AX XOR AL,AL STC RET SERVICE ENDP ; ENTRY 0EF57h ; Disk interrupt entry ;INT_E: STI ; Floppy disk attention ; PUSH DS ; PUSH AX ; MOV AX,40h ; MOV DS,AX ; OR Byte ptr DS:3Eh,80h ; Raise "attention" flag ; MOV AL,20h ; Send end_of_interrupt code ; OUT 20h,AL ; ...to 8259 interrupt chip ; POP AX ; POP DS ; RETI ; SETDENSITY PROC FAR DENSITY : word PUBLIC SETDENSITY mov ax,DENSITY MOV CS:DENSITYFLAG,AL RET SETDENSITY ENDP GETDENSITY PROC FAR PUBLIC GETDENSITY xor ax,ax MOV al,CS:DENSITYFLAG RET GETDENSITY ENDP SETDBLSTEP PROC FAR STEP : word PUBLIC SETDBLSTEP mov ax,STEP MOV CS:DBLSTEP,AL RET SETDBLSTEP ENDP GETDBLSTP PROC FAR PUBLIC GETDBLSTEP xor ax,ax MOV al,CS:DBLSTEP RET GETDBLSTEP ENDP DENSITYFLAG DB 1 ;MFM = 1, FM = 0 DBLSTEP DB 0 ;NO DOUBLE STEPPING CODE ENDS END