P8000/WEGA/contrib/wdos/src/disk.asm

569 lines
12 KiB
NASM

;**************************************************************************
;**************************************************************************
;
; WDOS-BIOS - Quelle (C) ZFT/KEAW Abt. Basissoftware - 1988
; Programm: disk.asm
;
; Bearbeiter : P. Hoge
; Datum : 24.9.89
; Version : 1.1
;
;**************************************************************************
;
; Hard- u. Floppy Disk-Treiber
;
;**************************************************************************
;**************************************************************************
.PUBLIC DISK
.PUBLIC DISK_SETUP
.PUBLIC DISKINT
.PUBLIC SEEK
.EXTERNAL DDS ;NEAR
.EXTERNAL LONG HF_TBL_VEC
.EXTERNAL LONG HF1_TBL_VEC
.EXTERNAL LONG DISK_POINTER
.external byte DISK_BASE
.EXTERNAL BYTE FD_TBL
.EXTERNAL BYTE FD1_TBL
.EXTERNAL BYTE FD2_TBL
.EXTERNAL BYTE DISKETTE_STATUS
.EXTERNAL BYTE SEEK_STATUS
.external byte intin
.external byte intout
.external byte diskin
.external byte diskout
.external byte hdtyp
.external byte diskrq
;-----INT 13 ---------------------------------------------------
;
; THIS INTERFARCE PROVIDES ACCESS DISKS
;
;---------------------------------------------------------------
;
;INPUT (AH = HEX VALUE)
;
; (AH)=00 RESET DISK - Nullop
; (AH)=01 READ THE STATUS OF THE LAST DISK OPERATION INTO (AL)
; NOTE: DL<80H - DISKETTE
; DL>80H - DISK
; (AH)=02 READ THE DESIRED SECTORS INTO MEMORY
; (AH)=03 WRITE THE DESIRED SECTORS FROM MEMORY
; (AH)=04 VERIFY THE DESIRED SECTORS - Nullop
; (AH)=05 FORMAT THE DESIRED TRACK - Nullop
; (AH)=06 UNUSED
; (AH)=07 UNUSED
; (AH)=08 RETURN THE CURRENT DRIVE PARAMETERS
; (AH)=09 INITIALIZE DRIVE PAIR CHARACTERISTICS (HD) - Nullop
; INTERRUPT 41 POINTS TO DATA BLOCK FOR DRIVE 0
; INTERRUPT 46 POINTS TO DATA BLOCK FOR DRIVE 1
; (AH)=0A READ LONG (HD) - nicht moeglich
; (AH)=0B WRITE LONG (HD) - nicht moeglich
; (AH)=0C SEEK (HD) - Nullop
; (AH)=0D ALTERNATE DISK RESET (HD) - Nullop
; (AH)=0E UNUSED
; (AH)=0F UNUSED
; (AH)=10 TEST DRIVE READY (HD) - nicht moeglich
; (AH)=11 RECALIBRATE (HD) - Nullop
; (AH)=12 UNUSED
; (AH)=13 UNUSED
; (AH)=14 CONTROLLER INTERNAL DIAGNOSTIC (HD) -Nullop
; (AH)=15 READ DASD TYPE
; (AH)=16 READ DISK CHANGE (FD)
; (AH)=17 SET DISK TYPE (FD) - Nullop
;
; REGISTERS USED FOR DISK OPERATIONS
;
; (DL) - DRIVE NUMBER
; (DH) - HEAD NUMBER
; (CH) - CYLINDER NUMBER (Track)
; (CL) - SECTOR NUMBER
; (AL) - NUMBER OF SECTORS (MAXIMUN POSSIBLE RANGE 1 - 80H,
; (ES:BX) - ADDRESS OF BUFFER FOR READS AND WRITES,
;OUTPUT
; AH = STATUS OF CURRENT OPERATION
; STATUS BITS ARE DEFINED IN THE EQUATES BELOW
; CY = 0 SUCCESSFUL OPERATION (AH=0 ON RETURN)
; CY = 1 FAILED OPERATION (AH HAS ERROR REASON)
;
; IF DRIVE PARAMETERS WERE RAQUESTED
;
; DL = NUMBER OF CONSECUTIVE ACKNOWLEDGING DRIVES ATTACHED (0-2)
; DH = MAXIMUM USEABLE VALUE FOR HEAD NUMBER
; CH = MAXIMUM USEABLE VALUE FOR CYLINDER NUMBER
; CL = MAXIMUM USEABLE VALUE FOR SECTOR NUMBER
; AND CYLINDER NUMBER HIGH BITS
;
; IF READ DASD TYP WAS REQUESTED,
;
; AH =0 - NOT PRESENT
; 1 - DISKETTE - NO CHANGE LINE AVAILABLE (360 kByte Drive)
; 2 - DISKETTE - CHANGE LINE AVAILABLE (720 KByte / 1.2 MByte Drive)
; 3 - FIXED DISK
; CX,DX = NUMBER OF 512 BYTE BLOCKS WHEN AH = 3
;
; REGISTERS WILL BE PRSERVED EXEPT WHEN THEY ARE USED TO RETURN
; INFORMATION.
;---------------------------------------------------------------------------
BAD_CMD EQU 01H
INIT_FAIL EQU 07H
TIME_OUT EQU 80H
DISK_CHANGE EQU 06H
LASTD: defb 0 ;letztes angesprochenes Drive
NSECT: defb 0 ;Sektoren/Spur LW 0
defb 0 ;LW 1
defb 0 ;LW 2
defb 0 ;LW 3
defb 0 ;LW 4
defb 0 ;LW 5
;-----------------------------------------------------
;DISK_SETUP
; THIS ROUTINE DOES A PRELIMINARY CHECK TO SEE
; WHAT TYPE OF DISKETTE DRIVES ARE ATTACH TO THE
; SYSTEM.
;-----------------------------------------------------
DISK_SETUP ;NEAR
push ds
push bx
sub ax,ax
mov ds,ax
mov cs:LASTD,al
mov cs:NSECT,ax
mov cs:NSECT+2,ax
mov cs:NSECT+4,ax
mov al,cs:hdtyp+0 ;Type HD 0
mov bx,offset FD2_TBL ;20 MByte HD
cmp al,2
jz DS1
mov bx,offset FD1_TBL ;10 MByte HD
cmp al,1
jz DS1
mov bx,offset FD_TBL ;5 MByte HD
DS1: mov HF_TBL_VEC,bx
mov al,cs:hdtyp+1 ;Type HD 1
mov bx,offset FD2_TBL ;20 MByte HD
cmp al,2
jz DS2
mov bx,offset FD1_TBL ;10 MByte HD
cmp al,1
jz DS2
mov bx,offset FD_TBL ;5 MByte HD
DS2: mov HF1_TBL_VEC,bx ;Drive 0
CALL DDS
MOV SEEK_STATUS,0
pop bx
POP DS
RET
;---------------------------------------
; DISK BIOS ENTRY POINT
;---------------------------------------
DISK ;PROC FAR
STI ;ENABLE INTERRUPTS
CMP AH,08H ;GET PARAMETERS IS A SPECIAL CASE
JNZ DISK1
JMP GET_PARM
DISK1: CMP AH,15H ;READ DASD TYPE IS ALSO
JNZ DISK2
JMP DISK_TYPE
DISK2: PUSH BX ;SAVE REGISTERS DURING OPERATION
PUSH CX
PUSH DX
PUSH DS
PUSH SI
CALL DISK_CONT ;PERFORM THE OPERATON
MOV AH,DISKETTE_STATUS ;GET STATUS FROM OPERATION
CMP AH,1 ;SET THE CARRY FLAG TO INDICATE
CMC ;SUCCESS OR FAILURE
POP SI
POP DS
POP DX
POP CX
POP BX
RET FAR 2 ;THPROW AWAY SAVED FLAGS
M1: ;FUNCTION TRANSFER TABLE
DW RETURN_OK ;00H DISK RESET
DW READ_STATUS ;01H
DW DISK_READ ;02H
DW DISK_WRITE ;03H
DW RETURN_OK ;04H DISK VERIFY
DW RETURN_OK ;05H FORMAT TRACK
DW BAD_COMD ;06H FORMAT BAD SECTORS
DW BAD_COMD ;07H FORMAT DRIVE
DW BAD_COMD ;08H RETURN PARMS
DW RETURN_OK ;09H INIT DRIVE
DW BAD_COMD ;0AH READ LONG
DW BAD_COMD ;0BH WRITE LONG
DW RETURN_OK ;0CH SEEK
DW RETURN_OK ;0DH DISK RESET
DW BAD_COMD ;0EH READ BUFFER
DW BAD_COMD ;0FH WRITE BUFFER
DW RETURN_OK ;10H TEST READY
DW RETURN_OK ;11H RECALIBRATE
DW BAD_COMD ;12H RAM DIAGNOSTIC
DW BAD_COMD ;13H DRIVE DIAGNOSTIC
DW RETURN_OK ;14H CONTROLLER DIAGNISTIC
DW BAD_COMD ;15H GET DISK TYPE
DW RDISK_CHANGE ;16H READ DISK CHANGE
DW RETURN_OK ;17H SET DISK TYPE
M1L: EQU $-M1
DISK_CONT ;PROC NEAR
CALL DDS
CMP AH,1
JZ READ_STATUS
MOV DISKETTE_STATUS,0
PUSH AX
MOV AL,AH ;GET INTO LOW BYTE
XOR AH,AH ;ZERO HIGH BYTE
SAL AX,1 ;*2 FOR TABLE LOOKUP
MOV SI,AX ;PUT INTO SI FOR BRANCH
CMP AX,M1L ;TEST WITHIN RANGE
JNB BAD_COMD_P
POP AX
JMP CS:[SI]+M1
BAD_COMD_P:
POP AX
BAD_COMD:
MOV AL,0
MOV DISKETTE_STATUS,BAD_CMD
RETURN_OK:
RET
;-------------------------------------------------
;READ STATUS (AH = 02H)
;-------------------------------------------------
READ_STATUS ;PROC NEAR
MOV AL,DISKETTE_STATUS ;OBTAIN REVIOUS STATUS
RET
;-------------------------------------------------
;DISK READ ROUTINE (AH = 02H)
;-------------------------------------------------
DISK_READ ;PROC NEAR
mov ah,1
jmp short DRW0
;------------------------------------------------
;DISK WRITE ROUTINE (AH = 03H)
;------------------------------------------------
DISK_WRITE ;PROC NEAR
mov ah,2
DRW0: push cx
push dx
push ax
push bx
mov cs:LASTD,dl
cmp dl,80h ;HD ?
jnc DRW6
push ax
sub ax,ax
mov ds,ax
pop ax
lds si,DISK_POINTER
cmp si,522h ;Standard Parametervektor
jnz DRW1
sub bx,bx
mov bl,dl
mov bl,cs:NSECT[bx] ;Sektoren/Spur aus internem Merker
or bl,bl ;0= kein Eintrag
jnz DRW2
DRW1: mov bl,[si]+4 ;Sektoren/Spur aus Parametervector
DRW2: cmp bl,0ffh ;cpmform und msform setzen diesen
jnz DRW4 ;Wert auf ff, die Anzahl ergibt sich:
sub bx,bx
mov bl,dl
mov bl,cs:NSECT[bx] ;Sektoren/Spur aus internem Merker
or bl,bl ;0= kein Eintrag
jnz DRW4
mov bl,al ;Wert aus al
DRW4: cmp bl,8 ;8*512 in 9*512 umwandeln
jnz DRW5
inc bl
DRW5: mov bh,[si]+3 ;Sektorlaenge
mov al,2 ;Anzahl der Koepfe stets 2
jmp short DRW7
DRW6: call GET_VEC
mov si,bx
mov bh,2 ;Sektorlaenge 512 Byte
mov bl,[si]+14 ;Anzahl der Sektoren
mov al,[si]+2 ;Anzahl der Koepfe
DRW7: cmp dl,80H
jc DRW8
sub dl,7eh ;Drive 0,1 FD, 2,3 HD, 4-7 FD
DRW8: mov cs:diskrq+1,dl ;Drive
;Berechnung der Blocknummer:
;(((Cylinder * Anzahl Koepfe) + Kopfnummer) * Anzahl Sektoren) + Sektornummer-1
push dx
mov dh,cl
shr dh,1 ;obere 2 Bit der Cylinder Nr.
shr dh,1
shr dh,1
shr dh,1
shr dh,1
shr dh,1
mov dl,ch
sub ah,ah
mul dx ;Cyl * Koepfe
pop dx
mov dl,dh ;Head
sub dh,dh
add ax,dx
mov dl,bl ;Anzahl der Sektoren
sub dh,dh
mul dx ;* Anzahl der Sektoren
sub ch,ch
and cl,3FH ;Sektor
dec cl
add ax,cx ;Ergebnis: Blocknummer
mov dx,ax
;Berechnung der Sektorlaenge
mov cx,80h
or bh,bh ;Sektorlaenge
jz DRW10 ;128 Byte
DRW9: add cx,cx
dec bh
jnz DRW9
DRW10: mov ax,cx
;Berechnung des Byte-Offsets
;Offset = Blocknummer * Sektorlaenge
mul dx
mov cs:diskrq+2,dh
mov cs:diskrq+3,dl
mov cs:diskrq+4,ah
mov cs:diskrq+5,al
;Berechnung der Byteantahl
pop bx
pop ax
mov cs:diskrq+0,ah ;Request-Code
sub ah,ah ;al = Anzahl der Sektoren
mul cx ;* Sektorlaenge
mov cs:diskrq+10,ah
mov cs:diskrq+11,al
;Berechnung der physischen Adresse
mov ax,es
mov cl,12
shr ax,cl
mov dx,ax
mov ax,es
mov cl,4
shl ax,cl
add ax,bx
jnc DRW11
inc dx ;ES:BX changet to 000X:ax
DRW11: mov cs:diskrq+6,dh
mov cs:diskrq+7,dl
mov cs:diskrq+8,ah
mov cs:diskrq+9,al
mov word ptr cs:diskout+2,0c00h ;Anzahl der Bytes
DRW12: sti
nop
cli
mov ah,cs:intout ;kann Int gegeben werden ?
or ah,ah
jnz DRW12
mov cs:intout,3 ;Disk-Int
out 0,al ;Int ausloesen
sti
call DDS
; MOV AX,09001H ;LOAD WAIT CODE AND TYPE
; INT 15H ;PERFORM OTHER FUNCTION
WT1: TEST SEEK_STATUS,80H ;TEST FOR INTERRUPT
JZ WT1
MOV SEEK_STATUS,0 ;TURN OFF INTERRUPT FLAG
;internen Wert Sektoren/Spur aus Sektor 0/ Spur 0 ermitteln
pop dx
pop cx
cmp dl,6 ;Floppy ?
jnc WT4
or ch,dh ;Spur 0 / Head 0 ?
jnz WT4
cmp cl,1 ;Sektor 1
jnz WT4
sub dh,dh
mov cl,es:[bx]+21 ;Format-ID Byte
cmp cl,0f9h
jc WT2 ;keine DOS-Diskette
mov cl,es:[bx]+24 ;Anzahl Sektoren/Track
cmp cl,8
jz WT3
cmp cl,9
jz WT3
cmp cl,15
jz WT3
WT2: sub cl,cl ;spezielles Format
WT3: mov bx,dx
mov cs:NSECT[bx],cl
WT4: ret
;-------------------------------------------------------------
;DISK_INT
; THIS ROUTINE HANDLES THE DISKETTE INTERRUPT
;INPUT
; NONE
;OUTPUT
; THE INTERRUPT FLAG IS SET IS SEEK_STATUS
;-------------------------------------------------------------
DISKINT ;PROC FAR ;>>> ENTRY POINT FOR ORG 0EF57H
PUSH DS ;SAVE REGISTERS
PUSH AX
CALL DDS ;SETUP DATA ADDRESSING
mov cs:intin,0 ;weitere Ints erlauben
mov al,cs:diskin+2
mov DISKETTE_STATUS,al
mov cs:diskin+1,0 ;weiteren Disk-Int erlauben
sti
MOV SEEK_STATUS,0FFH ;TURN ON INTERRUPT OCCURRED
; MOV AX,09101H ;INTERRUPT OTHER TASK
; INT 15H ;GO PERFORM OTHER TASK
POP AX ;RECOVER REG
POP DS
IRET
;---------------------------------------------
; GET PARAMETERS (AH = 8)
;---------------------------------------------
GET_PARM ;NEAR ;GET DRIVE PARAMETERS
PUSH DS
PUSH BX
CALL DDS
MOV DISKETTE_STATUS,0
cmp dl,80h
jc G3
AND DL,7FH ;Hard-Disk
CMP DL,2 ;TEST WITHIN RANGE
JAE G4
call GET_VEC
MOV AX,[BX] ;MAX NUMBER OF CYLINDERS
dec ax
MOV CH,AL
AND AX,0300H ;HIGH TWO BITS OF CYL
SHR AX,1
SHR AX,1
OR AL,[BX]+14 ;SECTORS
MOV CL,AL
MOV DH,[BX]+2 ;HEADS
DEC DH
MOV DL,2 ;DRIVE COUNT
G1: SUB AX,AX
G2: POP BX ;RESTORE REGISTERS
POP DS
RET FAR 2
G3: cmp dl,2
jnc G4
mov cl,cs:DISK_BASE+4 ;letzte Sektor-Nr.
mov ch,79 ;letzte Track-Nr.
mov dh,1 ;letzte Kopfnummer
mov dl,2 ;Anzahl der Laufwerke
jmp short G1
G4: sub ax,ax
mov cx,ax
mov dx,ax
mov ah,INIT_FAIL
mov DISKETTE_STATUS,ah
stc ;Set Error Flag
jmp short G2
;------------------------------------------------
;READ DASD TYPE (AH = 15H)
;------------------------------------------------
DISK_TYPE ;PROC NEAR
push ds
call DDS
mov DISKETTE_STATUS,0
cmp dl,80h
jnc DT2
cmp dl,2
jnc DT3
mov ah,1 ;CHANGE LINE not available
DT1: sub al,al
pop ds
ret far 2
DT2: push bx
and dl,7fh
cmp dl,2 ;Test drive number
jnc DT3
CALL GET_VEC ;GET DISK PARM ADDRESS
MOV AL,[BX]+2 ;HEADS
MOV CL,[BX]+14
IMUL CL ;*NUMBER OF SECTORS
MOV CX,[BX] ;MAX NUMBER OF CYLINDERS
IMUL CX ;NUMBER OF SECTORS
MOV CX,DX ;HIGH ORDER HALF
MOV DX,AX ;LOW ORDER HALF
mov ah,3 ;Hard Disk
pop bx
jmp short DT1
DT3: sub ax,ax
mov cx,ax
mov dx,ax
jmp short DT1
;---------------------------------------
;SET UP DS:BX -> DISK PARMS
;---------------------------------------
GET_VEC ;PROC NEAR
SUB AX,AX
MOV DS,AX
LDS BX,HF_TBL_VEC ;DS:BX -> DRIVE PARAMETERS
TEST DL,1
JZ GV
mov ds,ax
LDS BX,HF1_TBL_VEC ;DS:BX -> DRIVE PARAMETERS
GV: RET
;------------------------------------------------
;READ DISK CHANGE (AH = 16H)
;------------------------------------------------
RDISK_CHANGE ;PROC NEAR
cmp dl,cs:LASTD
jz RC1
mov DISKETTE_STATUS,DISK_CHANGE
mov cs:LASTD,dl
RC1: ret
;-----------------------
;SEEK
;-----------------------
SEEK ;PROC NEAR
clc ;Clear CY
ret ;RETURN TO CALLER
END