home *** CD-ROM | disk | FTP | other *** search
/ Bila Vrana / BILA_VRANA.iso / 005A / TDSK22SR.ZIP / TDSK.ASM < prev   
Assembly Source File  |  1995-05-14  |  156KB  |  3,465 lines

  1.  
  2. ;┌───────────────────────────────────────────────────────────────────┐
  3. ;│                                                                   │
  4. ;│ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▄ │
  5. ;│  ▀▀▒▒█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ │
  6. ;│    ▒▒█  ▒▒▄ ▒▒▄  ▒▒▒▒▄   ▒▒▒▒▄     ▒▒▄   ▒▒▒▒▄   ▒▒▒▒▒▒▄ ▒▒▄  ▒▒▄ │
  7. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█▀▒▒▄ ▒▒█▀▒▒▄ ▒▒▄▀▒▒▄ ▒▒█▀▒▒▄ ▒▒█▀▀▀▀ ▒▒█ ▒▒█▀ │
  8. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█     ▒▒█▒▒█▀  │
  9. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒▒▒▄▀▀ ▒▒▒▒▄▀▀ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒▒▒▒▒▄ ▒▒▒▒█▀   │
  10. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█▀▒▒▄ ▒▒█▀▒▒▄ ▒▒█ ▒▒█ ▒▒█ ▒▒█  ▀▀▀▒▒█ ▒▒█▒▒▄   │
  11. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒▄ ▒▒█ ▒▒█ ▒▒▄  │
  12. ;│    ▒▒█  ▒▒▒▒▒▒▒▄ ▒▒█ ▒▒█ ▒▒▒▒▄▀▀  ▀▒▒▄▀▀ ▒▒▒▒▒█▀ ▒▒▒▒▒▒█ ▒▒█  ▒▒▄ │
  13. ;│     ▀▀   ▀▀▀▀▀▀▀  ▀▀  ▀▀  ▀▀▀▀      ▀▀    ▀▀▀▀▀   ▀▀▀▀▀▀  ▀▀   ▀▀ │
  14. ;│                                                                   │
  15. ;│           ░░▒▒▓▓██▓▓▒▒░░   Versión 2.2   ░░▒▒▓▓██▓▓▒▒░░           │
  16. ;│                                                                   │
  17. ;│                                                                   │
  18. ;│     CONTROLADOR DE DISCO VIRTUAL PARA SISTEMAS DOS Y WINDOWS 3    │
  19. ;│                                                                   │
  20. ;│              * * * Programa de Dominio Público * * *              │
  21. ;│                                                                   │
  22. ;│              (C) 1992-1995  Ciriaco García de Celis.              │
  23. ;│     Grupo Universitario de Informática. Facultad de Ciencias.     │
  24. ;│                Apartado 6062 - Valladolid (España)                │
  25. ;│                                                                   │
  26. ;│                        Internet Email:  ciri@gui.uva.es           │
  27. ;│                        FidoNet:         2:341/21.8                │
  28. ;│                                                                   │
  29. ;│      Mensajes en alemán cortesía de Axel Christoph Frinke         │
  30. ;│                        Internet Email:  acfrinke@uni-bonn.de      │
  31. ;│                                                                   │
  32. ;└───────────────────────────────────────────────────────────────────┘
  33.  
  34.    ;   Aviso:   Este programa contiene instrucciones exclusivas de los
  35.    ;          procesadores 386 y superiores.  Debe ser ensamblado como
  36.    ;          fichero  EXE,  de la siguiente manera,  para asegurar la
  37.    ;          compatibilidad con los procesadores 8086 y 286:
  38.    ;
  39.    ;          - Con TASM 2.0:
  40.    ;                            TASM tdsk /m3
  41.    ;                            TLINK tdsk
  42.    ;
  43.    ;          - Con MASM 6.0  (versiones anteriores de MASM generarían
  44.    ;            un disco virtual que requeriría  un  386  o  superior,
  45.    ;            además habría que mover las directivas  que  controlan
  46.    ;            el tipo de procesador y colocarlas con «peligro»):
  47.    ;
  48.    ;                            ML /Zm tdsk.asm
  49.    ;
  50.    ;                o alternativamente:
  51.    ;
  52.    ;                            ML /c /Zm tdsk.asm
  53.    ;                            TLINK tdsk
  54.    ;
  55.    ;               La ventaja de TLINK frente a LINK es que el fichero
  56.    ;            ejecutable ocupa  2 Kbytes  menos en disco (a la tabla
  57.    ;            ubicada al final del programa  se  le  asigna  memoria
  58.    ;            en la cabecera del fichero EXE y no ocupando disco).
  59.    ;
  60.    ;   IMPORTANTE:  Cualquier cambio realizado en el programa debe ser
  61.    ;                documentado,  indicando claramente en el listado y
  62.    ;                en el fichero DOC quién lo ha realizado.
  63.  
  64.  
  65. ; ------------ Macros de propósito general
  66.  
  67. XPUSH          MACRO regmem            ; apilar lista de registros
  68.                  IRP rm, <regmem>
  69.                    PUSH rm
  70.                  ENDM
  71.                ENDM
  72.  
  73. XPOP           MACRO regmem            ; desapilar lista de registros
  74.                  IRP rm, <regmem>
  75.                    POP rm
  76.                  ENDM
  77.                ENDM
  78.  
  79. ; ------------ Estructuras de datos
  80.  
  81. cab_PETICION   STRUC                   ; parte inicial común a todos
  82. tamano         DB    ?                 ; los comandos de la cabecera
  83. unidad         DB    ?                 ; de petición
  84. orden          DB    ?
  85. estado         DW    ?
  86. dos_info       DB    8 DUP (?)
  87. cab_PETICION   ENDS
  88.  
  89. cab_INIT_BBPB  STRUC                   ; para comandos INIT/BUILD_BPB
  90.                DB    (TYPE cab_PETICION) DUP (?)
  91. num_discos     DB    ?                 ; número de unidades definidas
  92. fin_resid_desp DW    ?                 ; área que quedará residente
  93. fin_resid_segm DW    ?
  94. bpb_cmd_desp   DW    ?                 ; línea de órdenes del CONFIG
  95. bpb_cmd_segm   DW    ?                 ; y puntero al BPB
  96. nuevo_disco    DB    ?                 ; (DOS 3+) (0-A:, 1-B:,...)
  97. cab_INIT_BBPB  ENDS
  98.  
  99. cab_MEDIACHECK STRUC                   ; estructura para MEDIA CHECK
  100.                DB    (TYPE cab_PETICION) DUP (?)
  101. media_descrip  DB    ?                 ; descriptor de medio
  102. cambio         DB    ?                 ; 1: no cambiado, 0FFh:sí, 0:?
  103. cab_MEDIACHECK ENDS
  104.  
  105. cab_READ_WRITE STRUC
  106.                DB    (TYPE cab_PETICION) DUP (?)
  107.                DB    ?                 ; descriptor de medio
  108. transfer_desp  DW    ?                 ; dirección de transferencia
  109. transfer_segm  DW    ?
  110. transfer_sect  DW    ?                 ; nº de sectores a transferir
  111. transfer_sini  DW    ?                 ; primer sector a transferir
  112. cab_READ_WRITE ENDS
  113.  
  114.  
  115. ; ************ Disco virtual: inicio del área residente.
  116.  
  117. _PRINCIPAL     SEGMENT
  118.                ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
  119.  
  120.                DD    -1           ; encadenamiento con otros drivers
  121. tipo_drive     DW    0800h        ; palabra de atributo:
  122.                                   ; bit 15 a 0: dispositivo de bloques
  123.                                   ; bit 14 a 0: sin control IOCTL
  124.                                   ; bit 13 a 0: formato IBM
  125.                                   ; bit 11 a 1: soportados Open/Close
  126.                                   ;             y Remove (DOS 3.0+)
  127.                DW    estrategia   ; rutina de estrategia
  128.                DW    interrupcion ; rutina de interrupción
  129.                DB    1            ; número de unidades
  130.  
  131. ; ------------ Variables y tablas de datos globales fijas. Estas
  132. ;              variables no serán movidas de sitio en otras versiones
  133. ;              de TURBODSK, con objeto de facilitar un control externo
  134. ;              del disco virtual por parte de otros programas. Todo lo
  135. ;              que está dentro del «área a actualizar» será copiado
  136. ;              sobre el TURBODSK residente al redefinir el disco, para
  137. ;              inicializar todas las variables precisas.
  138.  
  139. cs_tdsk        DW    ? ; Segmento de TDSK. Con QEMM-386, los drivers
  140.                        ; pueden ser relocalizados en memoria superior
  141.                        ; de tal manera que parte de la cabecera queda
  142.                        ; en memoria convencional, con el dispositivo
  143.                        ; completo en la memoria superior, en la que es
  144.                        ; ejecutado. Tras la instalación, QEMM copia en
  145.                        ; memoria convencional los primeros 18 bytes de
  146.                        ; la cabecera, entre los que está esta palabra,
  147.                        ; actualizándola. Pese a que la cadena de
  148.                        ; dispositivos del sistema pasa por la memoria
  149.                        ; convencional en este caso, esta variable nos
  150.                        ; permite conocer la dirección REAL en memoria
  151.                        ; superior (o en cualquier otra) de TURBODSK,
  152.                        ; que así es compatible con el LOADHI de QEMM.
  153.  
  154. id_tdsk        DB    "TDS22" ; esto es TURBODSK 2.2 y no otro
  155.                              ; controlador de dispositivo
  156.  
  157. num_ordenes    DB    10h     ; nº de órdenes soportadas
  158.  
  159. i_tdsk_ctrl    EQU   $       ; inicio del área a actualizar
  160.  
  161. tipo_soporte   DB    0FFh    ; 0: disco no formateado
  162.                              ; 1: se emplea memoria XMS 2.0+
  163.                              ; 2:  "    "     "     EMS 3.2+
  164.                              ; 3:  "    "     " convencional
  165.                              ; 0FFh: aún no ejecutada INIT
  166.  
  167. cambiado       DB    ?       ; al formatear el disco virtual se pone
  168.                              ; a 0FFh (para indicar cambio de disco)
  169.  
  170. mem_handle     DW    ?       ; para memoria EMS/XMS; si se utiliza
  171.                              ; memoria convencional, apunta al
  172.                              ; segmento donde empieza el disco
  173.  
  174. tdsk_psp       DW    ?       ; segmento del PSP residente si se
  175.                              ; utiliza memoria convencional
  176.  
  177. ems_pagina0    DW    ?       ; segmento de página EMS (si se emplea)
  178. ems_paginai    DW    ?       ; segmento alternativo
  179. ems_pagni      DB    ?       ; nº de página física alternativa
  180.  
  181. xms_driver     LABEL DWORD   ; dirección del controlador XMS, en el
  182. xms_desp       DW    ?       ; caso de emplear memoria XMS.
  183. xms_segm       DW    ?
  184.  
  185. cpu386         DB    OFF     ; a ON si 386 ó superior
  186.  
  187. f_tdsk_ctrl    EQU   $       ; final del área a actualizar
  188.  
  189. letra_unidad   DB    ?       ; letra ASCII del disco ('C', 'D',...)
  190.  
  191. bpb_ptr        DW    bpb     ; puntero al BPB del disco
  192.  
  193. rutina_larga   DB    OFF     ; a ON si reservado espacio en
  194.                              ; memoria para la larga rutina de
  195.                              ; gestión de memoria EMS.
  196.  
  197. ; ------------ Variables internas de TURBODSK; su ubicación podría
  198. ;              cambiar en futuras versiones del programa.
  199.  
  200. pcab_peticion  LABEL DWORD        ; puntero a la cabecera de petición
  201. pcab_pet_desp  DW    0
  202. pcab_pet_segm  DW    0
  203.  
  204. p_rutinas      LABEL WORD         ; tabla de rutinas del controlador
  205.                DW    init
  206.                DW    media_check
  207.                DW    build_bpb
  208.                DW    ioctl_input
  209.                DW    read
  210.                DW    read_nowait
  211.                DW    input_status
  212.                DW    input_flush
  213.                DW    write
  214.                DW    write_verify
  215.                DW    output_status
  216.                DW    output_flush
  217.                DW    ioctl_output
  218.                DW    open              ; DOS 3.0+
  219.                DW    close             ; DOS 3.0+
  220.                DW    remove            ; DOS 3.0+
  221.  
  222. media          EQU   0FAh    ; byte descriptor de medio utilizado por
  223.                              ; TURBODSK. No es 0F8h como en los discos
  224.                              ; virtuales del sistema ya que TURBODSK
  225.                              ; no es un dispositivo fijo. Este byte no
  226.                              ; es empleado por los discos estándar del
  227.                              ; dos y al ser mayor de 0F7h no provoca
  228.                              ; mensajes extraños con antiguos CHKDSKs.
  229.  
  230. bpb            LABEL BYTE    ; Estos valores del BPB son arbitrarios:
  231. bytes_sector   DW    512     ; se inicializarán si se define el disco
  232. sect_cluster   DB    1       ; al instalar desde el CONFIG; en caso
  233. sect_reserv    DW    1       ; contrario, como son correctos, el DOS
  234. num_fats       DB    1       ; no tendrá problemas para realizar sus
  235. entradas_raiz  DW    128     ; cálculos internos iniciales al instalar
  236. num_sect       DW    128     ; el driver. En concreto, el tamaño de
  237. media_byte     DB    media   ; sector influye de manera directa en el
  238. sectores_fat   DW    4       ; tamaño de los buffers de disco del DOS.
  239. fin_bpb        EQU   $
  240.  
  241. ; ------------ Rutina de estrategia del disco virtual.
  242.  
  243. estrategia     PROC  FAR
  244.                MOV   CS:pcab_pet_desp,BX
  245.                MOV   CS:pcab_pet_segm,ES
  246.                RET
  247. estrategia     ENDP
  248.  
  249. ; ------------ Rutina de interrupción del disco virtual. TURBODSK,
  250. ;              al igual que RAMDRIVE o VDISK, no define una pila
  251. ;              interna. Es responsabilidad del DOS que ésta tenga el
  252. ;              tamaño adecuado (con el disco en memoria XMS, el
  253. ;              controlador XMS puede requerir hasta 256 bytes de
  254. ;              pila). TURBODSK no consume más de 64 bytes de pila en
  255. ;              ningún momento, y sólo alrededor de 48 antes de llamar
  256. ;              al controlador XMS cuando se emplea esta memoria.
  257.  
  258. interrupcion   PROC  FAR
  259.                XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
  260.                LDS   BX,CS:pcab_peticion
  261.                MOV   AL,[BX].orden     ; AL = orden
  262.                MOV   AH,0              ; AX = orden
  263.                CMP   AL,CS:num_ordenes
  264.                JB    orden_ok          ; orden soportada
  265.                MOV   AL,3              ;   " desconocida (IOCTL INPUT)
  266. orden_ok:      CMP   CS:tipo_soporte,AH
  267.                JNE   no_test_fmt       ; tipo_soporte distinto de 0
  268.                MOV   AX,8102h          ; disco no formateado: error
  269.                JMP   exit_interr
  270. no_test_fmt:   SHL   AX,1              ; orden = orden * 2
  271.                MOV   SI,AX
  272.                XPUSH <BX,DS>
  273.                XOR   BP,BP
  274.                MOV   AX,100h
  275.                CALL  CS:[SI+OFFSET p_rutinas]  ; ejecutar orden
  276.                XPOP  <DS,BX>
  277.                AND   AH,AH
  278.                JNS   exit_interr          ; no hubo error (bit 15 = 0)
  279.                CMP   AL,3
  280.                JE    exit_interr          ; error de orden desconocida
  281.                MOV   [BX].transfer_sect,0 ; otro: movidos 0 sectores
  282. exit_interr:   MOV   [BX].estado,AX
  283.                XPOP  <ES,DS,BP,DI,SI,DX,CX,BX,AX>
  284.                RET
  285. interrupcion   ENDP
  286.  
  287. ; ------------ Las rutinas que controlan el dispositivo devuelven AX
  288. ;              con la palabra de estado. Pueden cambiar todos los
  289. ;              registros (de 16 bits), incluídos los de segmento. A la
  290. ;              entrada, BP=0 y AX=100h.
  291.  
  292. media_check:   MOV   AL,CS:cambiado    ; condición de «disco cambiado»
  293.                MOV   CS:cambiado,AH    ; de momento ya no cambiará más
  294.                MOV   [BX].cambio,AL
  295.  
  296. read_nowait:                           ; conjunto de órdenes con
  297. input_status:                          ; tratamiento idéntico
  298. input_flush:
  299. output_status:
  300. output_flush:
  301. ioctl_output:
  302. open:
  303. close:
  304. retorno_ok:    RET                     ; no hay error, ignorar orden
  305.  
  306. build_bpb:     MOV   [BX].bpb_cmd_desp,OFFSET bpb
  307.                MOV   [BX].bpb_cmd_segm,CS
  308.                JMP   retorno_ok
  309.  
  310. ioctl_input:   MOV   AX,8103h          ; orden no soportada
  311.                RET
  312.  
  313. remove:        MOV   AH,3              ; fin de función, indicar
  314.                RET                     ; «controlador ocupado»
  315.  
  316. nueva_int19    PROC                    ; Interceptar reinicialización
  317.                .286
  318.                PUSHA
  319.                XPUSH <DS,ES>           ; Esto es una interrupción
  320.                XOR   AX,AX
  321.                MOV   ES,AX
  322.                CMP   AL,CS:tipo_soporte ; ¿Disco formateado?
  323.                JE    no_lib             ; no
  324.                MOV   CS:tipo_soporte,AL ; sí: anularlo
  325.                CALL  procesa_io        ; CF=1: liberar memoria EMS/XMS
  326. no_lib:        LEA   SI,ant19off
  327.                MOV   DI,64h            ; desplazamiento de INT 19h
  328.                PUSH  CS
  329.                POP   DS
  330.                CLI
  331.                MOVSW
  332.                MOVSW
  333.                XPOP  <ES,DS>
  334.                POPA
  335.                DB    0EAh              ; código de JMP FAR SEG:OFF
  336. ant19off       DW    ?
  337. ant19seg       DW    ?
  338.                .8086
  339. nueva_int19    ENDP
  340.  
  341. read:          INC   BP                ; indicar lectura (BP=1)
  342. write:                                 ; escritura (BP=0)
  343. write_verify:
  344.  
  345. init_io        PROC                        ; preparar registros E/S
  346.                LES   DI,DWORD PTR [BX].transfer_desp  ; * direc. ES:DI
  347.                LDS   AX,DWORD PTR [BX].transfer_sect  ; nº sectores AX
  348.                MOV   BX,DS                 ; 1º sector ¡DS indefinido!
  349. io_proc:       MOV   SI,CS:bytes_sector
  350.                ADD   AX,BX
  351.                JNC   io_ok?                ; último sector < 65536
  352. io_no_ok:      MOV   AX,8108h              ; «sector no encontrado»
  353.                RET
  354. io_ok?:        CMP   AX,CS:num_sect
  355.                JA    io_no_ok              ; sector final ¡fuera!
  356.                SUB   AX,BX
  357.                MUL   SI                    ; DX(CF):AX = tamaño bloque
  358.                RCR   AX,1                  ; CF:AX/2 -> AX = palabras
  359.                MOV   CX,DI
  360.                NEG   CX                    ; 10000h-CX: CF=1 si CX<>0
  361.                CMC                         ; CF:CX bytes hasta fin de
  362.                RCR   CX,1                  ; segmento = (10000h-DI)/2
  363.                CMP   AX,CX
  364.                JAE   io_cx_ok
  365.                MOV   CX,AX                 ; * tamaño: CX palabras
  366. io_cx_ok:      JCXZ  io_no_ok              ; CX=0 si DI=0FFFFh (fatal)
  367.                MOV   AX,BX                 ; sector inicial
  368.                MUL   SI                    ; * desplazamiento en DX:AX
  369.                CLC                         ; ¡no reinicializando!
  370. init_io        ENDP
  371.  
  372. ; ------------ Area residente dependiente del tipo de memoria empleada
  373. ;              por el disco. La rutina instalada por defecto es la más
  374. ;              larga de todas, para «dejar hueco» donde copiar encima
  375. ;              las otras si se va a utilizar otro tipo de memoria. Si
  376. ;              se modifican las rutinas, convendría medirlas por si
  377. ;              acaso la de memoria EMS deja de ser la más larga...
  378.  
  379. procesa_io     EQU   $
  380.  
  381.                ; ---- La rutina de gestión de memoria EMS transfiere
  382.                ;      bloques de hasta 16Kb de una vez. Intenta mapear
  383.                ;      en la página física 0: si no puede, debido a un
  384.                ;      solapamiento con el buffer de transferencia del
  385.                ;      programa principal (si está también en memoria
  386.                ;      EMS), utiliza otra página alternativa que dista
  387.                ;      al menos 32 Kb absolutos de la 0. Para dilucidar
  388.                ;      si hay solapamiento, se compara la distancia
  389.                ;      entre direcciones origen y destino antes de la
  390.                ;      transferencia: si es mayor de 401h párrafos
  391.                ;      (16400 bytes, 16 para redondeo) no hay problema.
  392.                ;      Ante un solapamiento se procede a restaurar el
  393.                ;      contexto de las páginas mapeadas, antes y
  394.                ;      después de la transferencia, para poder acceder
  395.                ;      a la memoria expandida donde está el buffer del
  396.                ;      programa principal.
  397.  
  398. procesa_ems    PROC
  399.                JNC   no_emslib
  400.                MOV   DH,45h            ; sistema reinicializando:
  401.                CALL  llama_EMM         ; liberar memoria EMS
  402.                RET
  403. no_emslib:     MOV   SI,DX             ; preservar DX
  404.                MOV   DH,47h
  405.                CALL  llama_EMM         ; DH=47h -> salvar contexto EMS
  406.                MOV   DX,SI             ; recuperar DX
  407.                MOV   BX,4000h          ; tamaño de página (16 Kb)
  408.                DIV   BX                ; AX = 1ª página EMS a mapear
  409.                MOV   SI,DX             ; offset relativo en 1ª página
  410. procesa_pag:   PUSH  CX                ; **
  411.                MOV   BX,DI
  412.                MOV   CL,4
  413.                SHR   BX,CL             ; bytes del offset -> párrafos
  414.                MOV   CX,ES
  415.                ADD   BX,CX             ; AX = segmento de datos
  416.                MOV   CX,CS:ems_pagina0
  417.                MOV   DS,CX
  418.                XOR   DL,DL             ; intentar emplear página 0
  419.                SUB   BX,CX
  420.                JNC   rpos
  421.                NEG   BX                ; valor absoluto
  422. rpos:          CMP   BX,401h           ; distancia respecto página EMS
  423.                JAE   no_conflicto      ; más de 16 Kb: no solapamiento
  424.                CALL  copia_contexto    ; está CX apilado
  425.                MOV   DS,CS:ems_paginai
  426.                MOV   DL,CS:ems_pagni   ; usar página alternativa
  427.                OR    BP,8000h          ; indicar su uso
  428. no_conflicto:  POP   CX                ; * pila totalmente equilibrada
  429.                MOV   BX,AX
  430.                MOV   DH,44h            ; DL = 0 ó 2 (página física)
  431.                CALL  llama_EMM         ; DH = 44h -> mapear página EMS
  432.                XPUSH <CX,SI>           ; ++
  433.                SUB   SI,4000h
  434.                NEG   SI                ; SI = 4000h - SI: «resto»
  435.                SHR   SI,1              ; bytes -> palabras
  436.                CMP   CX,SI
  437.                JB    cx_ok             ; no ocupada toda la página
  438.                MOV   CX,SI
  439. cx_ok:         POP   SI                ; + SI=desplazamiento relativo
  440.                CLD
  441.                POP   BX                ; + palabras restantes
  442.                SUB   BX,CX             ; descontar las que se moverán
  443.                PUSH  BX                ; * volver a apilar el viejo CX
  444.                CALL  coloca_regs
  445.                CMP   CS:cpu386,ON      ; ¿386 o superior?
  446.                JNE   trans_16bit
  447.                .386
  448.                PUSHAD
  449.                SHR   CX,1              ; nº palabras de 32 bit a mover
  450.                JCXZ  transferido       ; evitar desgracia
  451.                XOR   EAX,EAX           ; asegurar no violación
  452.                DEC   AX                ; de segmento-64K
  453.                AND   ECX,EAX           ; EAX = 0FFFFh
  454.                AND   ESI,EAX
  455.                AND   EDI,EAX
  456.                REP   MOVSD             ; transferencia ultrarrápida
  457. transferido:   POPAD                   ; POPAD falla en muchos 386
  458.                .8086
  459.                NOP                     ; arreglar fallo de POPAD
  460.                ADD   CX,CX
  461.                ADD   DI,CX             ; simular cambio normal de DI
  462.                ADD   SI,CX             ; y de SI
  463.                JMP   fin_trans
  464. trans_16bit:   REP   MOVSW             ; mover palabras de 16 bit
  465. fin_trans:     CALL  coloca_regs
  466.                AND   BP,BP             ; ¿se usó página alternativa?
  467.                JNS   ahorra_ms
  468.                CALL  copia_contexto    ; está CX apilado
  469.                AND   BP,1              ; de momento, no se usará más
  470. ahorra_ms:     POP   CX                ; **
  471.                JCXZ  fin_leer          ; no quedan más palabras
  472.                INC   AX                ; próxima página EMS
  473.                XOR   SI,SI             ; ahora desde inicio página EMS
  474.                JMP   procesa_pag
  475. fin_leer:      MOV   DH,48h
  476.                CALL  llama_EMM         ; DH=47h restaurar contexto EMS
  477.                MOV   AX,100h           ; no hubo problemas
  478.                RET
  479. procesa_ems    ENDP
  480.  
  481.                ; ---- ¡Cuidado!: esta rutina debe ser invocada siempre
  482.                ;      con la pila (SP) tal y como estaba al principio
  483.                ;      del procedimiento «procesa_ems», y utilizando
  484.                ;      siempre CALL, para que en el caso de que haya
  485.                ;      errores retorne correctamente al nivel anterior
  486.                ;      (nivel previo a «procesa_ems»). Se corrompe DX
  487.                ;      y, si hay error, AX también (devuelve 810Ch).
  488.  
  489. llama_EMM      PROC
  490.                XPUSH <AX,BX,CX,BP>
  491.                MOV   AX,DX             ; función en AX
  492. llama_denuevo: MOV   DX,CS:mem_handle  ; handle EMS
  493.                XPUSH <AX,BX>
  494.                INT   67h               ; llamar al EMM
  495.                MOV   CL,AH
  496.                XPOP  <BX,AX>
  497.                AND   CL,CL
  498.                JZ    llama_ok          ; además, ZF = 1
  499.                CMP   CL,82h
  500.                JE    llama_denuevo     ; intentarlo hasta que funcione
  501. llama_ok:      XPOP  <BP,CX,BX,AX>
  502.                JNE   ret_atras
  503.                RET
  504. ret_atras:     POP   AX                ; sacar dirección de retorno
  505.                MOV   AX,810Ch          ; error de «anomalía general»
  506.                RET                     ; retornar dos niveles atrás
  507. llama_EMM      ENDP
  508.  
  509.                ; ---- ¡Cuidado!: esta rutina debe ser invocada siempre
  510.                ;      con CX (y sólo CX) apilado: recarga CX desde la
  511.                ;      pila y corrompe BX dejando aún en la pila CX.
  512.  
  513. copia_contexto PROC
  514.                XPOP  <BX,CX>           ; equilibrar pila a llama_EMM
  515.                MOV   DH,48h
  516.                CALL  llama_EMM         ; restaurar contexto EMS
  517.                MOV   DH,47h
  518.                CALL  llama_EMM         ; preservarlo de nuevo
  519.                PUSH  CX
  520.                JMP   BX                ; más rápido que PUSH BX/RET
  521. copia_contexto ENDP
  522.  
  523. coloca_regs    PROC                    ; ¿invertir sentido?
  524.                TEST  BP,1
  525.                JNZ   colocados
  526.                XCHG  SI,DI             ; escritura: invertir sentido
  527.                XPUSH <DS,ES>
  528.                XPOP  <DS,ES>
  529. colocados:     RET
  530. coloca_regs    ENDP
  531.  
  532. tam_proc_ems   EQU   $-OFFSET procesa_ems   ; tamaño de esta rutina
  533.  
  534.                ; <<< Fin del código residente del disco virtual >>>
  535.  
  536.  
  537. ; ************ Instalación (invocada desde CONFIG.SYS).
  538.  
  539. init           PROC
  540.                MOV   CS:modo,CONFIG         ; ejecutando desde CONFIG
  541.                CALL  obtDosVer              ; obtener versión del DOS
  542.                LEA   AX,retorno_ok
  543.                MOV   CS:p_rutinas,AX        ; anular rutina INIT
  544.                INC   CS:tipo_soporte        ; 0: disco no formateado
  545.                MOV   CS:cs_tdsk,CS          ; inicializar esa variable
  546.                CMP   CS:dosver,300h         ; ¿DOS inferior al 3.0?
  547.                JAE   dos_ok                 ; DOS 3.0+
  548.                AND   CS:tipo_drive,0F7FFh   ; ajustar atributos
  549.                MOV   CS:num_ordenes,0Dh     ; y número de órdenes
  550. dos_ok:        MOV   SI,[BX].bpb_cmd_desp
  551.                MOV   ES,[BX].bpb_cmd_segm   ; ES:SI -> parámetros
  552.                MOV   [BX].num_discos,1      ; una unidad de disco
  553.                LEA   AX,bpb_ptr
  554.                MOV   [BX].bpb_cmd_desp,AX
  555.                MOV   [BX].bpb_cmd_segm,CS   ; inicializado puntero BPB
  556.                CALL  desvia_int19           ; controlar INT 19h
  557.                CALL  inic_letra             ; obtener letra de unidad
  558.                MOV   BX,CS
  559.                MOV   DS,BX                  ; DS: -> _PRINCIPAL
  560.                MOV   BX,SI                  ; ES:BX -> parámetros
  561.                CALL  salta_nombre           ; buscar inicio parámetros
  562.                CALL  procesar_param         ; procesar parámetros
  563.                PUSH  DS                     ;
  564.                POP   ES                     ; ES: -> _PRINCIPAL
  565.                CMP   param_h,ON
  566.                JE    fin_instalar           ; piden ayuda
  567.                CALL  max_sector             ; obtener mayor sector
  568.                MOV   BX,param_tsect
  569.                CMP   BX,AX                  ; ¿el nuestro es mayor?
  570.                JBE   sect_def_ok            ; no
  571.                MOV   bytes_sector,BX        ; sí: ajustar BPB
  572. sect_def_ok:   CALL  errores_config
  573.                TEST  lista_err,ERROR0+ERROR1
  574.                JNZ   fin_instalar           ; algún error importante
  575.                CMP   param_tdisco,0         ; ¿se define disco ahora?
  576.                JE    fin_instalar           ; no: no hay más que hacer
  577.                CALL  mem_info               ; evaluar memoria del PC
  578.                CMP   tdisco,0               ; ¿se reservará memoria?
  579.                JE    fin_instalar           ; no: no hay más que hacer
  580.                CALL  mem_reserva            ; reservar memoria
  581.                JC    fin_instalar           ; fallo al reservarla
  582.                CALL  test_CPU               ; detectar 386 ó superior
  583.                CALL  adaptar_param          ; adaptar parámetros disco
  584.                CALL  preparar_BPB           ; BPB del nuevo disco
  585.                CALL  prep_driver            ; preparar el driver
  586.                CALL  formatear_tdsk         ; inic. BOOT, FAT y ROOT
  587. fin_instalar:  CALL  info_disco             ; informar sobre el disco
  588.                CMP   tipo_soporte,2
  589.                JE    res_largo              ; se utiliza memoria EMS
  590.                CMP   param_a,ON
  591.                JE    res_largo              ; se indicó /A
  592.                CALL  eval_xms
  593.                CALL  eval_ems
  594.                CMP   ems_kb,0
  595.                JE    res_corto              ; no hay memoria EMS
  596.                CMP   xms_kb,0
  597.                JNE   res_corto              ; la hay, pero también XMS
  598. res_largo:     MOV   AX,tam_proc_ems
  599.                MOV   rutina_larga,ON        ; dejar sitio a rutina EMS
  600.                JMP   bytes_res_ok
  601. res_corto:     MOV   AX,tam_proc_xms        ; dejar sitio a XMS/conv.
  602.                MOV   BX,tam_proc_con
  603.                CMP   AX,BX
  604.                JAE   bytes_res_ok
  605.                XCHG  AX,BX
  606. bytes_res_ok:  LDS   BX,CS:pcab_peticion
  607.                ADD   AX,OFFSET procesa_io
  608.                MOV   [BX].fin_resid_desp,AX ; reservar memoria para
  609.                MOV   [BX].fin_resid_segm,CS ; las rutinas a usar
  610.                MOV   AX,100h                ; instalación siempre Ok.
  611.                RET
  612. init           ENDP
  613.  
  614. ; ------------ Redefinición (invocada desde el AUTOEXEC.BAT o el DOS).
  615.  
  616. main           PROC  FAR
  617.                MOV   CS:modo,AUTOEXEC       ; ejecutando desde el DOS
  618.                CALL  obtDosVer              ; obtener versión del DOS
  619.                CALL  gestionar_ram          ; gestión de memoria
  620.                MOV   AX,_PRINCIPAL          ; programa de un segmento
  621.                MOV   DS,AX                  ; DS: -> _PRINCIPAL
  622.                MOV   BX,81h                 ; ES:BX línea de órdenes
  623.                CALL  procesar_param         ; procesar parámetros
  624.                CMP   param_h,ON
  625.                JE    exit_instalar          ; piden ayuda
  626.                PUSH  DS
  627.                POP   ES                     ; ES: --> _PRINCIPAL
  628.                CALL  errores_Dos
  629.                TEST  err_grave,0FFFFh
  630.                JNZ   exit_instalar          ; algún error grave
  631.                MOV   ES,segm_tdsk           ; ES: --> disco residente
  632.                CMP   param_a,ON
  633.                JNE   cabria_ems
  634.                CMP   ES:rutina_larga,ON
  635.                JE    cabria_ems             ; cabe la rutina EMS
  636.                OR    lista_err,ERROR2
  637. cabria_ems:    TEST  lista_err,ERROR0+ERROR2  ; ¿error sintaxis ó EMS?
  638.                JNZ   exit_instalar          ; sí: no modificar disco
  639.                CMP   param_tdiscof,ON
  640.                JNE   exit_instalar          ; no indicado nuevo tamaño
  641.                CMP   ES:tipo_soporte,0
  642.                JE    cont_instalar          ; no estaba formateado aún
  643.                CALL  desinstala             ; liberar memoria ocupada
  644. cont_instalar: CALL  mem_info               ; evaluar memoria del PC
  645.                CMP   tdisco,0               ; ¿se reservará memoria?
  646.                JE    exit_instalar          ; no: no hay más que hacer
  647.                CALL  mem_reserva            ; reservar memoria
  648.                JC    exit_instalar          ; fallo reservando memoria
  649.                CALL  test_CPU               ; detectar 386 ó superior
  650.                CALL  adaptar_param          ; adaptar parámetros disco
  651.                CALL  preparar_BPB           ; BPB del nuevo disco
  652.                CALL  relocalizar            ; autoreubicación de TDSK
  653.                CALL  prep_driver            ; preparar el driver
  654.                CALL  formatear_tdsk         ; BOOT, FAT y ROOT
  655. exit_instalar: CALL  info_disco             ; informar sobre el disco
  656.                CMP   tipo_soporte,3         ; ¿memoria convencional?
  657.                JNE   fin_no_res             ; no usada
  658.                CALL  renombrar_mcb          ; cambiar nombre del MCB
  659.                MOV   DX,6                   ; usada: 96 bytes de PSP
  660.                MOV   AX,3100h
  661.                INT   21h                    ; terminar residente
  662. fin_no_res:    CALL  set_errorlevel         ; preparar ERRORLEVEL
  663.                MOV   AH,4Ch
  664.                INT   21h                    ; final normal
  665. main           ENDP
  666.  
  667. ; ------------ Inicializar la variable con la versión del DOS
  668.  
  669. obtDosVer      PROC
  670.                XPUSH <AX,BX,CX,DX>
  671.                MOV   AH,30h
  672.                INT   21h
  673.                XCHG  AH,AL
  674.                MOV   CS:dosver,AX
  675.                XPOP  <DX,CX,BX,AX>
  676.                RET
  677. obtDosVer      ENDP
  678.  
  679. ; ------------ Determinar segmento del PSP, último segmento de memoria
  680. ;              y liberar espacio de entorno. Se modifica también el
  681. ;              bloque de memoria de TDSK reduciéndolo a 96 bytes: esto
  682. ;              provoca la creación de un bloque de control de memoria
  683. ;              en el offset 96 del PSP, lo cual no es peligroso. El
  684. ;              objetivo de esta maniobra es poder asignar memoria al
  685. ;              disco después (sólo si hace falta memoria convencional)
  686. ;              usando los servicios estándar del DOS.
  687.  
  688. gestionar_ram  PROC
  689.                MOV   CS:segm_psp,DS         ; indicar segmento del PSP
  690.                MOV   AX,DS:[2]              ; segmento más alto
  691.                MOV   CS:top_ram,AX          ; indicar tope de memoria
  692.                PUSH  ES
  693.                MOV   ES,DS:[2Ch]            ; segmento del entorno
  694.                MOV   AH,49h
  695.                INT   21h                    ; liberar área de entorno
  696.                POP   ES                     ; ES: -> PSP
  697.                MOV   BX,6
  698.                MOV   AH,4Ah                 ; hacer creer al DOS que
  699.                INT   21h                    ; TDSK ocupa sólo 96 bytes
  700.                RET
  701. gestionar_ram  ENDP
  702.  
  703. ; ------------ Leer los parámetros de la línea de comandos (ES:BX).
  704. ;              Se inicializan las correspondientes variables. En caso
  705. ;              de error, se dejan a cero las variables y se acumula en
  706. ;              «lista_err» un ERROR0 (error de sintaxis).
  707.  
  708. procesar_param PROC
  709.                CALL  busca_param       ; saltar delimitadores
  710.                JC    fin_param         ; no hay más parámetros
  711.                CALL  param_barra       ; gestionar parámetro tipo "/A"
  712.                JC    procesar_param    ; era parámetro tipo "/A"
  713.                MOV   param_tdisco,AX   ; es numérico: tamaño del disco
  714.                MOV   param_tdiscof,ON  ; parámetro de tamaño indicado
  715. p_param2:      CALL  busca_param
  716.                JC    fin_param
  717.                CALL  param_barra
  718.                JC    p_param2
  719.                MOV   param_tsect,AX    ; tamaño de sector
  720. p_param3:      CALL  busca_param
  721.                JC    fin_param
  722.                CALL  param_barra
  723.                JC    p_param3
  724.                MOV   param_tdir,AX     ; entradas al directorio
  725. p_param4:      CALL  busca_param
  726.                JC    fin_param
  727.                CALL  param_barra
  728.                JC    p_param4
  729.                MOV   param_tcluster,AX ; tamaño de cluster
  730. p_param5:      CALL  busca_param
  731.                JC    fin_param
  732.                CALL  param_barra       ; últimas opciones posibles
  733.                JC    p_param5
  734. fin_param:     CALL  validacion        ; validación de parámetros
  735.                RET
  736. procesar_param ENDP
  737.  
  738. param_barra    PROC
  739.                CMP   AX,"e/"           ; ¿indicado /E?
  740.                JNE   p_exp1?
  741.                MOV   param_e,ON
  742.                JMP   p_barra_exit
  743. p_exp1?:       CMP   AX,"a/"           ; ¿indicado /A?
  744.                JNE   p_exp2?
  745. p_exp:         MOV   param_a,ON
  746.                JMP   p_barra_exit
  747. p_exp2?:       CMP   AX,"x/"           ; /A y /X son equivalentes
  748.                JE    p_exp
  749.                CMP   AX,"c/"           ; ¿indicado /C?
  750.                JNE   p_ayuda?
  751.                MOV   param_c,ON
  752.                JMP   p_barra_exit
  753. p_ayuda?:      CMP   AX,"h/"           ; ¿indicado /H?
  754.                JNE   p_exit?
  755. p_ayuda:       MOV   param_h,ON
  756.                JMP   p_barra_exit
  757. p_exit?:       CMP   AX,"?/"           ; /H y /? son equivalentes
  758.                JE    p_ayuda
  759.                CMP   AX,"m/"           ; ¿indicado /M?
  760.                JNE   param_id?
  761.                MOV   param_m,ON
  762.                JMP   p_barra_exit
  763. param_id?:     CMP   AX,"i/"           ; ¿indicado /I= o /I:?
  764.                JNE   param_fats?
  765.                ADD   BX,3
  766.                CMP   BYTE PTR ES:[BX-1],'='
  767.                JE    p_id_ok
  768.                CMP   BYTE PTR ES:[BX-1],':'
  769.                JNE   param_b_mal
  770. p_id_ok:       CALL  obt_num           ; leer código telefónico
  771.                MOV   param_i,ON
  772.                MOV   codigo_tfno,AX
  773.                SUB   BX,2
  774.                JMP   p_barra_exit
  775. param_fats?:   CMP   AX,"f/"           ; ¿indicado /F= o /F:?
  776.                JNE   param_unidad?
  777.                ADD   BX,3
  778.                CMP   BYTE PTR ES:[BX-1],'='
  779.                JE    p_f_ok
  780.                CMP   BYTE PTR ES:[BX-1],':'
  781.                JNE   param_b_mal
  782. p_f_ok:        CALL  obt_num           ; leer número de FATs
  783.                MOV   param_f,AX
  784.                SUB   BX,2
  785.                JMP   p_barra_exit
  786. param_unidad?: CMP   AH,':'            ; ¿parámetro de unidad?
  787.                JNE   param_num?
  788.                AND   AL,255-32         ; poner en mayúsculas
  789.                MOV   param_unidad,AL
  790.                JMP   p_barra_exit
  791. param_num?:    CMP   AL,'/'
  792.                JNE   param_num         ; puede ser número
  793. param_b_mal:   OR    lista_err,ERROR0
  794. param_num:     CALL  obt_num           ; es parámetro numérico: leerlo
  795.                CLC                     ; no es parámetro barrado
  796.                RET
  797. p_barra_exit:  ADD   BX,2              ; saltar este parámetro
  798.                STC                     ; es parámetro barrado
  799.                RET
  800. param_barra    ENDP
  801.  
  802. validacion     PROC
  803.                MOV   AX,0FFFFh
  804.                CMP   AX,param_tdisco   ; ¿números correctos?
  805.                JE    sintax_err
  806.                CMP   AX,param_tsect
  807.                JE    sintax_err
  808.                CMP   AX,param_tdir
  809.                JE    sintax_err
  810.                CMP   AX,param_tcluster
  811.                JE    sintax_err
  812.                CMP   param_tdisco,0
  813.                JE    valida_tsect      ; no indicado tamaño (o 0)
  814.                CMP   param_tdisco,8
  815.                JB    sintax_err
  816.                CMP   param_tdisco,65534
  817.                JA    sintax_err
  818. valida_tsect:  MOV   AX,param_tsect
  819.                CMP   AX,0
  820.                JE    valida_tclus      ; no indicado tamaño de sector
  821.                CMP   AX,32
  822.                JE    valida_tclus
  823.                CMP   AX,64
  824.                JE    valida_tclus
  825.                CMP   AX,128
  826.                JE    valida_tclus
  827.                CMP   AX,256
  828.                JE    valida_tclus
  829.                CMP   AX,512
  830.                JE    valida_tclus
  831.                CMP   AX,1024
  832.                JE    valida_tclus
  833.                CMP   AX,2048
  834.                JNE   sintax_err
  835. valida_tclus:  CMP   param_tcluster,256
  836.                JAE   sintax_err        ; debe estar entre 0..255
  837.                CMP   param_f,1
  838.                JB    pf_a1             ; /F=1 ó /F=2 exclusivamente
  839.                CMP   param_f,2         ; si no, forzarlo y perdonar
  840.                JBE   fin_validar
  841.                MOV   param_f,2
  842.                JMP   fin_validar
  843. pf_a1:         MOV   param_f,1
  844.                JMP   fin_validar
  845. sintax_err:    MOV   param_tdiscof,OFF ; no definir disco ahora
  846.                XOR   AX,AX
  847.                MOV   param_tdisco,AX
  848.                MOV   param_tsect,AX
  849.                MOV   param_tdir,AX
  850.                MOV   param_tcluster,AX
  851.                OR    lista_err,ERROR0  ; aviso de error de sintaxis
  852. fin_validar:   RET
  853. validacion     ENDP
  854.  
  855. salta_nombre   PROC                    ; saltar nombre del driver en
  856.                MOV   AL,ES:[BX]        ; línea de órdenes del CONFIG
  857.                INC   BX
  858.                CMP   AL,' '
  859.                JE    fin_nombre
  860.                CMP   AL,9
  861.                JE    fin_nombre
  862.                CMP   AL,0Dh
  863.                JE    fin_nombre
  864.                CMP   AL,0Ah
  865.                JE    fin_nombre
  866.                AND   AL,AL
  867.                JZ    fin_nombre        ; necesario para DOS 2.x
  868.                JMP   salta_nombre
  869. fin_nombre:    DEC   BX
  870.                RET
  871. salta_nombre   ENDP
  872.  
  873. busca_param    PROC                    ; saltar delimitadores
  874.                DEC   BX
  875. p_delimit:     INC   BX
  876.                MOV   AX,ES:[BX]
  877.                CMP   AL,' '
  878.                JE    p_delimit         ; espacio en blanco
  879.                CMP   AL,9
  880.                JE    p_delimit         ; tabulador
  881.                CMP   AL,13
  882.                JE    p_final           ; CR ó LF indican el final
  883.                CMP   AL,10
  884.                JE    p_final
  885.                OR    AX,"  "           ; poner en minúsculas
  886.                CLC
  887.                RET
  888. p_final:       STC                     ; se acabaron los parámetros
  889.                RET
  890. busca_param    ENDP
  891.  
  892. obt_num        PROC                    ; leer número: devolver 65535
  893.                XPUSH <CX,DX,SI>        ; si hay error
  894.                XOR   AX,AX             ; número en proceso de creación
  895. otro_digito:   MOV   CL,ES:[BX]
  896.                CMP   CL,'0'
  897.                JB    no_digito
  898.                CMP   CL,'9'
  899.                JBE   digito_ok
  900. no_digito:     CMP   CL,' '            ; posibles delimitadores...
  901.                JE    fin_num
  902.                CMP   CL,9
  903.                JE    fin_num
  904.                CMP   CL,13
  905.                JE    fin_num
  906.                CMP   CL,10
  907.                JE    fin_num
  908.                CMP   CL,'/'
  909.                JE    fin_num
  910.                JMP   num_incorr
  911. digito_ok:     XOR   DX,DX
  912.                MOV   SI,10
  913.                MUL   SI                ; AX = AX * 10
  914.                JC    num_incorr
  915.                XOR   CH,CH
  916.                SUB   CL,'0'
  917.                ADD   AX,CX             ; AX = AX + dato
  918.                JC    num_incorr
  919.                INC   BX
  920.                JMP   otro_digito
  921. num_incorr:    MOV   AX,65535          ; indicar valor incorrecto
  922. fin_num:       XPOP  <SI,DX,CX>
  923.                RET
  924. obt_num        ENDP
  925.  
  926. ; ------------ Detectar errores que se pueden producir sólo en la
  927. ;              línea de comandos.
  928.  
  929. errores_Dos    PROC
  930.                PUSH  ES
  931.                CMP   dosver,200h       ; necesario DOS 2.x+
  932.                JAE   existe_tdsk?
  933.                OR    err_grave,ERROR0  ; error de DOS incorrecto
  934.                JMP   fin_err_Dos
  935. existe_tdsk?:  CALL  reside_tdsk?      ; ¿instalado TURBODSK?
  936.                CMP   segm_tdsk,0
  937.                JNE   busca_unidad      ; ya instalado
  938.                OR    err_grave,ERROR1  ; error: TURBODSK no instalado
  939.                JMP   fin_err_Dos
  940. busca_unidad:  MOV   ES,segm_tdsk      ; ES: -> disco virtual
  941.                CMP   param_unidad,0
  942.                JE    disco_defecto     ; no se indicó letra de unidad
  943.                CALL  obtener_segm      ; segmento del TDSK indicado
  944.                JC    fin_err_Dos       ; fallo (no es unidad TDSK)
  945. disco_defecto: CALL  max_sector        ; obtener mayor sector
  946.                MOV   BX,param_tsect
  947.                CMP   BX,AX
  948.                JBE   fin_err_Dos       ; tamaño de sector correcto
  949.                OR    lista_err,ERROR3  ; el tamaño no definible ahora
  950.                MOV   param_tsect,0     ; ignorar tamaño indicado
  951. fin_err_Dos:   CALL  test32Mb
  952.                CALL  testWin
  953.                POP   ES
  954.                RET
  955. errores_Dos    ENDP
  956.  
  957. ; ------------ Detectar errores que se pueden producir sólo desde
  958. ;              el CONFIG.SYS
  959.  
  960. errores_config PROC
  961.                CMP   param_unidad,0
  962.                JE    no_unidad
  963.                OR    lista_err,ERROR1
  964. no_unidad:     CMP   param_c,ON
  965.                JNE   fin_err_con
  966.                OR    lista_err,ERROR1
  967. fin_err_con:   CALL  test32Mb
  968.                RET
  969. errores_config ENDP
  970.  
  971. ; ------------ Preparar valor de ERRORLEVEL para el retorno.
  972.  
  973. set_errorlevel PROC
  974.                MOV   AL,255
  975.                TEST  err_grave,ERROR1  ; ¿TDSK no instalado?
  976.                JNZ   fin_cod_ok
  977.                DEC   AL
  978.                TEST  err_grave,ERROR2  ; ¿unidad incorrecta?
  979.                JNZ   fin_cod_ok
  980.                DEC   AL
  981.                TEST  err_grave,ERROR3  ; ¿dentro de Windows?
  982.                JNZ   fin_cod_ok
  983.                DEC   AL
  984.                TEST  lista_err,ERROR0  ; error de sintaxis
  985.                JNZ   fin_cod_ok
  986.                CMP   param_h,ON        ; ayuda: handle desconocido
  987.                JE    fin_cod_ok
  988.                MOV   AL,BYTE PTR ES:mem_handle  ; handle XMS/EMS
  989.                CMP   ES:tipo_soporte,0
  990.                JNE   fin_cod_ok
  991.                MOV   AL,0              ; disco no formateado
  992. fin_cod_ok:    RET
  993. set_errorlevel ENDP
  994.  
  995. ; ------------ Obtener mayor tamaño de sector definido en el sistema.
  996.  
  997. max_sector     PROC
  998.                XPUSH <BX,ES>
  999.                MOV   AH,52h
  1000.                INT   21h               ; Get List of Lists
  1001.                ADD   BX,10h
  1002.                CMP   CS:dosver,30Ah
  1003.                JAE   psect_ok
  1004.                INC   BX                ; DOS anterior al 3.1
  1005. psect_ok:      MOV   AX,ES:[BX]        ; mayor tamaño de sector
  1006.                XPOP  <ES,BX>           ; definido por cualquier disp.
  1007.                RET
  1008. max_sector     ENDP
  1009.  
  1010. ; ------------ Si el disco es de más de 32 Mb, comprobar si el sector
  1011. ;              es de al menos 1024 bytes.
  1012.  
  1013. test32Mb       PROC
  1014.                CMP   param_tdisco,32768
  1015.                JBE   fin32mb
  1016.                CMP   param_tsect,1024
  1017.                JAE   fin32mb
  1018.                OR    lista_err,ERROR15      ; sector de menos de 1024
  1019.                MOV   param_tdisco,32768     ; evitar fallo posterior
  1020. fin32mb:       RET
  1021. test32Mb       ENDP
  1022.  
  1023. ; ------------ Desde Windows, no se permite redefinir el disco.
  1024.  
  1025. testWin        PROC
  1026.                CMP   param_tdiscof,ON
  1027.                JNE   fin_testWin       ; no redefinido el disco
  1028.                CMP   dosver,300h
  1029.                JB    fin_testWin       ; no buscar Windows en DOS 2.x
  1030.                MOV   AX,1600h
  1031.                INT   2Fh
  1032.                AND   AL,AL             ; ¿Windows en modo extendido?
  1033.                JZ    noWinEnh
  1034.                CMP   AL,80h            ; ¿Windows en modo extendido?
  1035.                JE    noWinEnh
  1036. siWin:         OR    err_grave,ERROR3  ; estamos dentro de Windows
  1037.                JMP   fin_testWin
  1038. noWinEnh:      MOV   AX,4680h
  1039.                INT   2Fh
  1040.                AND   AX,AX
  1041.                JZ    siWin             ; Windows en modo real/estándar
  1042. fin_testWin:   RET
  1043. testWin        ENDP
  1044.  
  1045. ; ------------ Verificar la presencia en memoria de TURBODSK. Se
  1046. ;              inicializa «segm_tdsk» y «letra_unidad» indicando dónde
  1047. ;              reside el primer dispositivo TURBODSK de todos los que
  1048. ;              puede haber instalados. La letra de la unidad se halla
  1049. ;              del propio TDSK residente, para evitar conflictos con
  1050. ;              programas que manipulan ilegalmente la lista de
  1051. ;              unidades, del tipo de Stacker o Smartdrive.
  1052.  
  1053. reside_tdsk?   PROC
  1054.                XPUSH <AX, SI>
  1055.                CALL  lista_discos
  1056.                LEA   SI,area_trabajo-4
  1057. busca_final:   ADD   SI,4
  1058.                CMP   WORD PTR [SI],0
  1059.                JNE   busca_final       ; ir al final de la tabla
  1060. busca_tdsk:    SUB   SI,4
  1061.                CMP   SI,OFFSET area_trabajo
  1062.                JB    fin_busca         ; no reside (segm_tdsk = 0)
  1063.                CMP   BYTE PTR [SI+3],1
  1064.                JNE   busca_tdsk
  1065.                MOV   AX,[SI]           ; encontrada unidad TURBODSK
  1066.                MOV   segm_tdsk,AX
  1067.                PUSH  DS
  1068.                MOV   DS,AX
  1069.                MOV   AL,letra_unidad   ; con esta letra de unidad
  1070.                POP   DS
  1071.                MOV   letra_unidad,AL
  1072. fin_busca:     XPOP  <SI, AX>
  1073.                RET
  1074. reside_tdsk?   ENDP
  1075.  
  1076. ; ------------ Obtener el segmento de la unidad TURBODSK indicada, si
  1077. ;              existe, accediendo a una tabla de dispositivos que se
  1078. ;              crea. A la salida, CF=1 si esa unidad no es TURBODSK.
  1079.  
  1080. obtener_segm   PROC
  1081.                CALL  lista_discos
  1082.                LEA   SI,area_trabajo-4
  1083. busca_ultimo:  ADD   SI,4
  1084.                CMP   WORD PTR [SI],0
  1085.                JNE   busca_ultimo      ; realmente, el primero
  1086. recorre_dsks:  SUB   SI,4
  1087.                CMP   SI,OFFSET area_trabajo
  1088.                JB    tdsk_no_hay
  1089.                CMP   BYTE PTR [SI+3],1
  1090.                JNE   recorre_dsks
  1091.                PUSH  DS
  1092.                MOV   DS,[SI]
  1093.                MOV   AL,letra_unidad   ; unidad del TDSK residente
  1094.                POP   DS
  1095.                CMP   AL,param_unidad   ; disco TDSK: ¿es el buscado?
  1096.                JNE   recorre_dsks
  1097.                MOV   letra_unidad,AL   ; inicializar letra de unidad
  1098.                MOV   AX,[SI]
  1099.                MOV   segm_tdsk,AX      ; inicializar segmento
  1100.                MOV   ES,AX
  1101.                CLC
  1102.                RET
  1103. tdsk_no_hay:   OR    err_grave,ERROR2  ; unidad indicada no es TDSK
  1104.                STC
  1105.                RET
  1106. obtener_segm   ENDP
  1107.  
  1108. ; ------------ Colocar nuevo gestor de INT 19h al instalar TDSK desde
  1109. ;              el CONFIG.SYS. En algunos entornos multitarea basados
  1110. ;              en el modo virtual-86 del 386 y superiores, si no se
  1111. ;              libera la memoria EMS/XMS tras una cancelación de la
  1112. ;              tarea virtual, ésta queda permanentemente ocupada hasta
  1113. ;              un reset «frío» del sistema, sin poder ser aprovechada
  1114. ;              por los demás procesos. La INT 19h se ejecuta cuando la
  1115. ;              tarea en curso va a ser inminentemente cancelada por el
  1116. ;              sistema, y TURBODSK la intercepta para poder liberar la
  1117. ;              memoria EMS/XMS en el último instante. La rutina que
  1118. ;              controla INT 19h contiene código de 286, por lo que se
  1119. ;              chequea la presencia de este procesador.
  1120.  
  1121. desvia_int19   PROC
  1122.                XPUSH <BX,DS,ES>
  1123.                MOV   BX,CS
  1124.                MOV   DS,BX
  1125.                CALL  test_CPU
  1126.                CMP   cpu286,ON
  1127.                JNE   fin_desvia19      ; no es 286 ó superior
  1128.                MOV   AX,3519h
  1129.                INT   21h               ; ES:BX anterior INT 19h
  1130.                MOV   ant19off,BX
  1131.                MOV   ant19seg,ES
  1132.                LEA   DX,nueva_int19
  1133.                MOV   AX,2519h
  1134.                INT   21h               ; nueva rutina de control
  1135. fin_desvia19:  XPOP  <ES,DS,BX>
  1136.                RET
  1137. desvia_int19   ENDP
  1138.  
  1139. ; ------------ Obtener la letra de la unidad de disco definida. Esta
  1140. ;              rutina se invoca sólo desde CONFIG.SYS con DS:BX
  1141. ;              apuntando a la cabecera de petición de la orden INIT.
  1142.  
  1143. inic_letra     PROC
  1144.                XPUSH <AX,BX,SI,DS>
  1145.                MOV   AL,[BX].nuevo_disco    ; unidad en DOS 3.0+
  1146.                ADD   AL,'A'
  1147.                PUSH  CS
  1148.                POP   DS                     ; DS -> _PRINCIPAL
  1149.                CMP   dosver,300h
  1150.                JAE   letra_ok
  1151.                CALL  lista_discos           ; hallar unidad en DOS 2.x
  1152.                LEA   SI,area_trabajo
  1153.                XOR   AL,AL                  ; cuenta de discos
  1154. cuenta_discos: ADD   AL,[SI+2]
  1155.                ADD   SI,4
  1156.                CMP   WORD PTR [SI],0
  1157.                JNE   cuenta_discos
  1158.                ADD   AL,'A'
  1159. letra_ok:      MOV   letra_unidad,AL        ; guardar letra de unidad
  1160.                XPOP  <DS,SI,BX,AX>
  1161.                RET
  1162. inic_letra     ENDP
  1163.  
  1164. ; ------------ Crear una lista de todos los dispositivos de bloque
  1165. ;              del sistema. La lista tiene una entrada de 4 bytes
  1166. ;              para cada dispositivo: los dos primeros indican el
  1167. ;              segmento en que reside, el siguiente el número de
  1168. ;              unidades que controla y el último vale 1 ó 0 para
  1169. ;              indicar si es una unidad TDSK o no. El final de la
  1170. ;              lista lo señaliza un segmento igual a 0.
  1171.  
  1172. lista_discos   PROC
  1173.                XPUSH <AX,BX,CX,DX,SI,DI,ES>
  1174.                MOV   AH,52h            ; "Get list of lists"
  1175.                INT   21h               ; obtener puntero en ES:BX
  1176.                MOV   CX,17h            ; supuesto DOS 2.x
  1177.                CMP   dosver,300h
  1178.                JB    pdisp_ok
  1179.                MOV   CX,28h            ; supuesto DOS 3.0x
  1180.                CMP   dosver,30Ah
  1181.                JB    pdisp_ok
  1182.                MOV   CX,22h            ; versiones del DOS superiores
  1183. pdisp_ok:      ADD   BX,CX
  1184.                LEA   DI,area_trabajo-4 ; tabla de dispositivos-4
  1185. disp_otro:     ADD   DI,4
  1186. disp_skip:     LES   BX,ES:[BX]        ; siguiente dispositivo
  1187.                CMP   BX,-1
  1188.                JE    disp_fin
  1189.                TEST  BYTE PTR ES:[BX+5],80h
  1190.                JNZ   disp_skip         ; es dispositivo de caracteres
  1191.                MOV   CL,ES:[BX+10]     ; es de bloques
  1192.                MOV   [DI],ES           ; anotar dirección
  1193.                MOV   [DI+2],CL
  1194.                MOV   BYTE PTR [DI+3],0 ; de momento, no es TDSK
  1195.                PUSH  DI
  1196.                LEA   SI,id_tdsk        ; identificación de TURBODSK
  1197.                MOV   DI,SI
  1198.                MOV   CX,5
  1199.                CLD
  1200.                REP   CMPSB             ; ¿es TURBODSK?
  1201.                POP   DI
  1202.                JNE   disp_otro         ; es de bloques, pero no TDSK
  1203.                MOV   AX,ES:cs_tdsk     ; segmento real de TDSK
  1204.                MOV   [DI],AX           ; corregir dirección en tabla
  1205.                INC   BYTE PTR [DI+3]   ; indicar dispositivo TDSK
  1206.                JMP   disp_otro         ; buscar hasta completar tabla
  1207. disp_fin:      MOV   WORD PTR [DI],0   ; final de la lista
  1208.                XPOP  <ES,DI,SI,DX,CX,BX,AX>
  1209.                RET
  1210. lista_discos   ENDP
  1211.  
  1212. ; ------------ Liberar la memoria ocupada por un TURBODSK residente.
  1213.  
  1214. desinstala     PROC
  1215.                MOV   DX,ES:mem_handle
  1216.                MOV   AL,ES:tipo_soporte
  1217.                DEC   AL
  1218.                JZ    libera_ext        ; liberar memoria extendida
  1219.                DEC   AL
  1220.                JZ    libera_exp        ; liberar memoria expandida
  1221.                PUSH  ES
  1222.                MOV   ES,DX
  1223.                MOV   AH,49h            ; liberar memoria convencional:
  1224.                INT   21h
  1225.                POP   ES
  1226.                PUSH  ES
  1227.                PUSHF                   ; condición de error
  1228.                MOV   ES,ES:tdsk_psp    ; liberar PSP residente
  1229.                MOV   AH,49h
  1230.                INT   21h
  1231.                PUSHF
  1232.                CMP   dosver,31Eh
  1233.                JA    mcb_ok            ; DOS 3.31+: el MCB es correcto
  1234.                MOV   AX,ES
  1235.                DEC   AX
  1236.                MOV   ES,AX
  1237.                MOV   DI,8
  1238.                MOV   CX,DI
  1239.                CLD
  1240.                MOV   AL,' '
  1241.                REP   STOSB             ; hasta DOS 3.30 borrar nombre
  1242. mcb_ok:        POPF
  1243.                JNC   lib_con_ok?       ; liberado correctamente
  1244.                POPF
  1245.                POP   ES
  1246.                STC                     ; ha habido fallo
  1247.                JMP   desinstalado
  1248. lib_con_ok?:   POPF                    ; recuperar condición de error
  1249.                POP   ES
  1250.                JMP   desinstalado
  1251. libera_ext:    MOV   AH,0Ah
  1252.                CALL  ES:xms_driver
  1253.                CMP   AX,1
  1254.                JE    desinstalado      ; éxito al liberar memoria XMS
  1255.                STC
  1256.                JMP   desinstalado      ; fallo
  1257. libera_exp:    MOV   AH,45h
  1258.                INT   67h
  1259.                CMP   AH,0
  1260.                JE    desinstalado
  1261.                CMP   AH,82h            ; ¿EMM ocupado?
  1262.                JE    libera_exp
  1263.                STC                     ; fallo al liberar memoria EMS
  1264. desinstalado:  MOV   ES:tipo_soporte,0 ; disco «no formateado»
  1265.                JNC   desins_ok
  1266.                OR    lista_err,ERROR14 ; fallo al liberar memoria
  1267.                STC
  1268. desins_ok:     RET
  1269. desinstala     ENDP
  1270.  
  1271. ; ------------ Determinar la configuración del sistema: tipos de
  1272. ;              memoria y cantidad de la misma. Se indica en «tdisco»
  1273. ;              un valor 0 si no se define ahora el disco, sea cual sea
  1274. ;              el motivo del fallo, y se actualiza la variable que
  1275. ;              indica los mensajes de error y advertencia a imprimir.
  1276.  
  1277. mem_info       PROC
  1278.                MOV   tdisco,0          ; ley de Murphy
  1279.                CALL  eval_xms          ; inicializar «xms_kb»
  1280.                CALL  eval_ems          ; inicializar «ems_kb»
  1281.                CALL  eval_con          ; inicializar «con_kb»
  1282.                MOV   AX,param_tdisco   ; cantidad de memoria necesaria
  1283.                CMP   param_a,ON
  1284.                JNE   no_ems            ; no solicitan memoria EMS
  1285.                MOV   BX,ems_kb         ; solicitan memoria EMS...
  1286.                AND   BX,BX
  1287.                JNZ   usara_ems
  1288.                OR    lista_err,ERROR7  ; no hay memoria EMS disponible
  1289.                JMP   mem_infoado
  1290. usara_ems:     CMP   AX,BX
  1291.                JBE   usar_ems          ; piden algo razonable
  1292.                MOV   AX,BX
  1293.                OR    lista_err,ERROR4  ; rebajado el tamaño
  1294. usar_ems:      MOV   tdisco,AX
  1295.                MOV   tipo_soporte,2    ; indicar memoria expandida
  1296.                JMP   mem_infoado
  1297. no_ems:        CMP   param_e,ON
  1298.                JNE   no_xms            ; no solicitan memoria XMS
  1299.                MOV   BX,xms_kb         ; solicitan memoria XMS...
  1300.                AND   BX,BX
  1301.                JNZ   usara_xms
  1302.                OR    lista_err,ERROR6  ; no hay memoria XMS disponible
  1303.                JMP   mem_infoado
  1304. usara_xms:     CMP   AX,BX
  1305.                JBE   usar_xms          ; piden algo razonable
  1306.                MOV   AX,BX
  1307.                OR    lista_err,ERROR4  ; rebajado el tamaño
  1308. usar_xms:      MOV   tdisco,AX
  1309.                MOV   tipo_soporte,1    ; indicar memoria extendida
  1310.                JMP   mem_infoado
  1311. no_xms:        CMP   param_c,ON
  1312.                JNE   no_con            ; no solicitan memoria conv.
  1313. forzar_con:    MOV   BX,con_kb         ; solicitan memoria conv. ...
  1314.                AND   BX,BX
  1315.                JNZ   usara_con
  1316.                OR    lista_err,ERROR10 ; no hay memoria conv. libre
  1317.                JMP   mem_infoado
  1318. usara_con:     CMP   AX,BX
  1319.                JBE   usar_con          ; piden algo razonable
  1320.                MOV   AX,BX
  1321.                OR    lista_err,ERROR4  ; rebajado el tamaño
  1322. usar_con:      MOV   tdisco,AX
  1323.                MOV   tipo_soporte,3    ; indicar memoria convencional
  1324.                JMP   mem_infoado
  1325. no_con:        CMP   AX,xms_kb         ; no indicado tipo de memoria
  1326.                JBE   usar_xms          ; intentar emplear memoria XMS
  1327.                CMP   ES:rutina_larga,ON
  1328.                JE    valdria_ems
  1329.                MOV   BX,xms_kb
  1330.                CMP   BX,0              ; imposible usar EMS
  1331.                JNE   usara_xms         ; queda algo de XMS
  1332.                JMP   usar_con?
  1333. valdria_ems:   MOV   BX,ems_kb
  1334.                CMP   AX,BX
  1335.                JA    nv_ems
  1336.                JMP   usar_ems          ; emplear memoria EMS
  1337. nv_ems:        MOV   BX,ems_kb
  1338.                OR    BX,xms_kb
  1339.                JZ    usar_con?         ; no hay un ápice de XMS ni EMS
  1340.                OR    lista_err,ERROR4  ; rebajado el tamaño solicitado
  1341.                MOV   AX,xms_kb
  1342.                CMP   AX,ems_kb
  1343.                JAE   usar_xms          ; hay más o igual XMS que EMS
  1344.                MOV   AX,ems_kb
  1345.                JMP   usar_ems          ; hay algo de EMS (más que XMS)
  1346. usar_con?:     CMP   modo,AUTOEXEC
  1347.                JE    forzar_con        ; sólo se puede usar mem. conv.
  1348.                OR    lista_err,ERROR5  ; ho hay memoria EMS ni XMS
  1349. mem_infoado:   RET
  1350. mem_info       ENDP
  1351.  
  1352.                ; ---- Calcular memoria extendida disponible
  1353.  
  1354. eval_xms       PROC
  1355.                PUSH  ES
  1356.                MOV   AX,352Fh
  1357.                INT   21h               ; dirección de INT 2Fh en ES:BX
  1358.                MOV   AX,ES
  1359.                AND   AX,AX
  1360.                JZ    xms_ok            ; apunta a 0000:XXXX (DOS 2.x)
  1361.                MOV   AX,4300h
  1362.                INT   2Fh
  1363.                CMP   AL,80h            ; ¿hay controlador XMS?
  1364.                JNE   xms_ok
  1365.                MOV   AX,4310h          ; obtener su dirección
  1366.                INT   2Fh
  1367.                MOV   xms_segm,ES
  1368.                MOV   xms_desp,BX
  1369.                MOV   AH,8
  1370.                CALL  xms_driver        ; preguntar memoria libre
  1371.                AND   AX,AX
  1372.                JNZ   xms_kb_ok         ; no hubo fallo
  1373.                CMP   BL,0A0h
  1374.                JE    xms_kb_ok         ; asignada ya toda la memoria
  1375.                TEST  BL,80h
  1376.                JZ    xms_kb_ok         ; no hay memoria XMS disponible
  1377.                OR    lista_err,ERROR8  ; fallo real del controlador
  1378. xms_kb_ok:     CMP   AX,8              ; mayor bloque XMS disponible
  1379.                JB    xms_ok
  1380.                MOV   xms_kb,AX         ; mínimo necesario: 8 Kb
  1381. xms_ok:        POP   ES
  1382.                RET
  1383. eval_xms       ENDP
  1384.  
  1385.                ; ---- Calcular memoria expandida disponible. Si la
  1386.                ;      versión del EMM es 4.0 o superior, las páginas
  1387.                ;      de memoria expandida pueden no ser contiguas:
  1388.                ;      buscar una que diste 32 Kb de la página 0.
  1389.  
  1390. eval_ems       PROC
  1391.                PUSH  ES
  1392.                MOV   AX,3567h
  1393.                INT   21h               ; vector de INT 67h en ES:BX
  1394.                MOV   DI,10
  1395.                LEA   SI,emm_id
  1396.                MOV   CX,8
  1397.                CLD
  1398.                REP   CMPSB             ; ¿instalado controlador EMS?
  1399.                JE    ems_existe
  1400.                JMP   ems_ok
  1401. ems_existe:    MOV   CX,8000h          ; nº de intentos prudente
  1402. emm_llama:     MOV   AH,40h
  1403.                INT   67h
  1404.                AND   AH,AH
  1405.                JZ    emm_responde
  1406.                CMP   AH,82h
  1407.                LOOPE emm_llama
  1408. emm_fatal:     OR    lista_err,ERROR9  ; fallo del EMM
  1409.                JMP   ems_ok
  1410. emm_responde:  MOV   AH,41h
  1411.                INT   67h
  1412.                AND   AH,AH
  1413.                JZ    emm_pag_ok
  1414.                CMP   AH,82h
  1415.                JE    emm_responde      ; reintentar (EMM ocupado)
  1416.                JMP   emm_fatal
  1417. emm_pag_ok:    MOV   ems_pagina0,BX    ; inicializar página EMS
  1418.                ADD   BX,0C00h
  1419.                MOV   ems_paginai,BX
  1420.                MOV   ems_pagni,3       ; página alternativa: la 3
  1421.                MOV   AH,46h
  1422.                INT   67h               ; obtener versión del EMM
  1423.                CMP   AL,40h
  1424.                JB    emm_obt_kb        ; versión anterior a la 4.0
  1425.                MOV   ems4,ON
  1426. emm_obt_pag:   XPUSH <ES,DS>
  1427.                POP   ES
  1428.                MOV   AX,5800h          ; obtener dirección de páginas
  1429.                LEA   DI,area_trabajo
  1430.                INT   67h
  1431.                POP   ES
  1432.                AND   AH,AH
  1433.                JZ    emm_pags_ok
  1434.                CMP   AH,82h
  1435.                JE    emm_obt_pag
  1436.                JMP   emm_fatal
  1437. emm_pags_ok:   XOR   DX,DX
  1438.                CALL  emm_busca_pag     ; buscar página 0
  1439.                JC    emm_fatal
  1440.                MOV   ems_pagina0,BX
  1441. ems_busca_i:   INC   DX                ; buscar la siguiente
  1442.                CMP   DX,5              ; la 5ª y siguientes no valen
  1443.                JE    emm_fatal         ;            ├──────┤
  1444.                CALL  emm_busca_pag     ;            │      │
  1445.                JC    emm_fatal         ;     ┌>   ┌>├──────┤<-- pág i
  1446.                MOV   ems_paginai,BX    ;0C00h│ 32 │ │      │
  1447.                MOV   ems_pagni,DL      ; pá  │ Kb │ ├──────┤
  1448.                SUB   BX,ems_pagina0    ; rra │    │ │      │
  1449.                JNC   bxpositivo        ; fos │    └>├──────┤
  1450.                NEG   BX                ;     │      │      │
  1451. bxpositivo:    CMP   BX,0C00h          ;     └>     ├──────┤<-- pág 0
  1452.                JB    ems_busca_i       ; no distan 32 Kb: buscar otra
  1453. emm_obt_kb:    MOV   AH,42h
  1454.                INT   67h
  1455.                AND   AH,AH
  1456.                JZ    emm_kb_ok
  1457.                CMP   AH,82h
  1458.                JE    emm_obt_kb
  1459.                JMP   emm_fatal
  1460. emm_kb_ok:     MOV   CL,4
  1461.                SHL   BX,CL             ; páginas EMS disponibles
  1462.                MOV   ems_kb,BX         ; Kb EMS disponibles (0,16,...)
  1463. ems_ok:        POP   ES
  1464.                RET
  1465. eval_ems       ENDP
  1466.  
  1467. emm_busca_pag  PROC                    ; buscar página nº DX (EMS 4.0)
  1468.                LEA   SI,area_trabajo
  1469.                PUSH  CX
  1470. emm_otra_pag:  LODSW
  1471.                MOV   BX,AX             ; BX = segmento de la página
  1472.                LODSW                   ; AX = nº de la página
  1473.                CMP   AX,DX
  1474.                JE    hallada_pag
  1475.                LOOP  emm_otra_pag
  1476.                STC
  1477. hallada_pag:   POP   CX
  1478.                RET
  1479. emm_busca_pag  ENDP
  1480.  
  1481.                ; ---- Calcular el tamaño del mayor bloque de memoria
  1482.                ;      convencional disponible. Como mínimo se dejarán
  1483.                ;      unos 128 Kb libres en él, para que el usuario
  1484.                ;      pueda volver a ejecutar TDSK y el DOS tenga algo
  1485.                ;      de memoria libre. A la mitad de esos 128Kb (para
  1486.                ;      evitar solapamientos) es donde TURBODSK se
  1487.                ;      autorelocalizará antes de formatear el disco.
  1488.  
  1489. eval_con       PROC
  1490.                CMP   modo,AUTOEXEC     ; ¿se ejecuta desde el DOS?
  1491.                JNE   conv_ok           ; no, desde el config
  1492.                MOV   AH,48h
  1493.                MOV   BX,0FFFFh         ; pedir 1 Mb al DOS (fallará)
  1494.                INT   21h
  1495.                MOV   DX,BX             ; tamaño del mayor bloque
  1496.                MOV   CL,6
  1497.                SHR   BX,CL             ; BX = Kb del mayor bloque
  1498.                SUB   BX,128            ; restar 128 Kb
  1499.                JC    conv_ok           ; no quedan ni 128 Kb
  1500.                CMP   BX,8
  1501.                JB    conv_ok           ; no quedan siquiera 8 Kb
  1502.                MOV   con_kb,BX
  1503.                MOV   BX,DX             ; tamaño del mayor bloque
  1504.                MOV   AH,48h
  1505.                PUSH  BX
  1506.                INT   21h               ; localizarlo (AX=segmento)
  1507.                POP   BX
  1508.                XPUSH <ES,AX>           ; preservar ES y segmento (AX)
  1509.                ADD   AX,BX             ; añadir longitud
  1510.                SUB   AX,1024/16*64     ; restar 64 Kb
  1511.                MOV   segm_reubicar,AX  ; segmento de autoreubicación
  1512.                POP   ES                ; recuperar segmento del bloque
  1513.                MOV   AH,49h
  1514.                INT   21h               ; liberarlo
  1515.                POP   ES                ; recuperar ES
  1516. conv_ok:       RET
  1517. eval_con       ENDP
  1518.  
  1519. ; ------------ Reservar la memoria llamando al gestor que la controla.
  1520. ;              Con memoria XMS y existiendo un controlador EMS 4.0+ se
  1521. ;              comprueba si el handle XMS provoca la creacción de otro
  1522. ;              en EMS (caso de QEMM386 y otros emuladores de EMS) y en
  1523. ;              ese caso se le renombra, para mejorar la información de
  1524. ;              los programas de diagnóstico.
  1525.  
  1526. mem_reserva    PROC
  1527.                MOV   AL,tipo_soporte   ; tipo de memoria empleada
  1528.                DEC   AL
  1529.                JZ    mem_r_xms         ; 1: memoria extendida XMS
  1530.                DEC   AL
  1531.                JZ    mem_r_ems         ; 2: memoria expandida EMS
  1532.                MOV   CL,6
  1533.                MOV   BX,tdisco         ; 3: memoria convencional
  1534.                SHL   BX,CL
  1535.                MOV   AH,48h
  1536.                INT   21h
  1537.                MOV   mem_handle,AX     ; segmento del disco virtual
  1538.                MOV   BX,segm_psp
  1539.                MOV   tdsk_psp,BX       ; inicializar esta variable
  1540.                RET
  1541. mem_r_xms:     CMP   ems4,ON
  1542.                JNE   skip_lst_hndl
  1543.                LEA   BX,area_trabajo
  1544.                CALL  lista_handles     ; EMS 4.0+: listado de handles
  1545. skip_lst_hndl: MOV   AH,9
  1546.                MOV   DX,tdisco
  1547.                CALL  xms_driver        ; pedir memoria XMS
  1548.                AND   AX,AX
  1549.                JNZ   mem_rda_xms
  1550.                OR    lista_err,ERROR8  ; fallo del controlador XMS
  1551.                STC                     ; indicar error
  1552. mem_rda_xms:   MOV   mem_handle,DX
  1553.                PUSHF                   ; preservar condición de error
  1554.                CMP   ems4,ON
  1555.                JNE   skip_ren_hndl
  1556.                CALL  ren_handle        ; en EMS 4.0+ renombrar handle
  1557. skip_ren_hndl: POPF
  1558.                RET
  1559. mem_r_ems:     MOV   BX,tdisco
  1560.                ADD   BX,15
  1561.                AND   BL,11110000b      ; redondear para arriba
  1562.                MOV   tdisco,BX
  1563.                MOV   CL,4
  1564.                SHR   BX,CL             ; Kb -> nº páginas de 16 Kb
  1565.                MOV   AH,43h
  1566.                INT   67h               ; pedir memoria EMS
  1567.                AND   AH,AH
  1568.                JZ    mem_rda_ems
  1569.                OR    lista_err,ERROR9  ; fallo del controlador EMS
  1570.                STC                     ; indicar error
  1571.                RET
  1572. mem_rda_ems:   MOV   mem_handle,DX
  1573.                CMP   ems4,ON
  1574.                JNE   nhandle_ok
  1575.                CALL  nombrar_hndl      ; en EMS 4.0+ nombrar handle
  1576. nhandle_ok:    CLC
  1577.                RET
  1578. mem_reserva    ENDP
  1579.  
  1580. ren_handle     PROC                    ; detectar el handle EMS ligado
  1581.                XPUSH <ES,DS>           ; al handle XMS y renombrarlo
  1582.                POP   ES
  1583.                LEA   BX,area_trabajo[512]
  1584.                CALL  lista_handles     ; crear nueva lista de handles
  1585.                LEA   SI,area_trabajo
  1586.                LEA   DI,area_trabajo[512]
  1587.                MOV   CX,256
  1588.                CLD
  1589.                REP   CMPSW             ; comparar con vieja lista
  1590.                JE    ren_hnld_fin
  1591.                MOV   DX,[DI-2]         ; handle nuevo
  1592.                CALL  nombrar_hndl
  1593. ren_hnld_fin:  POP   ES
  1594.                RET
  1595. ren_handle     ENDP
  1596.  
  1597. lista_handles  PROC                    ; crear en DS:BX una lista con
  1598.                MOV   CX,256            ; los 256 posibles handles
  1599.                XOR   DX,DX             ; activos indicando los usados
  1600. listar_h:      MOV   AX,5300h
  1601.                LEA   DI,area_trabajo[tam_a_trabajo-8]  ; zona no usada
  1602.                XPUSH <BX,CX,DX>
  1603.                INT   67h
  1604.                XPOP  <DX,CX,BX>
  1605.                CMP   AH,0
  1606.                JE    handle_usado
  1607.                MOV   WORD PTR [BX],0   ; error (handle no usado)
  1608.                JMP   lista_h
  1609. handle_usado:  MOV   [BX],DX           ; anotar número de handle
  1610. lista_h:       ADD   BX,2
  1611.                INC   DX
  1612.                LOOP  listar_h
  1613.                RET
  1614. lista_handles  ENDP
  1615.  
  1616. nombrar_hndl   PROC                    ; nombrar handle (EMS 4.0+)
  1617.                MOV   AX,5301h
  1618.                LEA   SI,nombre_tdsk
  1619.                MOV   BL,letra_unidad
  1620.                MOV   [SI+5],BL
  1621.                INT   67h               ; dar nombre al handle
  1622.                RET
  1623. nombrar_hndl   ENDP
  1624.  
  1625. ; ------------ Detectar 286 y 386 o superior.
  1626.  
  1627. test_CPU       PROC
  1628.                PUSHF
  1629.                POP   AX
  1630.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  1631.                PUSH  AX            ; del registro de estado
  1632.                POPF
  1633.                PUSHF
  1634.                POP   AX
  1635.                AND   AH,0F0h
  1636.                CMP   AH,0F0h
  1637.                JE    fin_test_CPU  ; es 8086 o similar
  1638.                MOV   cpu286,ON     ; es 286 o superior
  1639.                AND   AH,70h        ; 286 pone bits 12, 13 y 14 a cero
  1640.                JZ    fin_test_CPU  ; es 286
  1641.                MOV   cpu386,ON     ; 386 o superior
  1642. fin_test_CPU:  RET
  1643. test_CPU       ENDP
  1644.  
  1645. ; ------------ Definir valores por defecto y adaptar los parámetros
  1646. ;              indicados por el usuario a la realidad. Esta rutina
  1647. ;              inicializa el futuro sector 0 del disco. No se permite
  1648. ;              que el usuario indique un directorio que ocupe más de
  1649. ;              medio disco. Para determinar el tipo de FAT se halla el
  1650. ;              nº de sectores libres del disco (llamémoslo nsect),
  1651. ;              descontanto el sector de arranque y el directorio raiz;
  1652. ;              y se aplica la siguiente fórmula, que devuelve el nº de
  1653. ;              cluster más alto del disco al considerar también la
  1654. ;              ocupación de la futura FAT (12 bits = 1,5 bytes):
  1655. ;
  1656. ;                 nsect * tamsect          2 * nsect * tamsect
  1657. ;                ------------------ + 1 = --------------------- + 1
  1658. ;                 tamcluster + 1,5         2 * tamcluster + 3
  1659. ;
  1660. ;                Al resultado se le suma 1, ya que los clusters se
  1661. ;              numeran a partir de 2, para calcular el cluster de nº
  1662. ;              más alto del disco. Si ese número es 4086 o más habrá
  1663. ;              de utilizarse una FAT de 16 bits, recalculándose la
  1664. ;              fórmula anterior sustituyendo 1,5 por 2 y 3 por 4. Al
  1665. ;              final, una vez determinado el tipo de FAT habrá de
  1666. ;              calcularse con exactitud el número de cluster más alto,
  1667. ;              ya que hay casos críticos en que una FAT12 no sirve
  1668. ;              pero al aplicar una FAT16 el número de clusters baja de
  1669. ;              nuevo de 4085 (debido al mayor consumo de disco de la
  1670. ;              FAT16) resultado de ello la asignación de una FAT12,
  1671. ;              pese a que se reserva espacio para la de 16. Hay que
  1672. ;              considerar además el caso de que el disco tenga 2 FAT.
  1673.  
  1674. adaptar_param  PROC
  1675.                MOV   AX,tdisco     ; en Kb
  1676.                MOV   BX,AX         ; entradas de directorio propuestas
  1677.                MOV   CL,1          ; sectores por cluster propuestos
  1678.                CMP   AX,128        ; ¿disco de 128 Kb o menos?
  1679.                JBE   prop_ok
  1680.                MOV   BX,128
  1681.                CMP   AX,512        ; ¿disco de 512 Kb o menos?
  1682.                JBE   prop_ok
  1683.                MOV   BX,256
  1684.                CMP   AX,2042       ; ¿disco de casi 2 Mb o menos?
  1685.                JBE   prop_ok
  1686.                MOV   CL,2          ; evitar FAT16
  1687.                CMP   AX,4084       ; ¿disco de casi 4 Mb o menos?
  1688.                JBE   prop_ok
  1689.                MOV   CL,4          ; evitar FAT16 hasta 8 Mb
  1690.                MOV   BX,384
  1691.                CMP   AX,16384      ; ¿disco de menos de 16 Mb?
  1692.                JB    prop_ok
  1693.                MOV   BX,512
  1694. prop_ok:       CMP   dosver,300h
  1695.                JAE   prop_valido
  1696.                CMP   AX,4084*2     ; en DOS 2.xx evitar FAT16
  1697.                JB    prop_valido
  1698.                MOV   CL,8
  1699.                CMP   AX,4084*4
  1700.                JB    prop_valido
  1701.                MOV   CL,16
  1702.                CMP   AX,4084*8
  1703.                JB    prop_valido
  1704.                MOV   CL,32
  1705. prop_valido:   MOV   tdir,BX
  1706.                MOV   tcluster,CL   ; inicializar valores recomendados
  1707.                MOV   DX,1024       ; AX = tamaño del disco en Kb
  1708.                MUL   DX            ; DX:AX = bytes totales del disco
  1709.                MOV   CX,param_tsect
  1710.                AND   CX,CX
  1711.                JNZ   tsect_def     ; se ha definido tamaño de sector
  1712. tsect_rec:     MOV   CX,tsect      ; tamaño por defecto
  1713. tsect_def:     CALL  divCX
  1714.                JNC   nsect_ok      ; menos de 65536 sectores: correcto
  1715.                OR    lista_err,ERROR11
  1716.                JMP   tsect_rec     ; asumir por defecto y recalcular
  1717. nsect_ok:      MOV   tsect,CX
  1718.                MOV   numsect,AX
  1719.                MOV   BX,AX
  1720.                SHR   BX,1          ; BX = 1/2 del nº total de sectores
  1721.                MOV   CX,param_tdir
  1722.                AND   CX,CX
  1723.                JNZ   tdir_def      ; se ha definido nº entradas
  1724. tdir_rec:      MOV   CX,tdir       ; nº por defecto
  1725. tdir_def:      MOV   AX,tsect
  1726.                XOR   DX,DX
  1727.                MOV   SI,32         ; 32 bytes = tamaño entrada direct.
  1728.                DIV   SI            ; AX nº entradas direct. por sector
  1729.                XCHG  AX,CX
  1730.                XOR   DX,DX         ; DX:AX = nº de entradas
  1731.                DIV   CX            ; CX = entradas en cada sector
  1732.                AND   DX,DX         ; AX = nº sectores del ROOT
  1733.                JZ    dir_ok?
  1734.                INC   AX            ; redondear tamaño de ROOT
  1735. dir_ok?:       CMP   AX,BX         ; BX = 1/2 nº sectores del disco
  1736.                JB    dir_ok
  1737.                OR    lista_err,ERROR12  ; directorio excesivo
  1738.                JMP   tdir_rec      ; directorio por defecto
  1739. dir_ok:        MOV   sdir,AX
  1740.                MUL   tsect
  1741.                MOV   CX,32
  1742.                CALL  divCX
  1743.                MOV   tdir,AX       ; optimizar tamaño de directorio
  1744.                MOV   AX,512
  1745.                XOR   DX,DX
  1746.                DIV   tsect         ; 512 / tamaño de sector
  1747.                MOV   BL,tcluster
  1748.                XOR   BH,BH
  1749.                MUL   BX            ; ajustar tamaño de cluster
  1750.                AND   AL,AL
  1751.                JZ    propclus_ok
  1752.                MOV   tcluster,AL
  1753. propclus_ok:   MOV   BX,param_tcluster
  1754.                AND   BX,BX
  1755.                JNZ   tcluster_def  ; se ha definido tamaño de cluster
  1756. tcluster_rec:  MOV   BL,tcluster   ; tamaño por defecto
  1757.                XOR   BH,BH
  1758. tcluster_def:  SHL   BX,1
  1759.                CMP   BX,numsect    ; ¿cabe seguro un cluster?
  1760.                JB    tcluster_ok
  1761. tcluster_mal:  OR    lista_err,ERROR13 ; tamaño de cluster incorrecto
  1762.                JMP   tcluster_rec
  1763. tcluster_ok:   SHR   BX,1
  1764.                MOV   AX,tsect
  1765.                MUL   BX            ; DX:AX = tamaño de cluster
  1766.                JC    tcluster_mal
  1767.                CMP   AX,31*1024
  1768.                JA    tcluster_mal  ; cluster de más de 31 Kb
  1769.                MOV   tcluster,BL   ; sectores por cluster
  1770.                MOV   tamcluster,AX ; tamaño de cluster
  1771.                MOV   CX,param_f    ; considerar número de FATs
  1772.                MOV   nfats,CL
  1773.                MOV   SI,3
  1774.                MOV   CX,param_f
  1775.                SHL   SI,CL
  1776.                SHR   SI,1
  1777.                CALL  eval_clust    ; obtener nº más alto de cluster
  1778.                CMP   AX,4086
  1779.                JAE   fat16         ; el nº más alto supera 4085
  1780.                MOV   CX,3
  1781.                MUL   CX            ; clusters * 3
  1782.                SHR   DX,1
  1783.                RCR   AX,1          ; clusters * 3 / 2 = clusters * 1,5
  1784.                JMP   calc_sfat
  1785. fat16:         MOV   SI,4
  1786.                MOV   CX,param_f    ; considerar número de FATs
  1787.                SHL   SI,CL
  1788.                SHR   SI,1
  1789.                CALL  eval_clust
  1790.                SHL   AX,1
  1791.                RCL   DX,1          ; clusters * 2
  1792. calc_sfat:     DIV   tsect         ; AX = nº sectores de FAT aprox.
  1793.                AND   DX,DX
  1794.                JZ    fat_ok
  1795.                INC   AX            ; redondeo
  1796. fat_ok:        MOV   sfat,AX
  1797.                MOV   AX,numsect    ; nº total de sectores
  1798.                DEC   AX            ; descontar BOOT
  1799.                SUB   AX,sdir       ; descontar ROOT
  1800.                SUB   AX,sfat       ; descontar FAT
  1801.                MOV   CL,tcluster
  1802.                XOR   CH,CH
  1803.                XOR   DX,DX
  1804.                DIV   CX            ; AX = número real de clusters
  1805.                INC   AX            ; se numeran desde 2
  1806.                MOV   ultclus,AX
  1807.                RET
  1808. adaptar_param  ENDP
  1809.  
  1810. eval_clust     PROC                ; obtener el nº más alto de cluster
  1811.                MOV   AX,numsect
  1812.                DEC   AX            ; restar BOOT
  1813.                SUB   AX,sdir       ; restar ROOT
  1814.                MUL   tsect         ; DX:AX = nsect * tamsect
  1815.                SHL   AX,1
  1816.                RCL   DX,1          ; DX:AX = nsect * tamsect * 2
  1817.                MOV   CX,tamcluster
  1818.                SHL   CX,1
  1819.                ADD   CX,SI         ; CX = 2 * tamcluster + SI
  1820.                DIV   CX
  1821.                INC   AX            ; los clusters se numeran desde 2
  1822.                AND   DX,DX         ; ¿sobra un «cacho» de cluster?
  1823.                JZ    clust_eval    ; redondear: ¡es preferible que
  1824.                INC   AX            ; sobre un poco de FAT a que falte!
  1825. clust_eval:    XOR   DX,DX         ; resultado en DX:AX
  1826.                RET
  1827. eval_clust     ENDP
  1828.  
  1829. ; ------------ Preparar el BPB del disco virtual según los parámetros
  1830. ;              y forzar que el DOS lo lea indicando cambio de disco.
  1831.  
  1832. preparar_BPB   PROC
  1833.                MOV   AX,tsect
  1834.                MOV   bytes_sector,AX
  1835.                MOV   AL,tcluster
  1836.                MOV   sect_cluster,AL
  1837.                MOV   AX,tdir
  1838.                MOV   entradas_raiz,AX
  1839.                MOV   AX,numsect
  1840.                MOV   num_sect,AX
  1841.                MOV   AL,nfats
  1842.                MOV   num_fats,AL
  1843.                MOV   AX,sfat
  1844.                MOV   sectores_fat,AX
  1845.                MOV   cambiado,0FFh     ; ha habido «cambio» de disco
  1846.                RET
  1847. preparar_BPB   ENDP
  1848.  
  1849. ; ------------ Preparar el disco para operar. ES apunta al disco al
  1850. ;              entrar. Se procederá a copiar la rutina necesaria en
  1851. ;              función del tipo de memoria que gestiona el disco.
  1852. ;              Después, se copiarán las variables que gestionan TDSK
  1853. ;              sobre la copia residente, así como el nuevo BPB.
  1854.  
  1855. prep_driver    PROC
  1856.                MOV   AL,tipo_soporte
  1857.                LEA   SI,procesa_xms
  1858.                MOV   CX,tam_proc_xms
  1859.                DEC   AL
  1860.                JZ    prep_mem          ; instalar rutina XMS
  1861.                LEA   SI,procesa_ems
  1862.                MOV   CX,tam_proc_ems
  1863.                DEC   AL
  1864.                JZ    prep_mem          ; instalar rutina EMS
  1865.                LEA   SI,procesa_con
  1866.                MOV   CX,tam_proc_con   ; instalar rutina memoria conv.
  1867. prep_mem:      LEA   DI,procesa_io
  1868.                CLD
  1869.                XPUSH <SI,DI,CX>
  1870.                REP   MOVSB             ; instalar rutina en el disco
  1871.                XPOP  <CX,DI,SI>
  1872.                XPUSH <ES,DS>
  1873.                POP   ES
  1874.                REP   MOVSB             ; y en el propio TDSK.EXE (para
  1875.                POP   ES                ; usarla después al formatear)
  1876.                LEA   CX,f_tdsk_ctrl
  1877.                LEA   SI,i_tdsk_ctrl
  1878.                SUB   CX,SI
  1879.                MOV   DI,SI
  1880.                REP   MOVSB             ; actualizar variables
  1881.                LEA   CX,fin_bpb
  1882.                LEA   SI,bpb
  1883.                SUB   CX,SI
  1884.                MOV   DI,SI
  1885.                REP   MOVSB             ; actualizar BPB
  1886.                RET
  1887. prep_driver    ENDP
  1888.  
  1889. ; ------------ Autorelocalización de TDSK.EXE
  1890. ;              Es necesario si se reserva memoria convencional para el
  1891. ;              disco virtual. El motivo es evitar que al inicializar
  1892. ;              la BOOT, la FAT y el ROOT al inicio del disco, si éste
  1893. ;              está justo encima de TDSK, TDSK se autodestruya. Por
  1894. ;              ello, TDSK se autocopiará en la mitad de los 128 Kb del
  1895. ;              mayor bloque de memoria libre, nunca utilizados por el
  1896. ;              disco (aunque este bloque no haya sido reservado, ¡como
  1897. ;              está libre!). Finalmente pasará a correr en ese nuevo
  1898. ;              destino. Se copia TODO, pila incluida. La copia se hace
  1899. ;              en «segm_reubicar» que apunta a la mitad de esos 128 Kb
  1900. ;              con objeto de evitar solapamientos origen/destino (TDSK
  1901. ;              ocupa sólo alrededor de 16 Kb en memoria).
  1902.  
  1903. relocalizar    PROC
  1904.                CMP   tipo_soporte,3
  1905.                JE    procede_reloc     ; usada memoria convencional
  1906.                RET
  1907. procede_reloc: PUSH  ES                ; * preservar ES
  1908.                MOV   ES,segm_reubicar  ; segmento de reubicación
  1909.                XOR   SI,SI
  1910.                XOR   DI,DI
  1911.                MOV   BX,SS             ; final de TURBODSK (pila)
  1912.                MOV   CX,DS             ; inicio de _PRINCIPAL
  1913.                SUB   BX,CX             ; tamaño de TDSK en párrafos
  1914.                MOV   CL,4
  1915.                SHL   BX,CL             ; ahora en bytes
  1916.                ADD   BX,tam_pila+16    ; 16 por si acaso
  1917.                MOV   CX,BX             ; CX = bytes a relocalizar
  1918.                CLD
  1919.                REP   MOVSB             ; auto-copiaje arriba
  1920.                MOV   AX,ES
  1921.                MOV   DS,AX             ; nuevo segmento de datos
  1922.                POP   ES                ; * restaurar ES
  1923.                MOV   BX,CS
  1924.                SUB   AX,BX             ; ES - CS --> cuantía del salto
  1925.                MOV   BX,SS
  1926.                ADD   BX,AX
  1927.                MOV   SS,BX             ; actualizar segmento de pila
  1928.                POP   AX                ; dirección de retorno cercano
  1929.                PUSH  DS                ; segmento de «retorno»
  1930.                PUSH  AX                ; offset
  1931.                RETF                    ; retorno cargando CS:
  1932. relocalizar    ENDP
  1933.  
  1934. ; ------------ Inicializar la BOOT, FAT y ROOT del disco virtual.
  1935. ;              En versiones del DOS anteriores a la 3.3, el sistema
  1936. ;              inexplicablemente hace caso omiso del cambio de disco
  1937. ;              (¿?), por lo que hay que avisarle ¡dos veces!, con el
  1938. ;              correspondiente doble cambio del byte descriptor de
  1939. ;              medio, para que se tome en serio el cambio de disco.
  1940. ;              Por fortuna desde el DOS 3.3 ya no es preciso hacer
  1941. ;              esta extraña maniobra. Para que el DOS acceda al disco,
  1942. ;              se le pregunta simplemente el espacio libre del mismo.
  1943.  
  1944. formatear_tdsk PROC
  1945.                PUSH  ES                ; *
  1946.                PUSH  DS
  1947.                POP   ES
  1948.                LEA   SI,sector_cero
  1949.                LEA   DI,area_trabajo
  1950.                MOV   CX,128
  1951.                CLD
  1952.                REP   MOVSB             ; primeros 128 bytes del BOOT
  1953.                XOR   AX,AX
  1954.                MOV   CX,tam_a_trabajo-128
  1955.                REP   STOSB             ; a 0 resto del área de trabajo
  1956.                LEA   DI,area_trabajo
  1957.                ADD   DI,tsect
  1958.                MOV   [DI-2],0AA55h     ; marca de sector válido
  1959.                CALL  escribe_sectAX    ; escribir sector BOOT (AX=0)
  1960.                LEA   DI,area_trabajo
  1961.                MOV   CX,tsect
  1962.                REP   STOSB             ; borrar area de trabajo
  1963.                MOV   AX,sfat
  1964.                MOV   CX,param_f        ; considerar número de FATs
  1965.                SHL   AX,CL
  1966.                SHR   AX,1
  1967.                ADD   AX,sdir           ; AX = sectores fat + dir. raiz
  1968. ini_fat:       CMP   AX,1
  1969.                JE    pfat
  1970.                CALL  escribe_sectAX    ; inicializar directorio raiz
  1971.                DEC   AX                ; y últimos sectores de la FAT
  1972.                JMP   ini_fat
  1973. pfat:          LEA   DI,area_trabajo
  1974.                MOV   BYTE PTR [DI],media
  1975.                MOV   AX,0FFFFh         ; inicializar 3 bytes FAT...
  1976.                MOV   DS:[DI+1],AX
  1977.                CMP   ultclus,4086      ; ¿menos de 4085 clusters?
  1978.                JB    pfat_ok
  1979.                MOV   DS:[DI+3],AL      ; inicializar 4º byte FAT
  1980. pfat_ok:       MOV   AX,1
  1981.                CALL  escribe_sectAX    ; primer sector FAT preparado
  1982.                CALL  fecha_hora
  1983.                LEA   SI,dir_raiz
  1984.                MOV   [SI+22],AX        ; hora actual
  1985.                MOV   [SI+24],DX        ; fecha actual
  1986.                LEA   DI,area_trabajo
  1987.                MOV   CX,32
  1988.                REP   MOVSB
  1989.                MOV   AX,sfat
  1990.                MOV   CX,param_f        ; considerar número de FATs
  1991.                SHL   AX,CL
  1992.                SHR   AX,1
  1993.                INC   AX
  1994.                CALL  escribe_sectAX    ; primer sector raiz preparado
  1995.                POP   ES                ; *
  1996.                CMP   dosver,31Eh
  1997.                JAE   formateado        ; DOS 3.3+
  1998.                NOT   ES:media_byte     ; cambiar descriptor de medio
  1999.                MOV   AH,36h            ; «obtener espacio libre»
  2000.                MOV   DL,ES:letra_unidad
  2001.                SUB   DL,'A'-1          ; unidad de disco virtual
  2002.                PUSH  DX
  2003.                INT   21h               ; primer acceso al disco
  2004.                POP   DX
  2005.                NOT   ES:media_byte     ; restaurar descriptor de medio
  2006.                MOV   ES:cambiado,0FFh  ; nuevo «cambio» de disco
  2007.                MOV   AH,36h
  2008.                INT   21h               ; acceder otra vez al disco
  2009. formateado:    RET
  2010. formatear_tdsk ENDP
  2011.  
  2012.                ; ---- Escribir el sector nº AX del disco virtual. No
  2013.                ;      se utiliza INT 26h (imposible desde el CONFIG).
  2014.  
  2015. escribe_sectAX PROC
  2016.                PUSHF                   ; preservar bit DF
  2017.                XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
  2018.                XOR   BP,BP             ; indicar escritura
  2019.                LEA   DI,area_trabajo   ; ES:DI buffer
  2020.                MOV   BX,AX             ; número de sector
  2021.                MOV   AX,1              ; 1 sector
  2022.                CALL  io_proc           ; acceder al disco directamente
  2023.                XPOP  <ES,DS,BP,DI,SI,DX,CX,BX,AX>
  2024.                POPF
  2025.                RET
  2026. escribe_sectAX ENDP
  2027.  
  2028.                ; ---- Obtener fecha y hora del sistema en DX y AX
  2029.  
  2030. fecha_hora     PROC
  2031.                MOV   AH,2Ah
  2032.                INT   21h               ; obtener fecha del sistema
  2033.                MOV   AL,32
  2034.                MUL   DH                ; AX = mes * 32
  2035.                SUB   CX,1980
  2036.                SHL   CL,1              ; (año-1980)*2
  2037.                ADD   AH,CL             ; sumar (año-1980)*512
  2038.                MOV   CL,DL             ; CX = dia (CH=0)
  2039.                ADD   AX,CX
  2040.                PUSH  AX                ; * guardar fecha
  2041.                MOV   AH,2Ch
  2042.                INT   21h               ; obtener hora del sistema
  2043.                MOV   AL,32
  2044.                MUL   CL                ; AX = minutos*32
  2045.                MOV   CL,3
  2046.                SHL   CH,CL
  2047.                XOR   CL,CL             ; CX = hora*2048
  2048.                ADD   AX,CX
  2049.                SHR   DH,1              ; segundos/2
  2050.                ADD   AL,DH
  2051.                ADC   AH,0
  2052.                POP   DX                ; * recuperar fecha
  2053.                RET
  2054. fecha_hora     ENDP
  2055.  
  2056. ; ------------ Cambiar el nombre al bloque de control de memoria para
  2057. ;              mejorar la información del comando MEM del sistema si
  2058. ;              el disco se define en memoria convencional/superior.
  2059.  
  2060. renombrar_mcb  PROC
  2061.                PUSH  ES
  2062.                MOV   AL,letra_unidad
  2063.                MOV   BYTE PTR nombre_tdsk+5,AL
  2064.                MOV   BYTE PTR nombre_tdsk+4,'('
  2065.                MOV   BYTE PTR nombre_tdsk+6,')'
  2066.                MOV   AX,segm_psp
  2067.                DEC   AX
  2068.                MOV   ES,AX
  2069.                LEA   SI,nombre_tdsk
  2070.                MOV   DI,8
  2071.                MOV   CX,DI
  2072.                CLD
  2073.                REP   MOVSB
  2074.                POP   ES
  2075.                RET
  2076. renombrar_mcb  ENDP
  2077.  
  2078. ; ------------ Informar sobre el disco virtual instalado.
  2079.  
  2080. info_disco     PROC
  2081.                CALL  InitMultiPrint
  2082.                LEA   DX,ayuda_txt      ; ayuda en español
  2083.                CMP   param_h,ON        ; ¿solicitud de ayuda?
  2084.                JNE   cont_info         ; no
  2085.                JMP   info_exit
  2086. cont_info:     TEST  err_grave,0FFFFh
  2087.                JZ    info_no_fatal
  2088.                LEA   DX,err_grave_gen  ; texto de encabezamiento
  2089.                CALL  imprimir          ; imprimir errores graves:
  2090.                LEA   DX,e0
  2091.                TEST  err_grave,ERROR0
  2092.                JZ    otro_fallo        ; no es error de DOS incorrecto
  2093.                CALL  imprimir
  2094.                MOV   SP,tam_pila
  2095.                PUSH  segm_psp          ; en DOS 1.x hay que terminar
  2096.                XOR   AX,AX             ; con CS = PSP
  2097.                PUSH  AX
  2098.                RETF                    ; ejecutar INT 20h de PSP:0
  2099. otro_fallo:    LEA   DX,e1
  2100.                TEST  err_grave,ERROR1
  2101.                JNZ   info_g
  2102.                LEA   DX,e2
  2103.                TEST  err_grave,ERROR2
  2104.                JNZ   info_g
  2105.                LEA   DX,e3
  2106. info_g:        JMP   info_exit
  2107. info_no_fatal: CMP   ES:tipo_soporte,0 ; error no fatal
  2108.                JNE   info_reporte
  2109.                LEA   DX,info_ins       ; disco no formateado
  2110.                CALL  imprimir
  2111.                CALL  impr_unidad
  2112.                LEA   DX,info_ins2
  2113.                CMP   lista_err,0
  2114.                JE    info_exit         ; sin mensajes de advertencia
  2115.                CALL  imprimir          ; ... o con ellos
  2116.                JMP   info_err
  2117. info_reporte:  CALL  pr_info           ; disco formateado
  2118.                CMP   lista_err,0
  2119.                JE    info_ret          ; sin mensajes de advertencia
  2120.                LEA   DX,cab_adv_txt    ; ... o con ellos
  2121.                CALL  imprimir          ; cabecera de advertencias
  2122. info_err:      MOV   AX,lista_err
  2123.                LEA   BX,tabla_mens-2   ; tabla de mensajes
  2124.                MOV   CX,16             ; 16 posibles mensajes
  2125. busca_err:     ADD   BX,2
  2126.                SHR   AX,1
  2127.                JC    informa
  2128. mas_mens:      LOOP  busca_err         ; no se produce ese error
  2129.                JMP   info_ret
  2130. informa:       LEA   DX,mens_cabec     ; inicio común a los mensajes
  2131.                CALL  imprimir
  2132.                MOV   DX,[BX]           ; dirección de ese mensaje
  2133.                CALL  imprimir
  2134.                JMP   mas_mens          ; acabar con todos
  2135. info_exit:     CALL  imprimir
  2136. info_ret:      RET
  2137. info_disco     ENDP
  2138.  
  2139. pr_info        PROC
  2140.                LEA   DX,info_txt
  2141.                CALL  imprimir
  2142.                CALL  impr_unidad
  2143.                LEA   DX,inf_tsect
  2144.                CALL  imprimir
  2145.                MOV   AX,ES:bytes_sector
  2146.                XOR   DX,DX
  2147.                MOV   CL,5
  2148.                CALL  print_32
  2149.                LEA   DX,inf_tdir
  2150.                CALL  imprimir
  2151.                MOV   AX,ES:entradas_raiz
  2152.                XOR   DX,DX
  2153.                MOV   CL,5
  2154.                CALL  print_32
  2155.                LEA   DX,inf_tdisco
  2156.                CALL  imprimir
  2157.                MOV   AX,ES:num_sect
  2158.                MUL   ES:bytes_sector
  2159.                MOV   BX,1024
  2160.                DIV   BX
  2161.                MOV   CL,5
  2162.                CALL  print_32
  2163.                LEA   DX,inf_tcluster
  2164.                CALL  imprimir
  2165.                MOV   AL,ES:sect_cluster
  2166.                XOR   AH,AH
  2167.                XOR   DX,DX
  2168.                MOV   CL,5
  2169.                CALL  print_32
  2170.                LEA   DX,inf_mem
  2171.                CALL  imprimir
  2172.                MOV   AL,ES:tipo_soporte
  2173.                LEA   DX,inf_mem_xms
  2174.                DEC   AL
  2175.                JZ    mem_ifdo          ; memoria XMS
  2176.                LEA   DX,inf_mem_ems
  2177.                DEC   AL
  2178.                JZ    mem_ifdo          ; memoria EMS
  2179.                LEA   DX,inf_mem_con
  2180.                CMP   ES:mem_handle,0A000h
  2181.                JB    mem_ifdo          ; memoria convencional
  2182.                LEA   DX,inf_mem_sup    ; memoria superior
  2183. mem_ifdo:      CALL  imprimir
  2184.                LEA   DX,inf_nclusters
  2185.                CALL  imprimir
  2186.  
  2187.                MOV   AX,ES:entradas_raiz
  2188.                MOV   BX,32
  2189.                MUL   BX                ; bytes ocupados por directorio
  2190.                DIV   ES:bytes_sector   ; AX = sectores del directorio
  2191.                ADD   AX,ES:sect_reserv
  2192.                ADD   AX,ES:sectores_fat
  2193.                SUB   AX,ES:num_sect
  2194.                NEG   AX                ; AX = sectores libres
  2195.                XOR   DX,DX
  2196.                MOV   BL,ES:sect_cluster
  2197.                XOR   BH,BH
  2198.                DIV   BX                ; AX = nº de clusters
  2199.                XOR   DX,DX
  2200.                MOV   CL,5
  2201.                CALL  print_32
  2202.                LEA   DX,inf_tfat
  2203.                CALL  imprimir
  2204.                LEA   DX,inf_tfat12
  2205.                CMP   AX,4085           ; ¿FAT12?
  2206.                JB    ifat_ok
  2207.                LEA   DX,inf_tfat16
  2208. ifat_ok:       CALL  imprimir
  2209.                LEA   DX,inf_final
  2210.                CALL  imprimir
  2211.                RET
  2212. pr_info        ENDP
  2213.  
  2214.                ; --- Imprimir letra de unidad en AL.
  2215.  
  2216. impr_unidad    PROC
  2217.                XPUSH <AX, DX>
  2218.                MOV   AL,letra_unidad
  2219.                MOV   AH,0
  2220.                MOV   WORD PTR area_trabajo,AX
  2221.                LEA   DX,area_trabajo
  2222.                CALL  imprimir
  2223.                XPOP  <DX, AX>
  2224.                RET
  2225. impr_unidad    ENDP
  2226.  
  2227. ; --- Imprimir un nº decimal de 32 bits en DXAX formateado por CL.
  2228. ;
  2229. ; Entradas:
  2230. ;       Si bit 4  = 1 --> se imprimirán signos separadores de millar
  2231. ;       bits  0-3 = nº total de dígitos (incluyendo separadores de
  2232. ;                   millar y parte fraccional)
  2233. ;       bits  5-7 = nº de dígitos de la parte fraccional (cuantos
  2234. ;                   dígitos de DXAX, empezando por la derecha,
  2235. ;                   se consideran parte fraccional, e irán precedidos
  2236. ;                   del correspondiente separador)
  2237. ;
  2238. ; Salidas: nº impreso, ningún registro modificado.
  2239. ;
  2240. ; * Ejemplo, si DXAX=9384320 y  CL=010 1 1011
  2241. ;   se imprimirá ( '_' representa un espacio en blanco ):  __93.843,20
  2242.  
  2243. print_32       PROC
  2244.                PUSH  DS
  2245.                PUSH  ES
  2246.                PUSH  CS
  2247.                PUSH  CS
  2248.                POP   DS
  2249.                POP   ES
  2250.                PUSH  AX                ; preservar todos los registros
  2251.                PUSH  BX
  2252.                PUSH  CX
  2253.                PUSH  DX
  2254.                PUSH  SI
  2255.                PUSH  DI
  2256.                PUSHF
  2257.                MOV   formato_pr32,CL   ; byte del formato de impresión elegido
  2258.                MOV   CX,idioma_seps
  2259. separ_pr32:    MOV   millares_pr32,CH  ; separador de millares
  2260.                MOV   fracc_pr32,CL     ; separador parte fraccional
  2261.                MOV   BX,OFFSET tabla_pr32
  2262.                MOV   CX,10
  2263. digit_pr32:    PUSH  CX
  2264.                PUSH  AX
  2265.                PUSH  DX
  2266.                XOR   DI,DI
  2267.                MOV   SI,1              ; DISI = 1
  2268.                DEC   CX                ; CX - 1
  2269.                JCXZ  hecho_pr32
  2270. factor_pr32:   SAL   SI,1
  2271.                RCL   DI,1              ; DISI * 2
  2272.                MOV   DX,DI
  2273.                MOV   AX,SI
  2274.                SAL   SI,1
  2275.                RCL   DI,1
  2276.                SAL   SI,1
  2277.                RCL   DI,1              ; DISI * 8
  2278.                ADD   SI,AX
  2279.                ADC   DI,DX             ; DISI = DISI*8 + DISI*2 = DISI*10
  2280.                LOOP  factor_pr32       ; DISI = DISI*10*10* ... (CX-1 veces)
  2281. hecho_pr32:    POP   DX                ; luego DISI = 10 elevado a (CX-1)
  2282.                POP   AX                ; CX se recuperará más tarde
  2283.                MOV   CL,0FFh
  2284. rep_sub_pr32:  INC   CL
  2285.                SUB   AX,SI
  2286.                SBB   DX,DI             ; DXAX = DXAX - DISI
  2287.                JNC   rep_sub_pr32      ; restar el factor cuanto se pueda
  2288.                ADD   AX,SI             ; subsanar el desbordamiento:
  2289.                ADC   DX,DI             ; DXAX = DXAX + DISI
  2290.                ADD   CL,'0'            ; pasar binario a ASCII
  2291.                MOV   [BX],CL
  2292.                POP   CX                ; CX se recupera ahora
  2293.                INC   BX
  2294.                LOOP  digit_pr32        ; próximo dígito del número
  2295.                STD                     ; transferencias (MOVS) hacia atrás
  2296.                DEC   BX                ; BX apunta al último dígito
  2297.                MOV   final_pr32,BX     ; último dígito
  2298.                MOV   ent_frac_pr32,BX  ; frontera parte entera/fraccional
  2299.                MOV   CL,5
  2300.                MOV   AL,formato_pr32
  2301.                SHR   AL,CL             ; AL = nº de decimales
  2302.                AND   AL,AL
  2303.                JZ    no_frac_pr32      ; ninguno
  2304.                MOV   CL,AL
  2305.                XOR   CH,CH
  2306.                MOV   SI,final_pr32
  2307.                MOV   DI,SI
  2308.                INC   DI
  2309.                REP   MOVSB             ; correr cadena arriba (hacer hueco)
  2310.                INC   final_pr32
  2311.                MOV   AL,fracc_pr32
  2312.                MOV   [DI],AL           ; poner separador de parte fraccional
  2313.                MOV   ent_frac_pr32,SI  ; indicar nueva frontera
  2314. no_frac_pr32:  MOV   AL,formato_pr32
  2315.                TEST  AL,16             ; interpretar el formato especificado
  2316.                JZ    poner_pr32        ; imprimir como tal
  2317. entera_pr32:   MOV   CX,final_pr32     ; añadir separadores de millar
  2318.                SUB   CX,ent_frac_pr32
  2319.                ADD   CX,3
  2320.                MOV   SI,final_pr32
  2321.                MOV   DI,SI
  2322.                INC   DI
  2323.                REP   MOVSB             ; correr cadena arriba (hacer hueco)
  2324.                MOV   AL,millares_pr32
  2325.                MOV   [DI],AL           ; poner separador de millares
  2326.                INC   final_pr32
  2327.                MOV   ent_frac_pr32,SI  ; usar esta variable como puntero
  2328.                SUB   SI,OFFSET tabla_pr32
  2329.                CMP   SI,3
  2330.                JAE   entera_pr32       ; próximo separador
  2331. poner_pr32:    MOV   BX,final_pr32
  2332.                MOV   BYTE PTR [BX+1],0 ; delimitador de fin de cadena
  2333.                MOV   BX,OFFSET tabla_pr32
  2334.                MOV   principio_pr32,BX ; inicio de cadena
  2335. limpiar_pr32:  MOV   AL,[BX]
  2336.                CMP   AL,'0'
  2337.                JE    blanco_pr32       ; cero a la izda --> poner " "
  2338.                CMP   AL,millares_pr32  ; separador millares a la izda
  2339.                JE    blanco_pr32
  2340.                CMP   AL,fracc_pr32
  2341.                JNE   acabar_pr32
  2342.                MOV   BYTE PTR [BX-1],'0' ; reponer 0 antes de la coma
  2343.                DEC   principio_pr32
  2344. acabar_pr32:   MOV   AL,formato_pr32   ; imprimir
  2345.                AND   AL,00001111b
  2346.                XOR   AH,AH
  2347.                MOV   DX,final_pr32
  2348.                SUB   DX,AX
  2349.                INC   DX                ; DX = offset 'principio'
  2350.                AND   AX,AX
  2351.                JNZ   format_pr32       ; longitud especificada por el usuario
  2352.                MOV   DX,principio_pr32 ; longitud obtenida del número
  2353. format_pr32:   CALL  imprimir
  2354.                POPF                    ; restaurar todos los registros
  2355.                POP   DI
  2356.                POP   SI
  2357.                POP   DX
  2358.                POP   CX
  2359.                POP   BX
  2360.                POP   AX
  2361.                POP   ES
  2362.                POP   DS
  2363.                RET                     ; salida del procedimiento
  2364. blanco_pr32:   MOV   BYTE PTR [BX],' ' ; sustituir 0 ó separador de millares
  2365.                INC   BX                ; a la izda. por espacio en blanco
  2366.                INC   principio_pr32
  2367.                CMP   BX,final_pr32
  2368.                JB    limpiar_pr32
  2369.                MOV   DX,BX             ; es el número 0.000.000.00X
  2370.                JMP   SHORT acabar_pr32 ; imprimir
  2371. formato_pr32   DB    0
  2372.                DB    5 DUP (' ')       ; espacios en blanco para cubrir la
  2373.                                        ; mayor plantilla que pueda ser espe-
  2374.                                        ; cificada en el formato
  2375. tabla_pr32     DT    0                 ; reservar 14 bytes (nº más ., más ASCIIZ)
  2376.                DW    0,0               ; aquí se solapa un buffer de 32 bytes
  2377. millares_pr32  DB    '.'               ; separador de millares
  2378. fracc_pr32     DB    ','               ;     "     parte fraccional
  2379. final_pr32     DW    0                 ; offset al último byte a imprimir
  2380. principio_pr32 DW    0                 ;  "     "  primer   "  "     "
  2381. ent_frac_pr32  DW    0                 ; offset a la frontera entero-fracc.
  2382.                DT    0                 ; $ - tabla_pr32 = 32 bytes usados por
  2383.                                        ; INT 21h al principio de print_32
  2384. print_32       ENDP
  2385.  
  2386. ; ------------ Dividir DX:AX / CX sin desbordamientos (cociente: AX,
  2387. ;              resto: DX). Si el cociente excede los 16 bits, CF = 1
  2388. ;              y todos los registros intactos.
  2389.  
  2390. divCX          PROC
  2391.                XPUSH <BX,SI,CX,AX,DX>
  2392.                MOV   SI,32
  2393.                XOR   BX,BX
  2394. divmas:        SHL   AX,1
  2395.                RCL   DX,1
  2396.                RCL   BX,1
  2397.                CMP   BX,CX
  2398.                JB    dividido          ; "no cabe"
  2399.                SUB   BX,CX
  2400.                INC   AL                ; 1 al cociente
  2401. dividido:      DEC   SI
  2402.                JNZ   divmas
  2403.                AND   DX,DX
  2404.                JZ    div_ok
  2405.                XPOP  <DX,AX>           ; error
  2406.                STC
  2407.                JMP   div_fin
  2408. div_ok:        MOV   DX,BX             ; resto en DX y cociente en AX
  2409.                ADD   SP,4              ; «sacar» sin sacar DX y AX
  2410.                CLC
  2411. div_fin:       XPOP  <CX,SI,BX>        ; recuperar CX, SI y BX
  2412.                RET
  2413. divCX          ENDP
  2414.  
  2415. ; ------------ Impresión en color o monocroma (esta última
  2416. ;              redireccionable). Desde el CONFIG.SYS se imprime en
  2417. ;              monocromo para no llamar la atención, a menos que
  2418. ;              indiquen /M, al contrario que desde el DOS.
  2419.  
  2420. imprimir       PROC
  2421.                PUSH  AX
  2422.                MOV   AL,param_m
  2423.                CMP   modo,CONFIG       ; ¿en CONFIG.SYS?
  2424.                JNE   m_ok              ; no
  2425.                XOR   AL,ON             ; sí: /M opera al revés
  2426. m_ok:          MOV   pr_mono,AL
  2427.                CALL  print
  2428.                POP   AX
  2429.                RET
  2430. imprimir       ENDP
  2431.  
  2432. ; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
  2433. ;              Si acaba en 0, se imprime como tal; en caso contrario,
  2434. ;              se supone que el mensaje es multilingüe y los diversos
  2435. ;              idiomas (1, 2, ... N) separan sus cadenas por sucesivos
  2436. ;              códigos 255. El carácter de control 127 realiza una
  2437. ;              pausa hasta que se pulsa una tecla.
  2438.  
  2439. print          PROC
  2440.                XPUSH <AX, BX, CX, DX, SI, DI, ES>
  2441.                CMP   idioma,0
  2442.                JNE   pr_decidir
  2443.                PUSH  DX                ; *
  2444.                MOV   AH,30h
  2445.                INT   21h
  2446.                XCHG  AH,AL
  2447.                MOV   CX,AX             ; CX = versión del DOS
  2448.                CMP   param_i,ON
  2449.                MOV   AX,codigo_tfno
  2450.                MOV   BX,1234h
  2451.                JNE   pr_busca_cod      ; parámetro /I=cod no indicado
  2452.                MOV   BX,AX
  2453.                MOV   AL,0FFh
  2454.                CMP   BX,255
  2455.                JAE   pr_cod            ; código mayor o igual de 255
  2456.                MOV   AL,BL             ; código menor de 255
  2457. pr_cod:        CMP   CX,200h
  2458.                JAE   pr_cod_tfno       ; DOS >= 2.X
  2459. pr_busca_cod:  CMP   CX,200h
  2460.                MOV   AX,1              ; inglés para DOS < 2.X
  2461.                JB    pr_habla_ax
  2462.                MOV   AL,0
  2463. pr_cod_tfno:   LEA   DX,area_trabajo
  2464.                MOV   AH,38h
  2465.                XPUSH <BX, CX>
  2466.                INT   21h               ; obtener información del pais
  2467.                XPOP  <CX, AX>
  2468.                JC    pr_habla_ax       ; fallo en la función
  2469.                CMP   CX,20Bh
  2470.                JE    pr_habla_ax       ; DOS 2.11: AX cód. telefónico
  2471.                CMP   CX,300h
  2472.                MOV   AX,1
  2473.                JB    pr_habla_ax       ; 2.x excepto 2.11: mala suerte
  2474.                MOV   AX,BX
  2475.                LEA   BX,area_trabajo
  2476.                MOV   CH,[BX+7]         ; separador de millares
  2477.                MOV   CL,[BX+9]         ; separador de decimales
  2478.                MOV   idioma_seps,CX
  2479. pr_habla_ax:   LEA   BX,info_paises-2
  2480.                MOV   CX,1              ; supuesto idioma 1
  2481. pr_busca_idi:  ADD   BX,2
  2482.                MOV   DX,[BX]
  2483.                CMP   AX,DX
  2484.                JE    pr_habla_ese
  2485.                AND   DX,DX
  2486.                JNZ   pr_busca_idi
  2487.                INC   CX                ; será otro idioma
  2488.                CMP   [BX+2],DX
  2489.                JNE   pr_busca_idi      ; no es fin de la tabla
  2490. pr_habla_ese:  MOV   idioma,CL
  2491.                POP   DX                ; *
  2492.  
  2493. pr_decidir:    MOV   CL,idioma
  2494.                MOV   CH,0              ; nº de idioma a usar (1..N)
  2495.                MOV   BX,DX
  2496. pr_busca_msg:  MOV   DX,BX
  2497.                DEC   BX
  2498. pr_busca_ter:  INC   BX
  2499.                CMP   BYTE PTR [BX],0
  2500.                JE    pr_usar_ese       ; acaba en 0: no buscar más
  2501.                CMP   BYTE PTR [BX],255
  2502.                JNE   pr_busca_ter
  2503.                INC   BX
  2504.                LOOP  pr_busca_msg      ; acaba en 255 pero no es ese
  2505. pr_usar_ese:   MOV   BX,DX
  2506.                DEC   BX
  2507. pr_cad_lon:    INC   BX
  2508.                CMP   BYTE PTR [BX],0
  2509.                JE    prlong_ok
  2510.                CMP   BYTE PTR [BX],127 ; carácter de pausa
  2511.                JE    prpausa
  2512.                CMP   BYTE PTR [BX],255
  2513.                JNE   pr_cad_lon        ; calcular longitud
  2514.                JMP   prlong_ok
  2515. prpausa:       PUSH  BX
  2516.                MOV   CX,BX
  2517.                SUB   CX,DX
  2518.                CALL  pr_cad            ; imprimir hasta el código 127
  2519. pr_limpbuf:    MOV   AH,1
  2520.                INT   16h
  2521.                JZ    pr_notec
  2522.                MOV   AH,0
  2523.                INT   16h               ; limpiar buffer del teclado
  2524.                JMP   pr_limpbuf
  2525. pr_notec:      MOV   AH,0
  2526.                INT   16h               ; esperar tecla
  2527.                POP   BX
  2528.                INC   BX
  2529.                MOV   DX,BX
  2530.                CMP   AL,27             ; ¿tecla ESC?
  2531.                STC
  2532.                JE    pr_ret
  2533.                JMP   pr_cad_lon        ; imprimir el resto
  2534. prlong_ok:     MOV   CX,BX
  2535.                SUB   CX,DX
  2536.                CALL  pr_cad            ; terminar impresión
  2537.                CLC
  2538. pr_ret:        XPOP  <ES, DI, SI, DX, CX, BX, AX>  ; CF=1 si se pulsó ESC
  2539.                RET
  2540. pr_cad:        ; MOV   AH,40h
  2541.                ; MOV   BX,1
  2542.                ; INT   21h               ; imprimir con el DOS
  2543.                MOV   SI,DX
  2544.                LEA   DI,area_trabajo
  2545.                PUSH  DS
  2546.                POP   ES                ; por si acaso
  2547.                CLD
  2548.                REP   MOVSB
  2549.                MOV   [DI],CL           ; ASCIIZ
  2550.                LEA   DX,area_trabajo
  2551.                CALL  MultiPrint        ; imprimir en color
  2552.                RET
  2553. print          ENDP
  2554.  
  2555. ; ------------ Impresión en pantalla, en color o monocromo, usando el
  2556. ;              BIOS o el DOS respectivamente. Antes deberá ejecutarse
  2557. ;              InitMultiPrint para inicializar.   Al  hacer scroll se
  2558. ;              intenta respetar el posible  color  global  de  fondo.
  2559. ;              Con «pr_mono» en ON se solicita imprimir en monocromo.
  2560. ;
  2561. ;              - El texto a imprimir es apuntado por DS:DX.
  2562. ;              - Códigos de control soportados:
  2563. ;
  2564. ;                 0 -> final de cadena
  2565. ;                 1 -> el siguiente carácter indica el color (BIOS)
  2566. ;                 2 -> el siguiente carácter indica el nº de veces que
  2567. ;                      se imprimirá el que viene detrás
  2568. ;                 3 -> avanzar cursor a la derecha
  2569. ;                10 -> retorno de carro y salto de línea estilo UNIX
  2570.  
  2571. MultiPrint     PROC
  2572.                XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
  2573.                PUSH  DS
  2574.                POP   ES
  2575.                PUSH  CS
  2576.                POP   DS
  2577.                LEA   AX,pr_AL_dos
  2578.                CMP   pr_mono,ON
  2579.                JE    pr_rut_ok
  2580.                LEA   AX,pr_AL_bios
  2581. pr_rut_ok:     MOV   pr_rut,AX         ; instalar rutina de impresión
  2582.                MOV   BX,DX
  2583. pr_otro:       MOV   AL,ES:[BX]
  2584.                PUSH  BX
  2585.                CMP   AL,' '
  2586.                JAE   pr_ASCII          ; no es un código de control
  2587.                AND   AL,AL
  2588.                JZ    pr_exit           ; código de control 0: final
  2589.                CMP   AL,1
  2590.                JE    pr_setcolor       ; código de control 1: color
  2591.                CMP   AL,2
  2592.                JE    pr_setveces       ; código de control 2: repetir
  2593. pr_ASCII:      CALL  pr_rut
  2594.                POP   BX
  2595.                INC   BX
  2596.                JMP   pr_otro
  2597. pr_setcolor:   MOV   AL,ES:[BX+1]
  2598.                MOV   pr_color,AL       ; actualizar color
  2599.                POP   BX
  2600.                ADD   BX,2
  2601.                JMP   pr_otro
  2602. pr_setveces:   MOV   AL,ES:[BX+1]
  2603.                MOV   pr_veces,AL       ; actualizar repeticiones
  2604.                POP   BX
  2605.                ADD   BX,2
  2606.                JMP   pr_otro
  2607. pr_exit:       XPOP  <BX,ES,DS,BP,DI,SI,DX,CX,BX,AX>
  2608.                RET
  2609. MultiPrint     ENDP
  2610.  
  2611. pr_AL_bios     PROC                    ; imprimir en color usando BIOS
  2612.                PUSH  AX
  2613.                MOV   AH,3
  2614.                MOV   BH,pr_pagina
  2615.                INT   10h               ; DX = coordenadas del cursor
  2616.                POP   AX
  2617.                CMP   AL,3
  2618.                JE    pr_derecha        ; código de control 3: avanzar
  2619.                CMP   AL,10
  2620.                JE    pr_crlf           ; código de control 10: CR & LF
  2621.                MOV   AH,9
  2622.                MOV   BH,pr_pagina
  2623.                MOV   BL,pr_color
  2624.                MOV   CL,pr_veces
  2625.                XOR   CH,CH
  2626.                PUSH  DX
  2627.                INT   10h               ; imprimir carácter
  2628.                POP   DX
  2629. pr_derecha:    ADD   DL,pr_veces
  2630.                MOV   pr_veces,1
  2631.                CMP   DL,pr_maxX
  2632.                JBE   pr_av
  2633. pr_crlf:       XOR   DL,DL             ; volver al inicio de línea
  2634.                INC   DH                ; salto a la siguiente
  2635.                CMP   DH,pr_maxY
  2636.                JBE   pr_av
  2637.                DEC   DH
  2638.                PUSH  DX                ; es preciso hacer scroll
  2639.                MOV   AX,601h
  2640.                MOV   BH,pr_colorb      ; color por defecto
  2641.                XOR   CX,CX
  2642.                MOV   DL,pr_maxX
  2643.                MOV   DH,pr_maxY
  2644.                INT   10h               ; hacer scroll usando BIOS
  2645.                POP   DX
  2646. pr_av:         MOV   BH,pr_pagina
  2647.                MOV   AH,2
  2648.                INT   10h               ; posicionar cursor
  2649.                RET                     ; retorno del procedimiento
  2650. pr_AL_bios     ENDP
  2651.  
  2652. pr_AL_dos      PROC                    ; imprimir usando DOS
  2653.                CMP   AL,3
  2654.                JNE   pr_no_der
  2655.                MOV   AL,' '            ; código de control 3: avanzar
  2656. pr_no_der:     CMP   AL,10
  2657.                JNE   pr_dos
  2658.                MOV   AL,13             ; código de control 10: CR & LF
  2659.                CALL  pr_dos            ; llamada "recursiva"
  2660.                MOV   AL,10
  2661. pr_dos:        MOV   CL,pr_veces
  2662.                XOR   CH,CH
  2663.                MOV   pr_veces,1
  2664.                MOV   DL,AL
  2665. pr_chr:        XPUSH <DX,CX>
  2666.                MOV   AH,2
  2667.                INT   21h               ; imprimir carácter
  2668.                XPOP  <CX,DX>
  2669.                LOOP  pr_chr
  2670.                RET
  2671. pr_AL_dos      ENDP
  2672.  
  2673. InitMultiPrint PROC
  2674.                XPUSH <AX,BX,CX,DX,BP,DS,ES>
  2675.                PUSH  CS
  2676.                POP   DS
  2677.                MOV   pr_veces,1
  2678.                MOV   pr_color,15       ; valores por defecto
  2679.                MOV   pr_mono,OFF
  2680. pr_i_80?:      MOV   AH,0Fh
  2681.                INT   10h
  2682.                CMP   AH,80             ; ¿80 ó más columnas?
  2683.                JAE   pr_i_video_ok     ; así es
  2684.                MOV   AX,3
  2685.                INT   10h               ; forzar modo de 80 columnas
  2686.                JMP   pr_i_80?
  2687. pr_i_video_ok: MOV   pr_maxX,AH        ; inicializar máxima coord. X
  2688.                MOV   pr_pagina,BH      ; inicializar página activa
  2689.                MOV   AX,40h
  2690.                MOV   ES,AX             ; ES: -> variables del BIOS
  2691.                MOV   AL,ES:[84h]       ; variable de nº líneas - 1
  2692.                CMP   AL,24             ; ¿el BIOS define la variable?
  2693.                JB    pr_i_maxy_ok      ; no
  2694.                MOV   pr_maxY,AL        ; inicializar máxima coord. Y
  2695. pr_i_maxy_ok:  MOV   AH,8              ; (BH = página)
  2696.                INT   10h               ; obtener color por defecto
  2697.                MOV   pr_colorb,AH
  2698.                XPOP  <ES,DS,BP,DX,CX,BX,AX>
  2699.                RET
  2700. InitMultiPrint ENDP
  2701.  
  2702. pr_pagina      DB    0       ; página de visualización activa
  2703. pr_veces       DB    1       ; veces que se imprime cada carácter
  2704. pr_color       DB    15      ; color BIOS para imprimir
  2705. pr_colorb      DB    ?       ; color por defecto en pantalla
  2706. pr_maxX        DB    80      ; máxima coordenada X en pantalla
  2707. pr_maxY        DB    24      ; máxima coordenada Y en pantalla
  2708. pr_mono        DB    OFF     ; a ON si imprimir en monocromo
  2709. pr_rut         DW    ?       ; apunta a pr_AL_bios / pr_AL_dos
  2710.  
  2711. ; ------------ Rutina de gestión de memoria XMS. Se copiará sobre
  2712. ;              la de memoria EMS si se utiliza memoria XMS.
  2713. ;              En esta rutina se emplea la pila para pasar los
  2714. ;              parámetros al controlador XMS.
  2715.  
  2716. procesa_xms    PROC
  2717.                MOV   DS,CS:mem_handle
  2718.                JNC   no_xmslib
  2719.                .286                    ; rutina ejecutada desde 286+
  2720.                PUSHA                   ; sistema reinicializando:
  2721.                MOV   AH,0Dh
  2722.                CALL  llama_XMS         ; desbloquear EMB (prudente)
  2723.                MOV   AH,0Ah
  2724.                CALL  llama_XMS         ; liberar EMB
  2725.                POPA
  2726.                .8086
  2727.                RET
  2728. no_xmslib:     DEC   BP                ; leer/escribir en el disco
  2729.                JNZ   xms_escribe
  2730.                PUSH  ES
  2731.                PUSH  DI                ; segmento:offset destino
  2732.                PUSH  BP                ; handle destino (BP=0)
  2733. xms_escribe:   PUSH  DX
  2734.                PUSH  AX                ; desplazamiento DX:AX
  2735.                PUSH  DS                ; handle fuente/destino
  2736.                JZ    xms_general
  2737.                INC   BP                ; hacer BP = 0
  2738.                PUSH  ES
  2739.                PUSH  DI                ; segmento:offset fuente
  2740.                PUSH  BP                ; handle fuente (BP=0)
  2741. xms_general:   SHL   CX,1              ; palabras -> bytes
  2742.                RCL   BP,1              ; BP era 0
  2743.                PUSH  BP                ; tamaño bloque (parte alta)
  2744.                PUSH  CX                ; tamaño bloque (parte baja)
  2745.                MOV   SI,SP
  2746.                PUSH  SS
  2747.                POP   DS                ; DS:SI apuntando a la pila
  2748.                MOV   AH,0Bh            ; función para mover EMB
  2749.                CALL  llama_XMS         ; mover EMB (DS no importa)
  2750.                ADD   SP,16             ; equilibrar pila
  2751.                CMP   AL,1              ; ¿falló el controlador?
  2752.                JE    xms_proc_ok
  2753.                MOV   AX,0C81h          ; anomalía general
  2754. xms_proc_ok:   XCHG  AH,AL             ; colocar resultado
  2755.                RET
  2756. procesa_xms    ENDP
  2757.  
  2758. llama_XMS      PROC
  2759.                MOV   DX,DS             ; handle en DS (si utilizado)
  2760.                CALL  CS:xms_driver     ; ejecutar función XMS
  2761.                RET
  2762. llama_XMS      ENDP
  2763.  
  2764. tam_proc_xms   EQU   $-OFFSET procesa_xms   ; tamaño de esta rutina
  2765.  
  2766. ; ------------ Rutina de gestión de memoria convencional. Se copiará
  2767. ;              sobre la de memoria EMS si se utiliza memoria conv.
  2768.  
  2769. procesa_con    PROC
  2770.                JC    con_exit          ; sistema inicializándose
  2771.                MOV   BX,16             ; bytes por párrafo
  2772.                DIV   BX                ; AX = segmento, DX = offset
  2773.                ADD   AX,CS:mem_handle  ; segmento de inicio datos
  2774.                MOV   DS,AX
  2775.                MOV   SI,DX             ; DS:SI inicio de datos
  2776.                DEC   BP                ; y ES:DI destino del buffer
  2777.                JZ    con_general       ; es lectura
  2778.                XCHG  SI,DI             ; escritura: intercambiar
  2779.                XPUSH <DS,ES>
  2780.                XPOP  <DS,ES>
  2781. con_general:   CLD
  2782.                CMP   CS:cpu386,ON
  2783.                JE    con_tr32bit
  2784.                REP   MOVSW
  2785.                JMP   con_tr_fin
  2786. con_tr32bit:   SHR   CX,1              ; nº palabras de 32 bit a mover
  2787.                JCXZ  con_trdo          ; evitar desgracia
  2788.                .386
  2789.                PUSHAD
  2790.                XOR   EAX,EAX           ; asegurar no violación
  2791.                DEC   AX                ; de segmento-64K
  2792.                AND   ECX,EAX           ; EAX = 0FFFFh
  2793.                AND   ESI,EAX
  2794.                AND   EDI,EAX
  2795.                REP   MOVSD             ; transferencia ultrarrápida
  2796. con_trdo:      POPAD                   ; POPAD falla en muchos 386
  2797.                NOP                     ; arreglar fallo de POPAD
  2798.                .8086
  2799. con_tr_fin:    MOV   AX,100h           ; todo fue bien, por supuesto
  2800. con_exit:      RET
  2801. procesa_con    ENDP
  2802.  
  2803. tam_proc_con   EQU   $-OFFSET procesa_con   ; tamaño de esta rutina
  2804.  
  2805.  
  2806. ; ************ Datos no residentes para la instalación
  2807.  
  2808. ON             EQU   1            ; constantes booleanas
  2809. OFF            EQU   0
  2810.  
  2811. CONFIG         EQU   1            ; TURBODSK ejecutado desde el CONFIG
  2812. AUTOEXEC       EQU   2            ; TURBODSK se ejecuta desde el DOS
  2813.  
  2814. emm_id         DB    "EMMXXXX0"   ; identificación del controlador EMS
  2815.  
  2816. nombre_tdsk    DB    "TDSK U: "   ; para nombrar handle EMS y el MCB
  2817.  
  2818. modo           DB    ?            ; CONFIG/AUTOEXEC
  2819. dosver         DW    ?            ; versión del DOS
  2820. top_ram        DW    0            ; segmento más alto de la RAM
  2821. segm_psp       DW    0            ; segmento del PSP
  2822. segm_tdsk      DW    0            ; segmento donde reside TURBODSK
  2823. segm_reubicar  DW    0            ; segmento donde reubicar TURBODSK
  2824. ems4           DB    OFF          ; a ON si EMS versión 4.0+
  2825. cpu286         DB    OFF          ; a ON si 286 ó superior
  2826. idioma         DB    0            ; selecciona el número de idioma (1..N)
  2827. idioma_seps    DW    ",."         ; separadores de millares/decimales
  2828.  
  2829. param_unidad   DB    0            ; letra de unidad (si indicada)
  2830. param_tdiscof  DB    OFF          ; a ON si se define tamaño de disco
  2831. param_tdisco   DW    0            ; tamaño de disco (si se define)
  2832. param_tsect    DW    0            ; tamaño de sector (si se define)
  2833. param_tdir     DW    0            ; número de entradas (si se define)
  2834. param_tcluster DW    0            ; tamaño de cluster (si se define)
  2835. param_a        DB    OFF          ; a ON si indicado parámetro /A o /X
  2836. param_e        DB    OFF          ; a ON si indicado parámetro /E
  2837. param_c        DB    OFF          ; a ON si indicado parámetro /C
  2838. param_h        DB    OFF          ; a ON si indicado parámetro /? o /H
  2839. param_m        DB    OFF          ; a ON si indicado parámetro /M
  2840. param_i        DB    OFF          ; Y ON si indicado parámetro /I
  2841. param_f        DW    1            ; nº de FATs (1-2): parámetro /F=
  2842.  
  2843. codigo_tfno    DW    ?            ; valor de /I= si se indica
  2844. tdisco         DW    ?            ; tamaño de disco (Kb)
  2845. ultclus        DW    ?            ; número más alto de cluster
  2846. tamcluster     DW    ?            ; tamaño de cluster (bytes)
  2847. sdir           DW    ?            ; sectores para directorio raiz
  2848. xms_kb         DW    0            ; Kb de memoria XMS libres
  2849. ems_kb         DW    0            ; Kb de memoria EMS libres
  2850. con_kb         DW    0            ; Kb de memoria convencional libres
  2851.  
  2852. sector_cero    LABEL BYTE
  2853.                JMP   SHORT botar
  2854.                NOP
  2855.                DB    "TDSK 2.2"   ; identificación del sistema
  2856. tsect          DW    512          ; tamaño de sector por defecto
  2857. tcluster       DB    ?            ; sectores por cluster
  2858.                DW    1            ; sectores reservados
  2859. nfats          DB    ?            ; número de FAT's
  2860. tdir           DW    ?            ; número de entradas al dir. raiz
  2861. numsect        DW    ?            ; nº sectores del disco (<=32Mb)
  2862.                DB    media        ; descriptor de medio
  2863. sfat           DW    ?            ; sectores por FAT
  2864.                DW    1, 1         ; sectores por pista / cabezas
  2865.                DD    0            ; sectores ocultos
  2866.                DD    0            ; nº total de sectores (si > 32Mb)
  2867.                DB    7 DUP (0)    ; 7 bytes reservados
  2868. botar:         DB    0EAh         ; código de JMP FAR...
  2869.                DW    0,0FFFFh     ; ...FFFF:0000 (programa BOOT)
  2870.                DB    "(C)1992 CiriSOFT"; resto de primeros 64 bytes
  2871.                DB    ". Grupo Universi"
  2872.                DB    "tario de Informá"
  2873.                DB    "tica (GUI) - Val"
  2874.                DB    "ladolid (España)"; resto de primeros 128 bytes
  2875.  
  2876. dir_raiz       DB    "TURBODSK   "; Directorio raiz: primera entrada
  2877.                DB    8            ; etiqueta de volúmen
  2878.                DB    10 DUP (0)   ; reservado
  2879.                DW    ?            ; hora (inicializado al formatear)
  2880.                DW    ?            ; fecha
  2881.                DW    0,0,0        ; últimos bytes (hasta 32)
  2882.  
  2883. ; ------------ Areas de datos para información del disco virtual
  2884.  
  2885.                ; --- Código telefónico de países de habla
  2886.                ;     hispana (mucha o poca).
  2887.  
  2888. info_paises    DW    54                ; Argentina
  2889.                DW    591               ; Bolivia
  2890.                DW    57                ; Colombia
  2891.                DW    506               ; Costa Rica
  2892.                DW    56                ; Chile
  2893.                DW    593               ; Ecuador
  2894.                DW    503               ; El Salvador
  2895.                DW    34                ; España
  2896.                DW    63                ; Filipinas
  2897.                DW    502               ; Guatemala
  2898.                DW    504               ; Honduras
  2899.                DW    212               ; Marruecos
  2900.                DW    52                ; México
  2901.                DW    505               ; Nicaragua
  2902.                DW    507               ; Panamá
  2903.                DW    595               ; Paraguay
  2904.                DW    51                ; Perú
  2905.                DW    80                ; Puerto Rico
  2906.                DW    508               ; República Dominicana
  2907.                DW    598               ; Uruguay
  2908.                DW    58                ; Venezuela
  2909.                DW    3                 ; Latinoamérica
  2910.                DW    0                 ; fin de la información
  2911.  
  2912.                ; --- Código telefónico de países de habla alemana.
  2913.  
  2914.                DW    41                ; Switzerland
  2915.                DW    43                ; Austria
  2916.                DW    49                ; Germany
  2917.                DW    0                 ; fin de la información
  2918.  
  2919.                DW    0                 ; no más idiomas
  2920.  
  2921. ; ------------ Mensaje de no formateado
  2922.  
  2923. info_ins       DB    10,1,10,"TURBODSK 2.2 - Unidad ",255
  2924.                DB    10,1,10,"TURBODSK 2.2 - Laufwerk ",255
  2925.                DB    10,1,10,"TURBODSK 2.2 - Drive ",0
  2926.  
  2927. info_ins2      DB    ": sin formatear.",10,1,14,255
  2928.                DB    ": nicht formatiert.",10,1,14,255
  2929.                DB    ": unformatted.",10,1,14,0
  2930.  
  2931. ; ------------ Cuadro de información
  2932.  
  2933. colA EQU 11+1*16  ; color del recuadro y los mensajes
  2934. colB EQU 15+1*16  ; color de los parámetros de operación del disco
  2935. colC EQU 15+0*16  ; color de lo que rodea a la ventana
  2936. colD EQU 10+1*16  ; color de «TURBODSK»
  2937.  
  2938. info_txt       DB    10,2,12,3,1,colA,"┌",2,27,"─┬",2,25,"─┐",1,colC
  2939.                DB    10,2,12,3,1,colA,"│ ",1,colD,"TURBODSK 2.2",1,colA
  2940.                DB    " - Unidad ",1,colB
  2941.                DB    255
  2942.  
  2943.                DB    10,2,10,3,1,colA,"┌",2,28,"─┬",2,28,"─┐",1,colC
  2944.                DB    10,2,10,3,1,colA,"│ ",1,colD,"TURBODSK 2.2",1,colA
  2945.                DB    " - Laufwerk ",1,colB
  2946.                DB    255
  2947.  
  2948.                DB    10,2,12,3,1,colA,"┌",2,26,"─┬",2,25,"─┐",1,colC
  2949.                DB    10,2,12,3,1,colA,"│ ",1,colD,"TURBODSK 2.2",1,colA
  2950.                DB    " - Drive ",1,colB
  2951.                DB    0
  2952.  
  2953. inf_tsect      DB    ":",1,colA,"  │ Tamaño de sector:",1,colB," ",255
  2954.                DB    ":",1,colA," │ Sektorgröße:",2,8," ",1,colB," ",255
  2955.                DB    ":",1,colA,"  │ Sector size:",2,5," ",1,colB," ",0
  2956.  
  2957. inf_tdir       DB    " ",1,colA,"│",1,colC,10,2,12,3
  2958.                DB    1,colA,"├",2,27,"─┤ Nº entradas raiz:",1,colB," "
  2959.                DB    255
  2960.  
  2961.                DB    " ",1,colA,"│",1,colC,10,2,10,3
  2962.                DB    1,colA,"├",2,28,"─┤ Verzeichniseinträge:",1,colB, " "
  2963.                DB    255
  2964.  
  2965.                DB    " ",1,colA,"│",1,colC,10,2,12,3
  2966.                DB    1,colA,"├",2,26,"─┤ Root entries:",2,4," ",1,colB," "
  2967.                DB    0
  2968.  
  2969. inf_tdisco     DB    " ",1,colA,"│",1,colC,10
  2970.                DB    2,12,3,1,colA,"│ Tamaño:  ",1,colB," "
  2971.                DB    255
  2972.  
  2973.                DB    " ",1,colA,"│",1,colC,10
  2974.                DB    2,10,3,1,colA,"│ Größe:",2,10," ",1,colB," "
  2975.                DB    255
  2976.  
  2977.                DB    " ",1,colA,"│",1,colC,10
  2978.                DB    2,12,3,1,colA,"│ Size:",2,4," ",1,colB," "
  2979.                DB    0
  2980.  
  2981. inf_tcluster   DB    " Kbytes    ",1,colA,"│ Sectores/cluster:",1,colB," "
  2982.                DB    255
  2983.                DB    " KB  ",1,colA,"│ Sektoren/Cluster:",2,3," ",1,colB," "
  2984.                DB    255
  2985.                DB    " Kbytes   ",1,colA,"│ Sectors/cluster: ",1,colB," "
  2986.                DB    0
  2987.  
  2988. inf_mem        DB    " ",1,colA,"│",1,colC,10
  2989.                DB    2,12,3,1,colA,"│ Memoria:  ",1,colB
  2990.                DB    255
  2991.  
  2992.                DB    " ",1,colA,"│",1,colC,10
  2993.                DB    2,10,3,1,colA,"│ Speicher: ",1,colB
  2994.                DB    255
  2995.  
  2996.                DB    " ",1,colA,"│",1,colC,10
  2997.                DB    2,12,3,1,colA,"│ Memory:   ",1,colB
  2998.                DB    0
  2999.  
  3000. inf_nclusters  DB    " ",1,colA,"│",1,colB," ",255
  3001.                DB    "  ",1,colA,"│",1,colB," ",255
  3002.                DB    1,colA,"│",1,colB," ",0
  3003.  
  3004. inf_tfat       DB    1,colA," clusters (",1,colB,"FAT",255
  3005.                DB    1,colA," Cluster  (",1,colB,"FAT",255
  3006.                DB    1,colA," clusters (",1,colB,"FAT",0
  3007.  
  3008. inf_tfat12     DB    "12",0
  3009. inf_tfat16     DB    "16",0
  3010.  
  3011. inf_final      DB    1,colA,")  ",1,colA,"│",1,colC,10,2,12,3
  3012.                DB    1,colA,"└",2,27,"─┴",2,25,"─┘",1,colC,10
  3013.                DB    255
  3014.  
  3015.                DB    1,colA,")",2,5," ",1,colA,"│",1,colC,10
  3016.                DB    2,10,3,1,colA,"└",2,28,"─┴",2,28,"─┘",1,colC,10
  3017.                DB    255
  3018.  
  3019.                DB    1,colA,")  ",1,colA,"│",1,colC,10,2,12,3
  3020.                DB    1,colA,"└",2,26,"─┴",2,25,"─┘",1,colC,10
  3021.                DB    0
  3022.  
  3023. inf_mem_xms    DB    "Extendida (XMS)",255
  3024.                DB    "Erweitert (XMS)",255
  3025.                DB    "Extended (XMS) ",0
  3026.  
  3027. inf_mem_ems    DB    "Expandida (EMS)",255
  3028.                DB    "Expansion (EMS)",255
  3029.                DB    "Expanded (EMS) ",0
  3030.  
  3031. inf_mem_sup    DB    " Superior (UMB) ",255
  3032.                DB    "Oberer Sp. (UMB)",255
  3033.                DB    "   Upper (UMB)  ",0
  3034.  
  3035. inf_mem_con    DB    "  Convencional ",255
  3036.                DB    "  Konventionell",255
  3037.                DB    "  Conventional ",0
  3038.  
  3039. ; ------------ Errores «leves»
  3040.  
  3041. ERROR0         EQU   1
  3042. ERROR1         EQU   2
  3043. ERROR2         EQU   4
  3044. ERROR3         EQU   8         ; TURBODSK es muy flexible y se instala
  3045. ERROR4         EQU   16        ; casi de cualquier forma, aunque a
  3046. ERROR5         EQU   32        ; veces no se reserve memoria y sea
  3047. ERROR6         EQU   64        ; necesario volver a ejecutarlo después
  3048. ERROR7         EQU   128       ; desde el DOS para «formatearlo».
  3049. ERROR8         EQU   256
  3050. ERROR9         EQU   512
  3051. ERROR10        EQU   1024
  3052. ERROR11        EQU   2048
  3053. ERROR12        EQU   4096
  3054. ERROR13        EQU   8192
  3055. ERROR14        EQU   16384
  3056. ERROR15        EQU   32768
  3057.  
  3058. lista_err      DW    0    ; palabra que indica los mensajes a imprimir
  3059.  
  3060. mens_cabec     DB    2,8,3,0
  3061.  
  3062. tabla_mens     DW    m0,m1,m2,m3,m4,m5,m6,m7
  3063.                DW    m8,m9,m10,m11,m12,m13,m14,m15
  3064.  
  3065. cab_adv_txt    DB    10,2,8,3,1,12
  3066.                DB    "Advertencias y/o errores de TURBODSK:",2,27," ",10,1,10
  3067.                DB    255
  3068.  
  3069.                DB    10,2,8,3,1,12
  3070.                DB    "Warnungen und Fehlermeldungen von TURBODSK:",2,27," ",10,1,10
  3071.                DB    255
  3072.  
  3073.                DB    10,2,8,3,1,12
  3074.                DB    "Warnings and errors of TURBODSK:",2,32," ",10,1,10
  3075.                DB    0
  3076.  
  3077. m0             DB    "- Error de sintaxis o parámetro fuera de rango.  No se define el",10,2,8,3
  3078.                DB    "  disco virtual ahora o no se modifica el que estaba definido.  ",10
  3079.                DB    255
  3080.  
  3081.                DB    "- Syntaxfehler oder ungültiger Parameter. Die RAM-Disk ist zur  ",10,2,8,3
  3082.                DB    "  Zeit nicht definiert bzw. wurde nicht modifiziert.",10
  3083.                DB    255
  3084.  
  3085.                DB    "- Syntax error and/or parameter out of range. The Ramdisk is not",10,2,8,3
  3086.                DB    "  defined now or the previous one is not modified.",2,14," ",10
  3087.                DB    0
  3088.  
  3089. m1             DB    "- El parámetro /C o la letra de unidad sólo han de emplearse",2,4," ",10,2,8,3
  3090.                DB    "  desde la línea de comandos o el AUTOEXEC (les ignoraré).",2,6," ",10
  3091.                DB    255
  3092.  
  3093.                DB    "- Parameter /C und Laufwerksbuchstaben können nur bei Aufrufen  ",2,4," ",10,2,8,3
  3094.                DB    "  von TURBODSK in der AUTOEXEC verwendet werden.                ",2,6," ",10
  3095.                DB    255
  3096.  
  3097.                DB    "- The /C parameter and the driver letter only can be used when  ",10,2,8,3
  3098.                DB    "  executing TURBODSK in command line or AUTOEXEC (now, ignored).",10
  3099.                DB    0
  3100.  
  3101. m2             DB    "- Para poder emplear memoria expandida hay que incluir la opción",10,2,8,3
  3102.                DB    "  /A en CONFIG.SYS, con objeto de dejar espacio para las rutinas",10,2,8,3
  3103.                DB    "  de control EMS: la memoria ocupada crecerá de 432 a 608 bytes.",10
  3104.                DB    255
  3105.  
  3106.                DB    "- Zur Verwendung von EMS müssen Sie Option /A in CONFIG.SYS     ",10,2,8,3
  3107.                DB    "  setzen, um Speicher für die EMS-Unterstützung zu reservieren. ",10,2,8,3
  3108.                DB    "  Dadurch erhöht sich der Speicherbedarf von 432 auf 608 Bytes. ",10
  3109.                DB    255
  3110.  
  3111.                DB    "- In order to use expanded memory you must include the /A option",10,2,8,3
  3112.                DB    "  in CONFIG.SYS, needed to reserve too space for the EMS support",10,2,8,3
  3113.                DB    "  routines: the memory used will increase from 432 to 608 bytes.",10
  3114.                DB    0
  3115.  
  3116. m3             DB    "- El tamaño de sector es mayor que el definido en cualquier otro",10,2,8,3
  3117.                DB    "  controlador de dispositivo: indíquese ese tamaño en CONFIG.SYS",10,2,8,3
  3118.                DB    "  para que el DOS ajuste sus buffers (¡más consumo de memoria!).",10
  3119.                DB    255
  3120.  
  3121.                DB    "- Die Sektorengröße ist größer als in allen anderen Treibern;   ",10,2,8,3
  3122.                DB    "  Sie müssen die Sektorgröße in CONFIG.SYS festlegen, da DOS die",10,2,8,3
  3123.                DB    "  Puffergröße anpassen muß (höherer Speicherverbrauch)          ",10
  3124.                DB    255
  3125.  
  3126.                DB    "- Sector size is greater than any other defined  by  any  device",10,2,8,3
  3127.                DB    "  driver loaded: you must indicate the sector size in CONFIG.SYS",10,2,8,3
  3128.                DB    "  because DOS need adjust buffers length (more memory spent!).  ",10
  3129.                DB    0
  3130.  
  3131. m4             DB    "- La cantidad de memoria solicitada no existe, se ha rebajado.  ",10
  3132.                DB    255
  3133.  
  3134.                DB    "- Die gewünschte Speichergröße existiert nicht und wurde reduziert.",10
  3135.                DB    255
  3136.  
  3137.                DB    "- The amount of memory requested does not exist: size reduced.  ",10
  3138.                DB    0
  3139.  
  3140. m5             DB    "- No hay memoria XMS/EMS disponible: no la reservo; ejecute TDSK",10,2,8,3
  3141.                DB    "  de nuevo desde el DOS para utilizar memoria convencional.",2,5," ",10
  3142.                DB    255
  3143.  
  3144.                DB    "- Kein XMS/EMS verfügbar: Führen Sie TDSK nochmals von der      ",10,2,8,3
  3145.                DB    "  Kommandozeile aus und benutzen Sie konventionellen Speicher.  ",2,5," ",10
  3146.                DB    255
  3147.  
  3148.                DB    "- There is not XMS/EMS memory available: execute TDSK again from",10,2,8,3
  3149.                DB    "  DOS command line or AUTOEXEC and use conventional memory.",2,5," ",10
  3150.                DB    0
  3151.  
  3152. m6             DB    "- No existe memoria XMS: pruebe a indicar EMS en su lugar (/A)  ",10
  3153.                DB    255
  3154.  
  3155.                DB    "- Kein XMS verfügbar: Versuchen Sie, EMS zu verwenden (/A).     ",10
  3156.                DB    255
  3157.  
  3158.                DB    "- There is not XMS memory available: try to request EMS (/A).   ",10
  3159.                DB    0
  3160.  
  3161. m7             DB    "- No existe memoria EMS: pruebe a indicar XMS en su lugar (/E)  ",10
  3162.                DB    255
  3163.  
  3164.                DB    "- Kein EMS verfügbar: Versuchen Sie, XMS zu verwenden (/E).     ",10
  3165.                DB    255
  3166.  
  3167.                DB    "- There is not EMS memory available: try to request XMS (/E).   ",10
  3168.                DB    0
  3169.  
  3170. m8             DB    "- Fallo del controlador XMS: imposible usar memoria extendida.  ",10
  3171.                DB    255
  3172.  
  3173.                DB    "- Fehler des XMS-Managers: Verwendung von XMS unmöglich.        ",10
  3174.                DB    255
  3175.  
  3176.                DB    "- XMS controller failure: imposible to use extended memory.",2,5," ",10
  3177.                DB    0
  3178.  
  3179. m9             DB    "- Fallo del controlador EMS: imposible usar memoria expandida.  ",10
  3180.                DB    255
  3181.  
  3182.                DB    "- Fehler des EMS-Managers: Verwendung von EMS unmöglich.        ",10
  3183.                DB    255
  3184.  
  3185.                DB    "- EMS controller failure: imposible to use expanded memory.",2,5," ",10
  3186.                DB    0
  3187.  
  3188. m10            DB    "- No existe suficiente memoria convencional para TURBODSK.",2,6," ",10
  3189.                DB    255
  3190.  
  3191.                DB    "- Nicht genügend konventioneller Speicher für TURBODSK verfügbar.",2,6," ",10
  3192.                DB    255
  3193.  
  3194.                DB    "- There is not sufficient conventional memory for TURBODSK.",2,5," ",10
  3195.                DB    0
  3196.  
  3197. m11            DB    "- Tamaño de sector incorrecto: lo establezco por defecto.",2,7," ",10
  3198.                DB    255
  3199.  
  3200.                DB    "- Ungültige Sektorengröße angegeben, Vorgabewert wird verwendet.",2,7," ",10
  3201.                DB    255
  3202.  
  3203.                DB    "- Incorrect sector size indicated: default values assumed.",2,6," ",10
  3204.                DB    0
  3205.  
  3206. m12            DB    "- Número de entradas incorrecto: lo establezco por defecto.",2,5," ",10
  3207.                DB    255
  3208.  
  3209.                DB    "- Ungültige Anz. von Verzeichnisanträgen, Vorgabewert wird verwendet.",2,5," ",10
  3210.                DB    255
  3211.  
  3212.                DB    "- Incorrect number of root entries: default value assumed.",2,6," ",10
  3213.                DB    0
  3214.  
  3215. m13            DB    "- Tamaño de cluster incorrecto: lo establezco por defecto.",2,6," ",10
  3216.                DB    255
  3217.  
  3218.                DB    "- Ungültige Clustergröße angegeben, Vorgabewert wird verwendet.",2,6," ",10
  3219.                DB    255
  3220.  
  3221.                DB    "- Incorrect cluster size indicated: default value assumed.",2,6," ",10
  3222.                DB    0
  3223.  
  3224. m14            DB    "- FATAL: fallo al liberar la memoria que ocupaba el disco.",2,6," ",10
  3225.                DB    255
  3226.  
  3227.                DB    "- ACHTUNG: Freigabe des belegten Speichers gescheitert.",2,6," ",10
  3228.                DB    255
  3229.  
  3230.                DB    "- FATAL: imposible to free memory alocated by TURBODSK.",2,9," ",10
  3231.                DB    0
  3232.  
  3233. m15            DB    "- Para discos de más de 32 Mb, hace falta un tamaño de sector de",10,2,8,3
  3234.                DB    "  al menos 1024 bytes.",2,42," ",10
  3235.                DB    255
  3236.  
  3237.                DB    "- Laufwerke mit mehr als 32 MB erfordern eine Sektorgröße",10,2,8,3
  3238.                DB    "  von mindestens 1024 Bytes.",2,42," ",10
  3239.                DB    255
  3240.  
  3241.                DB    "- In drives over 32 Mb, sector size must be at least 1024 bytes.",10
  3242.                DB    0
  3243.  
  3244. ; ------------ Errores «graves» (se imprime sólo el más importante)
  3245.  
  3246. err_grave      DW    0   ; tipo de error grave a imprimir
  3247.  
  3248. err_grave_gen  DB    10,1,10,"TURBODSK 2.2",10,1,12,0
  3249.  
  3250. e0             DB    "  - Este disco virtual requiere DOS 2.0 o superior.",10,255
  3251.                DB    "  - Diese RAM-Disk erfordert mindestens DOS 2.0.",10,255
  3252.                DB    "  - This Ram Disk needs at least DOS 2.0 or above.",10,0
  3253.  
  3254. e1             DB    "  - Instale primero TURBODSK desde CONFIG.SYS (con DEVICE).",10
  3255.                DB    "  - Puede solicitar ayuda con TDSK /?",10
  3256.                DB    255
  3257.  
  3258.                DB    "  - Sie müssen zuerst TURBODSK von der CONFIG.SYS aus installieren",10
  3259.                DB    "    (mit DEVICE). Hilfe erhalten Sie durch Eingabe von TDSK /?",10
  3260.                DB    255
  3261.  
  3262.                DB    "  - You must install first TURBODSK from CONFIG.SYS (using DEVICE).",10
  3263.                DB    "  - Help is available with TDSK /?",10
  3264.                DB    0
  3265.  
  3266. e2             DB "  - La unidad indicada no es un dispositivo TURBODSK 2.2",10,255
  3267.                DB "  - Angegebener Laufwerksbuchstabe bezeichnet keinen Treiber von TURBODSK.", 10,255
  3268.                DB "  - Drive letter indicated does not is a TURBODSK 2.2 device.",10,0
  3269.  
  3270. e3             DB    "  - No pueden modificarse las características de operación de",10
  3271.                DB    "    TURBODSK dentro de WINDOWS. Configúrelo con anterioridad.",10
  3272.                DB    255
  3273.  
  3274.                DB    "  - TURBODSK kann nicht innerhalb einer WINDOWS-Sitzung modifiziert werden.",10
  3275.                DB    "    Sie müssen die Einstellungen vorher durchführen.",10
  3276.                DB    255
  3277.  
  3278.                DB    "  - Operational characteristics of disk can not be altered inside",10,2,4
  3279.                DB    " a WINDOWS session. You must configure TURBODSK before.",10
  3280.                DB    0
  3281.  
  3282. ; ------------ Ayuda
  3283.  
  3284. colorA   EQU 15+4*16+128  ; color de «TURBODSK»
  3285. colorAm  EQU 14+1*16      ; color del marco de fondo de «TURBODSK»
  3286. colorB   EQU 13+1*16      ; color de la fecha
  3287. colorC   EQU 10+1*16      ; color de sintaxis y parámetros
  3288. colorD   EQU 15+1*16      ; color principal del texto
  3289. colorDm  EQU 11+1*16      ; color del marco de fondo
  3290. colorDmx EQU 11+0*16      ; color de la esquina del marco
  3291. colorE   EQU 11+1*16      ; color del nombre del autor
  3292. colorF   EQU 14+1*16      ; color para llamar la atención
  3293. colorG   EQU 12+1*16      ; color para la dirección de mail
  3294. colorH   EQU  9+1*16      ; color para mensaje de dominio público
  3295.  
  3296. ayuda_txt      LABEL BYTE
  3297.                DB    10,3,1,colorDm,"  ",1,colorA," TURBODSK 2.2 ",1,colorAm,"▄"
  3298.                DB    1,colorB,2,52," 30/4/95 ",1,colorDmx,"▄",10
  3299.                DB    3,1,colorE,"   ",1,colorAm,2,14,"▀",1,colorE
  3300.                DB    "  (C) 1995 Ciriaco García de Celis. ",1,colorG
  3301.                DB    "(Mail: ciri@gui.uva.es).",1,colorDm,"█",10
  3302.                DB    3,1,colorE," (C) Grupo Universitario de Informática. "
  3303.                DB    "Apartado 6062, Valladolid (España). ",1,colorDm,"█",10
  3304.                DB    3,1,colorH,2,18," ","* * *  Programa de Dominio Público  * * *"
  3305.                DB    2,18," ",1,colorDm,"█",10
  3306.                DB    3,1,colorD,"   Bienvenido al disco virtual ",1,colorF,"más rápido"
  3307.                DB    1,colorD,", con soporte de memoria EMS, XMS y ",1,colorDm,"█",10
  3308.                DB    3,1,colorD," convencional; redimensionable, fácil de usar. En DOS "
  3309.                DB    "5 ocupa 432-608 bytes. ",1,colorDm,"█",10
  3310.                DB    3,1,colorC,2,77," ",1,colorDm,"█",10
  3311.                DB    3,1,colorC," DEVICE=TDSK.EXE [tamaño [tsector "
  3312.                DB    "[nfich [scluster]]]] [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
  3313.                DB    3,1,colorC,2,77," ",1,colorDm,"█",10
  3314.                DB    3,1,colorD," ",1,colorF,"■",1,colorD," El tamaño debe de estar en "
  3315.                DB    "el rango 8 - 65534 Kb; son válidos sectores de ",1,colorDm
  3316.                DB    "█",10
  3317.                DB    3,1,colorD," 32 a 2048 bytes (en potencias de dos, aunque algún "
  3318.                DB    "sistema sólo los soporta ",1,colorDm,"█",10
  3319.                DB    3,1,colorD," de 128 a 512). El número de ficheros del directorio "
  3320.                DB    "raiz debe estar entre 1 ",1,colorDm,"█",10
  3321.                DB    3,1,colorD," y 65534 y el de sectores por cluster entre 1 y 255 ("
  3322.                DB    "en algún sistema han de ",1,colorDm,"█",10
  3323.                DB    3,1,colorD," ser potencia de dos). Según el tamaño se ajustará "
  3324.                DB    "lo demás automáticamente. ",1,colorDm,"█",10
  3325.                DB    3,1,colorD," ",1,colorF,"■",1,colorD," Se puede indicar ",1,colorC
  3326.                DB    "/E",1,colorD," para emplear memoria extendida XMS, y ",1,colorC
  3327.                DB    "/A",1,colorD," o ",1,colorC,"/X",1,colorD," para la ",1,colorDm
  3328.                DB    "█",10
  3329.                DB    3,1,colorD," expandida EMS; aunque por defecto, TURBODSK utilizará"
  3330.                DB    " automáticamente estas ",1,colorDm,"█",10
  3331.                DB    3,1,colorD," memorias si puede. Con la opción ",1,colorC,"/C"
  3332.                DB    1,colorD," se pide el uso de memoria convencional. ",1,colorDm
  3333.                DB    "█",10
  3334.                DB    3,1,colorD,32,1,colorF,"■",1,colorD," Tras ser instalado, se puede"
  3335.                DB    " ejecutar desde el DOS para cambiar el tamaño ",1,colorDm
  3336.                DB    "█",10
  3337.                DB    3,1,colorD," del disco (perdiéndose los datos almacenados):  con "
  3338.                DB    "un tamaño 0 se anula el ",1,colorDm,"█",10
  3339.                DB    3,1,colorD," disco por completo, liberándose la memoria. "
  3340.                DB    "Utilizando memoria convencional ",1,colorDm,"█",10
  3341.                DB    3,1,colorD," es ",1,colorF,"MUY",1,colorD," conveniente anular el "
  3342.                DB    "disco previo antes de modificar su tamaño. Con ",1,colorDm
  3343.                DB    "█",10
  3344.                DB    3,1,colorD," más de un disco presente se pueden distinguir "
  3345.                DB    "indicando la letra de unidad. ",1,colorDm,"█",10
  3346.                DB    3,1,1*16,"▄",1,colorDm,2,76,"▄█",10
  3347.  
  3348.                DB    255
  3349.  
  3350.                DB    10,3,1,colorDm,"  ",1,colorA," TURBODSK 2.2 ",1,colorAm,"▄"
  3351.                DB    1,colorB,2,53," 30/4/95 ",1,colorDmx,"▄",10
  3352.                DB    3,1,colorE,"   ",1,colorAm,2,14,"▀",1,colorE
  3353.                DB    "  (C) 1995 Ciriaco García de Celis. ",1,colorG
  3354.                DB    "(Mail: ciri@gui.uva.es). ",1,colorDm,"█",10
  3355.                DB    3,1,colorE," (C) Grupo Universitario de Informática. "
  3356.                DB    "Apartado 6062, Valladolid (Spanien). ",1,colorDm,"█",10
  3357.                DB    3,1,colorC,2,78," ",1,colorDm,"█",10
  3358.                DB    3,1,colorD,"   Willkommen bei der ",1,colorF,"schnelleren"
  3359.                DB    1,colorD,"  RAM-Disk,  die auch EMS-, XMS- und konven- ",1,colorDm,"█",10
  3360.                DB    3,1,colorD," tionellen Speicher unterstützt;  größenverstellbar,"
  3361.                DB    "  einfache  Bedienung wie ",1,colorDm,"█",10
  3362.                DB    3,1,colorD," bei DOS-RAM-Disks, erfordert maximal 608 Bytes. "
  3363.                DB    1,colorH," Das Programm ist Freeware!. ",1,colorDm,"█",10
  3364.                DB    3,1,colorC,2,78," ",1,colorDm,"█",10
  3365.                DB    3,1,colorC,"  DEVICE=TDSK.EXE [Größe [Sekt. [Dateien [Cluster]]]]"
  3366.                DB    " [/E] [/A|X] [/C] [/M]   ",1,colorDm,"█",10
  3367.                DB    3,1,colorC,2,78," ",1,colorDm,"█",10
  3368.                DB    3,1,colorD," ",1,colorF,"■",1,colorD," Zulässig für Größe: 8-65534 KB;"
  3369.                DB    " zulässig für Sektoren: 32-2048 Bytes (2er- ",1,colorDm,"█",10
  3370.                DB    3,1,colorD," Potenz),  obwohl einige DOS-Versionen nur 128,"
  3371.                DB    "  256  und  512  unterstützen. ",1,colorDm,"█",10
  3372.                DB    3,1,colorD, " Zulässige Anzahl der Verzeichniseinträge: "
  3373.                DB    "1-65534,  Sektoren/Cluster:  1-255 ",1,colorDm,"█",10
  3374.                DB    3,1,colorD," (einige Systeme erforden 2er-Potenzen)."
  3375.                DB    "  Nur die Größenangabe ist notwendig. ",1,colorDm,"█",10
  3376.                DB    3,1,colorD," ",1,colorF,"■",1,colorD," Bei ",1,colorC, "/E",1,colorD
  3377.                DB    " wird XMS, bei ",1,colorC, "/A",1,colorD," oder ",1,colorC,"/X",1,colorD
  3378.                DB    " wird EMS,  und bei ",1,colorC, "/C",1,colorD," wird konventioneller ",1,colorDm
  3379.                DB    "█",10,3,1,colorD, " Speicher benutzt. Normalerweise versucht TURBODSK,"
  3380.                DB    " XMS oder EMS zu benutzen. ",1,colorDm,"█",10
  3381.                DB    3,1,colorD,32,1,colorF,"■",1,colorD," Nach der Installation in"
  3382.                DB    " CONFIG.SYS sollte  TURBODSK später nochmal ausge- ",1,colorDm,"█",10
  3383.                DB    3,1,colorD," führt werden,  um die Größe zu ändern (den"
  3384.                DB    " Speicherverbrauch);  dadurch wird ",1,colorDm,"█",10
  3385.                DB    3,1,colorD," der Inhalt der  RAM-Disk  gelöscht. Durch Größe 0 wird"
  3386.                DB    " die RAM-Disk komplett ",1,colorDm,"█",10
  3387.                DB    3,1,colorD," gelöscht,  bei Verwendung von konventionellem Speicher"
  3388.                DB    " kann eine Annulierung ",1,colorDm,"█",10
  3389.                DB    3,1,colorF," VOR",1,colorD," der Größenveränderung sinnvoll sein. Wenn mehrere"
  3390.                DB    " TURBODSK's installiert ",1,colorDm,"█",10
  3391.                DB    3,1,colorD," sind, können diese durch ihren Laufwerksbuchstaben"
  3392.                DB    " angesteuert werden. ",2,6," ",1,colorDm,"█",10
  3393.                DB    3,1,1*16,"▄",1,colorDm,2,77,"▄█",10
  3394.  
  3395.                DB    255
  3396.  
  3397.                DB    10,3,1,colorDm,"  ",1,colorA," TURBODSK 2.2 ",1,colorAm,"▄"
  3398.                DB    1,colorB,2,52," 4/30/95 ",1,colorDmx,"▄",10
  3399.                DB    3,1,colorE,"   ",1,colorAm,2,14,"▀",1,colorE
  3400.                DB    "  (C) 1995 Ciriaco Garcia de Celis. ",1,colorG
  3401.                DB    "(Mail: ciri@gui.uva.es).",1,colorDm,"█",10
  3402.                DB    3,1,colorE,"  (C) Grupo Universitario de Informática. "
  3403.                DB    "Apartado 6062, Valladolid (Spain). ",1,colorDm,"█",10
  3404.                DB    3,1,colorC,2,77," ",1,colorDm,"█",10
  3405.                DB    3,1,colorD,"   Welcome to the ",1,colorF,"faster",1,colorD
  3406.                DB    " RAM disk!,  which includes support of both EMS, XMS "
  3407.                DB    1,colorDm,"█",10
  3408.                DB    3,1,colorD," and conventional memory.  Full resizeable,  easy to "
  3409.                DB    "use like DOS RAM disks, ",1,colorDm,"█",10
  3410.                DB    3,1,colorD," in DOS 5.0 it takes only about 432-608 bytes. "
  3411.                DB    1,colorH,"This program is freeware!.",2,4," ",1,colorDm,"█",10
  3412.                DB    3,1,colorC,2,77," ",1,colorDm,"█",10
  3413.                DB    3,1,colorC," DEVICE=TDSK.EXE [size [s_sector [files [s_cluster]]]]"
  3414.                DB    " [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
  3415.                DB    3,1,colorC,2,77," ",1,colorDm,"█",10
  3416.                DB    3,1,colorD," ",1,colorF,"■",1,colorD," Size must be in the range "
  3417.                DB    "8 - 65534 Kb; are valid sectors from 32 to 2048 ",1,colorDm
  3418.                DB    "█",10
  3419.                DB    3,1,colorD," bytes (in power of 2), though some DOS versions only "
  3420.                DB    "support 128, 256 & 512 ",1,colorDm,"█",10
  3421.                DB    3,1,colorD," bytes. Files of root may be 1 to 65534 and sectors "
  3422.                DB    "by cluster can vary from ",1,colorDm,"█",10
  3423.                DB    3,1,colorD," 1 to 255 (some systems need a power of 2). Only the "
  3424.                DB    "size is necessary.",2,6," ",1,colorDm,"█",10
  3425.                DB    3,1,colorD," ",1,colorF,"■",1,colorC," /E",1,colorD," force the "
  3426.                DB    "use of XMS memory, ",1,colorC,"/A",1,colorD," and ",1,colorC
  3427.                DB    "/X",1,colorD," indicates the use of EMS memory ",1,colorDm
  3428.                DB    "█",10
  3429.                DB    3,1,colorD," and ",1,colorC,"/C",1,colorD," the conventional. By "
  3430.                DB    "default, TURBODSK try to use XMS or EMS memory. ",1,colorDm
  3431.                DB    "█",10
  3432.                DB    3,1,colorD," ",1,colorF,"■",1,colorD," After been installed in "
  3433.                DB    "CONFIG.SYS, TURBODSK must be executed in AUTOEXEC ",1,colorDm
  3434.                DB    "█",10
  3435.                DB    3,1,colorD," or command line in order to vary the disk size (the "
  3436.                DB    "amount of memory used); ",1,colorDm,"█",10
  3437.                DB    3,1,colorD," this operation erase the disk contents.  A size 0 "
  3438.                DB    "can be used to complitely ",1,colorDm,"█",10
  3439.                DB    3,1,colorD," anulation of the disk freezen the memory: when using "
  3440.                DB    "conventional memory it ",1,colorDm,"█",10
  3441.                DB    3,1,colorD," is useful to annulate the disk ",1,colorF,"BEFORE"
  3442.                DB    1,colorD," resizing. When more than one TURBODSK ",1,colorDm
  3443.                DB    "█",10
  3444.                DB    3,1,colorD," is installed, they can be identified using in "
  3445.                DB    "adition the drive letter.",2,5," ",1,colorDm,"█",10
  3446.                DB    3,1,1*16,"▄",1,colorDm,2,76,"▄█",10
  3447.  
  3448.                DB    0
  3449.  
  3450. tam_a_trabajo  EQU   4096              ; tamaño del mayor sector soportado
  3451.                                        ; por TURBODSK o del mayor texto
  3452.                                        ; a imprimir
  3453. area_trabajo   EQU   $
  3454.                DB    tam_a_trabajo DUP (?)
  3455.  
  3456. _PRINCIPAL     ENDS
  3457.  
  3458. tam_pila       EQU   2048              ; 2 Kb de pila son suficientes
  3459.  
  3460. _PILA          SEGMENT STACK 'STACK'
  3461.                DB    tam_pila DUP (?)
  3462. _PILA          ENDS
  3463.  
  3464.                END   main
  3465.