home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1995 November
/
PCWK1195.iso
/
inne
/
podstawy
/
dos
/
format
/
2m30src.exe
/
2M-ABIOS.ASM
next >
Wrap
Assembly Source File
|
1995-03-06
|
134KB
|
3,216 lines
;┌───────────────────────────────────────────────────────────────────┐
;│ │
;│ █████ █ █ █▀▀▀█ █▀▀▄ ▀▀█▀▀ ▄▀▀▀▄ █▀▀▀▀ │
;│ █ ██ ██ █ █ █ █ █ █ █ █ │
;│ █████ █ █ █ ▀▀▀▀▀ █████ ████ █ █ █ █████ │
;│ █ █ █ █ █ █ █ █ █ █ █ │
;│ █████ █ █ █ █ █▄▄▀ ▄▄█▄▄ ▀▄▄▄▀ █████ │
;│ │
;│ │
;│ 2M-ABIOS 1.3 - (C) 1994-1995 Ciriaco García de Celis. │
;│ │
;│ Código para emular al 100% la BIOS AMI de 1993. │
;│ │
;│ Si el ordenador posee disco duro y una BIOS moderna, la │
;│ INT 40h controla los accesos a disquete. Desviar esta │
;│ interrupción en lugar de la INT 13h permite que este │
;│ programa tome el control de las disqueteras antes que │
;│ cualquier otro (incluso aunque se instale después) y │
;│ además permite seguir trabajando al código del DOS que, │
;│ desde INT 13h, soluciona el cruce con las fronteras de │
;│ DMA antes de invocar a la INT 40h. │
;│ │
;│ Si el ordenador no utilizase la INT 40h en los accesos a │
;│ las disqueteras se desvía INT 13h y se cuelga este código │
;│ de la misma, cuidando evitar un cruce con el DMA a través │
;│ de un buffer intermedio auxiliar si es preciso. │
;│ │
;│ Para la versión AT: Para la versión PC/XT: │
;│ TASM 2m-abios /m5 TASM 2m-abios, 2m-xbios /m5 /dXT │
;│ TLINK 2m-abios TLINK 2m-xbios │
;│ │
;│ Con [+] se señalizan las líneas del listado que cambian │
;│ de manera intencionada y por algún motivo especial │
;│ respecto a la BIOS AMI original (entre otras no señaladas │
;│ por no tener un motivo tan especial de cambio). │
;│ │
;└───────────────────────────────────────────────────────────────────┘
IFDEF XT
ID EQU ,"X",
ELSE
.286 ; versión para AT o superior
ID EQU ,"A",
ENDIF
; ------------ Macros de propósito general.
XPUSH MACRO regmem ; apilar lista de registros
IRP rm, <regmem>
PUSH rm
ENDM
ENDM
XPOP MACRO regmem ; desapilar lista de registros
IRP rm, <regmem>
POP rm
ENDM
ENDM
IFNDEF XT
XPUSHA MACRO
PUSHA
ENDM
XPOPA MACRO
POPA
ENDM
XSHR MACRO regmem, cuenta
SHR regmem,cuenta
ENDM
XSHL MACRO regmem, cuenta
SHL regmem,cuenta
ENDM
XROR MACRO regmem, cuenta
ROR regmem,cuenta
ENDM
XROL MACRO regmem, cuenta
ROL regmem,cuenta
ENDM
DDS MACRO
PUSH 40h
POP DS
ENDM
ELSE
XPUSHA MACRO
XPUSH <AX, BX, CX, DX, SI, DI>
ENDM
XPOPA MACRO
XPOP <DI, SI, DX, CX, BX, AX>
ENDM
XSHR MACRO regmem, cuenta
REPT cuenta
SHR regmem,1
ENDM
ENDM
XSHL MACRO regmem, cuenta
REPT cuenta
SHL regmem,1
ENDM
ENDM
XROR MACRO regmem, cuenta
REPT cuenta
ROR regmem,1
ENDM
ENDM
XROL MACRO regmem, cuenta
REPT cuenta
ROL regmem,1
ENDM
ENDM
DDS MACRO
PUSH AX
MOV AX,40h
MOV DS,AX
POP AX
ENDM
ENDIF
; ************ Inicio del área residente.
_PRINCIPAL SEGMENT
ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
ORG 0
ini_residente EQU $
DD -1 ; encadenamiento con otros drivers
tipo_drive DW 8000h ; palabra de atributo:
; bit 15 a 1: dispositivo caracteres
; bit 14 a 0: sin control IOCTL
DW estrategia ; rutina de estrategia
DW interrupcion ; rutina de interrupción
DB "2M-BIOS$" ; nombre del dispositivo
estrategia PROC FAR
MOV CS:pcab_pet_segm,ES
MOV CS:pcab_pet_desp,BX
RET
estrategia ENDP
interrupcion PROC FAR
CALL main ; tras instalar: XPUSH <DS, BX> y MOV BX,??
pcab_pet_segm DW ?
MOV DS,BX
DB 0BBh ; opcode de MOV BX,??
pcab_pet_desp DW ?
MOV WORD PTR [BX+3],8103h ; código de error
XPOP <BX, DS>
RET
interrupcion ENDP
; ****************************************
; * *
; * D A T O S R E S I D E N T E S *
; * *
; ****************************************
; ------------ Identificación estandarizada del programa.
program_id LABEL BYTE
segmento_real DW 0 ; segmento real donde será cargado
offset_real DW 0 ; offset real " " "
longitud_total DW 0 ; zona de memoria ocupada (párrafos)
info_extra DB 03h ; bits 0, 1 y 2-> 000: normal, con PSP
; 001: bloque UMB XMS
; 010: *.SYS
; 011: *.SYS formato EXE
; bit 7 a 1: «extension_id» definida
multiplex_id DB 0 ; número Multiplex de este TSR
vectores_id DW tabla_vectores
extension_id DW 0
DB "*##*"
autor_nom_ver DB "CiriSOFT:2M-" ID "BIOS:1.3",0
DB 3 ; número de vectores de interrupción usados
tabla_vectores EQU $
DB 15h ; INT 15h
ant_int15 LABEL DWORD ; dirección original
ant_int15_off DW 0
ant_int15_seg DW 0
DB 2Fh ; INT 2Fh
ant_int2F LABEL DWORD ; dirección original
ant_int2F_off DW 0
ant_int2F_seg DW 0
DB 40h ; INT 40h
ant_int40 LABEL DWORD ; dirección original
ant_int40_off DW 0
ant_int40_seg DW 0
DB 13h ; INT 13h podría llegar a usarse
ant_int13 LABEL DWORD
ant_int13_off DW 0
ant_int13_seg DW 0
; ***************************************
; * *
; * C O D I G O R E S I D E N T E *
; * *
; ***************************************
; ------------ Rutina de gestión de INT 2Fh.
ges_int2F PROC FAR
STI
CMP AH,CS:multiplex_id
JE preguntan
JMP CS:ant_int2F ; saltar al gestor de INT 2Fh
preguntan: CMP DI,1992h
JNE ret_no_info ; no llama alguien del convenio
MOV AX,ES
CMP AX,1492h
JNE ret_no_info ; no llama alguien del convenio
PUSH CS
POP ES ; sí llama: darle información
LEA DI,autor_nom_ver
ret_no_info: MOV AX,0FFFFh ; "entrada multiplex en uso"
IRET
ges_int2F ENDP
; ------------ Rutina de gestión de INT 15h.
ges_int15 PROC FAR
STI
CMP AX,90FDh
JE ret_clc
CMP AX,9001h
JE ret_clc
JMP CS:ant_int15
ret_clc: CLC
RET 2
ges_int15 ENDP
; ------------ Rutina de control de INT 40h.
r_flags EQU WORD PTR [BP+18h] ; constantes para parámetros
r_flags_l EQU BYTE PTR [BP+18h]
r_flags_h EQU BYTE PTR [BP+19h]
r_ax EQU WORD PTR [BP+12h]
r_al EQU BYTE PTR [BP+12h]
r_ah EQU BYTE PTR [BP+13h]
r_cx EQU WORD PTR [BP+10h]
r_cl EQU BYTE PTR [BP+10h]
r_ch EQU BYTE PTR [BP+11h]
r_dx EQU WORD PTR [BP+0Eh]
r_dl EQU BYTE PTR [BP+0Eh]
r_dh EQU BYTE PTR [BP+0Fh]
r_bx EQU WORD PTR [BP+0Ch]
r_bl EQU BYTE PTR [BP+0Ch]
r_bh EQU BYTE PTR [BP+0Dh]
r_bp EQU WORD PTR [BP+0Ah]
r_si EQU WORD PTR [BP+08h]
r_di EQU WORD PTR [BP+06h]
r_ds EQU WORD PTR [BP+04h]
r_es EQU WORD PTR [BP+02h]
ges_int40 PROC
STI
CLD
PUSH AX
PUSH CX
PUSH DX
PUSH BX
PUSH BP
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP
MOV BP,SP
DDS
PUSH AX
MOV AL,AH
CMP AL,18h
JA mal_funcion
CMP AL,5
JBE func_oper
CMP AL,8
JNE func_aux?
MOV AL,6
JMP func_oper
func_aux?: CMP AL,15h
JB mal_funcion
SUB AL,0Eh
func_oper: CBW
MOV DI,AX
POP AX
SHL DI,1
JMP CS:tab_jmp[DI] ; ejecutar función
main_exit: MOV AL,AH ; preservar resultado
LAHF ; preservar flags
PUSH AX
DDS
MOV AL,r_dl ; DL a la llamada (unidad)
CMP AL,1
JA u_det ; unidad incorrecta
XOR AH,AH
MOV BX,90h
ADD BX,AX ; [BX] -> estado físico unidad
TEST BYTE PTR DS:[BX],10h ; ¿densidad determinada?
JZ u_det ; no
MOV DL,4 ; sí
MUL DL
MOV CL,AL
SHL DL,CL
OR DS:[8Fh],DL ; unidad determinada
u_det: POP AX
SAHF ; recuperar flags
MOV AH,AL ; recuperar resultado
exit_i40: MOV r_ah,AH ; AH para la salida del IRET
MOV AX,201H ; STI + STC en flags
JC set_err ; hay error
AND r_flags_l,0FEH ; CLC (si no hay error)
DEC AX ; dejar sólo STI
set_err: OR r_flags,AX ; flags a la salida del IRET
POP BP
POP ES
POP DS
POP DI
POP SI
POP BP
POP BX
POP DX
POP CX
POP AX ; registros con resultado
IRET
ges_int40 ENDP
mal_funcion: POP AX
MOV AH,1 ; función/parámetro incorrecto
MOV DS:[41h],AH ; código de error
STC ; condición de error
JMP exit_i40
; ------------ Función 0: Resetear el sistema de disco.
reset PROC
CALL full_init ; inicialización plena
MOV DS:[41h],AH ; código de error
MOV AL,AH ; preservar código
LAHF ; preservar flags
PUSH AX
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV CL,[SI+2]
POP DS
MOV DS:[40h],CL ; tics para detención motor
POP AX
SAHF
MOV AH,AL ; restaurado código y flags
JMP exit_i40
reset ENDP
; ------------ Inicialización plena.
full_init PROC
AND BYTE PTR DS:[3Eh],0F0h ; futuro recalibramiento
JMP init_fdc ; inicializar FDC
fdc_init: JC init_end
JMP send_specify ; enviar specify
specify_sent: JC init_end
XOR AH,AH ; no hay error
init_end: RET
full_init ENDP
; ------------ Función 1: Obtener resultado de la última operación.
get_status PROC
MOV AH,DS:[41h]
OR AH,AH
JZ no_err
STC
no_err: JMP exit_i40
get_status ENDP
; ------------ Función 15h: Obtener el tipo de disco.
get_disk_type PROC
CMP DL,1
JBE gdt_ok
MOV AH,1 ; función/parámetro incorrecto
STC
MOV DS:[41h],AH ; código de error
JMP gdt_exit
gdt_ok: MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico unidad
MOV BL,[BX] ; estado físico de la unidad
OR BL,BL
JNZ gdt_posible
XOR AH,AH ; no existe tal unidad
JMP gdt_bye
gdt_posible: AND BL,7
JZ gdt_without ; 360K
CMP BL,3
JE gdt_without ; 360K
CALL get_drive_type ; [+] Tipo disquetera en AL
CMP AL,3 ; [+] sin soporte cambio en 720
JE gdt_without ; [+] Bug en BIOS AMI original?
MOV AH,2
JMP gdt_bye ; con soporte cambio de línea
gdt_without: MOV AH,1 ; sin soporte cambio de línea
gdt_bye: CLC
MOV BYTE PTR DS:[41h],0 ; siempre sin error
gdt_exit: JMP main_exit
get_disk_type ENDP
; ------------ Función 17h: Establecer tipo de soporte para formateo.
set_type_fmt PROC
XOR AH,AH
CMP DL,1
JBE set_tp
set_tp_bad_p: MOV AH,1 ; función/parámetro incorrecto
set_tp_err: MOV DS:[41h],AH ; código de error
STC
JMP set_tp_exit
set_tp: CMP AL,0 ; validar parámetro
JE set_tp_bad_p
CMP AL,4
JA set_tp_bad_p
MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico unidad
CMP AL,1 ; ¿360K en 360K?
JNE set_tp_n360
MOV BYTE PTR DS:[BX],93h ; actualizar variable tipo
MOV BYTE PTR DS:[41h],0 ; anular errores previos
JMP set_tp_t_exit
set_tp_n360: MOV CX,AX
PUSH BX
CALL motor_on ; arrancar motor
POP SI
PUSH SI
CALL read_disk_chg ; ¿cambio de disco?
POP BX
CMP AH,6 ; (0: no, 6: sí)
JBE set_tp_cd ; haya cambio o no
CMP AH,80h
JNE set_tp_cd ; sí existe disco
CMP BYTE PTR DS:[BX],97h ; ¿250 Kbps y no es 5.25?
JE set_tp_err ; error
MOV BYTE PTR DS:[BX],61h ; 300 Kbps, try 360 en 1.2
JMP set_tp_err ; error
set_tp_cd: CMP CL,4 ; ¿720K en 720K?
JNE set_tp_n720 ; no
MOV BYTE PTR DS:[BX],97h ; actualizar variable tipo
JMP set_tp_t_exit
set_tp_n720: CMP CL,2 ; ¿360K en 1.2M?
JNE set_tp_ndd ; no
MOV BYTE PTR DS:[BX],74h ; actualizar variable tipo
JMP set_tp_t_exit
set_tp_ndd: MOV BYTE PTR DS:[BX],15h ; 1.2M en 1.2M
set_tp_t_exit: OR AH,AH ; comprobar posible error
JNZ set_tp_err
MOV BYTE PTR DS:[41h],0
set_tp_exit: JMP main_exit
set_type_fmt ENDP
; ------------ Función 16h: Detectar cambio de disco.
detect_change PROC
CMP DL,1
JBE det_ch
MOV AH,1 ; función/parámetro incorrecto
det_ch_r_err: STC
JMP det_ch_end
det_ch: XOR DH,DH
MOV BX,90h
ADD BX,DX ; [BX] -> estado físico
CMP BYTE PTR DS:[BX],0 ; ¿estado indeterminado?...
MOV AH,80h ; "unidad no preparada"
JE det_ch_r_err ; ...en efecto
MOV AH,[BX]
AND AH,7
JZ det_ch_yes ; 360K en 360K, no es posible
CMP AH,3
JE det_ch_yes ; no es 360K en 360K
CALL get_drive_type ; [+] Tipo disquetera en AL
CMP AL,3 ; [+] sin soporte cambio en 720
JNE det_ch_calc ; [+] Bug en BIOS AMI original?
det_ch_yes: MOV AH,6 ; hay cambio (o desconocido)
STC
JMP det_ch_end
det_ch_calc: CALL motor_on ; arrancar motor
MOV DX,3F7h
IN AL,DX ; leer línea de cambio de disco
SHL AL,1
JC det_ch_yes ; hay cambio de disco
XOR AH,AH ; no lo hay
det_ch_end: MOV DS:[41h],AH ; actualizar código de error
PUSH AX
PUSH SI
PUSH DS
MOV SI,0
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+2]
POP DS
MOV DS:[40h],AL ; tiempo detención motor
POP SI
POP AX
JMP main_exit
detect_change ENDP
; ------------ Funciones 2, 3 y 4: Leer, escribir y verificar.
read_wr_verify PROC
CMP DL,1
JBE rwv_posible
MOV AH,1 ; función/parámetro incorrecto
rwv_err: MOV DS:[41h],AH ; código de error
XOR AL,AL
STC
JMP rwv_exit
rwv_posible: MOV SI,90h
PUSH DX
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico
CMP BYTE PTR DS:[SI],0 ; ¿estado indeterminado?...
POP DX
JNE rwv_state_ok ; no
PUSH AX
CALL get_drive_type ; obtener tipo disquetera en AL
JZ rwv_type_ok ; ha resultado posible
POP AX
rwv_not_ready: MOV AH,80h ; "unidad no preparada"
JMP rwv_err
rwv_type_ok: OR AL,AL ; ¿existe la unidad?
POP AX
JZ rwv_not_ready ; no existe esa unidad
MOV BYTE PTR DS:[SI],2 ; probando 1.2M en 1.2M
rwv_state_ok: MOV DI,3Fh
AND BYTE PTR DS:[DI],7Fh ; operación Read/Verify
CMP AH,3 ; ¿operación de escritura?
JNE rwv_nowr
OR BYTE PTR DS:[DI],80h ; operación Write/Format
rwv_nowr: PUSH SI
CALL get_drive_type ; obtener tipo disquetera en AL
JNZ rwv_media_ok
CMP AL,1
JE rwv_set360 ; es de 360K
CMP AL,3
JNE rwv_media_ok ; no es de 720K
MOV BYTE PTR DS:[SI],97h ; forzar medio de 720K
JMP rwv_media_ok
rwv_set360: MOV BYTE PTR DS:[SI],93h ; forzar medio de 360K
rwv_media_ok: CALL motor_on ; arrancar motores
CALL read_disk_chg ; leer línea de cambio de disco
POP SI
JNC rwv_no_dschg ; no hay cambio de disco
rwv_end_err: CALL end_io_access
JMP rwv_err
rwv_no_dschg: TEST BYTE PTR DS:[SI],10h ; ¿densidad determinada?
JNZ rwv_set_rate ; en efecto
CALL detect_media ; pues determinarla
JC rwv_end_err ; problemas
JMP rwv_dens_ok
rwv_set_rate: CALL select_rate ; seleccionar la velocidad
rwv_dens_ok: MOV SI,90h
PUSH DX
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico unidad
POP DX
MOV AX,0AF03H ; AF byte 0 specify 2.88
CMP BYTE PTR DS:[SI],0D7h ; ¿2.88M?
JE rwv_spec_ok ; así es
MOV AX,0DF03h ; DF para 360/1.2/720
CMP BYTE PTR DS:[SI],17h ; ¿1.44M?
JNE rwv_spec_ok ; no
MOV AH,0BFh ; sí
rwv_spec_ok: MOV SI,AX ; SI 0-7: orden specify
MOV DI,2 ; DI 0-7: byte 1 specify
MOV CH,3 ; comando de 3 bytes
OR BYTE PTR DS:[3Eh],80h ; no esperar INT
CALL exec_cmd
JC rwv_end_err ; fallo
MOV AX,r_ax
XOR AH,AH
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV CL,r_AL ; [+]
ADD CL,r_CL ; [+] último sector a acceder
DEC CL
CMP CL,[SI+4] ; [+] fix por si el DOS está
JBE rwv_usok ; [+] atontado
MOV [SI+4],CL ; [+]
rwv_usok: MOV CL,[SI+3] ; bytes/sector
SHL AL,CL ; multiplicar por nº sectores
MOV CL,80h
MUL CL ; y por 128
POP DS
DEC AX ; un byte menos...
MOV CX,AX ; ...cuenta para el DMA
CALL eval_dir_DMA
JNC rwv_dma_ok ; no hay problemas con el DMA
MOV CX,r_cx ; restaurar CX
JMP rwv_end_err ; problemas con el DMA
rwv_dma_ok: MOV AX,r_ax
CMP AH,2 ; ¿operación de lectura?
JNE rwv_no_read
MOV AH,46h ; byte de modo DMA para lectura
JMP rwv_dma_set
rwv_no_read: CMP AH,3 ; ¿escritura?
MOV AH,4Ah ; modo DMA para escritura
JZ rwv_dma_set
MOV AH,42h ; modo DMA para verificación
rwv_dma_set: CALL set_dma ; preparar DMA
MOV AX,r_ax
MOV CX,r_cx ; restaurar parámetros
JMP perform_io ; efectuar E/S
io_performed: CALL end_io_access
OR AL,AL
JZ rwv_end
SUB BL,CL ; próximo sector-sector inicial
MOV AL,BL ; nº sectores transferidos
rwv_end: MOV AH,DS:[41h]
OR AH,AH ; ¿error?
JZ rwv_exit
STC ; señalizar error
rwv_exit: MOV r_al,AL ; nº sectores transferidos
JMP main_exit
read_wr_verify ENDP
; ------------ Función 5: Formatear pista.
format_track PROC
CMP DL,1
JBE fmt_do
MOV AH,1 ; función/parámetro incorrecto
fmt_exit_err: MOV DS:[41h],AH ; código de error
STC
JMP main_exit
fmt_do: MOV SI,90h
PUSH DX
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico unidad
POP DX
CMP BYTE PTR DS:[SI],0
MOV AH,80h ; "unidad no preparada"
JE fmt_exit_err ; indeterminado
MOV DI,3Fh
OR BYTE PTR DS:[DI],80h ; no esperar INT
CALL motor_on ; arrancar motores
CALL read_disk_chg ; leer línea de cambio de disco
JNC fmt_posible ; no hay cambio de disco
fmt_err: CALL end_io_access
JMP fmt_exit_err ; error
fmt_posible: CALL select_rate ; seleccionar la velocidad
CALL send_specify ; enviar comando specify
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
IFDEF XTDEBUG ; (se usó en las pruebas)
MOV AL,r_AL ; [+] sectores por pista
MOV [SI+4],AL ; [+]
ELSE
MOV AL,[SI+4] ; sectores por pista
ENDIF
POP DS
XOR AH,AH
MOV CL,4
MUL CL ; 4 bytes para cada uno
MOV CX,AX
DEC CX ; un byte menos...
CALL eval_dir_DMA ; ...cuenta para el DMA
JC fmt_err ; cruza frontera de DMA
MOV AH,4Ah ; modo DMA para escritura
CALL set_dma ; preparar DMA
MOV CX,r_cx ; restaurar CX
CALL seek ; llevar el cabezal a la pista
JNC fmt_continue ; no hay problemas
fmt_err_res: MOV BX,42h
MOV CX,7
PUSH AX
CALL get_results ; leer bytes de resultados
POP AX
JMP fmt_exit ; error
fmt_continue: XSHL DH,2
OR DH,DL ; DH = byte 1 del comando
MOV DL,0CDh ; comando de formateo del FDC
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
PUSH AX
MOV AX,[SI+7] ; GAP formateo/byte de relleno
MOV [BP],AX ; preservarlo
POP AX
MOV DI,[SI+3] ; bytes/sector, sectores/pista
POP DS
MOV SI,DX ; primeros bytes del comando
MOV CH,6 ; comando de 6 bytes
AND BYTE PTR DS:[3Eh],7Fh ; con espera de IRQ
CALL exec_cmd
JC fmt_err_res ; hay error
MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
JC fmt_exit
CALL get_bios_err ; obtener código de error
fmt_exit: MOV DS:[41h],AH ; código de error
CALL end_io_access
MOV AH,DS:[41h]
OR AH,AH
JZ fmt_end ; no hay error
STC
fmt_end: JMP main_exit
format_track ENDP
; ------------ Función 8: Obtener parámetros de disco.
get_drv_param PROC
CMP DL,80h
JB gdrv_do
MOV AH,1 ; función/parámetro incorrecto
MOV DS:[41h],AH ; código de error
STC
JMP main_exit
gdrv_do: XOR DI,DI
XOR SI,SI
XOR DH,DH
MOV AL,DS:[10h] ; hardware instalado
AND AL,0C1h ; nº disqueteras (7-6) y bit
MOV DI,2 ; que indica arrancable (0)
CMP AL,41h ; ¿dos disqueteras? (DI=2)
JE gdrv_ndisk_ok ; en efecto
DEC DI
CMP AL,1 ; ¿una disquetera? (DI=1)
JE gdrv_ndisk_ok ; así es
JMP gdrv_res_null ; no hay disqueteras
gdrv_ndisk_ok: CMP DL,1
JBE gdrv_a_or_b ; la disquetera es A: o B:
JMP gdrv_half_res
gdrv_a_or_b: CALL peek_cmos ; leer tipo de disqueteras
OR DL,DL
JNZ gdrv_sel
MOV CL,4
SHR AL,CL ; dejar disquetera en bits 0-3
gdrv_sel: AND AL,0Fh
JZ gdrv_media? ; no existe esa unidad
CMP AL,5
JA gdrv_media? ; es mayor de 2.88M
XOR AH,AH
MOV SI,AX
MOV DH,AL
MOV BX,90h
ADD BL,DL ; [BX] -> estado físico unidad
MOV AL,[BX]
TEST AL,10h ; ¿densidad determinada?
JNZ gdrv_calc_p ; en efecto
CMP SI,1 ; ¿unidad de 360K?
MOV AL,93h ; 360K en 360K, 250 Kbps
JE gdrv_media_ok
CMP SI,2 ; ¿unidad de 1.2M?
MOV AL,2 ; "intentando 1.2M"
JE gdrv_media_ok
CMP SI,3 ; ¿unidad de 720K?
MOV AL,97h ; 720K en 720K, 250 Kbps
JE gdrv_media_ok
CMP SI,4 ; ¿unidad de 1.44M?
MOV AL,7 ; "intentando 1.44M"
JE gdrv_media_ok
MOV AL,0C7h ; 2.88M en 2.88M
gdrv_media_ok: MOV [BX],AL
JMP gdrv_calc_p ; medio físico asignado
gdrv_media?: MOV BX,90h
ADD BL,DL ; [BX] -> estado físico unidad
MOV AL,[BX]
TEST AL,10h ; ¿densidad determinada?
JZ gdrv_eval ; no
MOV AH,AL
AND AL,0C0h ; aislar bits de velocidad
CMP AL,80h ; ¿250 Kbps?
MOV SI,2 ; 1.2M
JNE gdrv_m144?
TEST AH,4
MOV SI,1 ; 360K
JZ gdrv_calc_p
MOV SI,4 ; 1.44M
gdrv_m144?: TEST AH,7
JZ gdrv_calc_p
MOV SI,4 ; 1.44M
gdrv_calc_p: MOV BX,DI
MOV DI,SI
DEC DI
ADD DI,DI
MOV AX,CS:tab_disksize[DI] ; AL sect/pista, AH pistas
MOV r_dh,1 ; dos cabezales
MOV DI,CS:tab_ptr_1e[DI] ; DI -> tabla parámetros
PUSH CS
POP ES ; ES:DI -> parámetros disco
gdrv_set_res: MOV r_dl,BL ; número de unidades
MOV r_ch,AH ; mayor número de cilindro
MOV r_cl,AL ; mayor número de sector
MOV r_bl,DH ; tipo de la unidad
MOV r_bh,0
MOV r_es,ES ; ES:DI para la salida
MOV r_di,DI
XOR AX,AX
MOV DS:[41h],AH ; resultado correcto
MOV r_al,AL
JMP main_exit
gdrv_res_null: XOR DI,DI ; devolver todo a 0
gdrv_half_res: XOR DH,DH
XOR AX,AX
MOV ES,AX
MOV r_dh,0
MOV BX,DI
XOR DI,DI
JMP gdrv_set_res ; resultado trivial
gdrv_eval: MOV BX,DI
OR SI,SI
JZ gdrv_res_null ; no existe la unidad
CMP SI,3
JBE gdrv_calc_p ; es de 5¼
XOR SI,SI
JMP gdrv_res_null
get_drv_param ENDP
; ------------ Función 18h: Establecer densidad de formateo.
set_media_fmt PROC
CMP DL,1
JBE setm_do
MOV AH,1 ; función/parámetro incorrecto
setm_exit_err: STC
JMP main_exit
setm_do: CALL get_drive_type ; obtener tipo disquetera en AL
JZ setm_drv_ok
setm_drv_unkn: MOV AH,0Ch ; tipo de unidad desconocido
JMP setm_exit_err
setm_drv_ok: XOR AH,AH
MOV DI,AX ; tipo de unidad
MOV DL,r_dl
MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico unidad
CMP AL,1 ; ¿360K?
JNE setm_not360
MOV CX,r_cx ; restaurar CX
CMP CX,2709h ; ¿40 pistas 9 sectores?
LEA SI,t360in360
JNZ setm_drv_unkn ; sólo se permite ese formato
JMP setm_360in360
setm_not360: CMP AL,3 ; ¿720K?
JNE setm_not720
MOV CX,r_cx ; restaurar CX
CMP CX,4F09h ; ¿80 pistas 9 sectores?
JNE setm_drv_unkn ; sólo se permite ese formato
JMP setm_setm
setm_not720: CMP AL,4 ; ¿1.44M?
JE setm_1440
CMP AL,2 ; ¿1.2M?
JE setm_1200
CMP AL,5 ; ¿2.88M?
JNE setm_drv_unkn
MOV CX,r_cx ; 2.88M: restaurar CX
CMP CX,4F24h ; ¿80 pistas 36 sectores?
JE setm_setm ; correcto
CMP CX,4F12h ; ¿80 pistas 18 sectores?
JE setm_setm ; correcto
CMP CX,4F09h ; ¿80 pistas 9 sectores?
JE setm_setm ; correcto
JMP setm_drv_unkn ; permitir sólo esos formatos
setm_1200: MOV CX,r_cx ; restaurar CX
CMP CX,4F0Fh ; ¿80 pistas 15 sectores?
JE setm_setm ; correcto
CMP CX,2709h ; ¿80 pistas 9 sectores?
JNE setm_drv_unkn ; permitir sólo esos formatos
JMP setm_setm ; correcto
setm_1440: MOV CX,r_cx ; restaurar CX
CMP CX,4F12h ; ¿80 pistas 18 sectores?
JE setm_setm ; correcto
CMP CX,4F09h ; ¿80 pistas 9 sectores?
JNE setm_drv_unkn ; permitir sólo esos formatos
setm_setm: MOV CX,r_cx ; restaurar CX
CMP CX,4F12h ; ¿80 pistas 18 sectores?
MOV AL,17h ; su byte de medio físico
LEA SI,t1440 ; es 1.44M
MOV DH,0 ; 500 Kbps
JZ setm_m_ok
CMP CX,4F09h ; ¿80 pistas 9 sectores?
MOV AL,97h ; su byte de medio físico
LEA SI,t720 ; es 720K
MOV DH,2 ; 250 Kbps
JZ setm_m_ok
CMP CX,4F0Fh ; ¿80 pistas 15 sectores?
MOV AL,15h ; su byte de medio físico
LEA SI,t1200 ; es 1.2M
MOV DH,0 ; 500 Kbps
JZ setm_m_ok
CMP CX,4F24h ; ¿80 pistas 36 sectores?
MOV AL,0D7h ; su byte de medio físico
LEA SI,t2880 ; es 2.88M
MOV DH,3 ; 1 Mbps
JZ setm_m_ok
MOV AL,74h ; byte medio físico 360K en 1.2
LEA SI,t360en1200 ; es 360K en 1.2M
MOV DH,1 ; 300 Kbps
setm_m_ok: MOV [BX],AL ; establecer medio físico
PUSH DX
CALL set_rate ; velocidad de transferencia DH
POP DX
MOV AL,[BX]
AND AL,0C0h
AND BYTE PTR DS:[8Bh],3Fh ; borrar bits de velocidad
OR BYTE PTR DS:[8Bh],AL ; nueva velocidad
MOV r_di,SI
MOV r_es,CS ; retornar tabla parámetros
MOV BYTE PTR DS:[41h],0 ; no hay error
XOR AH,AH
JMP main_exit
setm_360in360: MOV DH,2 ; 250 Kbps
MOV AL,93h ; 360K en 360K
JMP setm_m_ok
set_media_fmt ENDP
; ------------ Recalibrar.
recalibrate PROC
PUSH SI
PUSH CX
PUSH DX
MOV DH,DL
MOV DL,7 ; comando "recalibrate"
MOV SI,DX
MOV CH,2 ; comando de 2 bytes
AND BYTE PTR DS:[3Eh],7Fh ; con espera de IRQ
CALL exec_cmd
JC recal_end ; fallo
MOV SI,8 ; "leer estado interrupciones"
MOV CH,1 ; comando de 1 byte
OR BYTE PTR DS:[3Eh],80h ; sin espera de IRQ
CALL exec_cmd
JC recal_end ; fallo
MOV BX,42h
MOV CX,2 ; 2 bytes de resultado
CALL get_results ; almacenar resultado
JC recal_end ; fallo
MOV BX,42h
MOV AH,40h
MOV DL,[BX] ; ST0
AND DL,60h
CMP DL,60h ; ¿terminación anormal y
STC ; seek-end?
JE recal_end ; fallo
POP DX
PUSH DX
XOR DH,DH
MOV BX,94H
ADD BX,DX
MOV BYTE PTR DS:[BX],0 ; cilindro en curso = 0
MOV CL,DL
MOV DL,1
SHL DL,CL
OR DS:[3Eh],DL ; unidad recalibrada
IFNDEF XT
MOV CX,43h
CALL wait_time ; retardo de 1 ms
ELSE
MOV CX,1
CALL retardo ; retardo de 1 ms
ENDIF
XOR AH,AH
recal_end: MOV DS:[41h],AH ; código de error / acierto
POP DX
POP CX
POP SI
RET
recalibrate ENDP
; ------------ Llevar el cabezal al cilindro adecuado.
seek PROC
PUSH BX
PUSH CX
MOV AH,DS:[3Eh] ; estado de recalibración
MOV CL,DL
INC CL
SHR AH,CL
JC seek_only
CALL recalibrate ; hay que recalibrar
JNC seek_only
CALL recalibrate ; segundo intento
JNC seek_only
JMP seek_exit
seek_only: MOV BX,94H
XOR DH,DH
ADD BX,DX ; [BX] -> cilindro actual
MOV SI,90h
ADD SI,DX ; [SI] -> estado físico unidad
MOV DL,CH
TEST BYTE PTR DS:[SI],20h ; ¿hacer double stepping?
JZ seek_cil_ok1
ADD DL,DL ; sí: cilindro=cilindro*2
seek_cil_ok1: CMP [BX],DL ; ¿ya estamos en ese cilindro?
MOV DX,r_dx
JNE seek_do ; aún no
CMP BYTE PTR DS:[41h],40h ; ¿hubo "seek error"?
JE seek_do
XOR AH,AH ; no, seek innecesario
JMP seek_exit
seek_do: XSHL DH,2
OR DH,DL ; byte 1 del comando seek
MOV DL,0FH ; orden seek
MOV SI,DX
MOV CL,CH ; cilindro
MOV DX,r_dx ; unidad / cabezal
MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico
TEST BYTE PTR DS:[BX],20h ; ¿hacer double stepping?
JZ seek_cil_ok2 ; no
ADD CL,CL ; sí: cilindro=cilindro*2
seek_cil_ok2: MOV DI,CX
MOV CH,3 ; comando de 3 bytes
AND BYTE PTR DS:[3Eh],7Fh ; hay que esperar IRQ
CALL exec_cmd
JNC seek_ok ; seek correcto
JMP seek_result
seek_ok: MOV SI,8 ; "leer estado interrupciones"
MOV CH,1 ; comando de 1 byte
OR BYTE PTR DS:[3Eh],80h ; no hay que esperar IRQ
CALL exec_cmd
JC seek_result ; fallo
MOV BX,42h
MOV CX,2
CALL get_results ; leer bytes de resultados
JC seek_result
MOV BX,42h
MOV AH,40h ; "seek error"
MOV DL,[BX] ; ST0
AND DL,60h
CMP DL,60h ; comprobarlo
STC
JE seek_result ; terminación brusca
MOV DX,r_dx ; restaurar DX
POP CX
PUSH CX ; restaurar CX
MOV SI,94H
XOR DH,DH
ADD SI,DX
MOV [SI],CH ; actualizar cilindro actual
MOV BX,90h
ADD BX,DX ; [BX] -> estado físico unidad
MOV BL,[BX]
TEST BL,20h ; ¿double stepping?
JZ seek_cil_ok3
ADD [SI],CH ; pues cilindro*2
seek_cil_ok3: PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+9] ; tiempo estabilización cabezal
POP DS
TEST BYTE PTR DS:[3Fh],80h ; ¿operación en curso?
JZ seek_wait ; es lectura o verificación
OR AL,AL
JNZ seek_wait ; escritura, cte != 0
CMP BL,17h
MOV AL,0Fh
JE seek_wait ; 15 ms excepto para 360K
AND BL,7
MOV AL,14h
JZ seek_wait ; 20 ms para unidades de 360K
CMP BL,3
JE seek_wait ; 20 ms para unidades de 360K
MOV AL,0Fh ; 15 ms para demás unidades
seek_wait: OR AL,AL
JZ seek_wait_end
IFNDEF XT
MOV CX,43h
CALL wait_time ; esperar 1 ms...
ELSE
MOV CX,1
CALL retardo ; retardo de 1 ms
ENDIF
DEC AL
JMP seek_wait ; ...durante AL veces
seek_wait_end: XOR AH,AH
seek_result: MOV DS:[41h],AH ; resultado
seek_exit: MOV DX,r_dx ; restaurar DX
POP CX
POP BX
RET
seek ENDP
; ------------ Ejecutar operación de E/S a través del FDC.
perform_io PROC
CALL seek
JNC p_io
p_io_dsk_err: MOV AL,0 ; fallo
PUSH AX
MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
POP AX
JMP p_io_exit
p_io: PUSH DS ; preparar bytes comando R/W
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AX,[SI+2]
AND AX,0FF00h ; AH = bytes por sector
MOV AL,CL ; AL = primer sector
MOV [BP],AX
MOV BX,[SI+4] ; BL=sectores/pista, BH=GAP R/W
MOV CL,[SI+6] ; CL=longitud de sector (tam=0)
POP DS
MOV SI,90h
XOR DH,DH
ADD SI,DX ; nº sector/tamaño (bytes 4-5)
MOV DL,[SI] ; estado físico de la unidad
AND DL,7
MOV DH,1Bh ; GAP R/W para 1.2M/1.44M/2.88M
CMP DL,5
JE p_io_gap_ok ; 1.2M en 1.2M
CMP BYTE PTR DS:[SI],17h
JE p_io_gap_ok ; 1.44M
CMP BYTE PTR DS:[SI],0D7h
JE p_io_gap_ok ; 2.88M
MOV DH,23h ; GAP R/W para 360K en 1.2M
CMP DL,4
JE p_io_gap_ok ; 360K en 1.2M
MOV DH,2Ah ; GAP R/W para demás casos
p_io_gap_ok: MOV BH,DH ; BX=numsect/GAP (bytes 6-7)
MOV DX,r_dx ; restaurar DX
PUSH CX
MOV CL,CH ; cilindro
MOV CH,DH ; cabezal
MOV DI,CX ; cabezal/cilindro (bytes 2-3)
XSHL DH,2
OR DH,DL ; byte 1 de comando FDC
MOV DL,0E6h ; comando leer datos
MOV AX,r_ax ; orden
CMP AH,3 ; ¿write?
JNE p_io_orden_ok
MOV DL,0C5h ; comando escribir datos
p_io_orden_ok: MOV SI,DX ; (bytes 0-1 de la orden)
POP CX
MOV CH,9
AND BYTE PTR DS:[3Eh],7Fh ; esperar interrupción
CALL exec_cmd
JNC p_io_dsk_ok
JMP p_io_dsk_err ; fallo
p_io_dsk_ok: MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
JNC p_io_res_ok
MOV AL,0
JMP p_io_exit ; fallo: respetar código error
p_io_res_ok: CALL get_bios_err
p_io_exit: MOV DS:[41h],AH
MOV DX,r_dx ; restaurar registros
MOV BX,r_bx
MOV CX,r_cx
JMP io_performed ; continuar operación E/S
perform_io ENDP
; ------------ Arrancar motor si no lo está.
motor_on PROC
PUSH DX
PUSH CX
CLI ; * evitar reentrada
MOV BYTE PTR DS:[40h],0FFh ; evitar detención motor
AND BYTE PTR DS:[3Fh],0CFh ; a 0 bits de disquetera
MOV CH,DL
XSHL DL,4
OR DS:[3Fh],DL ; nueva disquetera seleccionada
MOV CL,CH
MOV DL,DS:[3Fh] ; estado de motores
INC CL
SHR DL,CL
JC motor_is_on ; motor ya en marcha
MOV DL,1
DEC CL
SHL DL,CL
OR DS:[3Fh],DL ; señalizar que está en marcha
STI ; * fin de la fase crítica
MOV AL,DS:[3Fh] ; estado de motores
XROR AL,4
OR AL,0CH ; no resetear, modo DMA
MOV DX,3F2h
OUT DX,AL ; registro salida digital
MOV AX,90FDh
INT 15h ; permitir multitarea
JC motor_on_end
MOV AH,DS:[3Fh]
PUSH DS
PUSH SI
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+0Ah]
POP SI ; AL = tiempo aceleración motor
POP DS ; en octavos de segundo
SHL AH,1
JNC motor_on_rv ; operación read/verify
CMP AL,8
JAE motor_on_wait
MOV AL,8
JMP motor_on_wait ; escritura: al menos 1 segundo
motor_on_rv: CMP AL,5
JAE motor_on_wait
MOV AL,5 ; read/verify: al menos 625 ms
motor_on_wait:IFNDEF XT
MOV CX,208EH
CALL wait_time ; retardo de unos 125 ms
ELSE
MOV CX,125
CALL retardo ; retardo de unos 125 ms
ENDIF
DEC AL
JNZ motor_on_wait ; completar retardo
JMP motor_on_end
motor_is_on: STI
MOV AL,DS:[3Fh] ; estado de motores
XROR AL,4
OR AL,0CH ; no resetear, modo DMA
MOV DX,3F2h
OUT DX,AL ; seleccionar unidad
motor_on_end: POP CX
POP DX
RET
motor_on ENDP
; ------------ Asignar cuenta para detención motor y devolver en BL
; y AL el próximo número de sector a transferir.
end_io_access PROC
PUSH AX
PUSH DS
XOR BX,BX
MOV DS,BX
LDS BX,DWORD PTR DS:[78h] ; DS:BX -> INT 1Eh
MOV AH,[BX+2] ; tics hasta detención motor
MOV AL,[BX+4]
INC AL ; sectores/pista + 1
POP DS
MOV BX,42h
CMP CH,[BX+3] ; ¿mismo cilindro resultante?
JNE end_io_exit
CMP DH,[BX+4] ; ¿mismo cabezal resultante?
JNE end_io_exit
MOV AL,[BX+5] ; número de sector resultante
end_io_exit: MOV DS:[40h],AH ; tiempo para detención motor
MOV BL,AL ; último nº sector transferido
POP AX
RET
end_io_access ENDP
; ------------ Leer la línea de cambio de disco y bajarla si está
; activa.
read_disk_chg PROC
PUSH CX
CALL get_drive_type ; obtener tipo disquetera en AL
MOV AH,0
JNZ fallo_cmos
CMP AL,3 ; [+] Evitar test en 720K:
JE rdchg_set_cod ; [+] Bug en BIOS AMI original?
DEC AL
JZ rdchg_set_cod ; evitar test en 360K
fallo_cmos: MOV AL,[SI] ; estado físico de la unidad
AND AL,7
JZ rdchg_set_cod ; evitar test en 360K
CMP AL,3
JE rdchg_set_cod ; evitar test en 360K
MOV DX,3F7h ; registro de entrada digital
IN AL,DX ; leer línea de cambio de disco
SHL AL,1
JNC rdchg_exit ; no hay cambio de disco
AND BYTE PTR DS:[SI],0EFH ; medio no determinado
CALL full_init ; inicialización plena
JC rdchg_exit ; fallo
MOV DX,r_dx ; restaurar DX
MOV CH,1
CALL seek ; cabezal a cilindro 1
JC rdchg_exit
MOV CH,0
CALL seek ; cabezal a cilindro 0
JC rdchg_exit
MOV AH,6 ; error "disk changed"
MOV DX,3F7h
IN AL,DX ; leer línea de cambio de disco
SHL AL,1
JNC rdchg_set_cod ; se ha podido bajar
MOV AH,80h ; no se pudo: no hay disquete
rdchg_set_cod: OR AH,AH
JZ rdchg_exit
STC
rdchg_exit: MOV DX,r_dx ; restaurar DX
POP CX
RET
read_disk_chg ENDP
; ------------ Programar el DMA para efectuar la E/S.
set_dma PROC
PUSH AX
PUSH DX
CLI
MOV AL,AH
OUT 0CH,AL ; clear first/last flip-flop
JMP SHORT $+2 ; retardo para E/S
JMP SHORT $+2
OUT 0BH,AL ; registro de modo del DMA
JMP SHORT $+2
JMP SHORT $+2
MOV AL,CL
OUT 5,AL
JMP SHORT $+2
JMP SHORT $+2
MOV AL,CH
OUT 5,AL ; enviada cuenta de bytes
JMP SHORT $+2
JMP SHORT $+2
MOV AL,BL
OUT 4,AL
JMP SHORT $+2
JMP SHORT $+2
MOV AL,BH
OUT 4,AL ; enviada dirección base
JMP SHORT $+2
JMP SHORT $+2
MOV AX,ES
OUT 81H,AL ; registro de página canal 2
JMP SHORT $+2
JMP SHORT $+2
MOV AL,2
OUT 0AH,AL ; habilitar canal 2 del DMA
STI
POP DX
POP AX
RET
set_dma ENDP
; ------------ Calcular parámetros para programar el DMA.
eval_dir_DMA PROC
PUSH CX
XOR AX,AX
MOV CX,ES ; segmento ES
SHL CX,1 ; desplazar...
RCL AL,1
SHL CX,1
RCL AL,1
SHL CX,1
RCL AL,1
SHL CX,1
RCL AL,1 ; ... AL:CX >> 4
MOV BX,r_bx ; offset BX
ADD BX,CX
ADC AX,0 ; AX:BX dirección física 20 bit
MOV ES,AX ; página de DMA
POP CX
MOV AX,CX
ADD AX,BX
JNC eval_dma_ret ; no cruza frontera de 64k
MOV AH,9 ; "DMA across 64k boundary"
eval_dma_ret: RET
eval_dir_DMA ENDP
; ------------ Enviar comando completo al FDC de CH bytes, contenido
; en SI, DI, [BP], BX y CL (parte baja - alta).
send_full_cmd PROC
MOV AX,SI
MOV AH,AL
CALL fdc_write ; enviar SI-L
DEC CH
JBE send_full_ret ; acabado (ZF=1) ó error (CF=1)
MOV AX,SI
CALL fdc_write ; enviar SI-H
DEC CH
JBE send_full_ret
MOV AX,DI
MOV AH,AL
CALL fdc_write ; enviar DI-L
DEC CH
JBE send_full_ret
MOV AX,DI
CALL fdc_write ; enviar DI-H
DEC CH
JBE send_full_ret
MOV AX,[BP]
MOV AH,AL
CALL fdc_write ; enviar [BP]-L
DEC CH
JBE send_full_ret
MOV AX,[BP]
CALL fdc_write ; enviar [BP]-H
DEC CH
JBE send_full_ret
MOV AH,BL
CALL fdc_write ; enviar BL
DEC CH
JBE send_full_ret
MOV AH,BH
CALL fdc_write ; enviar BH
DEC CH
JBE send_full_ret
MOV AH,CL
CALL fdc_write ; enviar CL
send_full_ret: RET
send_full_cmd ENDP
; ------------ Enviar comando al FDC con/sin espera de interrupción.
exec_cmd PROC
TEST BYTE PTR DS:[3Eh],80h ; ¿hay que esperar IRQ?
JZ exec_cmd_irq ; sí
AND BYTE PTR DS:[3Eh],7Fh ; no: devolver a 0 bit IRQ
CALL send_full_cmd ; enviar comando
RET
exec_cmd_irq: CALL send_full_cmd ; enviar comando
JC exec_cmd_ret
MOV AX,9001h
INT 15h ; permitir multitarea
STI
JC exec_cmd_err
CALL wait_int ; esperar IRQ
JNC exec_cmd_ok
exec_cmd_err: MOV AH,80h ; "not ready" (AH=80h)
exec_cmd_ret: RET
exec_cmd_ok: AND BYTE PTR DS:[3Eh],7Fh ; bit IRQ listo para otra
XOR AH,AH ; éxito
RET
exec_cmd ENDP
; ------------ Enviar byte al FDC.
IFNDEF XT
fdc_write PROC
PUSH CX
PUSH DX
MOV CX,2
CALL wait_time ; esperar 15-30 µs
MOV DX,3F4h ; registro de estado
PUSH AX
MOV AH,40h
XOR CX,CX
CALL wait0 ; esperar FDC listo para OUT
JC fdc_wr_fail
MOV AH,80h
XOR CX,CX
CALL wait1
JC fdc_wr_fail ; error
POP AX
MOV DX,3F5h ; registro de datos
MOV AL,AH
OUT DX,AL ; escribir el byte
JMP fdc_wr_ret
fdc_wr_fail: POP AX
MOV AH,80h ; error "not ready"
fdc_wr_ret: POP DX
POP CX
RET
fdc_write ENDP
ELSE
fdc_write PROC
XPUSH <CX, DX, AX>
MOV DX,3F4h ; registro de estado del FDC
XOR CX,CX ; evitar cuelgue total si falla
espera_wr: IN AL,DX ; leer registro de estado
TEST AL,80h ; ¿bit 7 inactivo?
LOOPZ espera_wr ; así es: el FDC está ocupado
JCXZ fdc_wr_nok
POP AX
PUSH AX
INC DX ; apuntar al registro de datos
MOV AL,AH
OUT DX,AL ; enviar byte al FDC
XPOP <AX, DX, CX>
CLC
RET
fdc_wr_nok: POP AX
MOV AH,80h ; timeout
XPOP <DX, CX>
STC
RET
fdc_write ENDP
ENDIF
; ------------ Leer del FDC CX bytes de resultado en [BX++].
get_results PROC
PUSH DX
get_one_byte: PUSH CX
CALL fdc_read
POP CX
JC get_res_ret ; no hay más bytes que leer
MOV [BX],AL
INC BX
LOOP get_one_byte ; leer todos los bytes
IFNDEF XT
MOV CX,4
CALL wait_time ; esperar 45-60 µs
ELSE
CALL retardo53 ; retardo de 53 ms
ENDIF
MOV DX,3F4h
IN AL,DX ; leer registro de estado
TEST AL,10h
JZ get_res_ok ; el FDC no está ocupado
MOV AH,20h
STC ; lo estaba: "bad NEC"
JMP get_res_ret
get_res_ok: XOR AH,AH ; operación correcta
get_res_ret: POP DX
RET
get_results ENDP
; ------------ Leer byte del FDC.
IFNDEF XT
fdc_read PROC
PUSH DX
MOV CX,3
CALL wait_time ; esperar 30-45 µs
MOV DX,3F4h ; registro de estado
MOV AH,80h
XOR CX,CX
CALL wait1 ; esperar FDC listo para E/S
MOV AH,80h
JC fdc_read_end ; error "not ready" (AH=80h)
IN AL,DX
TEST AL,40h ; ¿el FDC quiere dar un byte?
JNZ fdc_read_ok
MOV AH,20H ; no: error "bad NEC" (AH=20h)
STC
JMP fdc_read_end
fdc_read_ok: JMP SHORT $+2 ; retardo para E/S
JMP SHORT $+2
MOV DX,3F5h ; registro de datos
IN AL,DX ; leer el byte
fdc_read_end: POP DX
RET
fdc_read ENDP
ELSE
fdc_read PROC
XPUSH <CX, DX>
MOV DX,3F4h ; registro de estado del FDC
XOR CX,CX ; evitar cuelgue total si falla
espera_rd: IN AL,DX ; leer registro de estado
TEST AL,80h ; ¿bit 7 inactivo?
LOOPZ espera_rd ; así es: el FDC está ocupado
JCXZ fdc_rd_nok
INC DX ; apuntar al registro de datos
IN AL,DX ; leer byte del FDC
CLC
XPOP <DX, CX>
RET
fdc_rd_nok: MOV AH,80h ; timeout
STC
XPOP <DX, CX>
RET
fdc_read ENDP
ENDIF
; ------------ Obtener código de error de la BIOS.
get_bios_err PROC
MOV BX,42h ; área de resultados del FDC
MOV BX,[BX]
TEST BL,0C0h ; ¿que tal ST0?
MOV AH,0
JZ bios_err_det ; ¡perfecto!
TEST BL,40h ; ¿terminación brusca/anormal?
MOV AH,20H ; "bad NEC"
JZ bios_err_det
TEST BH,1 ; ¿falta marca de direcciones?
MOV AH,2 ; "address mark not found"
JNZ bios_err_det
TEST BH,2 ; ¿protegido contra escritura?
MOV AH,3 ; "write-protect error"
JNZ bios_err_det
TEST BH,4 ; ¿sector no encontrado?
MOV AH,4 ; "sector not found"
JNZ bios_err_det
TEST BH,10H ; ¿DMA no atendido a tiempo?
MOV AH,8 ; "DMA overrun"
JNZ bios_err_det
TEST BH,20H ; ¿falla el CRC?
MOV AH,10H ; "CRC error"
JNZ bios_err_det
TEST BH,80h ; ¿acceso fuera de la pista?
MOV AH,4 ; "sector not found"
JNZ bios_err_det
MOV AH,20H ; otro error: "bad NEC"
bios_err_det: RET
get_bios_err ENDP
; ------------ Reinicializar la controladora de disquetes.
init_fdc PROC
CALL reset_disk ; resetear FDC
JC init_fin ; fallo al resetear
MOV DX,3F4h ; registro de estado del FDC
IN AL,DX
TEST AL,80h
JZ init_otravez ; el FDC no está listo
TEST AL,40h
JZ init_bien ; el FDC espera datos de la CPU
init_otravez: CALL reset_disk ; otro intento más
MOV DX,3F4h
IN AL,DX
TEST AL,80h
JZ init_mal ; nada, que no tira
TEST AL,40h
JZ init_bien ; bueno, ya despierta
init_mal: MOV AH,20h ; fallo de la controladora
STC
JMP init_fin
init_bien: MOV AH,8 ; "leer estado interrupciones"
CALL fdc_write ; enviar comando
JC init_fin ; fallo
CALL fdc_read ; leer ST0
JC init_fin ; fallo
MOV DS:[42h],AL ; guardar ST0
PUSH AX
CALL fdc_read ; leer cilindro actual
MOV DS:[42h+1],AL ; guardarlo
POP CX
JC init_fin ; fallo
AND CL,0C0h
CMP CL,0C0h ; ¿terminación anormal?
JNE init_mal ; no es terminación anormal
XOR AH,AH ; ok: el FDC detecta el fallo
init_fin: JMP fdc_init
init_fdc ENDP
; ------------ Resetear el FDC.
reset_disk PROC
CLI
AND BYTE PTR DS:[3Fh],7Fh ; operación R/V
AND BYTE PTR DS:[3Eh],7Fh ; borrar bit IRQ
MOV AL,DS:[3Fh]
XROL AL,4 ; bits 7-4: motores
AND AL,0FBH ; bits 3-0: unidad
OR AL,8 ; interrupciones ON + reset
MOV DX,3F2h
OUT DX,AL ; hacer reset
IFNDEF XT
MOV CX,3
CALL wait_time ; retardo de 30-45µs
ELSE
CALL retardo53 ; pequeño retardo
ENDIF
OR AL,0CH
OUT DX,AL ; fin del reset
MOV AX,9001h
INT 15h ; facilitar multitarea
STI
JC fin_wait ; error
CALL wait_int ; esperar interrupción de disco
fin_wait: MOV AH,80h ; "unidad no preparada"
JC exit_reset ; hay error
AND BYTE PTR DS:[3Eh],7Fh ; borrar bit IRQ
XOR AH,AH ; no hay error
exit_reset: RET
reset_disk ENDP
; ------------ Enviar comando specify obtenido de INT 1Eh al FDC.
send_specify PROC
PUSH DS
XOR BX,BX
MOV DS,BX
LDS BX,DWORD PTR DS:[78h] ; DS:BX -> INT 1Eh
MOV AL,3 ; comando specify del FDC
MOV AH,[BX] ; byte 0 del comando specify
MOV SI,AX
MOV AL,[BX+1] ; byte 1 del comando specify
MOV DI,AX
MOV CH,3 ; orden de 3 bytes (SI, DI-L)
POP DS
OR BYTE PTR DS:[3Eh],80h ; no esperar IRQ
CALL exec_cmd ; mandar specify al FDC
JMP specify_sent
send_specify ENDP
; ------------ Esperar una interrupción de disco durante 2 segundos.
IFNDEF XT
wait_int PROC
MOV BX,3Eh ; variable con flag de INT
XOR CX,CX
CALL wait_event ; esperar IRQ durante 1 segundo
JNC wait_int_ret
XOR CX,CX
CALL wait_event ; esperar otro segundo más
wait_int_ret: RET
wait_int ENDP
ELSE
wait_int PROC
MOV BX,3Eh ; variable con flag de INT
MOV CX,37
CALL wait_event ; esperar IRQ durante 2 seg.
RET
wait_int ENDP
ENDIF
; ------------ Devolver en AL el tipo de la unidad DL.
get_drive_type PROC
CALL peek_cmos ; leer tipo de disqueteras
OR DL,DL
JNZ gdt_unidad_ok
XSHR AL,4 ; unidad A:
gdt_unidad_ok: AND AL,0Fh
CMP SP,SP ; ZF=1 -> resultado correcto
RET
get_drive_type ENDP
; ------------ Determinar la densidad del disquete.
detect_media PROC
PUSH DX
PUSH CX
PUSH BX
MOV BL,r_dl
XOR BH,BH
MOV DL,BL
CALL get_drive_type ; obtener tipo disquetera en AL
MOV AH,0
JZ dm_fast ; ha sido posible obtenerlo
JMP dm_slow ; usar procedimiento lento
dm_fast: MOV BYTE PTR DS:[BX+90h],0 ; estado físico unidad
DEC AX
JNZ dm_es_1200K?
MOV AL,93h ; 360K: 360K en 360K, 250 Kbps
dm_try: PUSH AX
MOV DH,AL
AND DH,0C0h
XSHR DH,6
CALL set_rate ; velocidad de transferencia DH
POP AX
dm_result: MOV DS:[BX+90h],AL ; estado físico...
TEST AL,10h ; ...¿determinado?
JZ dm_fails ; aún no
XOR AH,AH
JMP dm_exit ; sí: resultado correcto
NOP
dm_es_1200K?: DEC AX
JNZ dm_es_720K?
MOV AL,0
CALL read_ids ; 1.2M: 500 kbps
MOV AL,15h ; indicar 1.2M en 1.2M
JNC dm_result ; sí funciona
MOV AL,40h
MOV BYTE PTR DS:[BX+90h],2
CALL read_ids ; probar 300 Kbps
MOV AL,74h ; indicar 360K en 1.2M
JNC dm_result ; sí funciona
MOV AL,2 ; indicar "¿1.2M en 1.2M?"
JMP dm_result
dm_es_720K?: DEC AX
JNZ dm_es_1440K?
MOV AL,97h ; 720K: 250 Kbps
JMP dm_try ; a probar suerte
dm_es_1440K?: DEC AX
JNZ dm_es_2880K
MOV AL,0
CALL read_ids ; 1.44M: 500 Kbps
MOV AL,17h ; indicar 1.44M
JNC dm_result ; sí funciona
MOV AL,80h
CALL read_ids ; probar a 250 Kbps
MOV AL,97h ; indicar 720K
JNC dm_result ; sí funciona
MOV AL,7 ; indicar "¿1.44M?"
JMP dm_result
dm_es_2880K: MOV AL,0C0h
CALL read_ids ; 2.88M: 1 Mbps
MOV AL,0D7h ; indicar 2.88M en 2.88M
JNC dm_result ; sí funciona
MOV AL,0
CALL read_ids ; probar 500 Kbps
MOV AL,17h ; indicar 1.44M
JNC dm_result ; sí funciona
MOV AL,80h
CALL read_ids ; probar 250 Kbps
MOV AL,97h ; indicar 720K
JNC dm_result ; sí funciona
MOV AL,0C7h ; indicar "¿2.88M en 2.88M?"
JMP dm_result
dm_fails: STC ; condición de error
dm_exit: MOV DS:[41h],AH ; código de error
POP BX
POP CX
POP DX
RET
dm_slow: MOV AL,0
CALL read_ids ; probar 500 Kbps
MOV AL,15h ; indicar 1.2M en 1.2M
JNC dm_slow_ok ; sí funciona
MOV AL,40h
MOV BYTE PTR DS:[BX+90h],2
CALL read_ids ; probar 300 Kbps
MOV AL,74h ; indicar 360K en 1.2M
JNC dm_slow_ok ; sí funciona
MOV AL,80h
CALL read_ids ; probar 250 Kbps
MOV AL,97h ; indicar 720K ó 360K en 360K
JNC dm_slow_ok ; sí funciona
MOV AL,0C0h
CALL read_ids ; probar 1 Mbps
MOV AL,0D7h ; indicar 2.88M en 2.88M
JC dm_fails ; no funciona
dm_slow_ok: JMP dm_result
detect_media ENDP
; ------------ Efectuar una lectura de ID's a velocidad AL (bits 6-7).
read_ids PROC
PUSH BX
PUSHF
CLI
MOV BYTE PTR DS:[40h],0FFh ; evitar detención motor
POPF
XSHR AL,6 ; colocar bits de velocidad
MOV DH,AL
CALL set_rate ; velocidad de transferencia DH
MOV DL,r_dl
CALL recalibrate ; recalibrar
JNC read_id_try
CALL recalibrate ; segundo intento
JC read_id_err
read_id_try: MOV CX,3 ; 3 intentos
read_id_retry: PUSH CX
MOV DH,DL ; en el cabezal 0 de la unidad
MOV DL,4Ah ; comando de leer ID's
MOV SI,DX
MOV DL,DH
MOV CH,2 ; comando de 2 bytes
AND BYTE PTR DS:[3Eh],7Fh ; esperar interrupción
CALL exec_cmd
JC read_id_fails ; fallo
MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
JC read_id_fails
CALL get_bios_err ; obtener código de error
POP CX
OR AH,AH
JZ read_id_ret ; ya no hay fallo
LOOP read_id_retry ; reintentar
JMP read_id_err ; mala suerte
read_id_fails: POP CX
read_id_err: STC
read_id_ret: POP BX
RET
read_ids ENDP
; ------------ Seleccionar la velocidad de transferencia adecuada.
select_rate PROC
PUSH SI
MOV SI,90h
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico unidad
MOV DH,[SI] ; estado físico nueva unidad
MOV DL,DS:[8Bh] ; control del medio físico
AND DX,0C0C0h ; aislar bits de velocidad
CMP DL,DH ; ¿velocidad ya seleccionada?
JE selected_rate
AND BYTE PTR DS:[8Bh],3Fh ; no: borrar la anterior
OR DS:[8Bh],DH ; indicar la nueva
AND DH,0C0h
XROL DH,2
CALL set_rate ; nueva velocidad transferencia
selected_rate: POP SI
MOV DX,r_dx ; restaurar DX
RET
select_rate ENDP
; ------------ Establecer la velocidad de transferencia DH.
set_rate PROC
PUSH AX
MOV AL,DH
MOV DX,3F7h ; registro de control del disquete
OUT DX,AL ; seleccionar velocidad
POP AX
RET
set_rate ENDP
; ------------ Esperar que alguno de los bits a 1 de AH en el
; puerto DX se pongan a 0 en no más de CX 15.09 µs.
IFNDEF XT
wait0 PROC
PUSH AX
wait0_do: IN AL,DX ; leer del puerto E/S
TEST AL,AH
JZ wait0_end ; bit(s) ya a 0
wait0_delay0: IN AL,61h
TEST AL,10h
JZ wait0_delay0 ; esperar 15.09 µs
DEC CX
JZ wait0_fail ; timeout
IN AL,DX ; volver a leer del puerto E/S
TEST AL,AH
JZ wait0_end ; bit(s) ya a 0
wait0_delay1: IN AL,61h
TEST AL,10h
JNZ wait0_delay1 ; esperar 15.09 µs
DEC CX
JNZ wait0_do ; aún no hay timeout
wait0_fail: STC ; error de timeout
wait0_end: POP AX
RET
wait0 ENDP
ENDIF
; ------------ Esperar que alguno de los bits a 1 de AH en el
; puerto DX se pongan a 1 en no más de CX 15.09 µs.
IFNDEF XT
wait1 PROC
PUSH AX
wait1_do: IN AL,DX ; leer del puerto E/S
TEST AL,AH
JNZ wait1_end ; bit(s) ya a 1
wait1_delay0: IN AL,61h
TEST AL,10h
JZ wait1_delay0 ; esperar 15.09 µs
DEC CX
JZ wait1_fail ; timeout
IN AL,DX ; volver a leer del puerto E/S
TEST AL,AH
JNZ wait1_end ; bit(s) ya a 1
wait1_delay1: IN AL,61h
TEST AL,10h
JNZ wait1_delay1 ; esperar 15.09 µs
DEC CX
JNZ wait1_do ; aún no hay timeout
wait1_fail: STC ; error de timeout
wait1_end: POP AX
RET
wait1 ENDP
ENDIF
; ------------ Esperar evento durante CX 15.09 µs.
IFNDEF XT
wait_event PROC
PUSH AX
test_int: TEST BYTE PTR [BX],80h
JNZ fin_w_event ; llegó la interrupción
w_ref1: IN AL,61h
TEST AL,10h
JZ w_ref1 ; esperar 15 µs
DEC CX
JZ w_event_none ; timeout
TEST BYTE PTR [BX],80h
JNZ fin_w_event ; llegó la interrupción
w_ref2: IN AL,61h
TEST AL,10h
JNZ w_ref2 ; esperar 15 µs
DEC CX
JNZ test_int ; queda tiempo, esperar más
w_event_none: STC ; no llegó la interrupción
fin_w_event: POP AX
RET
wait_event ENDP
ELSE
wait_event PROC
PUSH AX
test_55ms: MOV AL,DS:[6Ch]
test_int: TEST BYTE PTR [BX],80h
JNZ fin_w_event ; llegó la interrupción
w_timer: CMP AL,DS:[6Ch]
JE test_int
LOOP test_55ms
STC ; no llegó la interrupción
fin_w_event: POP AX
RET
wait_event ENDP
ENDIF
; ------------ Retardo de CX 15.09 µs aproximadamente.
IFNDEF XT
wait_time PROC
PUSH AX
wait_ref_h: IN AL,61h
TEST AL,10h ; esperar ciclo de refresco
JZ wait_ref_h ; de memoria (15,09 µs)
DEC CX
JZ wait_time_fin ; fin de la espera
wait_ref_l: IN AL,61h
TEST AL,10h ; esperar ciclo de refresco
JNZ wait_ref_l ; de memoria (15,09 µs)
DEC CX
JNZ wait_ref_h ; completar espera
wait_time_fin: POP AX
RET
wait_time ENDP
ENDIF
; ------------ Simular la lectura del registro 10h de la CMOS, para
; el tipo de las disqueteras.
peek_cmos PROC
MOV AL,CS:tipo_drvs ; nuestro tipo simulado
RET
peek_cmos ENDP
; ------------ Esperar exactamente CX milisegundos.
IFDEF XT
retardo PROC
PUSHF
XPUSH <AX, BX, CX, DX>
retarda_mas: CMP CX,54 ; como máximo 54 ms cada vez
JBE retarda_fin
PUSH CX
MOV AX,54
CALL rt_ax
POP CX
SUB CX,54
JMP retarda_mas
retarda_fin: MOV AX,CX
CALL rt_ax
XPOP <DX, CX, BX, AX>
POPF
RET
rt_ax: PUSH CX
MOV DX,1000 ; retardo de hasta 54 ms
MUL DX
MUL CS:tbase
MOV CX,54925
DIV CX ; AX = contador iteraciones
MOV CX,AX
EVEN ; forzar alineamiento
retarda: DEC CX
JMP SHORT $+2
JNZ retarda
POP CX
RET
retardo ENDP
retardo53 PROC
MOV CX,CS:tbase
MOV CL,CH
MOV CH,0
SHR CX,1
SHR CX,1
EVEN ; forzar alineamiento
retarda_res: DEC CX
JMP SHORT $+2
JNZ retarda_res ; pausa de 53 µs
RET
retardo53 ENDP
ENDIF
; ------------ Datos.
tipo_drvs DB 0 ; tipo de disqueteras (definido al instalar)
IFDEF XT
tbase DW ? ; cte de tiempo para bucles de retardo
ENDIF
; --- Tabla de saltos a las funciones
tab_jmp DW reset, get_status
DW read_wr_verify, read_wr_verify, read_wr_verify
DW format_track, get_drv_param, get_disk_type
DW detect_change, set_type_fmt, set_media_fmt
; --- Tabla de tamaños en sectores y cilindros
tab_disksize DW 9 + 39 * 256 ; 360K
DW 15 + 79 * 256 ; 1.2M
DW 9 + 79 * 256 ; 720K
DW 18 + 79 * 256 ; 1.44M
DW 36 + 79 * 256 ; 2.88M
; --- Tablas de parámetros de disco (sintaxis INT 1Eh)
tab_ptr_1e DW t360in360, t1200, t720, t1440, t2880
; Bytes de esta tabla, similar a la de INT 1Eh:
;
; 0) byte 1 para 'Specify' (step rate-head unload)
; 1) byte 2 para 'Specify' (head load-modo DMA)
; 2) tics de reloj hasta detención del motor
; 3) tamaño de sector (0-128, 1-256, 2-512, ...)
; 4) sectores por pista
; 5) GAP3 para lectura/escritura
; 6) longitud concreta de sector si tamaño=0
; 7) GAP3 para formateo
; 8) byte de relleno al formatear
; 9) tiempo de estabilización del cabezal en ms
; 10) tiempo aceleración motor, en 1/8 segundos
; 11) número de cilindros menos uno
; 12) velocidad de transferencia (en bits 6-7)
t360in360 DB 0DFh, 002h, 025h, 002h, 009h ; 360K en 360K
DB 02Ah, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 027h, 080h
t1200 DB 0DFh, 002h, 025h, 002h, 00Fh ; 1.2M
DB 01Bh, 0FFh, 054h, 0F6h, 00Fh
DB 008h, 04Fh, 000h
t720 DB 0DFh, 002h, 025h, 002h, 009h ; 720K
DB 02Ah, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 04Fh, 080h
t1440 DB 0BFh, 002h, 025h, 002h, 012h ; 1.44M
DB 01Bh, 0FFh, 06Ch, 0F6h, 00Fh
DB 008h, 04Fh, 000h
t360en1200 DB 0DFh, 002h, 025h, 002h, 009h ; 360K en 1.2M
DB 02Ah, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 027h, 040h
t2880 DB 0AFh, 002h, 025h, 002h, 024h ; 2.88M
DB 01Bh, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 04Fh, 0C0h
; --- Fin del área residente para INT 40h
fin_residente EQU $
bytes_resid EQU fin_residente-ini_residente
; ------------ Rutina de gestión de INT 13h (si se necesita). Se llama
; a la INT 40h de manera que esta última no devuelva
; nunca errores de frontera de DMA, para lo que emplea un
; buffer auxiliar de 512 bytes para transferir el sector
; que cruzaría la frontera. En la función de formateo, al
; acceder a la primera pista del disco se invoca primero
; la interrupción original para que el DOS (cargado antes
; que este programa) se entere del cambio de soporte.
ges_int13 PROC
STI
CMP DL,80h
JB floppy
JMP CS:ant_int13
floppy: CMP AH,2
JB floppy_bios
CMP AH,5
JE test_format
JB test_rwv
floppy_bios: INT 40h ; función sin problemas de DMA
RETF 2
ges_int13 ENDP
test_format PROC
XPUSH <DS, ES, BX>
XPUSHA
PUSH DX
OR DH,CH
POP DX
JNZ skip_aviso ; no es pista y cabezal 0
CMP CL,0FFh
JE skip_aviso ; 2M 3.0 simula el cambio
XPUSHA
PUSHF ; formatear con INT 13h para
CALL CS:ant_int13 ; avisar al DOS del nuevo disco
XPOPA
skip_aviso: MOV DI,CS:pbuffer
MOV SI,BX
PUSH ES
POP DS
PUSH CS
POP ES
MOV CX,256
CLD
REP MOVSW ; datos de formateo al buffer
XPOPA ; auxiliar
MOV BX,CS:pbuffer
INT 40h ; formateo
XPOP <BX, ES, DS> ; restaurar registros iniciales
RETF 2
test_format ENDP
test_rwv PROC ; para Read/Write/Verify
MOV CS:funcion,AH
MOV CS:nsects,AL
XPUSH <SI, DI>
XPUSH <AX, DX>
MOV AX,ES
MOV DX,16
MUL DX
ADD AX,BX
NEG AX ; AX = bytes hasta frontera DMA
XSHR AX,9
MOV SI,AX ; sectores antes frontera
XPOP <DX, AX>
PUSH AX
MOV AH,0
MOV DI,AX
POP AX
CMP SI,DI
JBE trwv_no_sobra
MOV SI,DI
trwv_no_sobra: SUB DI,SI ; sectores+1 tras frontera
JZ trwv_1ok
PUSH CX
MOV CX,SI
MOV AL,CL ; AL sectores antes de frontera
POP CX
trwv_1ok: AND AL,AL
JZ trwv_1cruza ; primer sector cruza frontera
INT 40h
PUSHF
JNC trwv_cont ; sin fallo E/S
trwv_exit: JMP trwv_ret
trwv_cont: AND DI,DI
JZ trwv_exit ; se acabó
POPF
trwv_1cruza: CMP CS:funcion,3 ; ¿escritura?
JNE trwv_sectdma
XPUSHA
XPUSH <DS, ES>
XSHL SI,9 ; sectores transferidos * 512
ADD SI,BX
MOV DI,CS:pbuffer
PUSH ES
POP DS
PUSH CS
POP ES
MOV CX,256
CLD
REP MOVSW ; sector conflictivo a través
XPOP <ES, DS> ; de buffer auxiliar
XPOPA
trwv_sectdma: XPUSH <ES, BX, CX>
PUSH CS
POP ES
MOV BX,CS:pbuffer ; ES:BX buffer auxiliar
MOV AH,CS:funcion
MOV AL,1 ; un sector
ADD CX,SI ; nuevo sector inicial
INT 40h
XPOP <CX, BX, ES>
PUSHF
JC trwv_ret ; fallo E/S
CMP CS:funcion,2 ; ¿lectura?
JNE trwv_tras?
XPUSHA
XPUSH <DS, ES>
XSHL SI,9 ; sectores transferidos * 512
MOV DI,SI
ADD DI,BX
MOV SI,CS:pbuffer
PUSH CS
POP DS
MOV CX,256
CLD
REP MOVSW ; sector conflictivo a través
XPOP <ES, DS> ; de buffer auxiliar
XPOPA
trwv_tras?: MOV AL,CS:nsects ; sectores transferidos
DEC DI
JZ trwv_ret ; no queda nada tras frontera
POPF
XPUSH <BX, CX>
INC SI
ADD CX,SI ; nuevo sector inicial
XSHL SI,9 ; sectores transferidos * 512
ADD BX,SI
MOV AX,DI ; sectores restantes
MOV AH,CS:funcion
INT 40h
XPOP <CX, BX>
MOV AL,CS:nsects ; número sectores transferidos
PUSHF
trwv_ret: POPF
XPOP <DI, SI>
RETF 2
test_rwv ENDP
funcion DB ?
nsects DB ?
pbuffer DW buffer_io
EVEN
buffer_io EQU $
; *****************************
; * *
; * I N S T A L A C I O N *
; * *
; *****************************
main PROC
ADD SP,2 ; quitar dirección de retorno
XPUSH <AX, BX, CX, DX, SI, DI, BP, DS, ES>
PUSH CS
POP DS
MOV WORD PTR interrupcion,531Eh ; opcode PUSH DS,BX
MOV BYTE PTR interrupcion+2,0BBh ; opcode MOV BX,??
PUSH CS
POP ES
CALL inic_general ; inicializar ciertas variables
CALL analiza_equipo
PUSH ES ; *
MOV BX,pcab_pet_segm
MOV ES,BX
MOV BX,pcab_pet_desp
LES BX,ES:[BX+12h] ; apuntar a los parámetros
CALL salta_nombre
LEA BP,parametros
CALL obtener_param
POP ES ; *
CALL set_params ; actualizar tipo de unidades
CMP param_13,ON
JNE int_ok ; no es parámetro /13
AND accion,NOT I40
int_ok: CALL valida_drives ; asegurar que hay unidades
TEST error,0FFFFh
JNZ exit_ins
CALL hay2m?
JC no_2m
OR error,ERR_HAY2M ; 2M ó 2MX residente
JMP exit_ins
no_2m: TEST accion,I40 ; ¿soporta INT 40h el sistema?
JNZ i40_ok ; en efecto
CALL set_i13 ; añadir soporte vía INT 13h
i40_ok: IFDEF XT
CALL cte_tiempos
MOV tbase,AX
CALL init_vars
ENDIF
CALL mx_get_handle ; obtener entrada Multiplex
JNC handle_ok
OR error,MX64FULL ; no quedan entradas
JMP exit_ins
handle_ok: MOV multiplex_id,AH ; entrada multiplex para 2M
CALL preservar_ints ; tomar nota de vectores
MOV DI,100h ; ORG 0 (compensar COM)
CALL activar_ints ; interceptar vectores
LEA DI,ptr_dev_info
CALL set_dev_params ; establecer tipo unidades DOS
IFNDEF XT
CALL setup_cmos ; ajustar byte cmos
ENDIF
exit_ins: CALL info
MOV BX,pcab_pet_segm
MOV ES,BX
MOV BX,pcab_pet_desp
MOV WORD PTR ES:[BX+3],100h ; indicar retorno correcto
MOV AX,longitud_total
MOV CL,4
SHL AX,CL
TEST error,0FFFFh
JZ exit_ok
MOV WORD PTR ES:[BX+14],0 ; OFFSET 0: no quedará
MOV WORD PTR ES:[BX+16],CS ; instalado en memoria
JMP exit_interr
exit_ok: MOV WORD PTR ES:[BX+14],AX ; OFFSET al último byte residente
MOV WORD PTR ES:[BX+16],CS
exit_interr: XPOP <ES, DS, BP, DI, SI, DX, CX, BX, AX>
RETF
main ENDP
;*********************************************************
;* *
;* SUBRUTINAS DE PROPOSITO GENERAL PARA LA INSTALACION *
;* *
;*********************************************************
INCLUDE 2MUTIL.INC
salta_nombre PROC ; saltar nombre del driver en
MOV AL,ES:[BX] ; línea de órdenes del CONFIG
INC BX
CMP AL,' '
JE fin_nombre
CMP AL,9
JE fin_nombre
CMP AL,0Dh
JE fin_nombre
CMP AL,0Ah
JE fin_nombre
AND AL,AL
JZ fin_nombre
JMP salta_nombre
fin_nombre: RET
salta_nombre ENDP
; ------------ Establecer tipo disqueteras (según BIOS o parámetros).
set_params PROC
PUSH ES
MOV AX,tipo_A
CMP AL,-1
JNE ta_calc ; A: definida por el usuario
MOV DL,0
CALL tipo_disco
MOV AL,BL
ta_calc: AND tipo_drvs,0Fh
MOV CL,4
SHL AL,CL
OR tipo_drvs,AL ; tipo A: en nibble alto
MOV AX,tipo_B
CMP AL,-1 ; B: definida por el usuario
JNE tb_calc
MOV DL,1
CALL tipo_disco
MOV AL,BL
tb_calc: AND tipo_drvs,0F0h
OR tipo_drvs,AL ; tipo B: en nibble bajo
POP ES
RET
set_params ENDP
; ------------ Asegurar que se conoce el tipo de las unidades.
valida_drives PROC
MOV AL,tipo_drvs
AND AL,AL
JNZ drvs_ok
OR error,ERR_MALDRV
drvs_ok: RET
valida_drives ENDP
; ------------ Código ejecutado desde la línea de comandos.
inicio PROC FAR
MOV AX,_PRINCIPAL
MOV DS,AX
LEA BP,parametros
MOV BX,81h
CALL obtener_param ; procesar parámetros
PUSH DS
POP ES
CALL residente?
JC dos_info
IFDEF XT
CALL cte_tiempos
PUSH DS
MOV DS,tsr_seg
MOV tbase,AX
POP DS
ENDIF
CMP param_ayuda,ON
JE dos_info
LEA DX,info_ins_txt
CALL print
JMP dos_exit
dos_info: LEA DX,info_txt
CALL print
JNC dos_exit
LEA DX,limpia_txt ; se pulsó ESC en la ayuda
CALL print
dos_exit: MOV AX,4C00h
INT 21h ; final normal
inicio ENDP
; ------------ Inicializar ciertas variables.
inic_general PROC
MOV AX,(bytes_resid+15)/16
MOV longitud_total,AX ; memoria necesaria
MOV segmento_real,CS ; anotar segmento del bloque
MOV offset_real,0 ; ídem con el offset
RET
inic_general ENDP
; ------------ Comprobar que la configuración es la adecuada. Para
; saber si la INT 13h de este ordenador acaba llamando a
; la INT 40h, se desvía la INT 40h y se provoca un inocuo
; reset de disquetes vía INT 13h para comprobar si pasa
; por la INT 40h.
analiza_equipo PROC
PUSH ES
CALL testAT
MOV AX,ERR_TIPOPC
IFNDEF XT
JC cod_err_ok ; no es AT o superior
ELSE
JNC cod_err_ok ; no es PC/XT
ENDIF
CALL test_i40
XOR AX,AX
cod_err_ok: OR error,AX
POP ES
RET
analiza_equipo ENDP
; --- Comprobar si la INT 40h está en uso
test_i40: XPUSH <DS, ES> ; *
MOV AX,3540h
INT 21h
XPUSH <ES, BX> ; vector de INT 40h original
LEA DX,i40_aux
MOV AX,2540h
INT 21h ; establecer nueva INT 40h
XOR AX,AX
MOV DL,0
INT 13h ; reset de disco
XPOP <DX, DS>
MOV AX,2540h
INT 21h ; restaurar INT 40h original
XPOP <ES, DS> ; *
RET
i40_aux PROC
OR CS:accion,I40 ; sí utilizada INT 40h
IRET ; desde la INT 13h
i40_aux ENDP
; ----- Detectar 286 ó superior.
testAT PROC
PUSHF
POP AX
OR AH,70h ; intentar activar bit 12, 13 ó 14
PUSH AX ; del registro de estado
POPF
PUSHF
POP AX
AND AH,0F0h
CMP AH,0F0h
JE testedAT
STC
testedAT: CMC ; CF = 0 en AT y 1 en PC/XT
RET
testAT ENDP
; ------------ Desviar también INT 13h ya que en esta máquina el
; gestor de INT 13h no invoca la INT 40h.
set_i13 PROC
INC offsets_ints ; usado un vector más
INC BYTE PTR tabla_vectores-1
MOV AX,CS
MOV CX,16
MUL CX
ADD AX,pbuffer
ADC DX,0 ; DX:AX = dirección 20 bits
MOV CX,DX
PUSH AX
ADD AX,511 ; buffer para el mayor sector
ADC DX,0
POP AX
CMP DX,CX
JE dma_ok
NEG AX
ADD pbuffer,AX ; saltar hasta próxima frontera
OR accion,BUFFERPLUS
dma_ok: MOV AX,pbuffer
ADD AX,512
SUB AX,OFFSET ges_int13
ADD AX,15
MOV CL,4
SHR AX,CL
ADD longitud_total,AX ; es necesaria más memoria
RET
set_i13 ENDP
; ------------ Devolver CF=0 si 2M o 2MX están instalados o se ha
; cargado el código 2M en modo SuperBOOT (en este último
; caso, la rutina funciona aunque QEMM modifique de modo
; temporal el límite de memoria a casi un mega en la
; llamada a INT 12h).
hay2m? PROC
PUSH ES
LEA SI,id_2m ; identificación del programa
MOV CX,id_2m_tam
MOV AX,1492h
MOV ES,AX
MOV DI,1992h ; ES:DI protocolo de búsqueda
CALL mx_find_tsr ; buscar si está en memoria
JNC hay2m?_ret
LEA SI,id_2mx ; identificación del programa
MOV CX,id_2mx_tam
CALL mx_find_tsr
JNC hay2m?_ret
INT 12h ; tamaño memoria convencional
MOV BX,640
CMP AX,256
JB base_sc_ok ; dato extraño
CMP AX,640
JA base_sc_ok ; dato extraño
MOV BX,AX
base_sc_ok: MOV AX,BX
ADD AX,127 ; redondeo
MOV CL,7
SHR AX,CL
SHL AX,CL ; hacia frontera de 128K
MOV CX,AX
SUB CX,BX ; buscar en área posible
DEC AX
MOV BX,64
MUL BX ; AX = segmento de SuperBOOT
CLD
scan_boot: MOV ES,AX
MOV DI,6
LEA SI,id_boot
PUSH CX ; *
MOV CX,id_boot_tam
REP CMPSB
POP CX ; *
JE hay2m?_ret ; CF = 0 -> 2M SuperBOOT
SUB AX,64
LOOPNZ scan_boot ; buscar 1K más abajo
nohaysb_ret: STC
hay2m?_ret: POP ES
RET
hay2m? ENDP
; ------------ Informar al usuario.
info PROC
TEST error,0FFFFh
JZ info_mas
LEA DX,no_inst_txt
CALL print
LEA DX,mal_cpu_txt
TEST error,ERR_TIPOPC
JNZ print_err
LEA DX,hay2m_txt
TEST error,ERR_HAY2M
JNZ print_err
LEA DX,null_drv_txt
TEST error,ERR_MALDRV
JNZ print_err
LEA DX,err_syntax_txt
TEST error,ERRSINTAX
JNZ print_err
LEA DX,err_mx64full
TEST error,MX64FULL
JZ fin_info
print_err: CALL print
RET
info_mas: LEA DX,instalado_txt
CALL print
CALL info_drives
TEST accion,BUFFERPLUS
JZ fin_info
LEA DX,dma_cross_txt
CALL print
fin_info: RET
info ENDP
; --- Informar de las unidades controladas.
info_drives PROC
MOV DL,0
CALL tipo_disco
AND BL,BL
JZ info_B
MOV BH,0
DEC BX
SHL BX,1
LEA DX,a_txt ; "A:"
CALL print
MOV DX,[BX+OFFSET ptr_txt_tipos] ; su tipo
CALL print
info_B: MOV DL,1
CALL tipo_disco
AND BL,BL
JZ info_exit
MOV BH,0
DEC BX
SHL BX,1
LEA DX,b_txt ; "B:"
CALL print
MOV DX,[BX+OFFSET ptr_txt_tipos] ; su tipo
CALL print
info_exit: LEA DX,i40_txt
TEST accion,I40
JNZ imodo_ok
LEA DX,i13_txt
imodo_ok: CALL print ; modo de instalación
RET
info_drives ENDP
; ------------ Calcular la constante de retardo básica para perder
; exactamente 54,925 ms. Con una regla de 3 se podrá
; después aplicar para hacer retardos de milisegundos.
IFDEF XT
cte_tiempos PROC
XPUSH <DS, ES, BX, CX, DX>
MOV AX,3508h
INT 21h
XPUSH <ES, BX> ; preservar vector de INT 8
PUSH DS
MOV AX,40h
MOV DS,AX
MOV AL,DS:[6Ch]
espera_i8: CMP AL,DS:[6Ch]
JE espera_i8 ; esperar INT 8 ... para que no
POP DS
LEA DX,i8_crono ; venga otra en un buen rato...
MOV AX,2508h
INT 21h ; nueva rutina de INT 8
IN AL,21h
PUSH AX ; preservar estado de IRQ's
MOV AL,11111110b
OUT 21h,AL ; permitir sólo IRQ0
MOV AH,0 ; fase
MOV CX,0 ; contador
MOV BX,CX ; seguiría a 0 si fallara
EVEN ; forzar alineamiento
cuenta_iter: DEC CX ; <─┐ bucle básico de retardo
JMP SHORT $+2 ; │
JNZ cuenta_iter ; <─┘ lo interrumpirá INT 8
POP AX ; anterior estado de IRQ's
OUT 21h,AL
XPOP <DX, DS>
PUSH BX ; valor real contado
MOV AX,2508h ; restaurar vector de INT 8
INT 21h
POP AX ; (65536-AX) vueltas en 54,9 ms
NEG AX ; constante de retardo básica
XPOP <DX, CX, BX, ES, DS>
RET
i8_crono: INC AH ; nueva INT 8 que interrumpe
CMP AH,1 ; el bucle de retardo
JE fase1
CMP AH,2
JE fase2
i8_exit: MOV AL,20h
OUT 20h,AL
IRET
fase1: MOV CX,0 ; sincronizar con el reloj
JMP i8_exit
fase2: MOV BX,CX ; anotar constante de retardo
MOV CX,1 ; forzar fin del bucle
JMP i8_exit
cte_tiempos ENDP
ENDIF
; ------------ Inicializar variables en el área de datos de la BIOS.
IFDEF XT
init_vars PROC
PUSH DS
MOV AX,40h
MOV DS,AX
AND BYTE PTR DS:[3Eh],01110000b
MOV BYTE PTR DS:[8Bh],00000000b
MOV DX,3F7h
MOV AL,0
OUT DX,AL
MOV BYTE PTR DS:[8Fh],01110111b
MOV BYTE PTR DS:[90h],0
MOV BYTE PTR DS:[91h],0
POP DS
RET
init_vars ENDP
ENDIF
; ------------ Ajustar byte CMOS con el tipo de las disqueteras.
IFNDEF XT
setup_cmos PROC
CMP param_c,ON
JNE modifica_cmos
RET ; con /C no alterar CMOS.
modifica_cmos: MOV AL,2Eh
CALL read_cmos
MOV BH,AL
MOV AL,2Fh
CALL read_cmos
MOV BL,AL ; BX = checksum
MOV AL,10h
CALL read_cmos ; byte CMOS tipo disqueteras
SUB AL,tipo_drvs ; diferencia relativa
CBW
SUB BX,AX ; nuevo checksum
MOV AL,10h
MOV AH,tipo_drvs
CALL write_cmos ; actualizar byte de tipo
MOV AL,2Eh
MOV AH,BH
CALL write_cmos
MOV AL,2Fh
MOV AH,BL
CALL write_cmos ; y checksum
RET
setup_cmos ENDP
read_cmos PROC
CLI
OUT 70h,AL
JMP SHORT $+2
JMP SHORT $+2
IN AL,71h
STI
RET
read_cmos ENDP
write_cmos PROC
CLI
OUT 70h,AL
JMP SHORT $+2
JMP SHORT $+2
MOV AL,AH
OUT 71h,AL
STI
RET
write_cmos ENDP
ENDIF
; ************ Datos no residentes para la instalación
ON EQU 1 ; constantes booleanas
OFF EQU 0
parametros LABEL BYTE
DB "?",0
DW param_ayuda
DB ON
DB "/?",0
DW param_ayuda
DB ON
DB "/H",0
DW param_ayuda
DB ON
DB "/13",0
DW param_13
DB ON
DB "/C",0
DW param_c
DB ON
DB "A",1
DW 0, 5
DW tipo_A
DW param_unidad
DB ON
DB "B",1
DW 0, 5
DW tipo_B
DW param_unidad
DB ON
DB "/I",0
DW param_i
DB ON
DB 0 ; fin de la tabla
param_ayuda DB OFF ; a ON si se solicita ayuda
param_c DB OFF ; a ON si se indica /C
param_unidad DB OFF ; a ON si se indica A: o B:
param_13 DB OFF ; a ON si se indica /13
tipos_drv LABEL BYTE
tipo_A DW -1 ; tipo de A:
tipo_B DW -1 ; y de B:
id_2m DB "CiriSOFT:2M:" ; marcas de presencia de 2M
id_2m_tam EQU $-OFFSET id_2m
id_2mx DB "CiriSOFT:2MX:"
id_2mx_tam EQU $-OFFSET id_2mx
id_boot DB "2M-STV"
id_boot_tam EQU $-OFFSET id_boot
ERR_TIPOPC EQU 1 ; códigos de error
ERR_HAY2M EQU 2
ERR_MALDRV EQU 4
ERRSINTAX EQU 8
MX64FULL EQU 16
I40 EQU 1 ; códigos de acción
BUFFERPLUS EQU 2
offsets_ints DW 3 ; número de vectores interceptados
DB 15h ; tabla de offsets de los vectores
DW ges_int15 ; de interrupción interceptados
DB 2Fh
DW ges_int2F
DB 40h
DW ges_int40
DB 13h ; INT 13h podría usarse
DW ges_int13
ptr_dev_info DW 0, i360, i1200, i720, i1440, i2880
i360 DB 4, 0 ; sectores iguales / tipo 360K
DW 0, 40 ; no detecta cambio / nº pistas
DB 1 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 2 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 112 ; BPB: entradas en el raíz
DW 720 ; BPB: nº total de sectores
DB 0FDh ; BPB: descriptor de medio
DW 2 ; BPB: sectores por FAT
DW 9, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i1200 DB 4, 1 ; sectores iguales / tipo 1.2M
DW 2, 80 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 1 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 224 ; BPB: entradas en el raíz
DW 2400 ; BPB: nº total de sectores
DB 0F9h ; BPB: descriptor de medio
DW 7 ; BPB: sectores por FAT
DW 15, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i720 DB 4, 2 ; sectores iguales / tipo 720K
DW 0, 80 ; no detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 2 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 112 ; BPB: entradas en el raíz
DW 1440 ; BPB: nº total de sectores
DB 0F9h ; BPB: descriptor de medio
DW 3 ; BPB: sectores por FAT
DW 9, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i1440 DB 4, 7 ; sectores iguales / tipo 1.44M
DW 2, 80 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 1 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 224 ; BPB: entradas en el raíz
DW 2880 ; BPB: nº total de sectores
DB 0F0h ; BPB: descriptor de medio
DW 9 ; BPB: sectores por FAT
DW 18, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i2880 DB 4, 9 ; sectores iguales / tipo 2.88M
DW 2, 80 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 2 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 224 ; BPB: entradas en el raíz
DW 5760 ; BPB: nº total de sectores
DB 0F0h ; BPB: descriptor de medio
DW 9 ; BPB: sectores por FAT
DW 36, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
accion DW 0
error DW 0
; ------------ Texto.
IFNDEF XT
info_ins_txt DB 13,10,"2M-" ID "BIOS 1.3 controla las unidades de disquete."
DB 13,10," Indique /? para obtener ayuda.",13,10,255
DB 13,10,"2M-" ID "BIOS 1.3 drives diskette drives."
DB 13,10," Execute with /? to obtain help.",13,10,0
ELSE
info_ins_txt DB 13,10,"2M-" ID "BIOS 1.3 controla las unidades de disquete."
DB 13,10," Base de tiempos interna ajustada."
DB 13,10," Indique /? para obtener ayuda.",13,10,255
DB 13,10,"2M-" ID "BIOS 1.3 drives diskette drives"
DB 13,10," Internal delay loop adjusted."
DB 13,10," Execute with /? to obtain help.",13,10,0
ENDIF
instalado_txt DB 13,10,"2M-" ID "BIOS 1.3 instalado en",255
DB 13,10,"2M-" ID "BIOS 1.3 installed on",0
a_txt DB " A:",0
b_txt DB " B:",0
ptr_txt_tipos DW d360, d1200, d720, d1440, d2880
d360 DB "360K",0
d1200 DB "1.2M",0
d720 DB "720K",0
d1440 DB "1.44M",0
d2880 DB "2.88M",0
i40_txt DB " [INT 40h]",13,10,0
i13_txt DB " [INT 13h]",13,10,0
no_inst_txt DB 13,10,"2M-" ID "BIOS 1.3 *NO* instalado.",13,10,255
DB 13,10,"2M-" ID "BIOS 1.3 *NOT* installed.",13,10,0
IFDEF XT
mal_cpu_txt DB " + Error: necesario equipo PC/XT. Utilice 2M-ABIOS en esta máquina.",13,10,255
DB " + Error: needs a PC/XT system. Try 2M-ABIOS on this system.",13,10,0
hay2m_txt DB " + Error: 2M-XBIOS debe instalarse *ANTES* de 2MX (y nunca en SuperBOOT).",13,10,255
DB " + Error: 2M-XBIOS must be installed *BEFORE* 2MX (and never in SuperBOOT).",13,10,0
ELSE
mal_cpu_txt DB " + Error: necesario equipo AT ó superior. Utilice 2M-XBIOS en esta máquina.",13,10,255
DB " + Error: needs AT or upper system. Try 2M-XBIOS on this system.",13,10,0
hay2m_txt DB " + Error: 2M-ABIOS debe instalarse *ANTES* de 2M (y nunca en SuperBOOT).",13,10,255
DB " + Error: 2M-ABIOS must be installed *BEFORE* 2M (and never in SuperBOOT).",13,10,0
ENDIF
null_drv_txt DB " + Utilice los parámetros para indicar expresamente el tipo de las unidades.",13,10,255
DB " + Please use the switches to set the correct diskette drives type.",13,10,0
err_syntax_txt DB " + Error de sintaxis: ejecútelo desde el símbolo DOS para obtener ayuda.",13,10,255
DB " + Syntax error: execute from DOS command line to obtain help.",13,10,0
err_mx64full DB " + Error: Ya hay 64 programas residentes con la misma técnica.",13,10,7,255
DB " + Error: There are already 64 TSR's with the same technique.",13,10,7,0
dma_cross_txt DB " - Nota: El buffer de E/S cruzaba una frontera de DMA y fue ampliado.",13,10
DB " Cambie la ubicación en memoria si desea ahorrar unos bytes.",13,10,255
DB " - Note: I/O buffer has been extended because it crosses a DMA boundary.",13,10
DB " Modify the memory location of 2M-" ID "BIOS to save a little memory.",13,10,0
limpia_txt DB 13," ",13,0
IFNDEF XT
info_txt LABEL BYTE
DB 13,10,10
DB " 2M-ABIOS 1.3 - SOPORTE BIOS ACTUALIZADO PARA DISCOS ESTANDAR",13,10
DB " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
DB " Sintaxis: DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10
DB " Algunos ordenadores poseen una BIOS antigua o con un diseño propio poco",13,10
DB " compatible en el control de disco. En estas máquinas 2M y otros programas",13,10
DB " de acceso a bajo nivel pueden fallar. En dichos casos, conviene instalar",13,10
DB " esta utilidad antes que 2M, y en general que cualquier otro software que",13,10
DB " acceda al subsistema de disco. Este programa es sólo para máquinas AT.",13,10,10
DB " 2M-ABIOS actualiza el soporte de disco flexible a la última tecnología",13,10
DB " de las BIOS AMI de 1993. Si con 2M-ABIOS instalado 2M no opera de manera",13,10
DB " totalmente correcta y en su máquina no está instalado algún otro software",13,10
DB " de disco incompatible con 2M, entonces su ordenador no es 100% compatible",13,10
DB " hardware con el estándar; esto es particularmente cierto si con 2M-ABIOS",13,10
DB " instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
DB " Esta utilidad también es útil para añadir soporte de 1.44M a máquinas",13,10
DB " con BIOS antigua. En estos casos, ignore la información sobre el tipo de",13,10
DB " la unidad que pueda reportar dicha BIOS al arrancar.",13,10,10
DB " [PULSA UNA TECLA]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10
DB " Sintaxis: DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10,10
DB " Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
DB " del eficaz código de control de disco de las BIOS AMI, relevando así por",13,10
DB " completo de esta tarea a la BIOS del sistema. Generalmente no hará falta",13,10
DB " indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).",13,10,10
DB ' Si al arrancar apareciera un mensaje como "Incorrect CMOS checksum", lo',13,10
DB " que es poco probable, incluya la opción /C, reinicialice el PC y reajuste",13,10
DB " la configuración entrando en el programa Setup del sistema. Así mismo, si",13,10
DB " en algún momento dudara acerca de si 2M-ABIOS está controlando realmente",13,10
DB " las unidades, puede utilizar la opción /13 para asegurarlo, si bien esta",13,10
DB " opción es poco recomendable cuando no es estrictamente necesaria. AMI es",13,10
DB " marca registrada de American Megatrends Inc.",13,10
DB 255
DB 13,10,10
DB " 2M-ABIOS 1.3 - BIOS DISKETTE SUPPORT UPGRADE UTILITY",13,10
DB " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática.",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
DB " Syntax: DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10
DB " Some computers have an old BIOS or a BIOS built with a peculiar design,",13,10
DB " few compatible in disk operation. In those systems 2M and other low-level",13,10
DB " software can fail. In this cases, you can install 2M-ABIOS before 2M and",13,10
DB " before any other TSR disk software. This program is only for use on AT",13,10
DB " computer systems.",13,10,10
DB " 2M-ABIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
DB " If 2M-ABIOS is installed and there isn't any other disk software",13,10
DB " incompatible with 2M installed, but 2M doesn't work full correctly on",13,10
DB " your computer, this probably means that your computer is not 100%",13,10
DB " hardware compatible with the AT standard. This is specially true if just",13,10
DB " 2M-ABIOS is installed and DOS standard diskettes don't work.",13,10,10
DB " This utility is also useful to add 1.44M support to systems with old",13,10
DB " designed BIOS. In this cases, you must ignore the information about disk",13,10
DB " type reported by such BIOS while booting.",13,10,10
DB " [PRESS ANY KEY]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10
DB " Syntax: DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10,10
DB " This program takes 3.4-4.2 Kb of RAM, and provides a full emulation of",13,10
DB " the effective disk control management of AMI BIOS, absolutely overriding",13,10
DB " your native BIOS in this job. You won't usually need to select the drive",13,10
DB " type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).",13,10,10
DB ' If during system boot a "Incorrect CMOS checksum" message appears, you',13,10
DB " must set the /C switch, reboot the system and run the Setup program (this",13,10
DB " is a very unusual problem). Also, if you realise that 2M-ABIOS is not",13,10
DB " driving your disks, you can set the /13 switch to avoid this problem; but",13,10
DB " this switch is only recomended when it is completely necessary. AMI is a",13,10
DB " registered trademark of American Megatrends Inc.",13,10
DB 0
ELSE
info_txt LABEL BYTE
DB 13,10,10
DB " 2M-XBIOS 1.3 - SOPORTE BIOS ACTUALIZADO PARA DISCOS ESTANDAR",13,10
DB " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
DB " Sintaxis: DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10
DB " La mayoría de PC/XT tiene una BIOS antigua sin soporte de alta densidad",13,10
DB " aunque admiten una controladora de AT de alta densidad. Para trabajar con",13,10
DB " unidades de alta densidad necesitan 2M-XBIOS. Además, 2MX suele requerir",13,10
DB " que esté instalado 2M-XBIOS, que debería ser cargado antes que cualquier",13,10
DB " otro software de disco. Este programa es sólo para máquinas PC/XT.",13,10,10
DB " 2M-XBIOS actualiza el soporte de disco flexible a la última tecnología",13,10
DB " de las BIOS AMI de 1993. Si con 2M-XBIOS instalado 2MX no opera de manera",13,10
DB " totalmente correcta y en su máquina no está instalado algún otro software",13,10
DB " de disco incompatible con 2MX entonces su ordenador no es 100% compatible",13,10
DB " hardware con el estándar; esto es particularmente cierto si con 2M-XBIOS",13,10
DB " instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
DB " Si en algún momento dudara acerca de si 2M-XBIOS está controlando las",13,10
DB " unidades realmente, puede utilizar la opción /13 para asegurarlo, si bien",13,10
DB " esta opción es poco recomendable cuando no es estrictamente necesaria.",13,10,10
DB " [PULSA UNA TECLA]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10
DB " Sintaxis: DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10,10
DB " Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
DB " del eficaz código de control de disco de las BIOS AMI, relevando así por",13,10
DB " completo de esta tarea a la BIOS del sistema. Generalmente será necesario",13,10
DB " indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI",13,10
DB " es marca registrada de American Megatrends Inc.",13,10
DB 255
DB 13,10,10
DB " 2M-XBIOS 1.3 - BIOS DISKETTE SUPPORT UPGRADE UTILITY",13,10
DB " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática.",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
DB " Syntax: DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10
DB " Most PC/XT systems have an old BIOS with no high density support, but",13,10
DB " they can be equiped with an AT high density disk controller. To work with",13,10
DB " high density drives they need 2M-XBIOS. Also, 2MX usually requires the",13,10
DB " previous installation of 2M-XBIOS: you must install it before any other",13,10
DB " TSR disk software. This program is only for use on PC/XT systems.",13,10,10
DB " 2M-XBIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
DB " If 2M-XBIOS is installed and there isn't any other disk software",13,10
DB " incompatible with 2MX installed, but 2MX doesn't work full correctly on",13,10
DB " your computer, this probably means that your computer is not 100%",13,10
DB " hardware compatible with the XT standard. This is specially true if just",13,10
DB " 2M-XBIOS is installed and DOS standard diskettes don't work.",13,10,10
DB " If at any moment you realise that 2M-XBIOS is not really driving your",13,10
DB " disks, you can set the /13 switch to avoid this problem; but this switch",13,10
DB " is only recomended when it is completely necessary.",13,10,10
DB " [PRESS ANY KEY]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10
DB " Syntax: DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10,10
DB " This program takes 3.4-4.2 Kb of RAM, and provides a full emulation of",13,10
DB " the effective disk control management of AMI BIOS, absolutely overriding",13,10
DB " your native BIOS in this job. You will usually need to select the drive",13,10
DB " type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI is a",13,10
DB " registered trademark of American Megatrends Inc.",13,10
DB 0
ENDIF
buffer_aux DB 64 DUP (0) ; buffer para alguna función del DOS
_PRINCIPAL ENDS
_PILA SEGMENT STACK 'STACK'
DB 1024 DUP (?) ; 1 Kb de pila es suficiente
_PILA ENDS
END inicio