home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Bila Vrana
/
BILA_VRANA.iso
/
005A
/
TDSK22SR.ZIP
/
TDSK.ASM
< prev
Wrap
Assembly Source File
|
1995-05-14
|
156KB
|
3,465 lines
;┌───────────────────────────────────────────────────────────────────┐
;│ │
;│ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▄ │
;│ ▀▀▒▒█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ │
;│ ▒▒█ ▒▒▄ ▒▒▄ ▒▒▒▒▄ ▒▒▒▒▄ ▒▒▄ ▒▒▒▒▄ ▒▒▒▒▒▒▄ ▒▒▄ ▒▒▄ │
;│ ▒▒█ ▒▒█ ▒▒█ ▒▒█▀▒▒▄ ▒▒█▀▒▒▄ ▒▒▄▀▒▒▄ ▒▒█▀▒▒▄ ▒▒█▀▀▀▀ ▒▒█ ▒▒█▀ │
;│ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█▒▒█▀ │
;│ ▒▒█ ▒▒█ ▒▒█ ▒▒▒▒▄▀▀ ▒▒▒▒▄▀▀ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒▒▒▒▒▄ ▒▒▒▒█▀ │
;│ ▒▒█ ▒▒█ ▒▒█ ▒▒█▀▒▒▄ ▒▒█▀▒▒▄ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▀▀▀▒▒█ ▒▒█▒▒▄ │
;│ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒▄ ▒▒█ ▒▒█ ▒▒▄ │
;│ ▒▒█ ▒▒▒▒▒▒▒▄ ▒▒█ ▒▒█ ▒▒▒▒▄▀▀ ▀▒▒▄▀▀ ▒▒▒▒▒█▀ ▒▒▒▒▒▒█ ▒▒█ ▒▒▄ │
;│ ▀▀ ▀▀▀▀▀▀▀ ▀▀ ▀▀ ▀▀▀▀ ▀▀ ▀▀▀▀▀ ▀▀▀▀▀▀ ▀▀ ▀▀ │
;│ │
;│ ░░▒▒▓▓██▓▓▒▒░░ Versión 2.2 ░░▒▒▓▓██▓▓▒▒░░ │
;│ │
;│ │
;│ CONTROLADOR DE DISCO VIRTUAL PARA SISTEMAS DOS Y WINDOWS 3 │
;│ │
;│ * * * Programa de Dominio Público * * * │
;│ │
;│ (C) 1992-1995 Ciriaco García de Celis. │
;│ Grupo Universitario de Informática. Facultad de Ciencias. │
;│ Apartado 6062 - Valladolid (España) │
;│ │
;│ Internet Email: ciri@gui.uva.es │
;│ FidoNet: 2:341/21.8 │
;│ │
;│ Mensajes en alemán cortesía de Axel Christoph Frinke │
;│ Internet Email: acfrinke@uni-bonn.de │
;│ │
;└───────────────────────────────────────────────────────────────────┘
; Aviso: Este programa contiene instrucciones exclusivas de los
; procesadores 386 y superiores. Debe ser ensamblado como
; fichero EXE, de la siguiente manera, para asegurar la
; compatibilidad con los procesadores 8086 y 286:
;
; - Con TASM 2.0:
; TASM tdsk /m3
; TLINK tdsk
;
; - Con MASM 6.0 (versiones anteriores de MASM generarían
; un disco virtual que requeriría un 386 o superior,
; además habría que mover las directivas que controlan
; el tipo de procesador y colocarlas con «peligro»):
;
; ML /Zm tdsk.asm
;
; o alternativamente:
;
; ML /c /Zm tdsk.asm
; TLINK tdsk
;
; La ventaja de TLINK frente a LINK es que el fichero
; ejecutable ocupa 2 Kbytes menos en disco (a la tabla
; ubicada al final del programa se le asigna memoria
; en la cabecera del fichero EXE y no ocupando disco).
;
; IMPORTANTE: Cualquier cambio realizado en el programa debe ser
; documentado, indicando claramente en el listado y
; en el fichero DOC quién lo ha realizado.
; ------------ 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
; ------------ Estructuras de datos
cab_PETICION STRUC ; parte inicial común a todos
tamano DB ? ; los comandos de la cabecera
unidad DB ? ; de petición
orden DB ?
estado DW ?
dos_info DB 8 DUP (?)
cab_PETICION ENDS
cab_INIT_BBPB STRUC ; para comandos INIT/BUILD_BPB
DB (TYPE cab_PETICION) DUP (?)
num_discos DB ? ; número de unidades definidas
fin_resid_desp DW ? ; área que quedará residente
fin_resid_segm DW ?
bpb_cmd_desp DW ? ; línea de órdenes del CONFIG
bpb_cmd_segm DW ? ; y puntero al BPB
nuevo_disco DB ? ; (DOS 3+) (0-A:, 1-B:,...)
cab_INIT_BBPB ENDS
cab_MEDIACHECK STRUC ; estructura para MEDIA CHECK
DB (TYPE cab_PETICION) DUP (?)
media_descrip DB ? ; descriptor de medio
cambio DB ? ; 1: no cambiado, 0FFh:sí, 0:?
cab_MEDIACHECK ENDS
cab_READ_WRITE STRUC
DB (TYPE cab_PETICION) DUP (?)
DB ? ; descriptor de medio
transfer_desp DW ? ; dirección de transferencia
transfer_segm DW ?
transfer_sect DW ? ; nº de sectores a transferir
transfer_sini DW ? ; primer sector a transferir
cab_READ_WRITE ENDS
; ************ Disco virtual: inicio del área residente.
_PRINCIPAL SEGMENT
ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
DD -1 ; encadenamiento con otros drivers
tipo_drive DW 0800h ; palabra de atributo:
; bit 15 a 0: dispositivo de bloques
; bit 14 a 0: sin control IOCTL
; bit 13 a 0: formato IBM
; bit 11 a 1: soportados Open/Close
; y Remove (DOS 3.0+)
DW estrategia ; rutina de estrategia
DW interrupcion ; rutina de interrupción
DB 1 ; número de unidades
; ------------ Variables y tablas de datos globales fijas. Estas
; variables no serán movidas de sitio en otras versiones
; de TURBODSK, con objeto de facilitar un control externo
; del disco virtual por parte de otros programas. Todo lo
; que está dentro del «área a actualizar» será copiado
; sobre el TURBODSK residente al redefinir el disco, para
; inicializar todas las variables precisas.
cs_tdsk DW ? ; Segmento de TDSK. Con QEMM-386, los drivers
; pueden ser relocalizados en memoria superior
; de tal manera que parte de la cabecera queda
; en memoria convencional, con el dispositivo
; completo en la memoria superior, en la que es
; ejecutado. Tras la instalación, QEMM copia en
; memoria convencional los primeros 18 bytes de
; la cabecera, entre los que está esta palabra,
; actualizándola. Pese a que la cadena de
; dispositivos del sistema pasa por la memoria
; convencional en este caso, esta variable nos
; permite conocer la dirección REAL en memoria
; superior (o en cualquier otra) de TURBODSK,
; que así es compatible con el LOADHI de QEMM.
id_tdsk DB "TDS22" ; esto es TURBODSK 2.2 y no otro
; controlador de dispositivo
num_ordenes DB 10h ; nº de órdenes soportadas
i_tdsk_ctrl EQU $ ; inicio del área a actualizar
tipo_soporte DB 0FFh ; 0: disco no formateado
; 1: se emplea memoria XMS 2.0+
; 2: " " " EMS 3.2+
; 3: " " " convencional
; 0FFh: aún no ejecutada INIT
cambiado DB ? ; al formatear el disco virtual se pone
; a 0FFh (para indicar cambio de disco)
mem_handle DW ? ; para memoria EMS/XMS; si se utiliza
; memoria convencional, apunta al
; segmento donde empieza el disco
tdsk_psp DW ? ; segmento del PSP residente si se
; utiliza memoria convencional
ems_pagina0 DW ? ; segmento de página EMS (si se emplea)
ems_paginai DW ? ; segmento alternativo
ems_pagni DB ? ; nº de página física alternativa
xms_driver LABEL DWORD ; dirección del controlador XMS, en el
xms_desp DW ? ; caso de emplear memoria XMS.
xms_segm DW ?
cpu386 DB OFF ; a ON si 386 ó superior
f_tdsk_ctrl EQU $ ; final del área a actualizar
letra_unidad DB ? ; letra ASCII del disco ('C', 'D',...)
bpb_ptr DW bpb ; puntero al BPB del disco
rutina_larga DB OFF ; a ON si reservado espacio en
; memoria para la larga rutina de
; gestión de memoria EMS.
; ------------ Variables internas de TURBODSK; su ubicación podría
; cambiar en futuras versiones del programa.
pcab_peticion LABEL DWORD ; puntero a la cabecera de petición
pcab_pet_desp DW 0
pcab_pet_segm DW 0
p_rutinas LABEL WORD ; tabla de rutinas del controlador
DW init
DW media_check
DW build_bpb
DW ioctl_input
DW read
DW read_nowait
DW input_status
DW input_flush
DW write
DW write_verify
DW output_status
DW output_flush
DW ioctl_output
DW open ; DOS 3.0+
DW close ; DOS 3.0+
DW remove ; DOS 3.0+
media EQU 0FAh ; byte descriptor de medio utilizado por
; TURBODSK. No es 0F8h como en los discos
; virtuales del sistema ya que TURBODSK
; no es un dispositivo fijo. Este byte no
; es empleado por los discos estándar del
; dos y al ser mayor de 0F7h no provoca
; mensajes extraños con antiguos CHKDSKs.
bpb LABEL BYTE ; Estos valores del BPB son arbitrarios:
bytes_sector DW 512 ; se inicializarán si se define el disco
sect_cluster DB 1 ; al instalar desde el CONFIG; en caso
sect_reserv DW 1 ; contrario, como son correctos, el DOS
num_fats DB 1 ; no tendrá problemas para realizar sus
entradas_raiz DW 128 ; cálculos internos iniciales al instalar
num_sect DW 128 ; el driver. En concreto, el tamaño de
media_byte DB media ; sector influye de manera directa en el
sectores_fat DW 4 ; tamaño de los buffers de disco del DOS.
fin_bpb EQU $
; ------------ Rutina de estrategia del disco virtual.
estrategia PROC FAR
MOV CS:pcab_pet_desp,BX
MOV CS:pcab_pet_segm,ES
RET
estrategia ENDP
; ------------ Rutina de interrupción del disco virtual. TURBODSK,
; al igual que RAMDRIVE o VDISK, no define una pila
; interna. Es responsabilidad del DOS que ésta tenga el
; tamaño adecuado (con el disco en memoria XMS, el
; controlador XMS puede requerir hasta 256 bytes de
; pila). TURBODSK no consume más de 64 bytes de pila en
; ningún momento, y sólo alrededor de 48 antes de llamar
; al controlador XMS cuando se emplea esta memoria.
interrupcion PROC FAR
XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
LDS BX,CS:pcab_peticion
MOV AL,[BX].orden ; AL = orden
MOV AH,0 ; AX = orden
CMP AL,CS:num_ordenes
JB orden_ok ; orden soportada
MOV AL,3 ; " desconocida (IOCTL INPUT)
orden_ok: CMP CS:tipo_soporte,AH
JNE no_test_fmt ; tipo_soporte distinto de 0
MOV AX,8102h ; disco no formateado: error
JMP exit_interr
no_test_fmt: SHL AX,1 ; orden = orden * 2
MOV SI,AX
XPUSH <BX,DS>
XOR BP,BP
MOV AX,100h
CALL CS:[SI+OFFSET p_rutinas] ; ejecutar orden
XPOP <DS,BX>
AND AH,AH
JNS exit_interr ; no hubo error (bit 15 = 0)
CMP AL,3
JE exit_interr ; error de orden desconocida
MOV [BX].transfer_sect,0 ; otro: movidos 0 sectores
exit_interr: MOV [BX].estado,AX
XPOP <ES,DS,BP,DI,SI,DX,CX,BX,AX>
RET
interrupcion ENDP
; ------------ Las rutinas que controlan el dispositivo devuelven AX
; con la palabra de estado. Pueden cambiar todos los
; registros (de 16 bits), incluídos los de segmento. A la
; entrada, BP=0 y AX=100h.
media_check: MOV AL,CS:cambiado ; condición de «disco cambiado»
MOV CS:cambiado,AH ; de momento ya no cambiará más
MOV [BX].cambio,AL
read_nowait: ; conjunto de órdenes con
input_status: ; tratamiento idéntico
input_flush:
output_status:
output_flush:
ioctl_output:
open:
close:
retorno_ok: RET ; no hay error, ignorar orden
build_bpb: MOV [BX].bpb_cmd_desp,OFFSET bpb
MOV [BX].bpb_cmd_segm,CS
JMP retorno_ok
ioctl_input: MOV AX,8103h ; orden no soportada
RET
remove: MOV AH,3 ; fin de función, indicar
RET ; «controlador ocupado»
nueva_int19 PROC ; Interceptar reinicialización
.286
PUSHA
XPUSH <DS,ES> ; Esto es una interrupción
XOR AX,AX
MOV ES,AX
CMP AL,CS:tipo_soporte ; ¿Disco formateado?
JE no_lib ; no
MOV CS:tipo_soporte,AL ; sí: anularlo
CALL procesa_io ; CF=1: liberar memoria EMS/XMS
no_lib: LEA SI,ant19off
MOV DI,64h ; desplazamiento de INT 19h
PUSH CS
POP DS
CLI
MOVSW
MOVSW
XPOP <ES,DS>
POPA
DB 0EAh ; código de JMP FAR SEG:OFF
ant19off DW ?
ant19seg DW ?
.8086
nueva_int19 ENDP
read: INC BP ; indicar lectura (BP=1)
write: ; escritura (BP=0)
write_verify:
init_io PROC ; preparar registros E/S
LES DI,DWORD PTR [BX].transfer_desp ; * direc. ES:DI
LDS AX,DWORD PTR [BX].transfer_sect ; nº sectores AX
MOV BX,DS ; 1º sector ¡DS indefinido!
io_proc: MOV SI,CS:bytes_sector
ADD AX,BX
JNC io_ok? ; último sector < 65536
io_no_ok: MOV AX,8108h ; «sector no encontrado»
RET
io_ok?: CMP AX,CS:num_sect
JA io_no_ok ; sector final ¡fuera!
SUB AX,BX
MUL SI ; DX(CF):AX = tamaño bloque
RCR AX,1 ; CF:AX/2 -> AX = palabras
MOV CX,DI
NEG CX ; 10000h-CX: CF=1 si CX<>0
CMC ; CF:CX bytes hasta fin de
RCR CX,1 ; segmento = (10000h-DI)/2
CMP AX,CX
JAE io_cx_ok
MOV CX,AX ; * tamaño: CX palabras
io_cx_ok: JCXZ io_no_ok ; CX=0 si DI=0FFFFh (fatal)
MOV AX,BX ; sector inicial
MUL SI ; * desplazamiento en DX:AX
CLC ; ¡no reinicializando!
init_io ENDP
; ------------ Area residente dependiente del tipo de memoria empleada
; por el disco. La rutina instalada por defecto es la más
; larga de todas, para «dejar hueco» donde copiar encima
; las otras si se va a utilizar otro tipo de memoria. Si
; se modifican las rutinas, convendría medirlas por si
; acaso la de memoria EMS deja de ser la más larga...
procesa_io EQU $
; ---- La rutina de gestión de memoria EMS transfiere
; bloques de hasta 16Kb de una vez. Intenta mapear
; en la página física 0: si no puede, debido a un
; solapamiento con el buffer de transferencia del
; programa principal (si está también en memoria
; EMS), utiliza otra página alternativa que dista
; al menos 32 Kb absolutos de la 0. Para dilucidar
; si hay solapamiento, se compara la distancia
; entre direcciones origen y destino antes de la
; transferencia: si es mayor de 401h párrafos
; (16400 bytes, 16 para redondeo) no hay problema.
; Ante un solapamiento se procede a restaurar el
; contexto de las páginas mapeadas, antes y
; después de la transferencia, para poder acceder
; a la memoria expandida donde está el buffer del
; programa principal.
procesa_ems PROC
JNC no_emslib
MOV DH,45h ; sistema reinicializando:
CALL llama_EMM ; liberar memoria EMS
RET
no_emslib: MOV SI,DX ; preservar DX
MOV DH,47h
CALL llama_EMM ; DH=47h -> salvar contexto EMS
MOV DX,SI ; recuperar DX
MOV BX,4000h ; tamaño de página (16 Kb)
DIV BX ; AX = 1ª página EMS a mapear
MOV SI,DX ; offset relativo en 1ª página
procesa_pag: PUSH CX ; **
MOV BX,DI
MOV CL,4
SHR BX,CL ; bytes del offset -> párrafos
MOV CX,ES
ADD BX,CX ; AX = segmento de datos
MOV CX,CS:ems_pagina0
MOV DS,CX
XOR DL,DL ; intentar emplear página 0
SUB BX,CX
JNC rpos
NEG BX ; valor absoluto
rpos: CMP BX,401h ; distancia respecto página EMS
JAE no_conflicto ; más de 16 Kb: no solapamiento
CALL copia_contexto ; está CX apilado
MOV DS,CS:ems_paginai
MOV DL,CS:ems_pagni ; usar página alternativa
OR BP,8000h ; indicar su uso
no_conflicto: POP CX ; * pila totalmente equilibrada
MOV BX,AX
MOV DH,44h ; DL = 0 ó 2 (página física)
CALL llama_EMM ; DH = 44h -> mapear página EMS
XPUSH <CX,SI> ; ++
SUB SI,4000h
NEG SI ; SI = 4000h - SI: «resto»
SHR SI,1 ; bytes -> palabras
CMP CX,SI
JB cx_ok ; no ocupada toda la página
MOV CX,SI
cx_ok: POP SI ; + SI=desplazamiento relativo
CLD
POP BX ; + palabras restantes
SUB BX,CX ; descontar las que se moverán
PUSH BX ; * volver a apilar el viejo CX
CALL coloca_regs
CMP CS:cpu386,ON ; ¿386 o superior?
JNE trans_16bit
.386
PUSHAD
SHR CX,1 ; nº palabras de 32 bit a mover
JCXZ transferido ; evitar desgracia
XOR EAX,EAX ; asegurar no violación
DEC AX ; de segmento-64K
AND ECX,EAX ; EAX = 0FFFFh
AND ESI,EAX
AND EDI,EAX
REP MOVSD ; transferencia ultrarrápida
transferido: POPAD ; POPAD falla en muchos 386
.8086
NOP ; arreglar fallo de POPAD
ADD CX,CX
ADD DI,CX ; simular cambio normal de DI
ADD SI,CX ; y de SI
JMP fin_trans
trans_16bit: REP MOVSW ; mover palabras de 16 bit
fin_trans: CALL coloca_regs
AND BP,BP ; ¿se usó página alternativa?
JNS ahorra_ms
CALL copia_contexto ; está CX apilado
AND BP,1 ; de momento, no se usará más
ahorra_ms: POP CX ; **
JCXZ fin_leer ; no quedan más palabras
INC AX ; próxima página EMS
XOR SI,SI ; ahora desde inicio página EMS
JMP procesa_pag
fin_leer: MOV DH,48h
CALL llama_EMM ; DH=47h restaurar contexto EMS
MOV AX,100h ; no hubo problemas
RET
procesa_ems ENDP
; ---- ¡Cuidado!: esta rutina debe ser invocada siempre
; con la pila (SP) tal y como estaba al principio
; del procedimiento «procesa_ems», y utilizando
; siempre CALL, para que en el caso de que haya
; errores retorne correctamente al nivel anterior
; (nivel previo a «procesa_ems»). Se corrompe DX
; y, si hay error, AX también (devuelve 810Ch).
llama_EMM PROC
XPUSH <AX,BX,CX,BP>
MOV AX,DX ; función en AX
llama_denuevo: MOV DX,CS:mem_handle ; handle EMS
XPUSH <AX,BX>
INT 67h ; llamar al EMM
MOV CL,AH
XPOP <BX,AX>
AND CL,CL
JZ llama_ok ; además, ZF = 1
CMP CL,82h
JE llama_denuevo ; intentarlo hasta que funcione
llama_ok: XPOP <BP,CX,BX,AX>
JNE ret_atras
RET
ret_atras: POP AX ; sacar dirección de retorno
MOV AX,810Ch ; error de «anomalía general»
RET ; retornar dos niveles atrás
llama_EMM ENDP
; ---- ¡Cuidado!: esta rutina debe ser invocada siempre
; con CX (y sólo CX) apilado: recarga CX desde la
; pila y corrompe BX dejando aún en la pila CX.
copia_contexto PROC
XPOP <BX,CX> ; equilibrar pila a llama_EMM
MOV DH,48h
CALL llama_EMM ; restaurar contexto EMS
MOV DH,47h
CALL llama_EMM ; preservarlo de nuevo
PUSH CX
JMP BX ; más rápido que PUSH BX/RET
copia_contexto ENDP
coloca_regs PROC ; ¿invertir sentido?
TEST BP,1
JNZ colocados
XCHG SI,DI ; escritura: invertir sentido
XPUSH <DS,ES>
XPOP <DS,ES>
colocados: RET
coloca_regs ENDP
tam_proc_ems EQU $-OFFSET procesa_ems ; tamaño de esta rutina
; <<< Fin del código residente del disco virtual >>>
; ************ Instalación (invocada desde CONFIG.SYS).
init PROC
MOV CS:modo,CONFIG ; ejecutando desde CONFIG
CALL obtDosVer ; obtener versión del DOS
LEA AX,retorno_ok
MOV CS:p_rutinas,AX ; anular rutina INIT
INC CS:tipo_soporte ; 0: disco no formateado
MOV CS:cs_tdsk,CS ; inicializar esa variable
CMP CS:dosver,300h ; ¿DOS inferior al 3.0?
JAE dos_ok ; DOS 3.0+
AND CS:tipo_drive,0F7FFh ; ajustar atributos
MOV CS:num_ordenes,0Dh ; y número de órdenes
dos_ok: MOV SI,[BX].bpb_cmd_desp
MOV ES,[BX].bpb_cmd_segm ; ES:SI -> parámetros
MOV [BX].num_discos,1 ; una unidad de disco
LEA AX,bpb_ptr
MOV [BX].bpb_cmd_desp,AX
MOV [BX].bpb_cmd_segm,CS ; inicializado puntero BPB
CALL desvia_int19 ; controlar INT 19h
CALL inic_letra ; obtener letra de unidad
MOV BX,CS
MOV DS,BX ; DS: -> _PRINCIPAL
MOV BX,SI ; ES:BX -> parámetros
CALL salta_nombre ; buscar inicio parámetros
CALL procesar_param ; procesar parámetros
PUSH DS ;
POP ES ; ES: -> _PRINCIPAL
CMP param_h,ON
JE fin_instalar ; piden ayuda
CALL max_sector ; obtener mayor sector
MOV BX,param_tsect
CMP BX,AX ; ¿el nuestro es mayor?
JBE sect_def_ok ; no
MOV bytes_sector,BX ; sí: ajustar BPB
sect_def_ok: CALL errores_config
TEST lista_err,ERROR0+ERROR1
JNZ fin_instalar ; algún error importante
CMP param_tdisco,0 ; ¿se define disco ahora?
JE fin_instalar ; no: no hay más que hacer
CALL mem_info ; evaluar memoria del PC
CMP tdisco,0 ; ¿se reservará memoria?
JE fin_instalar ; no: no hay más que hacer
CALL mem_reserva ; reservar memoria
JC fin_instalar ; fallo al reservarla
CALL test_CPU ; detectar 386 ó superior
CALL adaptar_param ; adaptar parámetros disco
CALL preparar_BPB ; BPB del nuevo disco
CALL prep_driver ; preparar el driver
CALL formatear_tdsk ; inic. BOOT, FAT y ROOT
fin_instalar: CALL info_disco ; informar sobre el disco
CMP tipo_soporte,2
JE res_largo ; se utiliza memoria EMS
CMP param_a,ON
JE res_largo ; se indicó /A
CALL eval_xms
CALL eval_ems
CMP ems_kb,0
JE res_corto ; no hay memoria EMS
CMP xms_kb,0
JNE res_corto ; la hay, pero también XMS
res_largo: MOV AX,tam_proc_ems
MOV rutina_larga,ON ; dejar sitio a rutina EMS
JMP bytes_res_ok
res_corto: MOV AX,tam_proc_xms ; dejar sitio a XMS/conv.
MOV BX,tam_proc_con
CMP AX,BX
JAE bytes_res_ok
XCHG AX,BX
bytes_res_ok: LDS BX,CS:pcab_peticion
ADD AX,OFFSET procesa_io
MOV [BX].fin_resid_desp,AX ; reservar memoria para
MOV [BX].fin_resid_segm,CS ; las rutinas a usar
MOV AX,100h ; instalación siempre Ok.
RET
init ENDP
; ------------ Redefinición (invocada desde el AUTOEXEC.BAT o el DOS).
main PROC FAR
MOV CS:modo,AUTOEXEC ; ejecutando desde el DOS
CALL obtDosVer ; obtener versión del DOS
CALL gestionar_ram ; gestión de memoria
MOV AX,_PRINCIPAL ; programa de un segmento
MOV DS,AX ; DS: -> _PRINCIPAL
MOV BX,81h ; ES:BX línea de órdenes
CALL procesar_param ; procesar parámetros
CMP param_h,ON
JE exit_instalar ; piden ayuda
PUSH DS
POP ES ; ES: --> _PRINCIPAL
CALL errores_Dos
TEST err_grave,0FFFFh
JNZ exit_instalar ; algún error grave
MOV ES,segm_tdsk ; ES: --> disco residente
CMP param_a,ON
JNE cabria_ems
CMP ES:rutina_larga,ON
JE cabria_ems ; cabe la rutina EMS
OR lista_err,ERROR2
cabria_ems: TEST lista_err,ERROR0+ERROR2 ; ¿error sintaxis ó EMS?
JNZ exit_instalar ; sí: no modificar disco
CMP param_tdiscof,ON
JNE exit_instalar ; no indicado nuevo tamaño
CMP ES:tipo_soporte,0
JE cont_instalar ; no estaba formateado aún
CALL desinstala ; liberar memoria ocupada
cont_instalar: CALL mem_info ; evaluar memoria del PC
CMP tdisco,0 ; ¿se reservará memoria?
JE exit_instalar ; no: no hay más que hacer
CALL mem_reserva ; reservar memoria
JC exit_instalar ; fallo reservando memoria
CALL test_CPU ; detectar 386 ó superior
CALL adaptar_param ; adaptar parámetros disco
CALL preparar_BPB ; BPB del nuevo disco
CALL relocalizar ; autoreubicación de TDSK
CALL prep_driver ; preparar el driver
CALL formatear_tdsk ; BOOT, FAT y ROOT
exit_instalar: CALL info_disco ; informar sobre el disco
CMP tipo_soporte,3 ; ¿memoria convencional?
JNE fin_no_res ; no usada
CALL renombrar_mcb ; cambiar nombre del MCB
MOV DX,6 ; usada: 96 bytes de PSP
MOV AX,3100h
INT 21h ; terminar residente
fin_no_res: CALL set_errorlevel ; preparar ERRORLEVEL
MOV AH,4Ch
INT 21h ; final normal
main ENDP
; ------------ Inicializar la variable con la versión del DOS
obtDosVer PROC
XPUSH <AX,BX,CX,DX>
MOV AH,30h
INT 21h
XCHG AH,AL
MOV CS:dosver,AX
XPOP <DX,CX,BX,AX>
RET
obtDosVer ENDP
; ------------ Determinar segmento del PSP, último segmento de memoria
; y liberar espacio de entorno. Se modifica también el
; bloque de memoria de TDSK reduciéndolo a 96 bytes: esto
; provoca la creación de un bloque de control de memoria
; en el offset 96 del PSP, lo cual no es peligroso. El
; objetivo de esta maniobra es poder asignar memoria al
; disco después (sólo si hace falta memoria convencional)
; usando los servicios estándar del DOS.
gestionar_ram PROC
MOV CS:segm_psp,DS ; indicar segmento del PSP
MOV AX,DS:[2] ; segmento más alto
MOV CS:top_ram,AX ; indicar tope de memoria
PUSH ES
MOV ES,DS:[2Ch] ; segmento del entorno
MOV AH,49h
INT 21h ; liberar área de entorno
POP ES ; ES: -> PSP
MOV BX,6
MOV AH,4Ah ; hacer creer al DOS que
INT 21h ; TDSK ocupa sólo 96 bytes
RET
gestionar_ram ENDP
; ------------ Leer los parámetros de la línea de comandos (ES:BX).
; Se inicializan las correspondientes variables. En caso
; de error, se dejan a cero las variables y se acumula en
; «lista_err» un ERROR0 (error de sintaxis).
procesar_param PROC
CALL busca_param ; saltar delimitadores
JC fin_param ; no hay más parámetros
CALL param_barra ; gestionar parámetro tipo "/A"
JC procesar_param ; era parámetro tipo "/A"
MOV param_tdisco,AX ; es numérico: tamaño del disco
MOV param_tdiscof,ON ; parámetro de tamaño indicado
p_param2: CALL busca_param
JC fin_param
CALL param_barra
JC p_param2
MOV param_tsect,AX ; tamaño de sector
p_param3: CALL busca_param
JC fin_param
CALL param_barra
JC p_param3
MOV param_tdir,AX ; entradas al directorio
p_param4: CALL busca_param
JC fin_param
CALL param_barra
JC p_param4
MOV param_tcluster,AX ; tamaño de cluster
p_param5: CALL busca_param
JC fin_param
CALL param_barra ; últimas opciones posibles
JC p_param5
fin_param: CALL validacion ; validación de parámetros
RET
procesar_param ENDP
param_barra PROC
CMP AX,"e/" ; ¿indicado /E?
JNE p_exp1?
MOV param_e,ON
JMP p_barra_exit
p_exp1?: CMP AX,"a/" ; ¿indicado /A?
JNE p_exp2?
p_exp: MOV param_a,ON
JMP p_barra_exit
p_exp2?: CMP AX,"x/" ; /A y /X son equivalentes
JE p_exp
CMP AX,"c/" ; ¿indicado /C?
JNE p_ayuda?
MOV param_c,ON
JMP p_barra_exit
p_ayuda?: CMP AX,"h/" ; ¿indicado /H?
JNE p_exit?
p_ayuda: MOV param_h,ON
JMP p_barra_exit
p_exit?: CMP AX,"?/" ; /H y /? son equivalentes
JE p_ayuda
CMP AX,"m/" ; ¿indicado /M?
JNE param_id?
MOV param_m,ON
JMP p_barra_exit
param_id?: CMP AX,"i/" ; ¿indicado /I= o /I:?
JNE param_fats?
ADD BX,3
CMP BYTE PTR ES:[BX-1],'='
JE p_id_ok
CMP BYTE PTR ES:[BX-1],':'
JNE param_b_mal
p_id_ok: CALL obt_num ; leer código telefónico
MOV param_i,ON
MOV codigo_tfno,AX
SUB BX,2
JMP p_barra_exit
param_fats?: CMP AX,"f/" ; ¿indicado /F= o /F:?
JNE param_unidad?
ADD BX,3
CMP BYTE PTR ES:[BX-1],'='
JE p_f_ok
CMP BYTE PTR ES:[BX-1],':'
JNE param_b_mal
p_f_ok: CALL obt_num ; leer número de FATs
MOV param_f,AX
SUB BX,2
JMP p_barra_exit
param_unidad?: CMP AH,':' ; ¿parámetro de unidad?
JNE param_num?
AND AL,255-32 ; poner en mayúsculas
MOV param_unidad,AL
JMP p_barra_exit
param_num?: CMP AL,'/'
JNE param_num ; puede ser número
param_b_mal: OR lista_err,ERROR0
param_num: CALL obt_num ; es parámetro numérico: leerlo
CLC ; no es parámetro barrado
RET
p_barra_exit: ADD BX,2 ; saltar este parámetro
STC ; es parámetro barrado
RET
param_barra ENDP
validacion PROC
MOV AX,0FFFFh
CMP AX,param_tdisco ; ¿números correctos?
JE sintax_err
CMP AX,param_tsect
JE sintax_err
CMP AX,param_tdir
JE sintax_err
CMP AX,param_tcluster
JE sintax_err
CMP param_tdisco,0
JE valida_tsect ; no indicado tamaño (o 0)
CMP param_tdisco,8
JB sintax_err
CMP param_tdisco,65534
JA sintax_err
valida_tsect: MOV AX,param_tsect
CMP AX,0
JE valida_tclus ; no indicado tamaño de sector
CMP AX,32
JE valida_tclus
CMP AX,64
JE valida_tclus
CMP AX,128
JE valida_tclus
CMP AX,256
JE valida_tclus
CMP AX,512
JE valida_tclus
CMP AX,1024
JE valida_tclus
CMP AX,2048
JNE sintax_err
valida_tclus: CMP param_tcluster,256
JAE sintax_err ; debe estar entre 0..255
CMP param_f,1
JB pf_a1 ; /F=1 ó /F=2 exclusivamente
CMP param_f,2 ; si no, forzarlo y perdonar
JBE fin_validar
MOV param_f,2
JMP fin_validar
pf_a1: MOV param_f,1
JMP fin_validar
sintax_err: MOV param_tdiscof,OFF ; no definir disco ahora
XOR AX,AX
MOV param_tdisco,AX
MOV param_tsect,AX
MOV param_tdir,AX
MOV param_tcluster,AX
OR lista_err,ERROR0 ; aviso de error de sintaxis
fin_validar: RET
validacion ENDP
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 ; necesario para DOS 2.x
JMP salta_nombre
fin_nombre: DEC BX
RET
salta_nombre ENDP
busca_param PROC ; saltar delimitadores
DEC BX
p_delimit: INC BX
MOV AX,ES:[BX]
CMP AL,' '
JE p_delimit ; espacio en blanco
CMP AL,9
JE p_delimit ; tabulador
CMP AL,13
JE p_final ; CR ó LF indican el final
CMP AL,10
JE p_final
OR AX," " ; poner en minúsculas
CLC
RET
p_final: STC ; se acabaron los parámetros
RET
busca_param ENDP
obt_num PROC ; leer número: devolver 65535
XPUSH <CX,DX,SI> ; si hay error
XOR AX,AX ; número en proceso de creación
otro_digito: MOV CL,ES:[BX]
CMP CL,'0'
JB no_digito
CMP CL,'9'
JBE digito_ok
no_digito: CMP CL,' ' ; posibles delimitadores...
JE fin_num
CMP CL,9
JE fin_num
CMP CL,13
JE fin_num
CMP CL,10
JE fin_num
CMP CL,'/'
JE fin_num
JMP num_incorr
digito_ok: XOR DX,DX
MOV SI,10
MUL SI ; AX = AX * 10
JC num_incorr
XOR CH,CH
SUB CL,'0'
ADD AX,CX ; AX = AX + dato
JC num_incorr
INC BX
JMP otro_digito
num_incorr: MOV AX,65535 ; indicar valor incorrecto
fin_num: XPOP <SI,DX,CX>
RET
obt_num ENDP
; ------------ Detectar errores que se pueden producir sólo en la
; línea de comandos.
errores_Dos PROC
PUSH ES
CMP dosver,200h ; necesario DOS 2.x+
JAE existe_tdsk?
OR err_grave,ERROR0 ; error de DOS incorrecto
JMP fin_err_Dos
existe_tdsk?: CALL reside_tdsk? ; ¿instalado TURBODSK?
CMP segm_tdsk,0
JNE busca_unidad ; ya instalado
OR err_grave,ERROR1 ; error: TURBODSK no instalado
JMP fin_err_Dos
busca_unidad: MOV ES,segm_tdsk ; ES: -> disco virtual
CMP param_unidad,0
JE disco_defecto ; no se indicó letra de unidad
CALL obtener_segm ; segmento del TDSK indicado
JC fin_err_Dos ; fallo (no es unidad TDSK)
disco_defecto: CALL max_sector ; obtener mayor sector
MOV BX,param_tsect
CMP BX,AX
JBE fin_err_Dos ; tamaño de sector correcto
OR lista_err,ERROR3 ; el tamaño no definible ahora
MOV param_tsect,0 ; ignorar tamaño indicado
fin_err_Dos: CALL test32Mb
CALL testWin
POP ES
RET
errores_Dos ENDP
; ------------ Detectar errores que se pueden producir sólo desde
; el CONFIG.SYS
errores_config PROC
CMP param_unidad,0
JE no_unidad
OR lista_err,ERROR1
no_unidad: CMP param_c,ON
JNE fin_err_con
OR lista_err,ERROR1
fin_err_con: CALL test32Mb
RET
errores_config ENDP
; ------------ Preparar valor de ERRORLEVEL para el retorno.
set_errorlevel PROC
MOV AL,255
TEST err_grave,ERROR1 ; ¿TDSK no instalado?
JNZ fin_cod_ok
DEC AL
TEST err_grave,ERROR2 ; ¿unidad incorrecta?
JNZ fin_cod_ok
DEC AL
TEST err_grave,ERROR3 ; ¿dentro de Windows?
JNZ fin_cod_ok
DEC AL
TEST lista_err,ERROR0 ; error de sintaxis
JNZ fin_cod_ok
CMP param_h,ON ; ayuda: handle desconocido
JE fin_cod_ok
MOV AL,BYTE PTR ES:mem_handle ; handle XMS/EMS
CMP ES:tipo_soporte,0
JNE fin_cod_ok
MOV AL,0 ; disco no formateado
fin_cod_ok: RET
set_errorlevel ENDP
; ------------ Obtener mayor tamaño de sector definido en el sistema.
max_sector PROC
XPUSH <BX,ES>
MOV AH,52h
INT 21h ; Get List of Lists
ADD BX,10h
CMP CS:dosver,30Ah
JAE psect_ok
INC BX ; DOS anterior al 3.1
psect_ok: MOV AX,ES:[BX] ; mayor tamaño de sector
XPOP <ES,BX> ; definido por cualquier disp.
RET
max_sector ENDP
; ------------ Si el disco es de más de 32 Mb, comprobar si el sector
; es de al menos 1024 bytes.
test32Mb PROC
CMP param_tdisco,32768
JBE fin32mb
CMP param_tsect,1024
JAE fin32mb
OR lista_err,ERROR15 ; sector de menos de 1024
MOV param_tdisco,32768 ; evitar fallo posterior
fin32mb: RET
test32Mb ENDP
; ------------ Desde Windows, no se permite redefinir el disco.
testWin PROC
CMP param_tdiscof,ON
JNE fin_testWin ; no redefinido el disco
CMP dosver,300h
JB fin_testWin ; no buscar Windows en DOS 2.x
MOV AX,1600h
INT 2Fh
AND AL,AL ; ¿Windows en modo extendido?
JZ noWinEnh
CMP AL,80h ; ¿Windows en modo extendido?
JE noWinEnh
siWin: OR err_grave,ERROR3 ; estamos dentro de Windows
JMP fin_testWin
noWinEnh: MOV AX,4680h
INT 2Fh
AND AX,AX
JZ siWin ; Windows en modo real/estándar
fin_testWin: RET
testWin ENDP
; ------------ Verificar la presencia en memoria de TURBODSK. Se
; inicializa «segm_tdsk» y «letra_unidad» indicando dónde
; reside el primer dispositivo TURBODSK de todos los que
; puede haber instalados. La letra de la unidad se halla
; del propio TDSK residente, para evitar conflictos con
; programas que manipulan ilegalmente la lista de
; unidades, del tipo de Stacker o Smartdrive.
reside_tdsk? PROC
XPUSH <AX, SI>
CALL lista_discos
LEA SI,area_trabajo-4
busca_final: ADD SI,4
CMP WORD PTR [SI],0
JNE busca_final ; ir al final de la tabla
busca_tdsk: SUB SI,4
CMP SI,OFFSET area_trabajo
JB fin_busca ; no reside (segm_tdsk = 0)
CMP BYTE PTR [SI+3],1
JNE busca_tdsk
MOV AX,[SI] ; encontrada unidad TURBODSK
MOV segm_tdsk,AX
PUSH DS
MOV DS,AX
MOV AL,letra_unidad ; con esta letra de unidad
POP DS
MOV letra_unidad,AL
fin_busca: XPOP <SI, AX>
RET
reside_tdsk? ENDP
; ------------ Obtener el segmento de la unidad TURBODSK indicada, si
; existe, accediendo a una tabla de dispositivos que se
; crea. A la salida, CF=1 si esa unidad no es TURBODSK.
obtener_segm PROC
CALL lista_discos
LEA SI,area_trabajo-4
busca_ultimo: ADD SI,4
CMP WORD PTR [SI],0
JNE busca_ultimo ; realmente, el primero
recorre_dsks: SUB SI,4
CMP SI,OFFSET area_trabajo
JB tdsk_no_hay
CMP BYTE PTR [SI+3],1
JNE recorre_dsks
PUSH DS
MOV DS,[SI]
MOV AL,letra_unidad ; unidad del TDSK residente
POP DS
CMP AL,param_unidad ; disco TDSK: ¿es el buscado?
JNE recorre_dsks
MOV letra_unidad,AL ; inicializar letra de unidad
MOV AX,[SI]
MOV segm_tdsk,AX ; inicializar segmento
MOV ES,AX
CLC
RET
tdsk_no_hay: OR err_grave,ERROR2 ; unidad indicada no es TDSK
STC
RET
obtener_segm ENDP
; ------------ Colocar nuevo gestor de INT 19h al instalar TDSK desde
; el CONFIG.SYS. En algunos entornos multitarea basados
; en el modo virtual-86 del 386 y superiores, si no se
; libera la memoria EMS/XMS tras una cancelación de la
; tarea virtual, ésta queda permanentemente ocupada hasta
; un reset «frío» del sistema, sin poder ser aprovechada
; por los demás procesos. La INT 19h se ejecuta cuando la
; tarea en curso va a ser inminentemente cancelada por el
; sistema, y TURBODSK la intercepta para poder liberar la
; memoria EMS/XMS en el último instante. La rutina que
; controla INT 19h contiene código de 286, por lo que se
; chequea la presencia de este procesador.
desvia_int19 PROC
XPUSH <BX,DS,ES>
MOV BX,CS
MOV DS,BX
CALL test_CPU
CMP cpu286,ON
JNE fin_desvia19 ; no es 286 ó superior
MOV AX,3519h
INT 21h ; ES:BX anterior INT 19h
MOV ant19off,BX
MOV ant19seg,ES
LEA DX,nueva_int19
MOV AX,2519h
INT 21h ; nueva rutina de control
fin_desvia19: XPOP <ES,DS,BX>
RET
desvia_int19 ENDP
; ------------ Obtener la letra de la unidad de disco definida. Esta
; rutina se invoca sólo desde CONFIG.SYS con DS:BX
; apuntando a la cabecera de petición de la orden INIT.
inic_letra PROC
XPUSH <AX,BX,SI,DS>
MOV AL,[BX].nuevo_disco ; unidad en DOS 3.0+
ADD AL,'A'
PUSH CS
POP DS ; DS -> _PRINCIPAL
CMP dosver,300h
JAE letra_ok
CALL lista_discos ; hallar unidad en DOS 2.x
LEA SI,area_trabajo
XOR AL,AL ; cuenta de discos
cuenta_discos: ADD AL,[SI+2]
ADD SI,4
CMP WORD PTR [SI],0
JNE cuenta_discos
ADD AL,'A'
letra_ok: MOV letra_unidad,AL ; guardar letra de unidad
XPOP <DS,SI,BX,AX>
RET
inic_letra ENDP
; ------------ Crear una lista de todos los dispositivos de bloque
; del sistema. La lista tiene una entrada de 4 bytes
; para cada dispositivo: los dos primeros indican el
; segmento en que reside, el siguiente el número de
; unidades que controla y el último vale 1 ó 0 para
; indicar si es una unidad TDSK o no. El final de la
; lista lo señaliza un segmento igual a 0.
lista_discos PROC
XPUSH <AX,BX,CX,DX,SI,DI,ES>
MOV AH,52h ; "Get list of lists"
INT 21h ; obtener puntero en ES:BX
MOV CX,17h ; supuesto DOS 2.x
CMP dosver,300h
JB pdisp_ok
MOV CX,28h ; supuesto DOS 3.0x
CMP dosver,30Ah
JB pdisp_ok
MOV CX,22h ; versiones del DOS superiores
pdisp_ok: ADD BX,CX
LEA DI,area_trabajo-4 ; tabla de dispositivos-4
disp_otro: ADD DI,4
disp_skip: LES BX,ES:[BX] ; siguiente dispositivo
CMP BX,-1
JE disp_fin
TEST BYTE PTR ES:[BX+5],80h
JNZ disp_skip ; es dispositivo de caracteres
MOV CL,ES:[BX+10] ; es de bloques
MOV [DI],ES ; anotar dirección
MOV [DI+2],CL
MOV BYTE PTR [DI+3],0 ; de momento, no es TDSK
PUSH DI
LEA SI,id_tdsk ; identificación de TURBODSK
MOV DI,SI
MOV CX,5
CLD
REP CMPSB ; ¿es TURBODSK?
POP DI
JNE disp_otro ; es de bloques, pero no TDSK
MOV AX,ES:cs_tdsk ; segmento real de TDSK
MOV [DI],AX ; corregir dirección en tabla
INC BYTE PTR [DI+3] ; indicar dispositivo TDSK
JMP disp_otro ; buscar hasta completar tabla
disp_fin: MOV WORD PTR [DI],0 ; final de la lista
XPOP <ES,DI,SI,DX,CX,BX,AX>
RET
lista_discos ENDP
; ------------ Liberar la memoria ocupada por un TURBODSK residente.
desinstala PROC
MOV DX,ES:mem_handle
MOV AL,ES:tipo_soporte
DEC AL
JZ libera_ext ; liberar memoria extendida
DEC AL
JZ libera_exp ; liberar memoria expandida
PUSH ES
MOV ES,DX
MOV AH,49h ; liberar memoria convencional:
INT 21h
POP ES
PUSH ES
PUSHF ; condición de error
MOV ES,ES:tdsk_psp ; liberar PSP residente
MOV AH,49h
INT 21h
PUSHF
CMP dosver,31Eh
JA mcb_ok ; DOS 3.31+: el MCB es correcto
MOV AX,ES
DEC AX
MOV ES,AX
MOV DI,8
MOV CX,DI
CLD
MOV AL,' '
REP STOSB ; hasta DOS 3.30 borrar nombre
mcb_ok: POPF
JNC lib_con_ok? ; liberado correctamente
POPF
POP ES
STC ; ha habido fallo
JMP desinstalado
lib_con_ok?: POPF ; recuperar condición de error
POP ES
JMP desinstalado
libera_ext: MOV AH,0Ah
CALL ES:xms_driver
CMP AX,1
JE desinstalado ; éxito al liberar memoria XMS
STC
JMP desinstalado ; fallo
libera_exp: MOV AH,45h
INT 67h
CMP AH,0
JE desinstalado
CMP AH,82h ; ¿EMM ocupado?
JE libera_exp
STC ; fallo al liberar memoria EMS
desinstalado: MOV ES:tipo_soporte,0 ; disco «no formateado»
JNC desins_ok
OR lista_err,ERROR14 ; fallo al liberar memoria
STC
desins_ok: RET
desinstala ENDP
; ------------ Determinar la configuración del sistema: tipos de
; memoria y cantidad de la misma. Se indica en «tdisco»
; un valor 0 si no se define ahora el disco, sea cual sea
; el motivo del fallo, y se actualiza la variable que
; indica los mensajes de error y advertencia a imprimir.
mem_info PROC
MOV tdisco,0 ; ley de Murphy
CALL eval_xms ; inicializar «xms_kb»
CALL eval_ems ; inicializar «ems_kb»
CALL eval_con ; inicializar «con_kb»
MOV AX,param_tdisco ; cantidad de memoria necesaria
CMP param_a,ON
JNE no_ems ; no solicitan memoria EMS
MOV BX,ems_kb ; solicitan memoria EMS...
AND BX,BX
JNZ usara_ems
OR lista_err,ERROR7 ; no hay memoria EMS disponible
JMP mem_infoado
usara_ems: CMP AX,BX
JBE usar_ems ; piden algo razonable
MOV AX,BX
OR lista_err,ERROR4 ; rebajado el tamaño
usar_ems: MOV tdisco,AX
MOV tipo_soporte,2 ; indicar memoria expandida
JMP mem_infoado
no_ems: CMP param_e,ON
JNE no_xms ; no solicitan memoria XMS
MOV BX,xms_kb ; solicitan memoria XMS...
AND BX,BX
JNZ usara_xms
OR lista_err,ERROR6 ; no hay memoria XMS disponible
JMP mem_infoado
usara_xms: CMP AX,BX
JBE usar_xms ; piden algo razonable
MOV AX,BX
OR lista_err,ERROR4 ; rebajado el tamaño
usar_xms: MOV tdisco,AX
MOV tipo_soporte,1 ; indicar memoria extendida
JMP mem_infoado
no_xms: CMP param_c,ON
JNE no_con ; no solicitan memoria conv.
forzar_con: MOV BX,con_kb ; solicitan memoria conv. ...
AND BX,BX
JNZ usara_con
OR lista_err,ERROR10 ; no hay memoria conv. libre
JMP mem_infoado
usara_con: CMP AX,BX
JBE usar_con ; piden algo razonable
MOV AX,BX
OR lista_err,ERROR4 ; rebajado el tamaño
usar_con: MOV tdisco,AX
MOV tipo_soporte,3 ; indicar memoria convencional
JMP mem_infoado
no_con: CMP AX,xms_kb ; no indicado tipo de memoria
JBE usar_xms ; intentar emplear memoria XMS
CMP ES:rutina_larga,ON
JE valdria_ems
MOV BX,xms_kb
CMP BX,0 ; imposible usar EMS
JNE usara_xms ; queda algo de XMS
JMP usar_con?
valdria_ems: MOV BX,ems_kb
CMP AX,BX
JA nv_ems
JMP usar_ems ; emplear memoria EMS
nv_ems: MOV BX,ems_kb
OR BX,xms_kb
JZ usar_con? ; no hay un ápice de XMS ni EMS
OR lista_err,ERROR4 ; rebajado el tamaño solicitado
MOV AX,xms_kb
CMP AX,ems_kb
JAE usar_xms ; hay más o igual XMS que EMS
MOV AX,ems_kb
JMP usar_ems ; hay algo de EMS (más que XMS)
usar_con?: CMP modo,AUTOEXEC
JE forzar_con ; sólo se puede usar mem. conv.
OR lista_err,ERROR5 ; ho hay memoria EMS ni XMS
mem_infoado: RET
mem_info ENDP
; ---- Calcular memoria extendida disponible
eval_xms PROC
PUSH ES
MOV AX,352Fh
INT 21h ; dirección de INT 2Fh en ES:BX
MOV AX,ES
AND AX,AX
JZ xms_ok ; apunta a 0000:XXXX (DOS 2.x)
MOV AX,4300h
INT 2Fh
CMP AL,80h ; ¿hay controlador XMS?
JNE xms_ok
MOV AX,4310h ; obtener su dirección
INT 2Fh
MOV xms_segm,ES
MOV xms_desp,BX
MOV AH,8
CALL xms_driver ; preguntar memoria libre
AND AX,AX
JNZ xms_kb_ok ; no hubo fallo
CMP BL,0A0h
JE xms_kb_ok ; asignada ya toda la memoria
TEST BL,80h
JZ xms_kb_ok ; no hay memoria XMS disponible
OR lista_err,ERROR8 ; fallo real del controlador
xms_kb_ok: CMP AX,8 ; mayor bloque XMS disponible
JB xms_ok
MOV xms_kb,AX ; mínimo necesario: 8 Kb
xms_ok: POP ES
RET
eval_xms ENDP
; ---- Calcular memoria expandida disponible. Si la
; versión del EMM es 4.0 o superior, las páginas
; de memoria expandida pueden no ser contiguas:
; buscar una que diste 32 Kb de la página 0.
eval_ems PROC
PUSH ES
MOV AX,3567h
INT 21h ; vector de INT 67h en ES:BX
MOV DI,10
LEA SI,emm_id
MOV CX,8
CLD
REP CMPSB ; ¿instalado controlador EMS?
JE ems_existe
JMP ems_ok
ems_existe: MOV CX,8000h ; nº de intentos prudente
emm_llama: MOV AH,40h
INT 67h
AND AH,AH
JZ emm_responde
CMP AH,82h
LOOPE emm_llama
emm_fatal: OR lista_err,ERROR9 ; fallo del EMM
JMP ems_ok
emm_responde: MOV AH,41h
INT 67h
AND AH,AH
JZ emm_pag_ok
CMP AH,82h
JE emm_responde ; reintentar (EMM ocupado)
JMP emm_fatal
emm_pag_ok: MOV ems_pagina0,BX ; inicializar página EMS
ADD BX,0C00h
MOV ems_paginai,BX
MOV ems_pagni,3 ; página alternativa: la 3
MOV AH,46h
INT 67h ; obtener versión del EMM
CMP AL,40h
JB emm_obt_kb ; versión anterior a la 4.0
MOV ems4,ON
emm_obt_pag: XPUSH <ES,DS>
POP ES
MOV AX,5800h ; obtener dirección de páginas
LEA DI,area_trabajo
INT 67h
POP ES
AND AH,AH
JZ emm_pags_ok
CMP AH,82h
JE emm_obt_pag
JMP emm_fatal
emm_pags_ok: XOR DX,DX
CALL emm_busca_pag ; buscar página 0
JC emm_fatal
MOV ems_pagina0,BX
ems_busca_i: INC DX ; buscar la siguiente
CMP DX,5 ; la 5ª y siguientes no valen
JE emm_fatal ; ├──────┤
CALL emm_busca_pag ; │ │
JC emm_fatal ; ┌> ┌>├──────┤<-- pág i
MOV ems_paginai,BX ;0C00h│ 32 │ │ │
MOV ems_pagni,DL ; pá │ Kb │ ├──────┤
SUB BX,ems_pagina0 ; rra │ │ │ │
JNC bxpositivo ; fos │ └>├──────┤
NEG BX ; │ │ │
bxpositivo: CMP BX,0C00h ; └> ├──────┤<-- pág 0
JB ems_busca_i ; no distan 32 Kb: buscar otra
emm_obt_kb: MOV AH,42h
INT 67h
AND AH,AH
JZ emm_kb_ok
CMP AH,82h
JE emm_obt_kb
JMP emm_fatal
emm_kb_ok: MOV CL,4
SHL BX,CL ; páginas EMS disponibles
MOV ems_kb,BX ; Kb EMS disponibles (0,16,...)
ems_ok: POP ES
RET
eval_ems ENDP
emm_busca_pag PROC ; buscar página nº DX (EMS 4.0)
LEA SI,area_trabajo
PUSH CX
emm_otra_pag: LODSW
MOV BX,AX ; BX = segmento de la página
LODSW ; AX = nº de la página
CMP AX,DX
JE hallada_pag
LOOP emm_otra_pag
STC
hallada_pag: POP CX
RET
emm_busca_pag ENDP
; ---- Calcular el tamaño del mayor bloque de memoria
; convencional disponible. Como mínimo se dejarán
; unos 128 Kb libres en él, para que el usuario
; pueda volver a ejecutar TDSK y el DOS tenga algo
; de memoria libre. A la mitad de esos 128Kb (para
; evitar solapamientos) es donde TURBODSK se
; autorelocalizará antes de formatear el disco.
eval_con PROC
CMP modo,AUTOEXEC ; ¿se ejecuta desde el DOS?
JNE conv_ok ; no, desde el config
MOV AH,48h
MOV BX,0FFFFh ; pedir 1 Mb al DOS (fallará)
INT 21h
MOV DX,BX ; tamaño del mayor bloque
MOV CL,6
SHR BX,CL ; BX = Kb del mayor bloque
SUB BX,128 ; restar 128 Kb
JC conv_ok ; no quedan ni 128 Kb
CMP BX,8
JB conv_ok ; no quedan siquiera 8 Kb
MOV con_kb,BX
MOV BX,DX ; tamaño del mayor bloque
MOV AH,48h
PUSH BX
INT 21h ; localizarlo (AX=segmento)
POP BX
XPUSH <ES,AX> ; preservar ES y segmento (AX)
ADD AX,BX ; añadir longitud
SUB AX,1024/16*64 ; restar 64 Kb
MOV segm_reubicar,AX ; segmento de autoreubicación
POP ES ; recuperar segmento del bloque
MOV AH,49h
INT 21h ; liberarlo
POP ES ; recuperar ES
conv_ok: RET
eval_con ENDP
; ------------ Reservar la memoria llamando al gestor que la controla.
; Con memoria XMS y existiendo un controlador EMS 4.0+ se
; comprueba si el handle XMS provoca la creacción de otro
; en EMS (caso de QEMM386 y otros emuladores de EMS) y en
; ese caso se le renombra, para mejorar la información de
; los programas de diagnóstico.
mem_reserva PROC
MOV AL,tipo_soporte ; tipo de memoria empleada
DEC AL
JZ mem_r_xms ; 1: memoria extendida XMS
DEC AL
JZ mem_r_ems ; 2: memoria expandida EMS
MOV CL,6
MOV BX,tdisco ; 3: memoria convencional
SHL BX,CL
MOV AH,48h
INT 21h
MOV mem_handle,AX ; segmento del disco virtual
MOV BX,segm_psp
MOV tdsk_psp,BX ; inicializar esta variable
RET
mem_r_xms: CMP ems4,ON
JNE skip_lst_hndl
LEA BX,area_trabajo
CALL lista_handles ; EMS 4.0+: listado de handles
skip_lst_hndl: MOV AH,9
MOV DX,tdisco
CALL xms_driver ; pedir memoria XMS
AND AX,AX
JNZ mem_rda_xms
OR lista_err,ERROR8 ; fallo del controlador XMS
STC ; indicar error
mem_rda_xms: MOV mem_handle,DX
PUSHF ; preservar condición de error
CMP ems4,ON
JNE skip_ren_hndl
CALL ren_handle ; en EMS 4.0+ renombrar handle
skip_ren_hndl: POPF
RET
mem_r_ems: MOV BX,tdisco
ADD BX,15
AND BL,11110000b ; redondear para arriba
MOV tdisco,BX
MOV CL,4
SHR BX,CL ; Kb -> nº páginas de 16 Kb
MOV AH,43h
INT 67h ; pedir memoria EMS
AND AH,AH
JZ mem_rda_ems
OR lista_err,ERROR9 ; fallo del controlador EMS
STC ; indicar error
RET
mem_rda_ems: MOV mem_handle,DX
CMP ems4,ON
JNE nhandle_ok
CALL nombrar_hndl ; en EMS 4.0+ nombrar handle
nhandle_ok: CLC
RET
mem_reserva ENDP
ren_handle PROC ; detectar el handle EMS ligado
XPUSH <ES,DS> ; al handle XMS y renombrarlo
POP ES
LEA BX,area_trabajo[512]
CALL lista_handles ; crear nueva lista de handles
LEA SI,area_trabajo
LEA DI,area_trabajo[512]
MOV CX,256
CLD
REP CMPSW ; comparar con vieja lista
JE ren_hnld_fin
MOV DX,[DI-2] ; handle nuevo
CALL nombrar_hndl
ren_hnld_fin: POP ES
RET
ren_handle ENDP
lista_handles PROC ; crear en DS:BX una lista con
MOV CX,256 ; los 256 posibles handles
XOR DX,DX ; activos indicando los usados
listar_h: MOV AX,5300h
LEA DI,area_trabajo[tam_a_trabajo-8] ; zona no usada
XPUSH <BX,CX,DX>
INT 67h
XPOP <DX,CX,BX>
CMP AH,0
JE handle_usado
MOV WORD PTR [BX],0 ; error (handle no usado)
JMP lista_h
handle_usado: MOV [BX],DX ; anotar número de handle
lista_h: ADD BX,2
INC DX
LOOP listar_h
RET
lista_handles ENDP
nombrar_hndl PROC ; nombrar handle (EMS 4.0+)
MOV AX,5301h
LEA SI,nombre_tdsk
MOV BL,letra_unidad
MOV [SI+5],BL
INT 67h ; dar nombre al handle
RET
nombrar_hndl ENDP
; ------------ Detectar 286 y 386 o superior.
test_CPU 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 fin_test_CPU ; es 8086 o similar
MOV cpu286,ON ; es 286 o superior
AND AH,70h ; 286 pone bits 12, 13 y 14 a cero
JZ fin_test_CPU ; es 286
MOV cpu386,ON ; 386 o superior
fin_test_CPU: RET
test_CPU ENDP
; ------------ Definir valores por defecto y adaptar los parámetros
; indicados por el usuario a la realidad. Esta rutina
; inicializa el futuro sector 0 del disco. No se permite
; que el usuario indique un directorio que ocupe más de
; medio disco. Para determinar el tipo de FAT se halla el
; nº de sectores libres del disco (llamémoslo nsect),
; descontanto el sector de arranque y el directorio raiz;
; y se aplica la siguiente fórmula, que devuelve el nº de
; cluster más alto del disco al considerar también la
; ocupación de la futura FAT (12 bits = 1,5 bytes):
;
; nsect * tamsect 2 * nsect * tamsect
; ------------------ + 1 = --------------------- + 1
; tamcluster + 1,5 2 * tamcluster + 3
;
; Al resultado se le suma 1, ya que los clusters se
; numeran a partir de 2, para calcular el cluster de nº
; más alto del disco. Si ese número es 4086 o más habrá
; de utilizarse una FAT de 16 bits, recalculándose la
; fórmula anterior sustituyendo 1,5 por 2 y 3 por 4. Al
; final, una vez determinado el tipo de FAT habrá de
; calcularse con exactitud el número de cluster más alto,
; ya que hay casos críticos en que una FAT12 no sirve
; pero al aplicar una FAT16 el número de clusters baja de
; nuevo de 4085 (debido al mayor consumo de disco de la
; FAT16) resultado de ello la asignación de una FAT12,
; pese a que se reserva espacio para la de 16. Hay que
; considerar además el caso de que el disco tenga 2 FAT.
adaptar_param PROC
MOV AX,tdisco ; en Kb
MOV BX,AX ; entradas de directorio propuestas
MOV CL,1 ; sectores por cluster propuestos
CMP AX,128 ; ¿disco de 128 Kb o menos?
JBE prop_ok
MOV BX,128
CMP AX,512 ; ¿disco de 512 Kb o menos?
JBE prop_ok
MOV BX,256
CMP AX,2042 ; ¿disco de casi 2 Mb o menos?
JBE prop_ok
MOV CL,2 ; evitar FAT16
CMP AX,4084 ; ¿disco de casi 4 Mb o menos?
JBE prop_ok
MOV CL,4 ; evitar FAT16 hasta 8 Mb
MOV BX,384
CMP AX,16384 ; ¿disco de menos de 16 Mb?
JB prop_ok
MOV BX,512
prop_ok: CMP dosver,300h
JAE prop_valido
CMP AX,4084*2 ; en DOS 2.xx evitar FAT16
JB prop_valido
MOV CL,8
CMP AX,4084*4
JB prop_valido
MOV CL,16
CMP AX,4084*8
JB prop_valido
MOV CL,32
prop_valido: MOV tdir,BX
MOV tcluster,CL ; inicializar valores recomendados
MOV DX,1024 ; AX = tamaño del disco en Kb
MUL DX ; DX:AX = bytes totales del disco
MOV CX,param_tsect
AND CX,CX
JNZ tsect_def ; se ha definido tamaño de sector
tsect_rec: MOV CX,tsect ; tamaño por defecto
tsect_def: CALL divCX
JNC nsect_ok ; menos de 65536 sectores: correcto
OR lista_err,ERROR11
JMP tsect_rec ; asumir por defecto y recalcular
nsect_ok: MOV tsect,CX
MOV numsect,AX
MOV BX,AX
SHR BX,1 ; BX = 1/2 del nº total de sectores
MOV CX,param_tdir
AND CX,CX
JNZ tdir_def ; se ha definido nº entradas
tdir_rec: MOV CX,tdir ; nº por defecto
tdir_def: MOV AX,tsect
XOR DX,DX
MOV SI,32 ; 32 bytes = tamaño entrada direct.
DIV SI ; AX nº entradas direct. por sector
XCHG AX,CX
XOR DX,DX ; DX:AX = nº de entradas
DIV CX ; CX = entradas en cada sector
AND DX,DX ; AX = nº sectores del ROOT
JZ dir_ok?
INC AX ; redondear tamaño de ROOT
dir_ok?: CMP AX,BX ; BX = 1/2 nº sectores del disco
JB dir_ok
OR lista_err,ERROR12 ; directorio excesivo
JMP tdir_rec ; directorio por defecto
dir_ok: MOV sdir,AX
MUL tsect
MOV CX,32
CALL divCX
MOV tdir,AX ; optimizar tamaño de directorio
MOV AX,512
XOR DX,DX
DIV tsect ; 512 / tamaño de sector
MOV BL,tcluster
XOR BH,BH
MUL BX ; ajustar tamaño de cluster
AND AL,AL
JZ propclus_ok
MOV tcluster,AL
propclus_ok: MOV BX,param_tcluster
AND BX,BX
JNZ tcluster_def ; se ha definido tamaño de cluster
tcluster_rec: MOV BL,tcluster ; tamaño por defecto
XOR BH,BH
tcluster_def: SHL BX,1
CMP BX,numsect ; ¿cabe seguro un cluster?
JB tcluster_ok
tcluster_mal: OR lista_err,ERROR13 ; tamaño de cluster incorrecto
JMP tcluster_rec
tcluster_ok: SHR BX,1
MOV AX,tsect
MUL BX ; DX:AX = tamaño de cluster
JC tcluster_mal
CMP AX,31*1024
JA tcluster_mal ; cluster de más de 31 Kb
MOV tcluster,BL ; sectores por cluster
MOV tamcluster,AX ; tamaño de cluster
MOV CX,param_f ; considerar número de FATs
MOV nfats,CL
MOV SI,3
MOV CX,param_f
SHL SI,CL
SHR SI,1
CALL eval_clust ; obtener nº más alto de cluster
CMP AX,4086
JAE fat16 ; el nº más alto supera 4085
MOV CX,3
MUL CX ; clusters * 3
SHR DX,1
RCR AX,1 ; clusters * 3 / 2 = clusters * 1,5
JMP calc_sfat
fat16: MOV SI,4
MOV CX,param_f ; considerar número de FATs
SHL SI,CL
SHR SI,1
CALL eval_clust
SHL AX,1
RCL DX,1 ; clusters * 2
calc_sfat: DIV tsect ; AX = nº sectores de FAT aprox.
AND DX,DX
JZ fat_ok
INC AX ; redondeo
fat_ok: MOV sfat,AX
MOV AX,numsect ; nº total de sectores
DEC AX ; descontar BOOT
SUB AX,sdir ; descontar ROOT
SUB AX,sfat ; descontar FAT
MOV CL,tcluster
XOR CH,CH
XOR DX,DX
DIV CX ; AX = número real de clusters
INC AX ; se numeran desde 2
MOV ultclus,AX
RET
adaptar_param ENDP
eval_clust PROC ; obtener el nº más alto de cluster
MOV AX,numsect
DEC AX ; restar BOOT
SUB AX,sdir ; restar ROOT
MUL tsect ; DX:AX = nsect * tamsect
SHL AX,1
RCL DX,1 ; DX:AX = nsect * tamsect * 2
MOV CX,tamcluster
SHL CX,1
ADD CX,SI ; CX = 2 * tamcluster + SI
DIV CX
INC AX ; los clusters se numeran desde 2
AND DX,DX ; ¿sobra un «cacho» de cluster?
JZ clust_eval ; redondear: ¡es preferible que
INC AX ; sobre un poco de FAT a que falte!
clust_eval: XOR DX,DX ; resultado en DX:AX
RET
eval_clust ENDP
; ------------ Preparar el BPB del disco virtual según los parámetros
; y forzar que el DOS lo lea indicando cambio de disco.
preparar_BPB PROC
MOV AX,tsect
MOV bytes_sector,AX
MOV AL,tcluster
MOV sect_cluster,AL
MOV AX,tdir
MOV entradas_raiz,AX
MOV AX,numsect
MOV num_sect,AX
MOV AL,nfats
MOV num_fats,AL
MOV AX,sfat
MOV sectores_fat,AX
MOV cambiado,0FFh ; ha habido «cambio» de disco
RET
preparar_BPB ENDP
; ------------ Preparar el disco para operar. ES apunta al disco al
; entrar. Se procederá a copiar la rutina necesaria en
; función del tipo de memoria que gestiona el disco.
; Después, se copiarán las variables que gestionan TDSK
; sobre la copia residente, así como el nuevo BPB.
prep_driver PROC
MOV AL,tipo_soporte
LEA SI,procesa_xms
MOV CX,tam_proc_xms
DEC AL
JZ prep_mem ; instalar rutina XMS
LEA SI,procesa_ems
MOV CX,tam_proc_ems
DEC AL
JZ prep_mem ; instalar rutina EMS
LEA SI,procesa_con
MOV CX,tam_proc_con ; instalar rutina memoria conv.
prep_mem: LEA DI,procesa_io
CLD
XPUSH <SI,DI,CX>
REP MOVSB ; instalar rutina en el disco
XPOP <CX,DI,SI>
XPUSH <ES,DS>
POP ES
REP MOVSB ; y en el propio TDSK.EXE (para
POP ES ; usarla después al formatear)
LEA CX,f_tdsk_ctrl
LEA SI,i_tdsk_ctrl
SUB CX,SI
MOV DI,SI
REP MOVSB ; actualizar variables
LEA CX,fin_bpb
LEA SI,bpb
SUB CX,SI
MOV DI,SI
REP MOVSB ; actualizar BPB
RET
prep_driver ENDP
; ------------ Autorelocalización de TDSK.EXE
; Es necesario si se reserva memoria convencional para el
; disco virtual. El motivo es evitar que al inicializar
; la BOOT, la FAT y el ROOT al inicio del disco, si éste
; está justo encima de TDSK, TDSK se autodestruya. Por
; ello, TDSK se autocopiará en la mitad de los 128 Kb del
; mayor bloque de memoria libre, nunca utilizados por el
; disco (aunque este bloque no haya sido reservado, ¡como
; está libre!). Finalmente pasará a correr en ese nuevo
; destino. Se copia TODO, pila incluida. La copia se hace
; en «segm_reubicar» que apunta a la mitad de esos 128 Kb
; con objeto de evitar solapamientos origen/destino (TDSK
; ocupa sólo alrededor de 16 Kb en memoria).
relocalizar PROC
CMP tipo_soporte,3
JE procede_reloc ; usada memoria convencional
RET
procede_reloc: PUSH ES ; * preservar ES
MOV ES,segm_reubicar ; segmento de reubicación
XOR SI,SI
XOR DI,DI
MOV BX,SS ; final de TURBODSK (pila)
MOV CX,DS ; inicio de _PRINCIPAL
SUB BX,CX ; tamaño de TDSK en párrafos
MOV CL,4
SHL BX,CL ; ahora en bytes
ADD BX,tam_pila+16 ; 16 por si acaso
MOV CX,BX ; CX = bytes a relocalizar
CLD
REP MOVSB ; auto-copiaje arriba
MOV AX,ES
MOV DS,AX ; nuevo segmento de datos
POP ES ; * restaurar ES
MOV BX,CS
SUB AX,BX ; ES - CS --> cuantía del salto
MOV BX,SS
ADD BX,AX
MOV SS,BX ; actualizar segmento de pila
POP AX ; dirección de retorno cercano
PUSH DS ; segmento de «retorno»
PUSH AX ; offset
RETF ; retorno cargando CS:
relocalizar ENDP
; ------------ Inicializar la BOOT, FAT y ROOT del disco virtual.
; En versiones del DOS anteriores a la 3.3, el sistema
; inexplicablemente hace caso omiso del cambio de disco
; (¿?), por lo que hay que avisarle ¡dos veces!, con el
; correspondiente doble cambio del byte descriptor de
; medio, para que se tome en serio el cambio de disco.
; Por fortuna desde el DOS 3.3 ya no es preciso hacer
; esta extraña maniobra. Para que el DOS acceda al disco,
; se le pregunta simplemente el espacio libre del mismo.
formatear_tdsk PROC
PUSH ES ; *
PUSH DS
POP ES
LEA SI,sector_cero
LEA DI,area_trabajo
MOV CX,128
CLD
REP MOVSB ; primeros 128 bytes del BOOT
XOR AX,AX
MOV CX,tam_a_trabajo-128
REP STOSB ; a 0 resto del área de trabajo
LEA DI,area_trabajo
ADD DI,tsect
MOV [DI-2],0AA55h ; marca de sector válido
CALL escribe_sectAX ; escribir sector BOOT (AX=0)
LEA DI,area_trabajo
MOV CX,tsect
REP STOSB ; borrar area de trabajo
MOV AX,sfat
MOV CX,param_f ; considerar número de FATs
SHL AX,CL
SHR AX,1
ADD AX,sdir ; AX = sectores fat + dir. raiz
ini_fat: CMP AX,1
JE pfat
CALL escribe_sectAX ; inicializar directorio raiz
DEC AX ; y últimos sectores de la FAT
JMP ini_fat
pfat: LEA DI,area_trabajo
MOV BYTE PTR [DI],media
MOV AX,0FFFFh ; inicializar 3 bytes FAT...
MOV DS:[DI+1],AX
CMP ultclus,4086 ; ¿menos de 4085 clusters?
JB pfat_ok
MOV DS:[DI+3],AL ; inicializar 4º byte FAT
pfat_ok: MOV AX,1
CALL escribe_sectAX ; primer sector FAT preparado
CALL fecha_hora
LEA SI,dir_raiz
MOV [SI+22],AX ; hora actual
MOV [SI+24],DX ; fecha actual
LEA DI,area_trabajo
MOV CX,32
REP MOVSB
MOV AX,sfat
MOV CX,param_f ; considerar número de FATs
SHL AX,CL
SHR AX,1
INC AX
CALL escribe_sectAX ; primer sector raiz preparado
POP ES ; *
CMP dosver,31Eh
JAE formateado ; DOS 3.3+
NOT ES:media_byte ; cambiar descriptor de medio
MOV AH,36h ; «obtener espacio libre»
MOV DL,ES:letra_unidad
SUB DL,'A'-1 ; unidad de disco virtual
PUSH DX
INT 21h ; primer acceso al disco
POP DX
NOT ES:media_byte ; restaurar descriptor de medio
MOV ES:cambiado,0FFh ; nuevo «cambio» de disco
MOV AH,36h
INT 21h ; acceder otra vez al disco
formateado: RET
formatear_tdsk ENDP
; ---- Escribir el sector nº AX del disco virtual. No
; se utiliza INT 26h (imposible desde el CONFIG).
escribe_sectAX PROC
PUSHF ; preservar bit DF
XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
XOR BP,BP ; indicar escritura
LEA DI,area_trabajo ; ES:DI buffer
MOV BX,AX ; número de sector
MOV AX,1 ; 1 sector
CALL io_proc ; acceder al disco directamente
XPOP <ES,DS,BP,DI,SI,DX,CX,BX,AX>
POPF
RET
escribe_sectAX ENDP
; ---- Obtener fecha y hora del sistema en DX y AX
fecha_hora PROC
MOV AH,2Ah
INT 21h ; obtener fecha del sistema
MOV AL,32
MUL DH ; AX = mes * 32
SUB CX,1980
SHL CL,1 ; (año-1980)*2
ADD AH,CL ; sumar (año-1980)*512
MOV CL,DL ; CX = dia (CH=0)
ADD AX,CX
PUSH AX ; * guardar fecha
MOV AH,2Ch
INT 21h ; obtener hora del sistema
MOV AL,32
MUL CL ; AX = minutos*32
MOV CL,3
SHL CH,CL
XOR CL,CL ; CX = hora*2048
ADD AX,CX
SHR DH,1 ; segundos/2
ADD AL,DH
ADC AH,0
POP DX ; * recuperar fecha
RET
fecha_hora ENDP
; ------------ Cambiar el nombre al bloque de control de memoria para
; mejorar la información del comando MEM del sistema si
; el disco se define en memoria convencional/superior.
renombrar_mcb PROC
PUSH ES
MOV AL,letra_unidad
MOV BYTE PTR nombre_tdsk+5,AL
MOV BYTE PTR nombre_tdsk+4,'('
MOV BYTE PTR nombre_tdsk+6,')'
MOV AX,segm_psp
DEC AX
MOV ES,AX
LEA SI,nombre_tdsk
MOV DI,8
MOV CX,DI
CLD
REP MOVSB
POP ES
RET
renombrar_mcb ENDP
; ------------ Informar sobre el disco virtual instalado.
info_disco PROC
CALL InitMultiPrint
LEA DX,ayuda_txt ; ayuda en español
CMP param_h,ON ; ¿solicitud de ayuda?
JNE cont_info ; no
JMP info_exit
cont_info: TEST err_grave,0FFFFh
JZ info_no_fatal
LEA DX,err_grave_gen ; texto de encabezamiento
CALL imprimir ; imprimir errores graves:
LEA DX,e0
TEST err_grave,ERROR0
JZ otro_fallo ; no es error de DOS incorrecto
CALL imprimir
MOV SP,tam_pila
PUSH segm_psp ; en DOS 1.x hay que terminar
XOR AX,AX ; con CS = PSP
PUSH AX
RETF ; ejecutar INT 20h de PSP:0
otro_fallo: LEA DX,e1
TEST err_grave,ERROR1
JNZ info_g
LEA DX,e2
TEST err_grave,ERROR2
JNZ info_g
LEA DX,e3
info_g: JMP info_exit
info_no_fatal: CMP ES:tipo_soporte,0 ; error no fatal
JNE info_reporte
LEA DX,info_ins ; disco no formateado
CALL imprimir
CALL impr_unidad
LEA DX,info_ins2
CMP lista_err,0
JE info_exit ; sin mensajes de advertencia
CALL imprimir ; ... o con ellos
JMP info_err
info_reporte: CALL pr_info ; disco formateado
CMP lista_err,0
JE info_ret ; sin mensajes de advertencia
LEA DX,cab_adv_txt ; ... o con ellos
CALL imprimir ; cabecera de advertencias
info_err: MOV AX,lista_err
LEA BX,tabla_mens-2 ; tabla de mensajes
MOV CX,16 ; 16 posibles mensajes
busca_err: ADD BX,2
SHR AX,1
JC informa
mas_mens: LOOP busca_err ; no se produce ese error
JMP info_ret
informa: LEA DX,mens_cabec ; inicio común a los mensajes
CALL imprimir
MOV DX,[BX] ; dirección de ese mensaje
CALL imprimir
JMP mas_mens ; acabar con todos
info_exit: CALL imprimir
info_ret: RET
info_disco ENDP
pr_info PROC
LEA DX,info_txt
CALL imprimir
CALL impr_unidad
LEA DX,inf_tsect
CALL imprimir
MOV AX,ES:bytes_sector
XOR DX,DX
MOV CL,5
CALL print_32
LEA DX,inf_tdir
CALL imprimir
MOV AX,ES:entradas_raiz
XOR DX,DX
MOV CL,5
CALL print_32
LEA DX,inf_tdisco
CALL imprimir
MOV AX,ES:num_sect
MUL ES:bytes_sector
MOV BX,1024
DIV BX
MOV CL,5
CALL print_32
LEA DX,inf_tcluster
CALL imprimir
MOV AL,ES:sect_cluster
XOR AH,AH
XOR DX,DX
MOV CL,5
CALL print_32
LEA DX,inf_mem
CALL imprimir
MOV AL,ES:tipo_soporte
LEA DX,inf_mem_xms
DEC AL
JZ mem_ifdo ; memoria XMS
LEA DX,inf_mem_ems
DEC AL
JZ mem_ifdo ; memoria EMS
LEA DX,inf_mem_con
CMP ES:mem_handle,0A000h
JB mem_ifdo ; memoria convencional
LEA DX,inf_mem_sup ; memoria superior
mem_ifdo: CALL imprimir
LEA DX,inf_nclusters
CALL imprimir
MOV AX,ES:entradas_raiz
MOV BX,32
MUL BX ; bytes ocupados por directorio
DIV ES:bytes_sector ; AX = sectores del directorio
ADD AX,ES:sect_reserv
ADD AX,ES:sectores_fat
SUB AX,ES:num_sect
NEG AX ; AX = sectores libres
XOR DX,DX
MOV BL,ES:sect_cluster
XOR BH,BH
DIV BX ; AX = nº de clusters
XOR DX,DX
MOV CL,5
CALL print_32
LEA DX,inf_tfat
CALL imprimir
LEA DX,inf_tfat12
CMP AX,4085 ; ¿FAT12?
JB ifat_ok
LEA DX,inf_tfat16
ifat_ok: CALL imprimir
LEA DX,inf_final
CALL imprimir
RET
pr_info ENDP
; --- Imprimir letra de unidad en AL.
impr_unidad PROC
XPUSH <AX, DX>
MOV AL,letra_unidad
MOV AH,0
MOV WORD PTR area_trabajo,AX
LEA DX,area_trabajo
CALL imprimir
XPOP <DX, AX>
RET
impr_unidad ENDP
; --- Imprimir un nº decimal de 32 bits en DXAX formateado por CL.
;
; Entradas:
; Si bit 4 = 1 --> se imprimirán signos separadores de millar
; bits 0-3 = nº total de dígitos (incluyendo separadores de
; millar y parte fraccional)
; bits 5-7 = nº de dígitos de la parte fraccional (cuantos
; dígitos de DXAX, empezando por la derecha,
; se consideran parte fraccional, e irán precedidos
; del correspondiente separador)
;
; Salidas: nº impreso, ningún registro modificado.
;
; * Ejemplo, si DXAX=9384320 y CL=010 1 1011
; se imprimirá ( '_' representa un espacio en blanco ): __93.843,20
print_32 PROC
PUSH DS
PUSH ES
PUSH CS
PUSH CS
POP DS
POP ES
PUSH AX ; preservar todos los registros
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSHF
MOV formato_pr32,CL ; byte del formato de impresión elegido
MOV CX,idioma_seps
separ_pr32: MOV millares_pr32,CH ; separador de millares
MOV fracc_pr32,CL ; separador parte fraccional
MOV BX,OFFSET tabla_pr32
MOV CX,10
digit_pr32: PUSH CX
PUSH AX
PUSH DX
XOR DI,DI
MOV SI,1 ; DISI = 1
DEC CX ; CX - 1
JCXZ hecho_pr32
factor_pr32: SAL SI,1
RCL DI,1 ; DISI * 2
MOV DX,DI
MOV AX,SI
SAL SI,1
RCL DI,1
SAL SI,1
RCL DI,1 ; DISI * 8
ADD SI,AX
ADC DI,DX ; DISI = DISI*8 + DISI*2 = DISI*10
LOOP factor_pr32 ; DISI = DISI*10*10* ... (CX-1 veces)
hecho_pr32: POP DX ; luego DISI = 10 elevado a (CX-1)
POP AX ; CX se recuperará más tarde
MOV CL,0FFh
rep_sub_pr32: INC CL
SUB AX,SI
SBB DX,DI ; DXAX = DXAX - DISI
JNC rep_sub_pr32 ; restar el factor cuanto se pueda
ADD AX,SI ; subsanar el desbordamiento:
ADC DX,DI ; DXAX = DXAX + DISI
ADD CL,'0' ; pasar binario a ASCII
MOV [BX],CL
POP CX ; CX se recupera ahora
INC BX
LOOP digit_pr32 ; próximo dígito del número
STD ; transferencias (MOVS) hacia atrás
DEC BX ; BX apunta al último dígito
MOV final_pr32,BX ; último dígito
MOV ent_frac_pr32,BX ; frontera parte entera/fraccional
MOV CL,5
MOV AL,formato_pr32
SHR AL,CL ; AL = nº de decimales
AND AL,AL
JZ no_frac_pr32 ; ninguno
MOV CL,AL
XOR CH,CH
MOV SI,final_pr32
MOV DI,SI
INC DI
REP MOVSB ; correr cadena arriba (hacer hueco)
INC final_pr32
MOV AL,fracc_pr32
MOV [DI],AL ; poner separador de parte fraccional
MOV ent_frac_pr32,SI ; indicar nueva frontera
no_frac_pr32: MOV AL,formato_pr32
TEST AL,16 ; interpretar el formato especificado
JZ poner_pr32 ; imprimir como tal
entera_pr32: MOV CX,final_pr32 ; añadir separadores de millar
SUB CX,ent_frac_pr32
ADD CX,3
MOV SI,final_pr32
MOV DI,SI
INC DI
REP MOVSB ; correr cadena arriba (hacer hueco)
MOV AL,millares_pr32
MOV [DI],AL ; poner separador de millares
INC final_pr32
MOV ent_frac_pr32,SI ; usar esta variable como puntero
SUB SI,OFFSET tabla_pr32
CMP SI,3
JAE entera_pr32 ; próximo separador
poner_pr32: MOV BX,final_pr32
MOV BYTE PTR [BX+1],0 ; delimitador de fin de cadena
MOV BX,OFFSET tabla_pr32
MOV principio_pr32,BX ; inicio de cadena
limpiar_pr32: MOV AL,[BX]
CMP AL,'0'
JE blanco_pr32 ; cero a la izda --> poner " "
CMP AL,millares_pr32 ; separador millares a la izda
JE blanco_pr32
CMP AL,fracc_pr32
JNE acabar_pr32
MOV BYTE PTR [BX-1],'0' ; reponer 0 antes de la coma
DEC principio_pr32
acabar_pr32: MOV AL,formato_pr32 ; imprimir
AND AL,00001111b
XOR AH,AH
MOV DX,final_pr32
SUB DX,AX
INC DX ; DX = offset 'principio'
AND AX,AX
JNZ format_pr32 ; longitud especificada por el usuario
MOV DX,principio_pr32 ; longitud obtenida del número
format_pr32: CALL imprimir
POPF ; restaurar todos los registros
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
RET ; salida del procedimiento
blanco_pr32: MOV BYTE PTR [BX],' ' ; sustituir 0 ó separador de millares
INC BX ; a la izda. por espacio en blanco
INC principio_pr32
CMP BX,final_pr32
JB limpiar_pr32
MOV DX,BX ; es el número 0.000.000.00X
JMP SHORT acabar_pr32 ; imprimir
formato_pr32 DB 0
DB 5 DUP (' ') ; espacios en blanco para cubrir la
; mayor plantilla que pueda ser espe-
; cificada en el formato
tabla_pr32 DT 0 ; reservar 14 bytes (nº más ., más ASCIIZ)
DW 0,0 ; aquí se solapa un buffer de 32 bytes
millares_pr32 DB '.' ; separador de millares
fracc_pr32 DB ',' ; " parte fraccional
final_pr32 DW 0 ; offset al último byte a imprimir
principio_pr32 DW 0 ; " " primer " " "
ent_frac_pr32 DW 0 ; offset a la frontera entero-fracc.
DT 0 ; $ - tabla_pr32 = 32 bytes usados por
; INT 21h al principio de print_32
print_32 ENDP
; ------------ Dividir DX:AX / CX sin desbordamientos (cociente: AX,
; resto: DX). Si el cociente excede los 16 bits, CF = 1
; y todos los registros intactos.
divCX PROC
XPUSH <BX,SI,CX,AX,DX>
MOV SI,32
XOR BX,BX
divmas: SHL AX,1
RCL DX,1
RCL BX,1
CMP BX,CX
JB dividido ; "no cabe"
SUB BX,CX
INC AL ; 1 al cociente
dividido: DEC SI
JNZ divmas
AND DX,DX
JZ div_ok
XPOP <DX,AX> ; error
STC
JMP div_fin
div_ok: MOV DX,BX ; resto en DX y cociente en AX
ADD SP,4 ; «sacar» sin sacar DX y AX
CLC
div_fin: XPOP <CX,SI,BX> ; recuperar CX, SI y BX
RET
divCX ENDP
; ------------ Impresión en color o monocroma (esta última
; redireccionable). Desde el CONFIG.SYS se imprime en
; monocromo para no llamar la atención, a menos que
; indiquen /M, al contrario que desde el DOS.
imprimir PROC
PUSH AX
MOV AL,param_m
CMP modo,CONFIG ; ¿en CONFIG.SYS?
JNE m_ok ; no
XOR AL,ON ; sí: /M opera al revés
m_ok: MOV pr_mono,AL
CALL print
POP AX
RET
imprimir ENDP
; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
; Si acaba en 0, se imprime como tal; en caso contrario,
; se supone que el mensaje es multilingüe y los diversos
; idiomas (1, 2, ... N) separan sus cadenas por sucesivos
; códigos 255. El carácter de control 127 realiza una
; pausa hasta que se pulsa una tecla.
print PROC
XPUSH <AX, BX, CX, DX, SI, DI, ES>
CMP idioma,0
JNE pr_decidir
PUSH DX ; *
MOV AH,30h
INT 21h
XCHG AH,AL
MOV CX,AX ; CX = versión del DOS
CMP param_i,ON
MOV AX,codigo_tfno
MOV BX,1234h
JNE pr_busca_cod ; parámetro /I=cod no indicado
MOV BX,AX
MOV AL,0FFh
CMP BX,255
JAE pr_cod ; código mayor o igual de 255
MOV AL,BL ; código menor de 255
pr_cod: CMP CX,200h
JAE pr_cod_tfno ; DOS >= 2.X
pr_busca_cod: CMP CX,200h
MOV AX,1 ; inglés para DOS < 2.X
JB pr_habla_ax
MOV AL,0
pr_cod_tfno: LEA DX,area_trabajo
MOV AH,38h
XPUSH <BX, CX>
INT 21h ; obtener información del pais
XPOP <CX, AX>
JC pr_habla_ax ; fallo en la función
CMP CX,20Bh
JE pr_habla_ax ; DOS 2.11: AX cód. telefónico
CMP CX,300h
MOV AX,1
JB pr_habla_ax ; 2.x excepto 2.11: mala suerte
MOV AX,BX
LEA BX,area_trabajo
MOV CH,[BX+7] ; separador de millares
MOV CL,[BX+9] ; separador de decimales
MOV idioma_seps,CX
pr_habla_ax: LEA BX,info_paises-2
MOV CX,1 ; supuesto idioma 1
pr_busca_idi: ADD BX,2
MOV DX,[BX]
CMP AX,DX
JE pr_habla_ese
AND DX,DX
JNZ pr_busca_idi
INC CX ; será otro idioma
CMP [BX+2],DX
JNE pr_busca_idi ; no es fin de la tabla
pr_habla_ese: MOV idioma,CL
POP DX ; *
pr_decidir: MOV CL,idioma
MOV CH,0 ; nº de idioma a usar (1..N)
MOV BX,DX
pr_busca_msg: MOV DX,BX
DEC BX
pr_busca_ter: INC BX
CMP BYTE PTR [BX],0
JE pr_usar_ese ; acaba en 0: no buscar más
CMP BYTE PTR [BX],255
JNE pr_busca_ter
INC BX
LOOP pr_busca_msg ; acaba en 255 pero no es ese
pr_usar_ese: MOV BX,DX
DEC BX
pr_cad_lon: INC BX
CMP BYTE PTR [BX],0
JE prlong_ok
CMP BYTE PTR [BX],127 ; carácter de pausa
JE prpausa
CMP BYTE PTR [BX],255
JNE pr_cad_lon ; calcular longitud
JMP prlong_ok
prpausa: PUSH BX
MOV CX,BX
SUB CX,DX
CALL pr_cad ; imprimir hasta el código 127
pr_limpbuf: MOV AH,1
INT 16h
JZ pr_notec
MOV AH,0
INT 16h ; limpiar buffer del teclado
JMP pr_limpbuf
pr_notec: MOV AH,0
INT 16h ; esperar tecla
POP BX
INC BX
MOV DX,BX
CMP AL,27 ; ¿tecla ESC?
STC
JE pr_ret
JMP pr_cad_lon ; imprimir el resto
prlong_ok: MOV CX,BX
SUB CX,DX
CALL pr_cad ; terminar impresión
CLC
pr_ret: XPOP <ES, DI, SI, DX, CX, BX, AX> ; CF=1 si se pulsó ESC
RET
pr_cad: ; MOV AH,40h
; MOV BX,1
; INT 21h ; imprimir con el DOS
MOV SI,DX
LEA DI,area_trabajo
PUSH DS
POP ES ; por si acaso
CLD
REP MOVSB
MOV [DI],CL ; ASCIIZ
LEA DX,area_trabajo
CALL MultiPrint ; imprimir en color
RET
print ENDP
; ------------ Impresión en pantalla, en color o monocromo, usando el
; BIOS o el DOS respectivamente. Antes deberá ejecutarse
; InitMultiPrint para inicializar. Al hacer scroll se
; intenta respetar el posible color global de fondo.
; Con «pr_mono» en ON se solicita imprimir en monocromo.
;
; - El texto a imprimir es apuntado por DS:DX.
; - Códigos de control soportados:
;
; 0 -> final de cadena
; 1 -> el siguiente carácter indica el color (BIOS)
; 2 -> el siguiente carácter indica el nº de veces que
; se imprimirá el que viene detrás
; 3 -> avanzar cursor a la derecha
; 10 -> retorno de carro y salto de línea estilo UNIX
MultiPrint PROC
XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
PUSH DS
POP ES
PUSH CS
POP DS
LEA AX,pr_AL_dos
CMP pr_mono,ON
JE pr_rut_ok
LEA AX,pr_AL_bios
pr_rut_ok: MOV pr_rut,AX ; instalar rutina de impresión
MOV BX,DX
pr_otro: MOV AL,ES:[BX]
PUSH BX
CMP AL,' '
JAE pr_ASCII ; no es un código de control
AND AL,AL
JZ pr_exit ; código de control 0: final
CMP AL,1
JE pr_setcolor ; código de control 1: color
CMP AL,2
JE pr_setveces ; código de control 2: repetir
pr_ASCII: CALL pr_rut
POP BX
INC BX
JMP pr_otro
pr_setcolor: MOV AL,ES:[BX+1]
MOV pr_color,AL ; actualizar color
POP BX
ADD BX,2
JMP pr_otro
pr_setveces: MOV AL,ES:[BX+1]
MOV pr_veces,AL ; actualizar repeticiones
POP BX
ADD BX,2
JMP pr_otro
pr_exit: XPOP <BX,ES,DS,BP,DI,SI,DX,CX,BX,AX>
RET
MultiPrint ENDP
pr_AL_bios PROC ; imprimir en color usando BIOS
PUSH AX
MOV AH,3
MOV BH,pr_pagina
INT 10h ; DX = coordenadas del cursor
POP AX
CMP AL,3
JE pr_derecha ; código de control 3: avanzar
CMP AL,10
JE pr_crlf ; código de control 10: CR & LF
MOV AH,9
MOV BH,pr_pagina
MOV BL,pr_color
MOV CL,pr_veces
XOR CH,CH
PUSH DX
INT 10h ; imprimir carácter
POP DX
pr_derecha: ADD DL,pr_veces
MOV pr_veces,1
CMP DL,pr_maxX
JBE pr_av
pr_crlf: XOR DL,DL ; volver al inicio de línea
INC DH ; salto a la siguiente
CMP DH,pr_maxY
JBE pr_av
DEC DH
PUSH DX ; es preciso hacer scroll
MOV AX,601h
MOV BH,pr_colorb ; color por defecto
XOR CX,CX
MOV DL,pr_maxX
MOV DH,pr_maxY
INT 10h ; hacer scroll usando BIOS
POP DX
pr_av: MOV BH,pr_pagina
MOV AH,2
INT 10h ; posicionar cursor
RET ; retorno del procedimiento
pr_AL_bios ENDP
pr_AL_dos PROC ; imprimir usando DOS
CMP AL,3
JNE pr_no_der
MOV AL,' ' ; código de control 3: avanzar
pr_no_der: CMP AL,10
JNE pr_dos
MOV AL,13 ; código de control 10: CR & LF
CALL pr_dos ; llamada "recursiva"
MOV AL,10
pr_dos: MOV CL,pr_veces
XOR CH,CH
MOV pr_veces,1
MOV DL,AL
pr_chr: XPUSH <DX,CX>
MOV AH,2
INT 21h ; imprimir carácter
XPOP <CX,DX>
LOOP pr_chr
RET
pr_AL_dos ENDP
InitMultiPrint PROC
XPUSH <AX,BX,CX,DX,BP,DS,ES>
PUSH CS
POP DS
MOV pr_veces,1
MOV pr_color,15 ; valores por defecto
MOV pr_mono,OFF
pr_i_80?: MOV AH,0Fh
INT 10h
CMP AH,80 ; ¿80 ó más columnas?
JAE pr_i_video_ok ; así es
MOV AX,3
INT 10h ; forzar modo de 80 columnas
JMP pr_i_80?
pr_i_video_ok: MOV pr_maxX,AH ; inicializar máxima coord. X
MOV pr_pagina,BH ; inicializar página activa
MOV AX,40h
MOV ES,AX ; ES: -> variables del BIOS
MOV AL,ES:[84h] ; variable de nº líneas - 1
CMP AL,24 ; ¿el BIOS define la variable?
JB pr_i_maxy_ok ; no
MOV pr_maxY,AL ; inicializar máxima coord. Y
pr_i_maxy_ok: MOV AH,8 ; (BH = página)
INT 10h ; obtener color por defecto
MOV pr_colorb,AH
XPOP <ES,DS,BP,DX,CX,BX,AX>
RET
InitMultiPrint ENDP
pr_pagina DB 0 ; página de visualización activa
pr_veces DB 1 ; veces que se imprime cada carácter
pr_color DB 15 ; color BIOS para imprimir
pr_colorb DB ? ; color por defecto en pantalla
pr_maxX DB 80 ; máxima coordenada X en pantalla
pr_maxY DB 24 ; máxima coordenada Y en pantalla
pr_mono DB OFF ; a ON si imprimir en monocromo
pr_rut DW ? ; apunta a pr_AL_bios / pr_AL_dos
; ------------ Rutina de gestión de memoria XMS. Se copiará sobre
; la de memoria EMS si se utiliza memoria XMS.
; En esta rutina se emplea la pila para pasar los
; parámetros al controlador XMS.
procesa_xms PROC
MOV DS,CS:mem_handle
JNC no_xmslib
.286 ; rutina ejecutada desde 286+
PUSHA ; sistema reinicializando:
MOV AH,0Dh
CALL llama_XMS ; desbloquear EMB (prudente)
MOV AH,0Ah
CALL llama_XMS ; liberar EMB
POPA
.8086
RET
no_xmslib: DEC BP ; leer/escribir en el disco
JNZ xms_escribe
PUSH ES
PUSH DI ; segmento:offset destino
PUSH BP ; handle destino (BP=0)
xms_escribe: PUSH DX
PUSH AX ; desplazamiento DX:AX
PUSH DS ; handle fuente/destino
JZ xms_general
INC BP ; hacer BP = 0
PUSH ES
PUSH DI ; segmento:offset fuente
PUSH BP ; handle fuente (BP=0)
xms_general: SHL CX,1 ; palabras -> bytes
RCL BP,1 ; BP era 0
PUSH BP ; tamaño bloque (parte alta)
PUSH CX ; tamaño bloque (parte baja)
MOV SI,SP
PUSH SS
POP DS ; DS:SI apuntando a la pila
MOV AH,0Bh ; función para mover EMB
CALL llama_XMS ; mover EMB (DS no importa)
ADD SP,16 ; equilibrar pila
CMP AL,1 ; ¿falló el controlador?
JE xms_proc_ok
MOV AX,0C81h ; anomalía general
xms_proc_ok: XCHG AH,AL ; colocar resultado
RET
procesa_xms ENDP
llama_XMS PROC
MOV DX,DS ; handle en DS (si utilizado)
CALL CS:xms_driver ; ejecutar función XMS
RET
llama_XMS ENDP
tam_proc_xms EQU $-OFFSET procesa_xms ; tamaño de esta rutina
; ------------ Rutina de gestión de memoria convencional. Se copiará
; sobre la de memoria EMS si se utiliza memoria conv.
procesa_con PROC
JC con_exit ; sistema inicializándose
MOV BX,16 ; bytes por párrafo
DIV BX ; AX = segmento, DX = offset
ADD AX,CS:mem_handle ; segmento de inicio datos
MOV DS,AX
MOV SI,DX ; DS:SI inicio de datos
DEC BP ; y ES:DI destino del buffer
JZ con_general ; es lectura
XCHG SI,DI ; escritura: intercambiar
XPUSH <DS,ES>
XPOP <DS,ES>
con_general: CLD
CMP CS:cpu386,ON
JE con_tr32bit
REP MOVSW
JMP con_tr_fin
con_tr32bit: SHR CX,1 ; nº palabras de 32 bit a mover
JCXZ con_trdo ; evitar desgracia
.386
PUSHAD
XOR EAX,EAX ; asegurar no violación
DEC AX ; de segmento-64K
AND ECX,EAX ; EAX = 0FFFFh
AND ESI,EAX
AND EDI,EAX
REP MOVSD ; transferencia ultrarrápida
con_trdo: POPAD ; POPAD falla en muchos 386
NOP ; arreglar fallo de POPAD
.8086
con_tr_fin: MOV AX,100h ; todo fue bien, por supuesto
con_exit: RET
procesa_con ENDP
tam_proc_con EQU $-OFFSET procesa_con ; tamaño de esta rutina
; ************ Datos no residentes para la instalación
ON EQU 1 ; constantes booleanas
OFF EQU 0
CONFIG EQU 1 ; TURBODSK ejecutado desde el CONFIG
AUTOEXEC EQU 2 ; TURBODSK se ejecuta desde el DOS
emm_id DB "EMMXXXX0" ; identificación del controlador EMS
nombre_tdsk DB "TDSK U: " ; para nombrar handle EMS y el MCB
modo DB ? ; CONFIG/AUTOEXEC
dosver DW ? ; versión del DOS
top_ram DW 0 ; segmento más alto de la RAM
segm_psp DW 0 ; segmento del PSP
segm_tdsk DW 0 ; segmento donde reside TURBODSK
segm_reubicar DW 0 ; segmento donde reubicar TURBODSK
ems4 DB OFF ; a ON si EMS versión 4.0+
cpu286 DB OFF ; a ON si 286 ó superior
idioma DB 0 ; selecciona el número de idioma (1..N)
idioma_seps DW ",." ; separadores de millares/decimales
param_unidad DB 0 ; letra de unidad (si indicada)
param_tdiscof DB OFF ; a ON si se define tamaño de disco
param_tdisco DW 0 ; tamaño de disco (si se define)
param_tsect DW 0 ; tamaño de sector (si se define)
param_tdir DW 0 ; número de entradas (si se define)
param_tcluster DW 0 ; tamaño de cluster (si se define)
param_a DB OFF ; a ON si indicado parámetro /A o /X
param_e DB OFF ; a ON si indicado parámetro /E
param_c DB OFF ; a ON si indicado parámetro /C
param_h DB OFF ; a ON si indicado parámetro /? o /H
param_m DB OFF ; a ON si indicado parámetro /M
param_i DB OFF ; Y ON si indicado parámetro /I
param_f DW 1 ; nº de FATs (1-2): parámetro /F=
codigo_tfno DW ? ; valor de /I= si se indica
tdisco DW ? ; tamaño de disco (Kb)
ultclus DW ? ; número más alto de cluster
tamcluster DW ? ; tamaño de cluster (bytes)
sdir DW ? ; sectores para directorio raiz
xms_kb DW 0 ; Kb de memoria XMS libres
ems_kb DW 0 ; Kb de memoria EMS libres
con_kb DW 0 ; Kb de memoria convencional libres
sector_cero LABEL BYTE
JMP SHORT botar
NOP
DB "TDSK 2.2" ; identificación del sistema
tsect DW 512 ; tamaño de sector por defecto
tcluster DB ? ; sectores por cluster
DW 1 ; sectores reservados
nfats DB ? ; número de FAT's
tdir DW ? ; número de entradas al dir. raiz
numsect DW ? ; nº sectores del disco (<=32Mb)
DB media ; descriptor de medio
sfat DW ? ; sectores por FAT
DW 1, 1 ; sectores por pista / cabezas
DD 0 ; sectores ocultos
DD 0 ; nº total de sectores (si > 32Mb)
DB 7 DUP (0) ; 7 bytes reservados
botar: DB 0EAh ; código de JMP FAR...
DW 0,0FFFFh ; ...FFFF:0000 (programa BOOT)
DB "(C)1992 CiriSOFT"; resto de primeros 64 bytes
DB ". Grupo Universi"
DB "tario de Informá"
DB "tica (GUI) - Val"
DB "ladolid (España)"; resto de primeros 128 bytes
dir_raiz DB "TURBODSK "; Directorio raiz: primera entrada
DB 8 ; etiqueta de volúmen
DB 10 DUP (0) ; reservado
DW ? ; hora (inicializado al formatear)
DW ? ; fecha
DW 0,0,0 ; últimos bytes (hasta 32)
; ------------ Areas de datos para información del disco virtual
; --- Código telefónico de países de habla
; hispana (mucha o poca).
info_paises DW 54 ; Argentina
DW 591 ; Bolivia
DW 57 ; Colombia
DW 506 ; Costa Rica
DW 56 ; Chile
DW 593 ; Ecuador
DW 503 ; El Salvador
DW 34 ; España
DW 63 ; Filipinas
DW 502 ; Guatemala
DW 504 ; Honduras
DW 212 ; Marruecos
DW 52 ; México
DW 505 ; Nicaragua
DW 507 ; Panamá
DW 595 ; Paraguay
DW 51 ; Perú
DW 80 ; Puerto Rico
DW 508 ; República Dominicana
DW 598 ; Uruguay
DW 58 ; Venezuela
DW 3 ; Latinoamérica
DW 0 ; fin de la información
; --- Código telefónico de países de habla alemana.
DW 41 ; Switzerland
DW 43 ; Austria
DW 49 ; Germany
DW 0 ; fin de la información
DW 0 ; no más idiomas
; ------------ Mensaje de no formateado
info_ins DB 10,1,10,"TURBODSK 2.2 - Unidad ",255
DB 10,1,10,"TURBODSK 2.2 - Laufwerk ",255
DB 10,1,10,"TURBODSK 2.2 - Drive ",0
info_ins2 DB ": sin formatear.",10,1,14,255
DB ": nicht formatiert.",10,1,14,255
DB ": unformatted.",10,1,14,0
; ------------ Cuadro de información
colA EQU 11+1*16 ; color del recuadro y los mensajes
colB EQU 15+1*16 ; color de los parámetros de operación del disco
colC EQU 15+0*16 ; color de lo que rodea a la ventana
colD EQU 10+1*16 ; color de «TURBODSK»
info_txt DB 10,2,12,3,1,colA,"┌",2,27,"─┬",2,25,"─┐",1,colC
DB 10,2,12,3,1,colA,"│ ",1,colD,"TURBODSK 2.2",1,colA
DB " - Unidad ",1,colB
DB 255
DB 10,2,10,3,1,colA,"┌",2,28,"─┬",2,28,"─┐",1,colC
DB 10,2,10,3,1,colA,"│ ",1,colD,"TURBODSK 2.2",1,colA
DB " - Laufwerk ",1,colB
DB 255
DB 10,2,12,3,1,colA,"┌",2,26,"─┬",2,25,"─┐",1,colC
DB 10,2,12,3,1,colA,"│ ",1,colD,"TURBODSK 2.2",1,colA
DB " - Drive ",1,colB
DB 0
inf_tsect DB ":",1,colA," │ Tamaño de sector:",1,colB," ",255
DB ":",1,colA," │ Sektorgröße:",2,8," ",1,colB," ",255
DB ":",1,colA," │ Sector size:",2,5," ",1,colB," ",0
inf_tdir DB " ",1,colA,"│",1,colC,10,2,12,3
DB 1,colA,"├",2,27,"─┤ Nº entradas raiz:",1,colB," "
DB 255
DB " ",1,colA,"│",1,colC,10,2,10,3
DB 1,colA,"├",2,28,"─┤ Verzeichniseinträge:",1,colB, " "
DB 255
DB " ",1,colA,"│",1,colC,10,2,12,3
DB 1,colA,"├",2,26,"─┤ Root entries:",2,4," ",1,colB," "
DB 0
inf_tdisco DB " ",1,colA,"│",1,colC,10
DB 2,12,3,1,colA,"│ Tamaño: ",1,colB," "
DB 255
DB " ",1,colA,"│",1,colC,10
DB 2,10,3,1,colA,"│ Größe:",2,10," ",1,colB," "
DB 255
DB " ",1,colA,"│",1,colC,10
DB 2,12,3,1,colA,"│ Size:",2,4," ",1,colB," "
DB 0
inf_tcluster DB " Kbytes ",1,colA,"│ Sectores/cluster:",1,colB," "
DB 255
DB " KB ",1,colA,"│ Sektoren/Cluster:",2,3," ",1,colB," "
DB 255
DB " Kbytes ",1,colA,"│ Sectors/cluster: ",1,colB," "
DB 0
inf_mem DB " ",1,colA,"│",1,colC,10
DB 2,12,3,1,colA,"│ Memoria: ",1,colB
DB 255
DB " ",1,colA,"│",1,colC,10
DB 2,10,3,1,colA,"│ Speicher: ",1,colB
DB 255
DB " ",1,colA,"│",1,colC,10
DB 2,12,3,1,colA,"│ Memory: ",1,colB
DB 0
inf_nclusters DB " ",1,colA,"│",1,colB," ",255
DB " ",1,colA,"│",1,colB," ",255
DB 1,colA,"│",1,colB," ",0
inf_tfat DB 1,colA," clusters (",1,colB,"FAT",255
DB 1,colA," Cluster (",1,colB,"FAT",255
DB 1,colA," clusters (",1,colB,"FAT",0
inf_tfat12 DB "12",0
inf_tfat16 DB "16",0
inf_final DB 1,colA,") ",1,colA,"│",1,colC,10,2,12,3
DB 1,colA,"└",2,27,"─┴",2,25,"─┘",1,colC,10
DB 255
DB 1,colA,")",2,5," ",1,colA,"│",1,colC,10
DB 2,10,3,1,colA,"└",2,28,"─┴",2,28,"─┘",1,colC,10
DB 255
DB 1,colA,") ",1,colA,"│",1,colC,10,2,12,3
DB 1,colA,"└",2,26,"─┴",2,25,"─┘",1,colC,10
DB 0
inf_mem_xms DB "Extendida (XMS)",255
DB "Erweitert (XMS)",255
DB "Extended (XMS) ",0
inf_mem_ems DB "Expandida (EMS)",255
DB "Expansion (EMS)",255
DB "Expanded (EMS) ",0
inf_mem_sup DB " Superior (UMB) ",255
DB "Oberer Sp. (UMB)",255
DB " Upper (UMB) ",0
inf_mem_con DB " Convencional ",255
DB " Konventionell",255
DB " Conventional ",0
; ------------ Errores «leves»
ERROR0 EQU 1
ERROR1 EQU 2
ERROR2 EQU 4
ERROR3 EQU 8 ; TURBODSK es muy flexible y se instala
ERROR4 EQU 16 ; casi de cualquier forma, aunque a
ERROR5 EQU 32 ; veces no se reserve memoria y sea
ERROR6 EQU 64 ; necesario volver a ejecutarlo después
ERROR7 EQU 128 ; desde el DOS para «formatearlo».
ERROR8 EQU 256
ERROR9 EQU 512
ERROR10 EQU 1024
ERROR11 EQU 2048
ERROR12 EQU 4096
ERROR13 EQU 8192
ERROR14 EQU 16384
ERROR15 EQU 32768
lista_err DW 0 ; palabra que indica los mensajes a imprimir
mens_cabec DB 2,8,3,0
tabla_mens DW m0,m1,m2,m3,m4,m5,m6,m7
DW m8,m9,m10,m11,m12,m13,m14,m15
cab_adv_txt DB 10,2,8,3,1,12
DB "Advertencias y/o errores de TURBODSK:",2,27," ",10,1,10
DB 255
DB 10,2,8,3,1,12
DB "Warnungen und Fehlermeldungen von TURBODSK:",2,27," ",10,1,10
DB 255
DB 10,2,8,3,1,12
DB "Warnings and errors of TURBODSK:",2,32," ",10,1,10
DB 0
m0 DB "- Error de sintaxis o parámetro fuera de rango. No se define el",10,2,8,3
DB " disco virtual ahora o no se modifica el que estaba definido. ",10
DB 255
DB "- Syntaxfehler oder ungültiger Parameter. Die RAM-Disk ist zur ",10,2,8,3
DB " Zeit nicht definiert bzw. wurde nicht modifiziert.",10
DB 255
DB "- Syntax error and/or parameter out of range. The Ramdisk is not",10,2,8,3
DB " defined now or the previous one is not modified.",2,14," ",10
DB 0
m1 DB "- El parámetro /C o la letra de unidad sólo han de emplearse",2,4," ",10,2,8,3
DB " desde la línea de comandos o el AUTOEXEC (les ignoraré).",2,6," ",10
DB 255
DB "- Parameter /C und Laufwerksbuchstaben können nur bei Aufrufen ",2,4," ",10,2,8,3
DB " von TURBODSK in der AUTOEXEC verwendet werden. ",2,6," ",10
DB 255
DB "- The /C parameter and the driver letter only can be used when ",10,2,8,3
DB " executing TURBODSK in command line or AUTOEXEC (now, ignored).",10
DB 0
m2 DB "- Para poder emplear memoria expandida hay que incluir la opción",10,2,8,3
DB " /A en CONFIG.SYS, con objeto de dejar espacio para las rutinas",10,2,8,3
DB " de control EMS: la memoria ocupada crecerá de 432 a 608 bytes.",10
DB 255
DB "- Zur Verwendung von EMS müssen Sie Option /A in CONFIG.SYS ",10,2,8,3
DB " setzen, um Speicher für die EMS-Unterstützung zu reservieren. ",10,2,8,3
DB " Dadurch erhöht sich der Speicherbedarf von 432 auf 608 Bytes. ",10
DB 255
DB "- In order to use expanded memory you must include the /A option",10,2,8,3
DB " in CONFIG.SYS, needed to reserve too space for the EMS support",10,2,8,3
DB " routines: the memory used will increase from 432 to 608 bytes.",10
DB 0
m3 DB "- El tamaño de sector es mayor que el definido en cualquier otro",10,2,8,3
DB " controlador de dispositivo: indíquese ese tamaño en CONFIG.SYS",10,2,8,3
DB " para que el DOS ajuste sus buffers (¡más consumo de memoria!).",10
DB 255
DB "- Die Sektorengröße ist größer als in allen anderen Treibern; ",10,2,8,3
DB " Sie müssen die Sektorgröße in CONFIG.SYS festlegen, da DOS die",10,2,8,3
DB " Puffergröße anpassen muß (höherer Speicherverbrauch) ",10
DB 255
DB "- Sector size is greater than any other defined by any device",10,2,8,3
DB " driver loaded: you must indicate the sector size in CONFIG.SYS",10,2,8,3
DB " because DOS need adjust buffers length (more memory spent!). ",10
DB 0
m4 DB "- La cantidad de memoria solicitada no existe, se ha rebajado. ",10
DB 255
DB "- Die gewünschte Speichergröße existiert nicht und wurde reduziert.",10
DB 255
DB "- The amount of memory requested does not exist: size reduced. ",10
DB 0
m5 DB "- No hay memoria XMS/EMS disponible: no la reservo; ejecute TDSK",10,2,8,3
DB " de nuevo desde el DOS para utilizar memoria convencional.",2,5," ",10
DB 255
DB "- Kein XMS/EMS verfügbar: Führen Sie TDSK nochmals von der ",10,2,8,3
DB " Kommandozeile aus und benutzen Sie konventionellen Speicher. ",2,5," ",10
DB 255
DB "- There is not XMS/EMS memory available: execute TDSK again from",10,2,8,3
DB " DOS command line or AUTOEXEC and use conventional memory.",2,5," ",10
DB 0
m6 DB "- No existe memoria XMS: pruebe a indicar EMS en su lugar (/A) ",10
DB 255
DB "- Kein XMS verfügbar: Versuchen Sie, EMS zu verwenden (/A). ",10
DB 255
DB "- There is not XMS memory available: try to request EMS (/A). ",10
DB 0
m7 DB "- No existe memoria EMS: pruebe a indicar XMS en su lugar (/E) ",10
DB 255
DB "- Kein EMS verfügbar: Versuchen Sie, XMS zu verwenden (/E). ",10
DB 255
DB "- There is not EMS memory available: try to request XMS (/E). ",10
DB 0
m8 DB "- Fallo del controlador XMS: imposible usar memoria extendida. ",10
DB 255
DB "- Fehler des XMS-Managers: Verwendung von XMS unmöglich. ",10
DB 255
DB "- XMS controller failure: imposible to use extended memory.",2,5," ",10
DB 0
m9 DB "- Fallo del controlador EMS: imposible usar memoria expandida. ",10
DB 255
DB "- Fehler des EMS-Managers: Verwendung von EMS unmöglich. ",10
DB 255
DB "- EMS controller failure: imposible to use expanded memory.",2,5," ",10
DB 0
m10 DB "- No existe suficiente memoria convencional para TURBODSK.",2,6," ",10
DB 255
DB "- Nicht genügend konventioneller Speicher für TURBODSK verfügbar.",2,6," ",10
DB 255
DB "- There is not sufficient conventional memory for TURBODSK.",2,5," ",10
DB 0
m11 DB "- Tamaño de sector incorrecto: lo establezco por defecto.",2,7," ",10
DB 255
DB "- Ungültige Sektorengröße angegeben, Vorgabewert wird verwendet.",2,7," ",10
DB 255
DB "- Incorrect sector size indicated: default values assumed.",2,6," ",10
DB 0
m12 DB "- Número de entradas incorrecto: lo establezco por defecto.",2,5," ",10
DB 255
DB "- Ungültige Anz. von Verzeichnisanträgen, Vorgabewert wird verwendet.",2,5," ",10
DB 255
DB "- Incorrect number of root entries: default value assumed.",2,6," ",10
DB 0
m13 DB "- Tamaño de cluster incorrecto: lo establezco por defecto.",2,6," ",10
DB 255
DB "- Ungültige Clustergröße angegeben, Vorgabewert wird verwendet.",2,6," ",10
DB 255
DB "- Incorrect cluster size indicated: default value assumed.",2,6," ",10
DB 0
m14 DB "- FATAL: fallo al liberar la memoria que ocupaba el disco.",2,6," ",10
DB 255
DB "- ACHTUNG: Freigabe des belegten Speichers gescheitert.",2,6," ",10
DB 255
DB "- FATAL: imposible to free memory alocated by TURBODSK.",2,9," ",10
DB 0
m15 DB "- Para discos de más de 32 Mb, hace falta un tamaño de sector de",10,2,8,3
DB " al menos 1024 bytes.",2,42," ",10
DB 255
DB "- Laufwerke mit mehr als 32 MB erfordern eine Sektorgröße",10,2,8,3
DB " von mindestens 1024 Bytes.",2,42," ",10
DB 255
DB "- In drives over 32 Mb, sector size must be at least 1024 bytes.",10
DB 0
; ------------ Errores «graves» (se imprime sólo el más importante)
err_grave DW 0 ; tipo de error grave a imprimir
err_grave_gen DB 10,1,10,"TURBODSK 2.2",10,1,12,0
e0 DB " - Este disco virtual requiere DOS 2.0 o superior.",10,255
DB " - Diese RAM-Disk erfordert mindestens DOS 2.0.",10,255
DB " - This Ram Disk needs at least DOS 2.0 or above.",10,0
e1 DB " - Instale primero TURBODSK desde CONFIG.SYS (con DEVICE).",10
DB " - Puede solicitar ayuda con TDSK /?",10
DB 255
DB " - Sie müssen zuerst TURBODSK von der CONFIG.SYS aus installieren",10
DB " (mit DEVICE). Hilfe erhalten Sie durch Eingabe von TDSK /?",10
DB 255
DB " - You must install first TURBODSK from CONFIG.SYS (using DEVICE).",10
DB " - Help is available with TDSK /?",10
DB 0
e2 DB " - La unidad indicada no es un dispositivo TURBODSK 2.2",10,255
DB " - Angegebener Laufwerksbuchstabe bezeichnet keinen Treiber von TURBODSK.", 10,255
DB " - Drive letter indicated does not is a TURBODSK 2.2 device.",10,0
e3 DB " - No pueden modificarse las características de operación de",10
DB " TURBODSK dentro de WINDOWS. Configúrelo con anterioridad.",10
DB 255
DB " - TURBODSK kann nicht innerhalb einer WINDOWS-Sitzung modifiziert werden.",10
DB " Sie müssen die Einstellungen vorher durchführen.",10
DB 255
DB " - Operational characteristics of disk can not be altered inside",10,2,4
DB " a WINDOWS session. You must configure TURBODSK before.",10
DB 0
; ------------ Ayuda
colorA EQU 15+4*16+128 ; color de «TURBODSK»
colorAm EQU 14+1*16 ; color del marco de fondo de «TURBODSK»
colorB EQU 13+1*16 ; color de la fecha
colorC EQU 10+1*16 ; color de sintaxis y parámetros
colorD EQU 15+1*16 ; color principal del texto
colorDm EQU 11+1*16 ; color del marco de fondo
colorDmx EQU 11+0*16 ; color de la esquina del marco
colorE EQU 11+1*16 ; color del nombre del autor
colorF EQU 14+1*16 ; color para llamar la atención
colorG EQU 12+1*16 ; color para la dirección de mail
colorH EQU 9+1*16 ; color para mensaje de dominio público
ayuda_txt LABEL BYTE
DB 10,3,1,colorDm," ",1,colorA," TURBODSK 2.2 ",1,colorAm,"▄"
DB 1,colorB,2,52," 30/4/95 ",1,colorDmx,"▄",10
DB 3,1,colorE," ",1,colorAm,2,14,"▀",1,colorE
DB " (C) 1995 Ciriaco García de Celis. ",1,colorG
DB "(Mail: ciri@gui.uva.es).",1,colorDm,"█",10
DB 3,1,colorE," (C) Grupo Universitario de Informática. "
DB "Apartado 6062, Valladolid (España). ",1,colorDm,"█",10
DB 3,1,colorH,2,18," ","* * * Programa de Dominio Público * * *"
DB 2,18," ",1,colorDm,"█",10
DB 3,1,colorD," Bienvenido al disco virtual ",1,colorF,"más rápido"
DB 1,colorD,", con soporte de memoria EMS, XMS y ",1,colorDm,"█",10
DB 3,1,colorD," convencional; redimensionable, fácil de usar. En DOS "
DB "5 ocupa 432-608 bytes. ",1,colorDm,"█",10
DB 3,1,colorC,2,77," ",1,colorDm,"█",10
DB 3,1,colorC," DEVICE=TDSK.EXE [tamaño [tsector "
DB "[nfich [scluster]]]] [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
DB 3,1,colorC,2,77," ",1,colorDm,"█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorD," El tamaño debe de estar en "
DB "el rango 8 - 65534 Kb; son válidos sectores de ",1,colorDm
DB "█",10
DB 3,1,colorD," 32 a 2048 bytes (en potencias de dos, aunque algún "
DB "sistema sólo los soporta ",1,colorDm,"█",10
DB 3,1,colorD," de 128 a 512). El número de ficheros del directorio "
DB "raiz debe estar entre 1 ",1,colorDm,"█",10
DB 3,1,colorD," y 65534 y el de sectores por cluster entre 1 y 255 ("
DB "en algún sistema han de ",1,colorDm,"█",10
DB 3,1,colorD," ser potencia de dos). Según el tamaño se ajustará "
DB "lo demás automáticamente. ",1,colorDm,"█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorD," Se puede indicar ",1,colorC
DB "/E",1,colorD," para emplear memoria extendida XMS, y ",1,colorC
DB "/A",1,colorD," o ",1,colorC,"/X",1,colorD," para la ",1,colorDm
DB "█",10
DB 3,1,colorD," expandida EMS; aunque por defecto, TURBODSK utilizará"
DB " automáticamente estas ",1,colorDm,"█",10
DB 3,1,colorD," memorias si puede. Con la opción ",1,colorC,"/C"
DB 1,colorD," se pide el uso de memoria convencional. ",1,colorDm
DB "█",10
DB 3,1,colorD,32,1,colorF,"■",1,colorD," Tras ser instalado, se puede"
DB " ejecutar desde el DOS para cambiar el tamaño ",1,colorDm
DB "█",10
DB 3,1,colorD," del disco (perdiéndose los datos almacenados): con "
DB "un tamaño 0 se anula el ",1,colorDm,"█",10
DB 3,1,colorD," disco por completo, liberándose la memoria. "
DB "Utilizando memoria convencional ",1,colorDm,"█",10
DB 3,1,colorD," es ",1,colorF,"MUY",1,colorD," conveniente anular el "
DB "disco previo antes de modificar su tamaño. Con ",1,colorDm
DB "█",10
DB 3,1,colorD," más de un disco presente se pueden distinguir "
DB "indicando la letra de unidad. ",1,colorDm,"█",10
DB 3,1,1*16,"▄",1,colorDm,2,76,"▄█",10
DB 255
DB 10,3,1,colorDm," ",1,colorA," TURBODSK 2.2 ",1,colorAm,"▄"
DB 1,colorB,2,53," 30/4/95 ",1,colorDmx,"▄",10
DB 3,1,colorE," ",1,colorAm,2,14,"▀",1,colorE
DB " (C) 1995 Ciriaco García de Celis. ",1,colorG
DB "(Mail: ciri@gui.uva.es). ",1,colorDm,"█",10
DB 3,1,colorE," (C) Grupo Universitario de Informática. "
DB "Apartado 6062, Valladolid (Spanien). ",1,colorDm,"█",10
DB 3,1,colorC,2,78," ",1,colorDm,"█",10
DB 3,1,colorD," Willkommen bei der ",1,colorF,"schnelleren"
DB 1,colorD," RAM-Disk, die auch EMS-, XMS- und konven- ",1,colorDm,"█",10
DB 3,1,colorD," tionellen Speicher unterstützt; größenverstellbar,"
DB " einfache Bedienung wie ",1,colorDm,"█",10
DB 3,1,colorD," bei DOS-RAM-Disks, erfordert maximal 608 Bytes. "
DB 1,colorH," Das Programm ist Freeware!. ",1,colorDm,"█",10
DB 3,1,colorC,2,78," ",1,colorDm,"█",10
DB 3,1,colorC," DEVICE=TDSK.EXE [Größe [Sekt. [Dateien [Cluster]]]]"
DB " [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
DB 3,1,colorC,2,78," ",1,colorDm,"█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorD," Zulässig für Größe: 8-65534 KB;"
DB " zulässig für Sektoren: 32-2048 Bytes (2er- ",1,colorDm,"█",10
DB 3,1,colorD," Potenz), obwohl einige DOS-Versionen nur 128,"
DB " 256 und 512 unterstützen. ",1,colorDm,"█",10
DB 3,1,colorD, " Zulässige Anzahl der Verzeichniseinträge: "
DB "1-65534, Sektoren/Cluster: 1-255 ",1,colorDm,"█",10
DB 3,1,colorD," (einige Systeme erforden 2er-Potenzen)."
DB " Nur die Größenangabe ist notwendig. ",1,colorDm,"█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorD," Bei ",1,colorC, "/E",1,colorD
DB " wird XMS, bei ",1,colorC, "/A",1,colorD," oder ",1,colorC,"/X",1,colorD
DB " wird EMS, und bei ",1,colorC, "/C",1,colorD," wird konventioneller ",1,colorDm
DB "█",10,3,1,colorD, " Speicher benutzt. Normalerweise versucht TURBODSK,"
DB " XMS oder EMS zu benutzen. ",1,colorDm,"█",10
DB 3,1,colorD,32,1,colorF,"■",1,colorD," Nach der Installation in"
DB " CONFIG.SYS sollte TURBODSK später nochmal ausge- ",1,colorDm,"█",10
DB 3,1,colorD," führt werden, um die Größe zu ändern (den"
DB " Speicherverbrauch); dadurch wird ",1,colorDm,"█",10
DB 3,1,colorD," der Inhalt der RAM-Disk gelöscht. Durch Größe 0 wird"
DB " die RAM-Disk komplett ",1,colorDm,"█",10
DB 3,1,colorD," gelöscht, bei Verwendung von konventionellem Speicher"
DB " kann eine Annulierung ",1,colorDm,"█",10
DB 3,1,colorF," VOR",1,colorD," der Größenveränderung sinnvoll sein. Wenn mehrere"
DB " TURBODSK's installiert ",1,colorDm,"█",10
DB 3,1,colorD," sind, können diese durch ihren Laufwerksbuchstaben"
DB " angesteuert werden. ",2,6," ",1,colorDm,"█",10
DB 3,1,1*16,"▄",1,colorDm,2,77,"▄█",10
DB 255
DB 10,3,1,colorDm," ",1,colorA," TURBODSK 2.2 ",1,colorAm,"▄"
DB 1,colorB,2,52," 4/30/95 ",1,colorDmx,"▄",10
DB 3,1,colorE," ",1,colorAm,2,14,"▀",1,colorE
DB " (C) 1995 Ciriaco Garcia de Celis. ",1,colorG
DB "(Mail: ciri@gui.uva.es).",1,colorDm,"█",10
DB 3,1,colorE," (C) Grupo Universitario de Informática. "
DB "Apartado 6062, Valladolid (Spain). ",1,colorDm,"█",10
DB 3,1,colorC,2,77," ",1,colorDm,"█",10
DB 3,1,colorD," Welcome to the ",1,colorF,"faster",1,colorD
DB " RAM disk!, which includes support of both EMS, XMS "
DB 1,colorDm,"█",10
DB 3,1,colorD," and conventional memory. Full resizeable, easy to "
DB "use like DOS RAM disks, ",1,colorDm,"█",10
DB 3,1,colorD," in DOS 5.0 it takes only about 432-608 bytes. "
DB 1,colorH,"This program is freeware!.",2,4," ",1,colorDm,"█",10
DB 3,1,colorC,2,77," ",1,colorDm,"█",10
DB 3,1,colorC," DEVICE=TDSK.EXE [size [s_sector [files [s_cluster]]]]"
DB " [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
DB 3,1,colorC,2,77," ",1,colorDm,"█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorD," Size must be in the range "
DB "8 - 65534 Kb; are valid sectors from 32 to 2048 ",1,colorDm
DB "█",10
DB 3,1,colorD," bytes (in power of 2), though some DOS versions only "
DB "support 128, 256 & 512 ",1,colorDm,"█",10
DB 3,1,colorD," bytes. Files of root may be 1 to 65534 and sectors "
DB "by cluster can vary from ",1,colorDm,"█",10
DB 3,1,colorD," 1 to 255 (some systems need a power of 2). Only the "
DB "size is necessary.",2,6," ",1,colorDm,"█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorC," /E",1,colorD," force the "
DB "use of XMS memory, ",1,colorC,"/A",1,colorD," and ",1,colorC
DB "/X",1,colorD," indicates the use of EMS memory ",1,colorDm
DB "█",10
DB 3,1,colorD," and ",1,colorC,"/C",1,colorD," the conventional. By "
DB "default, TURBODSK try to use XMS or EMS memory. ",1,colorDm
DB "█",10
DB 3,1,colorD," ",1,colorF,"■",1,colorD," After been installed in "
DB "CONFIG.SYS, TURBODSK must be executed in AUTOEXEC ",1,colorDm
DB "█",10
DB 3,1,colorD," or command line in order to vary the disk size (the "
DB "amount of memory used); ",1,colorDm,"█",10
DB 3,1,colorD," this operation erase the disk contents. A size 0 "
DB "can be used to complitely ",1,colorDm,"█",10
DB 3,1,colorD," anulation of the disk freezen the memory: when using "
DB "conventional memory it ",1,colorDm,"█",10
DB 3,1,colorD," is useful to annulate the disk ",1,colorF,"BEFORE"
DB 1,colorD," resizing. When more than one TURBODSK ",1,colorDm
DB "█",10
DB 3,1,colorD," is installed, they can be identified using in "
DB "adition the drive letter.",2,5," ",1,colorDm,"█",10
DB 3,1,1*16,"▄",1,colorDm,2,76,"▄█",10
DB 0
tam_a_trabajo EQU 4096 ; tamaño del mayor sector soportado
; por TURBODSK o del mayor texto
; a imprimir
area_trabajo EQU $
DB tam_a_trabajo DUP (?)
_PRINCIPAL ENDS
tam_pila EQU 2048 ; 2 Kb de pila son suficientes
_PILA SEGMENT STACK 'STACK'
DB tam_pila DUP (?)
_PILA ENDS
END main