Idioma

Gráficos y sonidos en lenguaje Ensamblador

EL SISTEMA CENTRAL DE ENTRADA-SALIDA DE LAS COMPUTADORAS ATARI


En cualquier sistema informático, los términos Entrada (Input) y Salida (Output) se refieren a la comunicación entre el microprocesador y cualquier dispositivo externo: un teclado, el editor de pantalla, una impresora, una unidad de disco, una grabadora u otro periférico similar. El Sistema Operativo ATARI contiene rutinas para interactuar con cualquiera de estos dispositivos en varios niveles, tal como muchas otras microcomputadoras. El aspecto del sistema ATARI que lo hace único (y, desde el punto de vista del programador, tan fácil de usar) es que todos los dispositivos externos se manejan de manera idéntica y se diferencian sólo cambiando aspectos menores de la rutina de entrada y salida.


La entrada es el paso de información desde el mundo exterior, por ejemplo, desde el teclado al microprocesador. La salida es el proceso inverso, en el que la información pasa del computador al exterior, por ejemplo, a una impresora. A lo largo del resto de este libro, nos referiremos al sistema Central de Entrada - Salida como CIO (Central Input-Output).


LOS VECTORES EN UNA COMPUTADORA ATARI


Mencionamos anteriormente que las técnicas y rutinas utilizadas en este libro funcionan con cualquier modelo de computadora ATARI porque ATARI garantiza que los vectores de las rutinas en el Sistema Operativo no cambiarán. Ubicada dentro del Sistema Operativo de su ATARI hay una Tabla de Saltos (Jump Table), que contiene las direcciones de todas las rutinas clave necesarias para la programación en lenguaje Ensamblador. La tabla se extiende desde $E450 hasta $E47F, y en un ATARI 800 con el Sistema Operativo B, la tabla se ve así:


DirecciónContiene la instrucción
E450JMP $EDEA
E453JMP $EDF0
E456JMP $E4C4
E459JMP $E959
E45CJMP $E8ED
E45FJMP $E7AE
E462JMP $E905
E465JMP $E944
E468JMP $EBF2
E46BJMP $E6D5
E46EJMP $E4A6
E471JMP $F223
E474JMP $F11B
E477JMP $F125
E47AJMP $EFE9
E47DJMP $EF5D

Es fácil ver por qué se llama Tabla de Saltos, ya que es una tabla de direcciones a las que saltará el control del programa cuando se acceda a ellas. "¿Por qué no saltar directamente a la dirección indicada?" se puede preguntar. En la respuesta se encuentra la clave para escribir programas que se ejecutarán en todas las computadoras ATARI. Supongamos que en lugar de acceder a $E456, elegimos saltar directamente a la ubicación $E4C4, sin pasar por la Tabla de Saltos. Todo funcionará bien y nuestro programa se ejecutará. Pero supongamos ahora que ATARI produce una computadora nueva, la 24800 XLTVB, y que el Sistema Operativo necesita modificarse un poco para acomodar varias características de esta magnífica máquina nueva. Nuestro programa está en problemas. ATARI nunca garantizó que la ubicación $E4C4 permanecería igual para siempre; sólo garantizaron que la tabla de salto siempre apuntaría a la dirección correcta. Es decir, si hubiéramos accedido a $E456 en lugar de $E4C4, nuestro programa siempre funcionaría, ya que se garantiza que la ubicación $E456 no cambiará. Veamos los diversos vectores en esta tabla de salto, con sus equivalencias ATARI (Los nombres que usaremos para estas direcciones en cualquier programa que escribamos) y sus usos:


EquivalenciaDirecciónUso
DISKIV$E450Rutina de inicio del administrador del disco
DSKINV$E453Vector del administrador de disco
CIOV$E456Vector de entrada/salida central
SIOV$E459Vector de entrada/salida serial
SETVBV$E45CEstablecer el vector de rutina de los temporizadores del sistema
SYSVBV$E45FProcesamiento de interrupción del Blanqueo Vertical del sistema
XITVBV$E462Salir del procesamiento del Blanqueo Vertical
SIOINV$E465Inicialización de entrada/salida en serie
SENDEV$E468Rutina de habilitación del envío del bus serie
INTINV$E46BRutina de manejo de interrupciones
CIOINV$E46EInicialización de Entrada/Salida Central
BLKBDV$E471Vector del modo Pizarra (Blackboard) a modo Bloc de notas
WARMSV$E474Punto de entrada del arranque en caliente (warm start) (Sigue a SYSTEM RESET)
COLDSV$E477Punto de entrada del arranque en frío (Sigue al encendido del equipo)
RBLOKV$E47AVector de rutina de lectura de bloques del cassette
CSOPIV$E47DVector del cassette abierto para entrada

Usaremos algunos de estos vectores en los programas que escribiremos y algunos nunca los usaremos, pero saber dónde están le ayudará si necesita utilizarlos en sus propios programas. Muchos son utilizados por el propio Sistema Operativo.


Para acceder a cualquiera de estas rutinas en el Sistema Operativo, simplemente necesitamos enviar un JSR a la dirección adecuada. Todas estas rutinas en el Sistema Operativo están escritas como subrutinas y, por lo tanto, terminan con instrucciones RTS, que devolverán el control a su programa. Por ejemplo, para acceder a CIO, simplemente necesitamos escribir


JSR CIOV	

y el trabajo está hecho. Por supuesto, se requiere una cantidad considerable de configuración antes de poder realizar esta llamada, que cubriremos en breve. Pero la llamada real al CIO no podría ser más sencilla.


Mientras analizamos los vectores disponibles en el Sistema Operativo, cubramos brevemente los vectores RAM y ROM. Se resumen en la siguiente tabla, con sus equivalencias, la información que contienen en el Sistema Operativo B y una breve descripción de su uso:


EquivalenciaDirecciónApunta aUso
CASINI$0002varíaVector de inicialización del cassette de arranque
DOSVEC$000AvaríaVector de ejecución de software de disco
DOSINI$000CvaríaVector de inicialización de disco
VDSLST$0200$E7B3Vector de la NMI de la DLI
VPRCED$0202$E7B2Vector del IRQ Continuar línea*
VINTER$0204$E7B2Vector del IRQ Interrumpir línea*
VBREAK$0206$E7B2Vector del IRQ de la instrucción BRK
VKEYBD$0208$FFBEVector del IRQ del Teclado
VSERIN$020A$EB11Vector del IRQ de la Entrada serie lista
VSEROR$020C$EA90Vector del IRQ de la Salida serie lista
VSEROC$020E$EAD1Vector del IRQ de la Salida serie terminada
VTIMR1$0210$E7B2Vector del IRQ del Temporizador 1 del POKEY
VTIMR2$0212$E7B2Vector del IRQ del Temporizador 2 del POKEY
VTIMR4$0214$E7B2Vector del IRQ del Temporizador 4 del POKEY
VIMIRQ$0216$E6F6Administrador del vector a la IRQ
VVBLKI$0222$E7D1Vector de la NMI del VBI Inmediato
VVBLKD$0224$E93EVector de la NMI del VBI Diferido
CDTMA1$0226varíaDirección del JSR del temporizador 1 del sistema
CDTMA2$0228varíaDirección del JSR del temporizador 1 del sistema
BRKKY $0236$E754Vector de la tecla BREAK, sólo para la versión B del Sistema Operativo
RUNVEC$02E0varíaVector de carga y ejecución
INIVEC$02E2varíaVector de inicialización de carga y ejecución

Los marcados con "*" no se utilizan actualmente. Observe que varios de estos vectores apuntan al mismo lugar en el Sistema Operativo: $E7B3. Esta es la dirección de la rutina central del procesamiento de interrupciones, que determina la naturaleza de la interrupción y dirige el control del programa a las rutinas apropiadas en el Sistema Operativo para manejar ese tipo de interrupción.


Estos vectores, a diferencia de los vectores ROM, no están organizados en una tabla de salto, por lo que no se puede acceder a ellos mediante una simple instrucción JSR. Sin embargo, sí apuntan a rutinas del Sistema Operativo que terminan en una instrucción RTS, por lo que podremos acceder a ellas mediante una instrucción JSR. El método adecuado es configurar un JSR en una ubicación que hace JMP indirectamente al vector anterior. Por ejemplo, supongamos que queremos vectorizar a través del vector DOSINI. Esto se hace correctamente con el siguiente código:


40 JSR MYSPOT
45
50
55
60 MYSPOT JMP (DOSINI)	

Siguiendo el JSR a MYSPOT, el RTS en la rutina del Sistema Operativo devolverá el control a la línea 45, momento en el cual su programa se reanudará.


Ahora que hemos visto cómo escribir programas que funcionarán en todas las computadoras ATARI, analicemos la filosofía del CIO y aprendamos a escribir programas que interactúen con el mundo real.


EL BLOQUE DE CONTROL DE ENTRADA-SALIDA (IOCB - INPUT/OUTPUT CONTROL BLOCK)


Hay dos partes en el sistema CIO en el ATARI: El Bloque de Control de Entrada - Salida (Input-Output Control Block), o IOCB, y la Tabla de Controladores (handler table). Analicémoslos uno por uno y luego veamos cómo trabajan en conjunto para formar un sistema CIO operativo. El IOCB es una sección de la memoria en la Página 3 que contiene la información configurada por el programador para decirle al ATARI qué dispositivo se desea usar y qué información se debe pasar. Cada IOCB requiere 16 bytes de información y tenemos 8 IOCB disponibles. Sus nombres y ubicaciones son las siguientes:


NombreUbicación
IOCB0$340 a 34F
IOCB1$350 a 35F
IOCB2$360 a 36F
IOCB3$370 a 37F
IOCB4$380 a 38F
IOCB5$390 a 39F
IOCB6$3A0 a 3AF
IOCB7$380 a 3BF

El sistema utiliza varios de estos IOCBs por defecto, aunque como programadores somos libres de usarlos o de cambiarlos para adaptarlos a nuestros propios propósitos. De hecho, el Sistema Operativo utiliza normalmente sólo 3 de ellos. Generalmente no es necesario redefinirlos, ya que tenemos otros 5 entre los que elegir. Los 3 utilizados por el Sistema Operativo son los siguientes:


1. IOCB0, el editor de pantalla. Al dirigir la salida al IOCB0, podemos pasar información al editor de pantalla. Este IOCB también controla la ventana de texto en cualquiera de los modos gráficos de pantalla dividida.

2. IOCB6, la pantalla para modos gráficos superiores a cero. Este IOCB se utiliza para todos los comandos gráficos como PLOT, DRAWTO, FILL y otros.


3. IOCB7, que dirige la salida a la impresora cuando se usa el comando LPRINT de BASIC. En la práctica, gran parte de la salida de BASIC dirigida a una impresora utiliza uno de los otros IOCBs, ya que el comando LPRINT no se utiliza con frecuencia. Hay más opciones de formato disponible si se abre un IOCB específico para su uso con una impresora.

Como probablemente ya habrá reconocido, BASIC usa los números de IOCB (0, 6 y 7) para dirigir la salida a estos dispositivos, como cuando se imprime en una pantalla GRAPHICS 1 ó 2 con este comando:


PRINT #6;"HELLO"	

A continuación, se describen los 16 bytes del IOCB y sus desplazamientos a partir del inicio del IOCB en uso:


EtiquetaDesplazamientoLongitudDescripción
ICHID01Índice en la tabla de nombres de dispositivos para este IOCB
ICDNO11Número de dispositivo
ICCOM21Byte de comando: determina la acción a tomar
ICSTA31Estado devuelto por el dispositivo
ICBAL/H4,52Dirección del buffer de dos bytes de la información almacenada
ICPTL/H6,72Dirección - 1 de la rutina de colocación de caracteres del dispositivo
ICBLL/H8,92Longitud del buffer
ICAX1101Primer byte auxiliar
ICAX2111Segundo byte auxiliar
ICAX3/412,132Bytes auxiliares 3 y 4: para los comandos NOTE y POINT del BASIC
ICAX5141Quinto byte auxiliar - también para los comandos NOTE y POINT
ICAX6151Byte auxiliar de reserva – actualmente sin uso

UN EJEMPLO SIMPLE DE E/S UTILIZANDO UN IOCB


Antes de entrar en los detalles de los distintos bytes necesarios para cada posible función de un IOCB, un programa de ejemplo le ayudará a comprender su uso. Tomemos un ejemplo BASIC simple y convirtámoslo a su equivalente en lenguaje Ensamblador. La línea de programación BASIC que queremos duplicar es:


CLOSE #4:OPEN #4,6,0,"D:*.*"	

Por ahora, necesitamos saber que el byte de comando almacenado en ICCOM debe ser $C para el comando CLOSE o 3 para el comando OPEN, y abrir el directorio del disco requiere un 6 en ICAX1. Veamos el programa necesario para abrir dicho archivo:


Listado 9.1


            0100 ; ******************************
            0110 ; Primero configuramos las equivalencias
            0120 ; ******************************
0000        0130        *=   $600
0341        0140 ICDNO  =    $0341
0342        0150 ICCOM  =    $0342
0344        0160 ICBAL  =    $0344
0345        0170 ICBAH  =    $0345
034A        0180 ICAX1  =    $034A
E456        0190 CIOV   =    $E456
            0200 ; ******************************
            0210 ; Ahora hacemos CLOSE #4 para estar seguros
            0220 ; ******************************
0600 A240   0230        LDX  #$40     ; #$40 para el IOCB #4
0602 A90C   0240        LDA  #$C      ; byte del comando CLOSE
0604 9D4203 0250        STA  ICCOM,X  ; X = IOCB #4
0607 2056E4 0260        JSR  CIOV     ; Deje que CIO haga el CLOSE
            0270 ; ******************************
            0280 ; Ahora abriremos el directorio
            0290 ; ******************************
060A A240   0300        LDX  #$40     ; Nuevamente, #$40 = IOCB4
060C A901   0310        LDA #1        ; Unidad de disco # 1
060E 9D4103 0320        STA ICDNO,X   ; Coloque el # de unidad aqui
0611 A903   0330        LDA #3        ; Para OPEN
0613 9D4203 0340        STA ICCOM,X   ; Byte del comando
0616 A906   0350        LDA #6        ; Para directorio de disco
0618 9D4A03 0360        STA ICAX1,X   ; Almacene 6 aqui
061B A929   0370        LDA #FILE&255 ; Ver discusion
061D 9D4403 0380        STA ICBAL,X   ; Byte bajo de la direccion del buffer
0620 A906   0390        LDA #FILE/256 ; Ver discusion
0622 9D4503 0400        STA ICBAH,X   ; Byte alto de la direccion del buffer
0625 2056E4 0410        JSR CIOV      ; Deje que CIO haga el OPEN
0628 60     0420        RTS           ; Todo listo
            0430 ; ******************************
            0440 ; Ahora necesitamos el nombre de archivo
            0450 ; ******************************
0629 44     0460 FILE   .BYTE "D:*.*",$9B
062A 3A
062B 2A
062C 2E
062D 2A
062E 9B	

Tanto en la parte del CLOSE como en la parte del OPEN del programa, cargamos el registro X con #$40, que actuará como desplazamiento en el IOCB4. (Si quisiéramos usar IOCB3, simplemente cargaríamos el registro X con #$30, y así sucesivamente para todos los demás IOCB). Luego almacenamos el byte de comando $C en ICCOM para ese IOCB y un JSR a CIOV hace el CLOSE por nosotros. Siempre es una buena idea cerrar un archivo antes de abrirlo, en caso de que ya estuviera abierto por algún otro motivo. Si el archivo ya está abierto, recibirá un error en la declaración del CIO. Puede verificar si hay un error en cualquier llamada al Sistema Operativo al pasar a alguna rutina propia de manejo de errores si después del JSR a CIOV, se establece la bandera Negativo en el registro de Estado del Procesador. Por lo tanto, deberíamos poner una instrucción BMI ERROR después de la instrucción JSR CIOV; pero para los propósitos de esta discusión, asumiremos que todo está bien. Sin embargo, nunca debe hacer esa suposición en sus programas.


Para abrir el archivo, ponemos un 1 en el byte ICDNO del IOCB4, para acceder a la unidad de disco 1, y luego ponemos el byte de comando 3 en el byte ICCOM del IOCB4, y ponemos un 6 en el byte ICAX1. Todo lo que nos queda por hacer antes de llamar al CIO es apuntar la dirección del buffer al nombre del archivo que queremos abrir. Este nombre se encuentra en la línea 460 y le hemos asignado la etiqueta FILE. Los $9B que siguen al nombre del archivo son el código hexadecimal para un retorno de carro, que siempre debe seguir a los nombres de archivos o dispositivos, como S: o P:


Para apuntar el buffer al nombre del archivo, necesitamos descomponer su dirección en bytes bajos y altos. El byte bajo es la dirección, a la que le hacemos AND 255, y que se escribe #FILE&255. El AND con 255 garantiza que obtendremos solo el byte bajo de la dirección. El byte alto se puede obtener dividiendo la dirección por 256, tal como hicimos en la línea 390. Los bytes bajo y alto se almacenan en ICBAL e ICBAH, respectivamente, y luego una llamada al CIO en la línea 410 completa el comando OPEN por nosotros.


Este sencillo ejemplo demuestra no sólo cómo abrir un directorio de disco, sino que también muestra exactamente cómo se realiza cada llamada a la rutina CIO en su ATARI. Primero configuramos los bytes apropiados en el IOCB y luego simplemente hacemos JSR a CIOV para realizar la tarea, ya sea abrir un archivo, leer información de un disco o cinta, o enviar información a una impresora. Todas estas operaciones se realizan utilizando esta misma secuencia de eventos, lo que hace que, una vez que comprenda el sistema, la entrada y salida en lenguaje Ensamblador en su ATARI sea tan simple. Tenga en cuenta que no es necesario modificar los 16 bytes del IOCB para realizar una llamada al CIO. De hecho veremos que, para algunos comandos, uno o dos de estos bytes es todo lo que se necesita modificar para implementar la función.


DETALLE DE LOS BYTES EN UN IOCB


Ahora que hemos visto cómo implementar una llamada simple al sistema Central de Entrada y Salida de las computadoras ATARI, revisaremos el espectro completo de información que debe almacenarse en las distintas ubicaciones del IOCB para poder implementar todas las posibles operaciones de E/S. Examinaremos cada byte del IOCB, en el orden en que aparecen.


El primer byte, ICHID, actúa como un índice en la tabla de dispositivos, por lo que siempre puede saber a qué dispositivo accede un IOCB mirando el primer byte. Esto lo establece el Sistema Operativo y no será necesario configurarlo para ningún uso. El Sistema Operativo determina este índice siguiendo el comando OPEN y almacena aquí la información adecuada.


ICDNO, el número de dispositivo, se utiliza con mayor frecuencia cuando hay más de una unidad de disco conectada al sistema. Se utiliza un IOCB diferente para comunicarse con cada unidad de disco, y el byte 2 del IOCB distingue entre las unidades en uso. Si se almacena un 1 aquí, el IOCB accederá a la unidad de disco 1 y de manera similar a las unidades 2 a 4.
Los bytes de comando para los distintos dispositivos que se pueden conectar a su computadora ATARI son los siguientes:


ComandoByteDescripción
Abrir3Abrir el dispositivo para su operación
Obtener registro5Recibir una línea
Obtener carácter7Recibir uno o más caracteres
Colocar registro9Enviar una línea
Colocar carácter11Enviar uno o más caracteres
Cerrar12Cerrar el dispositivo
Estado13Obtener estado del dispositivo
Dibujar línea17Dibujar una línea en los modos GRAPHICS
Comando FILL18Rellenar parte de la pantalla GRAPHICS con color
Formatear disco 254 Formatear disco

El cuarto byte del IOCB es ICSTA, que lo establece el Sistema Operativo tras el retorno del CIO. El estado también se establece en el registro Y al regresar de cualquier llamada al CIO, por lo que su programa puede leer el registro Y o ICSTA para determinar el éxito o el fracaso de cada operación de E/S. Cualquier estado negativo (valor superior a 128 decimal o $80 hexadecimal) indica que se produjo un error en la operación de E/S.


Los siguientes 2 bytes del IOCB actúan como un puntero al buffer utilizado para entrada o salida, y están en el orden habitual del 6502, es decir, el byte bajo primero: Se denominan ICBAL e ICBAH, respectivamente. Un buffer es un área de memoria que contiene la información que desea generar o en la que desea colocar la información de entrada. Por ejemplo, si desea enviar texto a una impresora, ICBAL e ICBAH están configurados para apuntar al área de memoria que contiene el texto que se va a imprimir. Si desea leer un archivo de disco en la memoria, estos bytes del IOCB están configurados para apuntar al área de la memoria donde desea colocar la información que se leerá del disco.


ICPTL e ICPTH actúan como otro puntero de 2 bytes; pero en este caso, apuntan a la dirección de la rutina de colocación de bytes del dispositivo, menos 1. Cada dispositivo que pueda abrirse para salida debe tener escrita una rutina de colocación de bytes, para que le diga a la computadora cómo enviarle información. Esto se cubrirá más detalladamente cuando analicemos la Tabla de Controladores.


Los siguientes 2 bytes del IOCB son ICBLL e ICBLH, que contienen la longitud del buffer de E/S, en bytes. Como veremos, hay un caso especial de E/S en el que igualamos la longitud del buffer a cero, estableciendo tanto ICBLL como ICBLH en cero. En este caso especial, la información transferida es hacia o desde el Acumulador, en lugar de hacia o desde la Memoria.


Dado que muchos dispositivos que se pueden conectar a su ATARI tienen varias funciones posibles, se debe poder definir en el IOCB la función que se implementará. Esto se hace usando el byte en ICAX1, el siguiente byte del IOCB. La siguiente tabla enumera los distintos bytes posibles para ICAX1. "TW" se refiere a una ventana de texto separada en la pantalla, como la configurada por el comando BASIC GRAPHICS 3; "RE" se refiere a una operación de LECTURA habilitada desde la pantalla; y "RD" significa que dicha LECTURA no está permitida o está deshabilitada.


DispositivoByte de ICAX1Función
Editor de pantalla8Salida a la pantalla
12Entrada desde el teclado y salida a la pantalla
13Entrada y salida de pantalla forzada
Pantalla8La pantalla se borra; sin TW; RD
12La pantalla se borra; sin TW; RE
24La pantalla se borra; TW; RD
28La pantalla se borra; TW; RE
40La pantalla no se borra; sin TW; RD
44La pantalla no se borra; sin TW; RE
56La pantalla no se borra; TW; RD
60La pantalla no se borra; TW; RE
Teclado4Lectura – nota: no es posible salida
Impresora8Escritura – nota: no es posible entrada
Grabadora de cinta 4Lectura
8Escritura
Puerto RS-232 5Lectura simultánea
8Escritura en bloque
9Escritura simultánea
13Lectura y escritura simultáneas
Unidad de disco 4Lectura
6Leer directorio del disco
8Escribir archivo nuevo
9Escribir – agregar
12Leer y escribir – modo de actualización

El último byte del IOCB que discutiremos aquí es ICAX2, el segundo byte auxiliar. ICAX2 se utiliza sólo en unos pocos casos especiales; en caso contrario, se establece en cero. Cuando se utiliza la grabadora de cassettes, si se almacena el valor 128 en ICAX2, se utilizan los espacios cortos entre grabaciones (los espacios silenciosos entre secciones de información en la cinta), lo que permitirá cargas más rápidas de una cinta escrita de esta manera. El valor cero en ICAX2 producirá los espacios entre registros (Inter Record Gaps - IRG) normales y más largos.


Al utilizar la impresora ATARI 820, almacenar un valor de 83 en ICAX2 hace que la impresora imprima de costado en lugar de su modo normal. Además, los valores de 70 u 87 en ICAX2 producirán caracteres normales o de doble ancho en esta impresora.
Finalmente, los modos gráficos 0 al 11 se especifican en el comando OPEN colocando el número del modo deseado en ICAX2. En combinación con los valores descritos anteriormente para ICAX1, ICAX2 le brinda al programador de lenguaje Ensamblador el control completo sobre el modo gráfico, la ventana de texto, la limpieza de pantalla y las funciones de lectura y escritura de la pantalla. Aprenderemos más sobre esto en el Capítulo 10.


LA TABLA DE CONTROLADORES (HANDLERS)


Ahora que hemos cubierto las diversas partes de un IOCB, describiremos brevemente la Tabla de Controladores y cómo funciona con los IOCB para formar el sistema de E/S con CIO. Luego veremos una serie de ejemplos que mostrarán cómo utilizar esta información para realizar muchos tipos diferentes de E/S desde el lenguaje Ensamblador. La forma más sencilla de examinar la Tabla de Controladores es visualizarla como un programa breve en lenguaje Ensamblador, como este:


0100 PRINTV = $E430
0110 CASETV = $E440
0120 EDITRV = $E400
0130 SCRENV = $E410
0140 KEYBDV = $E420
0150 ; *****************************
0160 ; Origen de HATABS = $031A
0170 ; *****************************
0180 *= $031A
0190 .BYTE "P"      ; Vector de la
0200 .WORD PRINTV   ;    Impresora
0210 .BYTE "C"      ; Vector de la
0220 .WORD CASETV   ;    Grabadora de cassette
0230 .BYTE "E"      ; Vector del
0240 .WORD EDITRV   ;    Editor
0250 .BYTE "S"      ; Vector de la
0260 .WORD SCRENV   ;    Pantalla
0270 .BYTE "K"      ; Vector del
0280 .WORD KEYBDV   ;    Teclado
0290 .BYTE 0        ; Entrada libre #1(DOS)
0300 .WORD 0,0
0310 .BYTE 0        ; Entrada libre #2(Interfaz 850)
0320 .WORD 0,0
0330 .BYTE 0        ; Entrada libre #3
0340 .WORD 0,0
0350 .BYTE 0        ; Entrada libre #4
0360 .BYTE 0,0
0370 .BYTE 0        ; Entrada libre #5
0380 .WORD 0,0
0390 .BYTE 0        ; Entrada libre #6
0400 .WORD 0,0
0410 .BYTE 0        ; Entrada libre #7
0420 .WORD 0,0	

Cada entrada en la Tabla de Controladores consta de la primera letra del dispositivo especificado, seguida del vector que apunta a la ubicación en memoria de la información necesaria para tratar con ese dispositivo. Como puede ver, quedan siete lugares libres en la Tabla de Controladores, por lo que el programador es libre de agregar los dispositivos que sean necesarios para cualquier propósito y serán tratados como los dispositivos ya especificados. Cabe señalar aquí otro punto muy importante sobre la Tabla de Controladores: Cada vez que el Sistema Operativo mira esta tabla para averiguar en qué parte de la memoria necesita buscar para ocuparse de un dispositivo en particular, lee la tabla de abajo hacia arriba. Esto es intencional y le permite insertar su propio controlador de impresora cerca de la parte inferior de la tabla. A medida que se busca en la tabla, su vector se encontrará primero y será el que se utilizará. Por lo tanto, puede escribir sus propias rutinas de manejo de impresora y sustituirlas por las rutinas normales fácilmente, simplemente colocando otra P: en una de las entradas libres inferiores y siguiéndola por el vector de dirección de 2 bytes que apunta a sus nuevas rutinas de manejo.


Veamos brevemente el punto de entrada de una Tabla de Controladores típica, que es la tabla a la que apunta la entrada en la Tabla de Controladores. Por ejemplo, el vector PRINTV, utilizado anteriormente, apunta a una segunda tabla: la tabla de punto de entrada del controlador de impresora. De hecho, todos los vectores anteriores apuntan a sus respectivas tablas de punto de entrada del controlador, y todas estas tablas están organizadas de manera idéntica. Contienen las direcciones menos 1 de las rutinas utilizadas para las siguientes funciones, en el siguiente orden:


OPENRutina de apertura del dispositivo
CLOSERutina de cierre del dispositivo
READRutina de lectura
WRITERutina de escritura
STATUSRutina de estado del dispositivo
SPECIALFunciones especiales, cuando estén implementadas

La tabla de puntos de entrada del controlador siempre termina con una instrucción JMP de 3 bytes, que apunta a la rutina de inicialización para ese dispositivo. Recuerde: Las direcciones encontradas en la tabla de puntos de entrada del controlador no apuntan a las rutinas OPEN y CLOSE, sino que apuntan a la dirección 1 byte más abajo en la memoria del comienzo de cada una de estas rutinas. ¡Obviamente es muy importante recordar esto cuando construya su propia tabla de puntos de entrada del controlador!


UNA RUTINA DE E/S SIMPLE


Veamos cómo podemos usar CIO para una función simple: escribir en la pantalla. Sabemos que, si queremos escribir una línea de texto en la pantalla, en BASIC todo lo que se requiere es una sola línea de código como esta:


PRINT "A SUCCESSFUL WRITE!"	

En lenguaje Ensamblador, también es bastante sencillo imprimir en la pantalla, ahora que entendemos el uso de IOCB y de CIO. Solo para repasar, no tenemos que abrir la pantalla como dispositivo si no lo queremos, ya que el Sistema Operativo le asigna el IOCB0 a la pantalla. Por lo tanto, podemos cargar el registro X con cero y usarlo como desplazamiento en el IOCB. Alternativamente, podemos usar direccionamiento Absoluto, ya que usaremos el primer IOCB. En el siguiente ejemplo, usaremos el registro X cargado con cero, para familiarizarnos con el procedimiento normal para insertar la información requerida en el IOCB. Aquí está la rutina para escribir la línea en la pantalla:


Listado 9.2


            0100 ; *****************************
            0110 ; Equivalencias CIO
            0120 ; *****************************
0340        0130 ICHID  =   $0340
0341        0140 ICDNO  =   $0341
0342        0150 ICCOM  =   $0342
0343        0160 ICSTA  =   $0343
0344        0170 ICBAL  =   $0344
0345        0180 ICBAH  =   $0345
0346        0190 ICPTL  =   $0346
0347        0200 ICPTH  =   $0347
0348        0210 ICBLL  =   $0348
0349        0220 ICBLH  =   $0349
034A        0230 ICAXl  =   $034A
034B        0240 ICAX2  =   $034B
E456        0250 CIOV   =   $E456
0000        0260        *=  $600
            0270 ; *****************************
            0280 ; Ahora cargamos los datos requeridos
            0290 ; *****************************
0600 A200   0300        LDX #0        ; Ya que es IOCB0
0602 A909   0310        LDA #9        ; Para poner registro
0604 9D4203 0320        STA ICCOM,X   ; Byte del comando
0607 A91F   0330        LDA #MSG&255  ; Byte bajo de MSG
0609 9D4403 0340        STA ICBAL,X   ;  en ICBAL
060C A906   0350        LDA #MSG/256  ; Byte alto de MSG
060E 9D4503 0360        STA ICBAH,X   ;  en ICBAH
0611 A900   0370        LDA #0        ; Largo de MSG
0613 9D4903 0380        STA ICBLH,X   ;  byte alto
0616 A9FF   0390        LDA #$FF      ; Largo de  MSG
0618 9D4803 0400        STA ICBLL,X   ; Ver discusion
            0410 ; *****************************
            0420 ; Ahora pongalo en la pantalla
            0430 ; *****************************
061B 2056E4 0440        JSR CIOV
061E 60     0450        RTS
            0460 ; *****************************
            0470 ; El mensaje en si
            0480 ; *****************************
061F 41     0490 MSG    .BYTE "A SUCCESSFUL WRITE!",$9B
0620 20
0621 53
0622 55
0623 43
0624 43
0625 45
0626 53
0627 53
0628 46
0629 55
062A 4C
062B 20
062C 57
062D 52
062E 49
062F 54
0630 45
0631 21
0632 9B	

Por supuesto, escribir en la pantalla es tan simple en BASIC que no hay razón para escribir este programa como una subrutina BASIC, por lo que no contiene la instrucción PLA habitual. Dado que necesitará imprimir en la pantalla para depurar programas en lenguaje Ensamblador, esta rutina puede convertirse en uno de los programas que utilice con más frecuencia.


Para probar este programa una vez que lo haya tipeado, simplemente escriba ASM para ensamblarlo, y cuando se complete el ensamblaje, escriba BUG para ingresar al modo DEBUG del cartucho Assembler/Editor. Luego escriba G600 para comenzar la ejecución en la dirección $600. Si el programa se ha escrito correctamente, debería aparecer la frase "A SUCCESSFUL WRITE!", seguido de la impresión en pantalla de los registros del 6502. Estos se imprimen siguiendo cada rutina que utiliza el cartucho Assembler/Editor. Este mismo procedimiento debe usarse para probar cada una de las rutinas dadas en este libro. Si surgen problemas, revise lo escrito.


¡¡¡TENGA EN CUENTA!!! ¡¡¡GUARDE SUS PROGRAMAS ANTES DE INTENTAR EJECUTARLOS!!! Entonces, si fallan o si su computadora falla, no tendrá que volver a escribir todo el programa.

En este programa, escribimos el mensaje completo en la pantalla usando el comando "poner registro (put-record)", por medio del almacenamiento de un 9 en ICCOM. La dirección del mensaje que queremos mostrar en la pantalla se almacena en ICBLL e ICBLH, como antes. Almacenamos un cero en el byte alto de la longitud del mensaje, pero $FF en el byte bajo.


¿Por qué $FF cuando el mensaje tiene sólo 20 bytes de longitud? Cuando se utiliza CIO en el modo "poner registro", el registro se genera byte a byte, hasta que se excede la longitud del buffer, establecida en ICBLL e ICBLH, o hasta que encuentra un RETURN en el registro que se genera. Tenga en cuenta que el mensaje que se configuró en la línea 490 termina con el byte $9B, que es un RETURN. Por lo tanto, el mensaje se enviará a la pantalla, luego se enviará un retorno de carro a la pantalla y luego finalizará la rutina. Establecimos la longitud del registro intencionalmente mayor al mensaje real, porque queremos que los $9B en el mensaje mismo terminen con la salida. De esta manera, no podemos cometer un error y sin querer acortar el mensaje debido a que configuramos ICBLL o ICBLH en un tamaño más pequeño de lo que pretendíamos.


Es importante tener en cuenta que no configuramos todos los bytes en el IOCB. De hecho, sólo necesitábamos configurar los bytes que utiliza nuestra rutina particular. Como verá a continuación, este es siempre el caso con las rutinas centrales de ATARI. La salida real a la pantalla se logra mediante la llamada a la rutina de E/S central en la línea 440, y el RTS en la línea siguiente devuelve el control al cartucho Assembler/Editor. Si esto fuera parte de un programa más grande en lenguaje Ensamblador, el resto del programa continuaría desde la línea 450 sin el RTS.


OTRAS FORMAS DE UNA RUTINA DE E/S


Veamos otra forma de escribir un mensaje en la pantalla, usando el sistema CIO. En lugar de cargar ICCOM con 9, para "poner registro", podemos cargarlo con 11, para "poner bytes". Los demás bytes del IOCB se configuran tal como se indica arriba, excepto ICBLL, que se configura con la longitud exacta del mensaje. Al contar los bytes del mensaje, no olvide incluir el byte $9B, el RETURN. El programa entonces se verá así:


Listado 9.3


            0100 ; *****************************
            0110 ; Equivalencias CIO
            0120 ; *****************************
0340        0130 ICHID  =   $0340
0341        0140 ICDNO  =   $0341
0342        0150 ICCOM  =   $0342
0343        0160 ICSTA  =   $0343
0344        0170 ICBAL  =   $0344
0345        0180 ICBAH  =   $0345
0346        0190 ICPTL  =   $0346
0347        0200 ICPTH  =   $0347
0348        0210 ICBLL  =   $0348
0349        0220 ICBLH  =   $0349
034A        0230 ICAX1  =   $034A
034B        0240 ICAX2  =   $034B
E456        0250 CIOV   =   $E456
0000        0260        *=  $600
            0270 ; *****************************
            0280 ; Ahora cargamos los datos requeridos
            0290 ; *****************************
0600 A200   0300        LDX #0        ; Ya que es IOCB0
0602 A90B   0310        LDA #11       ; Para poner bytes
0604 9D4203 0320        STA ICCOM,X   ; Byte de comando
0607 A91F   0330        LDA #MSG&255  ; Byte bajo de MSG
0609 9D4403 0340        STA ICBAL,X   ;  en ICBAL
060C A906   0350        LDA #MSG/256  ; Byte alto de MSG
060E 9D4503 0360        STA ICBAH,X   ;  en ICBAH
0611 A900   0370        LDA #0        ; Largo de  MSG
0613 9D4903 0380        STA ICBLH,X   ;  byte alto
0616 A914   0390        LDA #20       ; Largo de MSG
0618 9D4803 0400        STA ICBLL,X   ;  byte bajo
            0410 ; *****************************
            0420 ; Ahora pongalo en la pantalla
            0430 ; *****************************
061B 2056E4 0440        JSR CIOV
061E 60     0450        RTS
            0460 ; *****************************
            0470 ; El mensaje en sí
            0480 ; *****************************
061F 41     0490 MSG    .BYTE "A SUCCESSFUL WRITE!",$9B
0620 20
0621 53
0622 55
0623 43
0624 43
0625 45
0626 53
0627 53
0628 46
0629 55
062A 4C
062B 20
062C 57
062D 52
062E 49
062F 54
0630 45
0631 21
0632 9B	

Este programa consigue exactamente el mismo fin que la rutina anterior, pero de una forma diferente. Ambos programas escriben un mensaje en la pantalla que termina con un retorno de carro. Hay un caso especial de escritura en la pantalla en el que no queremos que el texto vaya seguido de un RETURN, como cuando solicitamos el ingreso de datos o cuando nos gustaría formatear la pantalla de una manera particular. En BASIC, esta instrucción es simplemente una instrucción PRINT seguida de un punto y coma, lo que inhibe el retorno de carro normal después de un comando PRINT. Si, por ejemplo, queremos imprimir un símbolo > en la pantalla para solicitar al usuario el ingreso de datos, pero queremos que el cursor permanezca en la misma línea que ese símbolo, en BASIC podemos escribir la siguiente línea para realizar esta tarea:


PRINT ">";	

En la programación en lenguaje Ensamblador, el código es el siguiente:


Listado 9.4


            0100 ; ******************************
            0110 ; Equivalencias CIO
            0120 ; ******************************
0340        0130 ICHID  =   $0340
0341        0140 ICDNO  =   $0341
0342        0150 ICCOM  =   $0342
0343        0160 ICSTA  =   $0343
0344        0170 ICBAL  =   $0344
0345        0180 ICBAH  =   $0345
0346        0190 ICPTL  =   $0346
0347        0200 ICPTH  =   $0347
0348        0210 ICBLL  =   $0348
0349        0220 ICBLH  =   $0349
034A        0230 ICAX1  =   $034A
034B        0240 ICAX2  =   $034B
E456        0250 CIOV   =   $E456
0000        0260        *=  $600
            0270 ; *****************************
            0280 ; Ahora cargamos los datos requeridos
            0290 ; para el caso especial de 1 carácter
            0300 ; *****************************
0600 A200   0310        LDX #0       ; Ya que es IOCB0
0602 A90B   0320        LDA #11      ; Para poner bytes
0604 9D4203 0330        STA ICCOM,X  ; Byte de comando
0607 A900   0340        LDA #0       ; Largo de MSG
0609 9D4903 0350        STA ICBLH,X  ;  byte alto
060C A900   0360        LDA #0       ; Largo de MSG
060E 9D4803 0370        STA ICBLL,X  ;  byte bajo
            0380 ; *****************************
            0390 ; Ahora pongalo en la pantalla
            0400 ; *****************************
0611 A93E   0410        LDA #62      ; Para el simbolo >
0613 2056E4 0420        JSR CIOV
0616 60     0430        RTS	

Si establecemos que la longitud del buffer sea igual a cero (estableciendo los bytes alto y bajo, ICBLL e ICBLH, en cero), entonces cuando se accede a CIOV, el carácter contenido en el Acumulador se imprimirá en el dispositivo de salida sin un siguiente retorno de carro. Esto se aplica a todos los dispositivos, incluidas las unidades de disco, las grabadoras, las impresoras y la pantalla, y señala una característica muy importante de las computadoras ATARI: La entrada y la salida son en gran medida independientes del dispositivo. Es decir, el Sistema Operativo trata a todos los dispositivos de manera similar, por lo que no tenemos que aprender a escribir un mensaje en la pantalla, luego aprender una forma diferente de enviar información a la impresora y aprender otro método más para pasar información a la unidad de disco. El método es idéntico una vez que se ha abierto el IOCB del dispositivo. Para demostrar esto, veremos una rutina para enviar el mismo mensaje a una impresora.


SALIDA A UNA IMPRESORA


Primero cerramos IOCB2, sólo para estar seguros; luego abrimos la impresora como dispositivo usando IOCB2; y luego enviamos nuestro mensaje.


Listado 9.5


0100; *******************************
0110 ; Equivalencias CIO
a 0120; *****************************
0340 0130 ICHID = $0340
0341 0140 ICDNO = $0341
0342 0150 ICCOM = $0342
0343 0160 ICSTA = $0343
0344 0170 ICBAL = $0344
0345 0180 ICBAH = $0345
0346 0190 ICPTL = $0346
0347 0200 ICPTH = $0347
0348 0210 ICBLL = $0348
0349 0220 ICBLH = $0349
034A ICAX1 = $034A
034B 0240 ICAX2 = $034B
E456 0250 CIOV = $E456
0000 0260 * = $600
0270 ; *******************************
0280 ; Primero cierre y abra IOCB2
0290; *****************************
0600 A220 0300 LDX #$20; Para el IOCB2
0602 A90C 0310 LDA #12; Comando de cierre
0604 9D4203 0320 STA ICCOM,X; En ICCOM
0607 2056E4 0330 JSR CIOV; Haga CLOSE
060A A220 0340 LDX #$20; IOCB2 nuevamente
060C A903 0350 LDA #3; Abrir archivo
060E 9D4203 0360 STA ICCOM,X; ¿El comando es
0611 A908 0370 LDA #8; Salida
0613 9D4A03 0380 STA ICAX1,X ; Abierto para salida
0616 A94C 0390 LDA #NAM&255 ; Byte bajo del dispositivo
0618 9D4403 0400 STA ICBAL,X; Señala "P:"
061B A906 0410 LDA #NAM/256 ; Byte alto
061D 9D4503 0420 STA ICBAH,X
0620 A900 0430 LDA #0
0622 9D4903 0440 STA ICBLH,X; Longitud de byte alta
0625 A9FF 0450 LDA #$FF
0627 9D4803 0460 STA ICBLL,X ; Longitud de byte baja
062A 2056E4 0470 JSR CIOV; Haga el OPEN
0480; *******************************
0490 ; Ahora imprimimos el mensaje
0500; *****************************
062D A220 0510 LDX #$20; Utilizando IOCB2
062F A909 0520 LDA #9; Poner registro
0631 9D4203 0530 STA ICCOM,X ; Comando
0634 A94F 0540 LDA #MSG&255; Dirección de MSG
0636 9D4403 0550 STA ICBAL,X ; Byte bajo
0639 A906 0560 LDA #MSG/256; Dirección de MSG
063B 9D4503 0570 STA ICBAH,X ; Byte alto
063E A900 0580 LDA #0; Longitud de MSG
0640 9D4903 0590 STA ICBLH,X ; byte alto
0643 A9FF 0600 LDA#$FF; Longitud de MSG
0645 9D4803 0610 STA ICBLL,X ; Byte bajo
0648 2056E4 0620 JSR CIOV; Ponga la línea
064B 60 0630 RTS ; Fin de rutina
064C 50 0640 NAM .BYTE "P:",$9B
064D 3A
064E 9B
064F 41 0650 MSG .BYTE "¡UNA ESCRITURA EXITOSA!",$9B
0650 20
0651 53
0652 55
0653 43
0654 43
0655 45
0656 53
0657 53
0658 46
0659 55
065A 4C
065B 20
065C 57
065D 52
065E 49
065F 54
0660 45
0661 21
0662 9B	

Listing 9.5


            0100 ; *****************************
            0110 ; Equivalencias CIO
            0120 ; *****************************
0340        0130 ICHID  =   $0340
0341        0140 ICDNO  =   $0341
0342        0150 ICCOM  =   $0342
0343        0160 ICSTA  =   $0343
0344        0170 ICBAL  =   $0344
0345        0180 ICBAH  =   $0345
0346        0190 ICPTL  =   $0346
0347        0200 ICPTH  =   $0347
0348        0210 ICBLL  =   $0348
0349        0220 ICBLH  =   $0349
034A        0230 ICAX1  =   $034A
034B        0240 ICAX2  =   $034B
E456        0250 CIOV   =   $E456
0000        0260        *=  $600
            0270 ; *****************************
            0280 ; Primero, cierre y abra IOCB2
            0290 ; *****************************
0600 A220   0300        LDX #$20      ; Para el IOCB2
0602 A90C   0310        LDA #12       ; Comando de cierre
0604 9D4203 0320        STA ICCOM,X   ; En ICCOM
0607 2056E4 0330        JSR CIOV      ; Haga CLOSE
060A A220   0340        LDX #$20      ; IOCB2 nuevamente
060C A903   0350        LDA #3        ; Abrir archivo
060E 9D4203 0360        STA ICCOM,X   ;  ?El comando es?
0611 A908   0370        LDA #8        ; Salida
0613 9D4A03 0380        STA ICAX1,X   ; Abrir para salida
0616 A94C   0390        LDA #NAM&255  ; Byte bajo del dispositivo
0618 9D4403 0400        STA ICBAL,X   ; Apunta a "P:"
061B A906   0410        LDA #NAM/256  ; Byte alto
061D 9D4503 0420        STA ICBAH,X
0620 A900   0430        LDA #0
0622 9D4903 0440        STA ICBLH,X   ; Largo del byte alto
0625 A9FF   0450        LDA #$FF
0627 9D4803 0460        STA ICBLL,X   ; Largo del byte bajo
062A 2056E4 0470        JSR CIOV      ; Haga el OPEN
            0480 ; *****************************
            0490 ; Ahora imprimimos el mensaje
            0500 ; *****************************
062D A220   0510        LDX #$20      ; Utilizando IOCB2
062F A909   0520        LDA #9        ; Poner registro
0631 9D4203 0530        STA ICCOM,X   ; Comando
0634 A94F   0540        LDA #MSG&255  ; Direccion de MSG
0636 9D4403 0550        STA ICBAL,X   ;  Byte bajo
0639 A906   0560        LDA #MSG/256  ; Direccion de  MSG
063B 9D4503 0570        STA ICBAH,X   ;  Byte alto
063E A900   0580        LDA #0        ; Largo de MSG
0640 9D4903 0590        STA ICBLH,X   ;  Byte alto
0643 A9FF   0600        LDA #$FF      ; Largo de MSG
0645 9D4803 0610        STA ICBLL,X   ;  Byte bajo
0648 2056E4 0620        JSR CIOV      ; Ponga la linea
064B 60     0630        RTS           ; Fin de la rutina
064C 50     0640 NAM    .BYTE "P:",$9B
064D 3A
064E 9B
064F 41     0650 MSG   .BYTE "A SUCCESSFUL WRITE!",$9B
0650 20
0651 53
0652 55
0653 43
0654 43
0655 45
0656 53
0657 53
0658 46
0659 55
065A 4C
065B 20
065C 57
065D 52
065E 49
065F 54
0660 45
0661 21
0662 9B	

Por supuesto, si está utilizando una impresora ATARI y desea imprimir usando texto expandido, tendrá que configurar ICAX1 e ICAX2 antes de la llamada final a CIOV, pero eso es trivial. Tenga en cuenta que no hemos hecho CLOSE del IOCB2 después de la impresión de nuestro mensaje por lo que, si queremos imprimir algo más, simplemente podemos enviarlo a través del IOCB2 sin necesidad de hacer OPEN nuevamente. Por supuesto, eso también significa que ahora no podemos usar IOCB2 para nada más como, por ejemplo, el acceso al disco. Si necesitamos acceder al disco, podemos usar uno de los otros IOCB, o podemos hacer CLOSE del IOCB2 primero y luego volver a hacerle OPEN para nuestra operación de disco.


Tenga en cuenta que, si queremos que el cabezal de impresión se detenga después de imprimir un solo carácter, sin un retorno de carro final, podemos usar el caso especial de buffer de longitud cero, tal como lo hicimos anteriormente para la pantalla.


SALIDA A UN DISCO


Para mostrar la versatilidad de las rutinas centrales de E/S del ATARI, ni siquiera le daremos aquí al programa la posibilidad de escribir la misma línea en un archivo de disco. Se describirá el método y podrá enviar información a su disco en el primer intento, ¡todo usted mismo! El único cambio necesario en el programa proporcionado anteriormente para la impresora es este: para usar la unidad de disco, el nombre del dispositivo es el archivo de disco que desea abrir. Por lo tanto, el programa es idéntico al anterior, pero la línea 640 debería leerse algo como:


640 NAM .BYTE "D1:MYFILE.1",$9B	

Eso es todo al respecto. Puede ver la belleza de usar rutinas CIO idénticas para todos los dispositivos. Ahora puede enviar información a cualquier dispositivo de su elección en lenguaje Ensamblador.


ENTRADA USANDO CIOV


El método para ingresar datos desde un dispositivo a su computadora ATARI es exactamente el mismo que para la salida, pero el dispositivo debe estar abierto para la entrada. Podríamos, por ejemplo, recuperar el mensaje anterior de nuestro archivo en disco "D1:MYFILE.1" abriendo este archivo para entrada, usando un 3 en ICCOM y un 4 en ICAX1, y apuntando ICBAL e ICBAH a la ubicación en la memoria para que se transfiera el mensaje. Por ejemplo, si queremos que el mensaje comience en la ubicación de memoria $680, estableceríamos ICBAL en #$80 e ICBAH en #6. Después de la llamada a CIOV, las ubicaciones de memoria $680 a $694 contendrán los bytes del mensaje, que luego podrán ser examinados por el resto de nuestro programa.


No se debe subestimar la facilidad y simplicidad de la E/S en las computadoras ATARI. En otras microcomputadoras, aprender a utilizar cada dispositivo es una tarea aparte. La entrada y la salida pueden utilizar diferentes rutinas, cada una con sus propias peculiaridades. La filosofía de la E/S Central utilizada en los ATARI nos simplifica enormemente este proceso. Ahora puede utilizar este sistema para mejorar enormemente sus habilidades de programación en lenguaje Ensamblador.


Una nota final sobre las rutinas de E/S: Si abrimos un IOCB para la entrada desde un archivo en la unidad de disco y un segundo IOCB para la salida a una impresora o a la pantalla, sería una tarea trivial transferir información muy rápidamente desde un dispositivo a otro apuntando al mismo buffer para ambos IOCB. Imprimir una copia impresa y copiar la memoria a un archivo de disco es simple. Incluso podemos transferir información desde la unidad de disco a la pantalla o a una grabadora.


ENTRADAS Y SALIDAS NO-CIO


TRES SISTEMAS DE E/S DIFERENTES


Además de CIO, existen otros dos métodos para utilizar la unidad de disco como dispositivo de entrada y salida. Ambos residen en el Sistema Operativo. Utilizan vectores llamados DSKINV y SIOV, a $E453 y $E459, respectivamente.


Los tres métodos de E/S de disco pueden verse como una cebolla, con múltiples capas de control. La capa exterior, que hace la mayor parte del trabajo por usted, es el sistema CIO; la capa intermedia, que hace parte del trabajo por usted, es el sistema DSKINV; y la capa interna, en la que el programador hace todo el trabajo, es el sistema SIOV. De hecho, SIOV, el vector de entrada-salida en serie (Serial Input-Output Vector), se utiliza para todas las comunicaciones que tienen lugar a través del bus serie, el conector de 13 clavijas en el costado de su computadora ATARI. Incluso el sistema CIO realiza las operaciones de entrada y salida reales llamando a SIO, después de usar la información en el IOCB para configurar todo para SIO. DSKINV, sobre el cual aprenderemos más en breve, también llama a SIO para realizar la E/S real.


TIPOS DE ARCHIVOS DE DISCO


Un disquete para su unidad de disco ATARI contiene 40 pistas concéntricas, algo así como un disco fonográfico. En un disco, sin embargo, las pistas son en realidad una espiral continua mientras que, en un disquete, cada pista es un círculo separado. Cada pista está dividida en 18 sectores. Para imaginar esto, imagine cortar el disco como una pizza, con 18 porciones iguales. Luego corte la pizza en 40 círculos concéntricos, como una diana con 40 anillos de diferentes colores. Cada trozo de pizza es un sector. Tendremos 18 X 40, o 720 sectores. En cada uno de los sectores, el ATARI puede almacenar 128 bytes de información.


En el proceso de formatear un disco, no solo se crean los 720 sectores, sino que también se crean una Tabla de Contenido del Volumen (VTOC - Volume Table Of Contents) y un directorio de disco. El directorio del disco actúa como la tabla de contenido de un libro, enumerando cada archivo (Capítulo) contenido en el disco y el número de sector (página) donde se puede encontrar ese archivo. El VTOC realiza un seguimiento de qué sectores ya se han llenado y cuáles permanecen vacíos, de modo que cuando guardamos un nuevo archivo en un disco parcialmente lleno, no sobrescribimos la información ya almacenada en otro archivo. Cuando eliminamos un archivo, sus sectores quedan liberados en el VTOC para poder volver a utilizarlos. Tenga en cuenta que cuando se elimina un archivo, en realidad solo se cambia 1 byte del archivo: el byte de estado o bandera. Los primeros cinco bytes de la entrada del directorio del disco para cada archivo son:


1. El byte de estado (status), que contiene el estado del archivo. Cada uno de los 4 bits del byte de estado se utiliza para almacenar información específica sobre ese archivo:
Bit 0 establecido en 1 si el archivo está abierto para salida
Bit 5 establecido en 1 si el archivo está bloqueado
Bit 6 establecido en 1 si el archivo está en uso
Bit 7 establecido en 1 si el archivo fue eliminado

2,3. La longitud del archivo, en sectores, en el orden habitual de byte bajo seguido de byte alto.


4,5. El número del primer sector del archivo, en orden bajo-alto.

Si tiene alguno de los muchos programas de utilidad de disco disponibles, puede recuperar un archivo eliminado simplemente cambiando el byte de estado de $80 a $40. Sin embargo, si escribe información en el disco antes de intentar este procedimiento, no funcionará. El VTOC se cambia cuando se elimina un archivo, liberando los sectores para su uso. Si ha escrito en el disco, encontrará que algunos de los sectores utilizados anteriormente para el archivo que desea recuperar han sido sobrescritos con la nueva información.


Para los fines de esta discusión, describiremos dos tipos de archivos diferentes utilizados por las computadoras ATARI. El primero, y con diferencia el más común, es el Archivo Vinculado, como el creado por esta instrucción BASIC:


SAVE "D:GAME"	

Primero, se busca el directorio del disco. Dado que un solo disco puede contener un máximo de 64 archivos, esta verificación garantiza que haya espacio en el directorio del disco para otro archivo, llamado GAME. Si, al comprobar el directorio, se encuentra un archivo llamado GAME, se elimina (a menos que esté bloqueado) y el nuevo archivo reemplaza al anterior. Suponiendo que este es el primer archivo GAME que se guardará y que hay espacio en el directorio del disco, los primeros 125 bytes del nuevo archivo GAME se escriben en el primer sector que el VTOC dice que está disponible. Tenga en cuenta que sólo se escriben 125 bytes del archivo, aunque cada sector puede contener 128 bytes. Esto deja espacio para los 3 bytes agregados por CIO, que conducen al nombre de archivo vinculado para este tipo de archivo.


Estos 3 bytes contienen la siguiente información:


Número de byte
125
126
127
765432 10
76543210
7 6543210
# archivo
enlace directo
# de bytes del sector

Los 6 bits superiores del byte 125 son el número de archivo, tomado del número del archivo en el directorio del disco. Por ejemplo, si GAME es el cuarto archivo listado en el directorio, entonces el número de archivo contenido en los 6 bits superiores del byte 125 de cada sector de GAME es 3, ya que la numeración comienza con el archivo 0. Este número se verifica al leer este archivo para asegurar que cada sector realmente pertenece al archivo GAME. Si, al leer un archivo, se encuentra un sector con un número de archivo diferente, se mostrará un mensaje de error en su pantalla. Por lo general, esto significa que las cosas realmente se han estropeado en su disco. Intentar arreglar un archivo de este tipo es una tarea difícil.


Los 2 bits de orden inferior del byte 125 se combinan con el byte 126 para producir un número de 10 bits que contiene el número del siguiente sector del archivo. Por lo tanto, después de leer el primer sector, el siguiente sector a leer se puede determinar a partir de este enlace directo, y así sucesivamente, hasta que se lea todo el archivo. Por eso lo llamamos archivo vinculado. El último sector de cada archivo contiene 00 como enlace directo, por lo que podemos determinar cuándo se ha leído el archivo completo.


El byte 127 de cada sector de un archivo vinculado contiene el número de bytes almacenados en ese sector. En todos los sectores excepto el último de cada archivo, este valor será igual a 125. Si el sector contiene menos de 125 bytes, se establecerá el bit alto del byte 127, el bit S, lo que indica un sector "corto" de menos de 125 bytes.


El segundo tipo principal de archivo de disco se llama Archivo Secuencial y tiene una estructura mucho más simple. No utiliza ni el directorio del disco ni el VTOC, y utiliza los 128 bytes de cada sector para almacenamiento. Los sectores de dicho archivo se leen de manera secuencial: El sector 3 se lee después del sector 2, que se leyó después del sector 1. El primer sector de dicho archivo contiene la dirección de carga (que indica en qué lugar de la memoria cargar este archivo) y la dirección de inicio (dónde comenzar la ejecución del programa una vez que se complete la carga). Este tipo de archivo suele encontrarse en juegos comerciales. Si intenta mirar el directorio de dicho disco, solo verás basura, ya que nunca se configuró ningún directorio para ese disco.


USO DE LOS DIFERENTES SISTEMAS DE E/S


CIO se utiliza generalmente para leer un Archivo Vinculado, como un programa BASIC o, el código fuente de un programa en lenguaje Ensamblador. Sin embargo, cuando desea leer un sector específico del disco, generalmente se utiliza DSKINV o SIO. Examinemos cómo realizaríamos estas tareas utilizando los tres tipos diferentes de llamadas de E/S.
Primero, abriremos un archivo de disco y lo leeremos en la memoria. El segmento del programa que abre un archivo es muy similar al programa anterior que abrió el directorio del disco:


Listado 9.6


            0100 ; *****************************
            0110 ; Equivalencias CIO
            0120 ; *****************************
0340        0130 ICHID  =   $0340
0341        0140 ICDNO  =   $0341
0342        0150 ICCOM  =   $0342
0343        0160 ICSTA  =   $0343
0344        0170 ICBAL  =   $0344
0345        0180 ICBAH  =   $0345
0346        0190 ICPTL  =   $0346
0347        0200 ICPTH  =   $0347
0348        0210 ICBLL  =   $0348
0349        0220 ICBLH  =   $0349
034A        0230 ICAX1  =   $034A
0348        0240 ICAX2  =   $034B
E456        0250 CIOV   =   $E456
0000        0260        *=  $600
            0270 ; *****************************
            0280 ; Abra un archivo llamado OBJECT.COD
            0290 ; *****************************
0600 A220   0300        LDX #$20      ; Utilice IOCB2
0602 A90C   0310        LDA #12       ; Para cerrar IOCB
0604 9D4203 0320        STA ICCOM,X   ; Byte de comando
0607 2056E4 0330        JSR CIOV      ; Haga el cierre
            0340 ; *****************************
060A A220   0350        LDX #$20      ; Utilice IOCB2 nuevamente
060C A903   0360        LDA #3        ; Comando abrir
060E 9D4203 0370        STA ICCOM,X   ; Byte del comando
0611 A904   0380        LDA #4        ; Abierto para lectura
0613 9D4A03 0390        STA ICAX1,X   ; En ICAX1
0616 A900   0400        LDA #0        ; 0 en ICAX2 es
0618 9D4B03 0410        STA ICAX2,X   ; Solo para estar seguros
061B A94F   0420        LDA #NAME&255 ; Byte bajo del archivo
061D 9D4403 0430        STA ICBAL,X   ;  Direccion del nombre
0620 A906   0440        LDA #NAME/256 ; Byte alto del archivo
0622 9D4503 0450        STA ICBAH,X   ;  Direccion del nombre
0625 2056E4 0460        JSR CIOV      ; Abra el archivo
            0470 ; *****************************
0628 A220   0480        LDX #$20      ; IOCB2
062A A900   0490        LDA #0
062C 9D4403 0500        STA ICBAL,X   ; Byte bajo de la direccion
062F A950   0510        LDA #$50      ; Byte alto de la direccion
0631 9D4503 0520        STA ICBAH,X   ;  Entonces es $5000
0634 A9FF   0530        LDA #$FF      ; Hacer que el largo del buffer
0636 9D4803 0540        STA ICBLL,X   ;  sea grande para que pueda
0639 9D4903 0550        STA ICBLH,X   ;  cargar el archivo completo
063C A905   0560        LDA #5        ; Obtener registro
063E 9D4203 0570        STA ICCOM,X   ; Byte del comando
0641 2056E4 0580        JSR CIOV      ; Leer el archivo completo
            0590 ; *****************************
0644 A220   0600        LDX #$20      ; IOCB2
0646 A90C   0610        LDA #12       ; Para cerrar el  IOCB
0648 9D4203 0620        STA ICCOM,X   ; Byte del comando
064B 2056E4 0630        JSR CIOV      ; Cierre el archivo
064E 60     0640        RTS           ; Fin de la rutina
            0650 ; *****************************
064F 44     0660 NAME   .BYTE "D1:OBJECT.COD",$9B
0650 31
0651 3A
0652 4F
0653 42
0654 4A
0655 45
0656 43
0657 54
0658 2E
0659 43
065A 4F
065B 44
065C 9B	

Este programa utiliza un truco para cargar el archivo completo en una sola operación. En las líneas 530 a 550, configuramos la longitud del buffer en $FFFF, o 65.535 bytes. Luego, la rutina CIO cargará el archivo completo y se detendrá cuando se hayan cargado 65.535 bytes (algo casi imposible) o cuando se encuentre un byte de final de línea. Por lo tanto, si nuestro archivo contiene bytes de final de línea ($9B), la carga finalizará y no cargaremos el archivo completo. ¿Cómo podemos solucionar este problema?


Dado que probablemente no sabremos con certeza si el archivo que se va a cargar contiene algún byte $9B, debemos ir a la segura y usar un método que cargue cualquier archivo. Para hacer esto, cargamos un sector (128 bytes) a la vez, continuando hasta que se logre una condición de error, que ocurrirá al final del archivo. Usando CIO, sabemos cuándo ocurre un error, ya que regresaremos de la llamada al CIO con la bandera Negativo establecida en uno. Echemos un vistazo al programa para realizar este tipo de carga usando CIO:


Listado 9.7


            0100 ; *****************************
            0110 ; Equivalencias CIO
            0120 ; *****************************
0340        0130 ICHID  =   $0340
0341        0140 ICDNO  =   $0341
0342        0150 ICCOM  =   $0342
0343        0160 ICSTA  =   $0343
0344        0170 ICBAL  =   $0344
0345        0180 ICBAH  =   $0345
0346        0190 ICPTL  =   $0346
0347        0200 ICPTH  =   $0347
0348        0210 ICBLL  =   $0348
0349        0220 ICBLH  =   $0349
034A        0230 ICAX1  =   $034A
034B        0240 ICAX2  =   $034B
E456        0250 CIOV   =   $E456
0000        0260        *=  $600
            0270 ; *****************************
            0280 ; Abra un archivo llamado OBJECT.COD
            0290 ; *****************************
0600 A220   0300        LDX #$20      ; Utilice IOCB2
0602 A90C   0310        LDA #12       ; Para cerrar el IOCB
0604 9D4203 0320        STA ICCOM,X   ; Byte del comando
0607 2056E4 0330        JSR CIOV      ; Haga el cierre
            0340 ; *****************************
060A A220   0350        LDX #$20      ; Utilice IOCB2 nuevamente
060C A903   0360        LDA #3        ; Comando para abrir
060E 9D4203 0370        STA ICCOM,X   ; Byte del comando
0611 A904   0380        LDA #4        ; Abierto para lectura
0613 9D4A03 0390        STA ICAX1,X   ; En ICAX1
0616 A900   0400        LDA #0        ; 0 en ICAX2 es
0618 9D4B03 0410        STA ICAX2,X   ; Solo para estar seguros
061B A969   0420        LDA #NAME&255 ; Byte bajo de la direccion
061D 9D4403 0430        STA ICBAL,X   ; del nombre del archivo
0620 A906   0440        LDA #NAME/256 ; Byte alto de la direccion
0622 9D4503 0450        STA ICBAH,X   ; del nombre del archivo
0625 2056E4 0460        JSR CIOV      ; Abra el archivo
            0470 ; *****************************
0628 A220   0480        LDX #$20      ; IOCB2
062A A900   0490        LDA #0
062C 9D4803 0500        STA ICBLL,X   ; Longitud baja del buffer
062F A980   0510        LDA #$80      ; Para cargar un sector
0631 9D4903 0520        STA ICBLH,X   ; A la vez
0634 A950   0530        LDA #$50      ; Byte alto de la
0636 9D4503 0540        STA ICBAH,X   ; direccion del buffer
0639 A905   0550        LDA #5        ; Obtener registro
063B 9D4203 0560        STA ICCOM,X   ; Byte del comando
063E A220   0570 LOOP   LDX #$20      ; Para cuando se realiza el ciclo
0640 A900   0580        LDA #0        ; Byte bajo de la
0642 9D4403 0590        STA ICBAL,X   ; direccion de buffer al comenzar
0645 2056E4 0600        JSR CIOV      ; Leer 1er sector
0648 3014   0610        BMI FIN       ; Si termino, vaya a END
064A A220   0620        LDX #$20      ; IOCB2
064C A980   0630        LDA #$80      ; Subir 128 bytes
064E 9D4403 0640        STA ICBAL,X   ; Para el buffer
0651 2056E4 0650        JSR CIOV      ; Leer siguiete  sector
0654 3008   0660        BMI FIN       ; Si termino, vaya a END
0656 A220   0670        LDX #$20      ; IOCB2
0658 FE4503 0680        INC ICBAH,X   ; Elevar el buffer nuevamente
065B 4C3E06 0690        JMP LOOP      ; Aun no termina - leer mas
            0700 ; *****************************
065E A220   0710 FIN    LDX #$20      ; IOCB2
0660 A90C   0720        LDA #12       ; Para cerrar el IOCB
0662 9D4203 0730        STA ICCOM,X   ; Byte del comando
0665 2056E4 0740        JSR CIOV      ; Haga el cierre
0668 60     0750        RTS           ; Fin de la rutina
            0760 ; *****************************
0669 44     0770 NAME   .BYTE "D1:OBJECT.COD",$9B
066A 31
066B 3A
066C 4F
066D 42
066E 4A
066F 45
0670 43
0671 54
0672 2E
0673 43
0674 4F
0675 44
0676 9B	

Continuamos el ciclo hasta que encontramos un error en E/S, momento en el cual pasamos a END para cerrar el archivo y finalizar la rutina. Debe tener cuidado de que no se produzcan errores distintos del error de fin de archivo, ya que este programa se bifurcará a END ante cualquier error. Por supuesto, sería bastante fácil escribir una rutina para determinar primero el código de error devuelto en el registro Y después de la llamada a CIOV y luego tomar las medidas apropiadas dependiendo del código de error. Tenga en cuenta que en esta rutina tenemos que encargarnos de algunas tareas domésticas para cargar el archivo, como incrementar la dirección del buffer en las líneas 630, 640 y 680; No tuvimos que preocuparnos por esto en el primer ejemplo. También tenemos que incorporar rutinas que antes no necesitábamos para determinar cuándo terminamos de cargar.


CARGAR USANDO EL CONTROLADOR (HANDLER) RESIDENTE DE DISCO


Para utilizar el controlador residente de disco, el programador debe configurar un Bloque de Control de Dispositivo (Device Control Block - DCB), que es exactamente análogo al IOCB que necesitamos configurar cuando usamos CIO. Las equivalencias para este DCB son las siguientes:


0100 ; *****************************
0110 ; Equivalencias SIO
0120 ; *****************************
0130 DDEVIC = $0300 ; ID del bus serie
0140 DUNIT  = $0301; Número de dispositivo
0150 DCOMND = $0302; Byte de comando
0160 DSTATS = $0303; Byte de estado
0170 DBUFLO = $0304 ; Direccion baja del buffer 
0180 DBUFHI = $0305; Dirección alta del buffer
0190 DTIMLO = $0306; Tiempo de espera del disco
0210 DBYTLO = $0308; Recuento de bytes bajo
0220 DBYTHI = $0309; Recuento de bytes alto
0230 DAUX1  = $030A; Auxiliar #1
0240 DAUX2  = $030B; Auxiliar #2
0250 SIOV   = $E459
0260 DSKINV = $E453	

El tercer byte tanto del IOCB como del DCB es el byte de comando, aunque los bytes de comando en sí son diferentes en los dos sistemas, y el quinto y sexto bytes de ambos sistemas son la dirección del buffer. El controlador residente de disco solo permite los siguientes 5 bytes de comando:


$21 Formatear un disco
$50 Escribir un sector
$52 Leer un sector
$53 Solicitud de estado
$57 Escribir un sector con verificación de escritura

Por lo tanto, es evidente que el controlador residente de disco es un sistema más limitado, pero mucho más simple que el CIO. Veamos cómo podemos usar el DCB y el controlador residente de disco, a través de DSKINV, para leer información del disco. Por supuesto, no leeremos archivos DOS normales utilizando este sistema; son Archivos Vinculados y el controlador residente de disco no está diseñado para manejarlos, sino los Secuenciales. Por lo tanto, supongamos que queremos leer los sectores $20 a $60, inclusive, en lugar de algún archivo de disco. El programa para hacer esto usando DSKINV es el siguiente:


Listado 9.8


            0100 ; *****************************
            0110 ; Equivalencias SIO
            0120 ; *****************************
0300        0130 DDEVIC =    $0300    ; ID del bus serie
0301        0140 DUNIT  =    $0301    ; Numero de dispositivo
0302        0150 DCOMND =    $0302    ; Byte del comando
0303        0160 DSTATS =    $0303    ; Byte de estado
0304        0170 DBUFLO =    $0304    ; Direccion baja del buffer
0305        0180 DBUFHI =    $0305    ; Direccion alta del buffer
0306        0190 DTIMLO =    $0306    ; Tiempo de espera del disco
0308        0200 DBYTLO =    $0308    ; Byte bajo del contador
0309        0210 DBYTHI =    $0309    ; Byte alto del contador
030A        0220 DAUX1  =    $030A    ; Auxiliar #1
030B        0230 DAUX2  =    $030B    ; Auxiliar #2
E459        0240 SIOV   =    $E459
E453        0250 DSKINV =    $E453
0000        0260        *=   $600
            0270 ; *****************************
            0280 ; Supongamos que el archivo comienza en el sector
            0290 ; $20 y se extiende al sector $60
            0300 ; *****************************
0600 A900   0310        LDA #0
0602 8D0B03 0320        STA DAUX2     ; Numero de sector - alto
0605 8D0803 0330        STA DBYTLO    ; Largo del buffer - bajo
0608 A980   0340        LDA #$80      ; Para cargar un sector
060A 8D0903 0350        STA DBYTHI    ;  A la vez
060D A950   0360        LDA #$50      ; Byte alto de
060F 8D0503 0370        STA DBUFHI    ;  Direccion del buffer
0612 A952   0380        LDA #$52      ; Obtener sector
0614 8D0203 0390        STA DCOMND    ; Byte del comando
0617 A920   0400        LDA #$20      ; Numero de sector - bajo
0619 8D0A03 0410        STA DAUX1     ;  Va aqui
061C A900   0420 LOOP   LDA #0        ; Byte bajo de la Direccion
061E 8D0403 0430        STA DBUFLO    ;  del buffer al comenzar
0621 2053E4 0440        JSR DSKINV    ; Leer 1er sector
0624 A980   0450        LDA #$80      ; Subir 128 bytes
0626 8D0403 0460        STA DBUFLO    ;  Para el buffer
0629 EE0A03 0470        INC DAUX1     ; Siguiente sector
062C AD0A03 0480        LDA DAUX1     ; ?Terminamos?
062F C960   0490        CMP #$60
0631 B010   0500        BCS FIN       ; Si
0633 2053E4 0510        JSR DSKINV    ; No - leer el siguiente sector
0636 EE0503 0520        INC DBUFHI    ; Elevar página del buffer
0639 EE0A03 0530        INC DAUX1     ; Siguiente sector
063C AD0A03 0540        LDA DAUX1     ; ?Terminamos?
063F C960   0550        CMP #$60
0641 90D9   0560        BCC LOOP      ; No
0643 60     0570 FIN    RTS           ; Todo terminado	

Como vimos anteriormente, cuanto más nos alejamos de la rutina inicial del CIO, más tareas domésticas debemos realizar. En este programa, debemos manejar el incremento de los sectores del disco y la ubicación del buffer después de cada lectura. También debemos determinar si hemos terminado comparando constantemente el número del sector con el sector final deseado, $60. Esto es lo que queríamos decir cuando comparamos los distintos sistemas de E/S con las capas de una cebolla. Cuanto más nos acercamos al núcleo, más trabajo tenemos que hacer y menos maneja el sistema por nosotros.


En el núcleo se encuentra el propio sistema de Entrada-Salida en Serie (Serial Input Output - SIO). Accedimos a DSKINV en este programa, pero podríamos haber llamado a SIOV en su lugar. Sin embargo, antes de hacerlo, habríamos tenido que configurar todo el DCB en lugar de sólo los bytes pertinentes, tal como lo hicimos. Por ejemplo, el ID del bus serie tendría que haberse establecido en $31, en DDEVIC, y el valor del tiempo de espera en algún valor razonable, como 45. Entonces podríamos haber logrado exactamente los mismos resultados reemplazando cada llamada a DSKINV con una llamada a SIOV, pero con el gasto de aún más tareas domésticas.


Tenga en cuenta que tanto CIOV como DSKINV llaman a SIOV para realizar la entrada y salida en serie, pero manejan sus respectivas tareas de limpieza antes de estas llamadas. Cuanto más se aleje del CIO, más preciso será su control del sistema, pero más trabajo tendrás que hacer. Esta es una regla general en informática: un lenguaje de alto nivel es el más fácil de usar, pero proporciona el menor control del sistema. A medida que adquiera más control, también necesitará trabajar más duro. Bueno, realmente no esperaba conseguir algo a cambio de nada, ¿verdad?


Con esto concluye nuestra discusión sobre la E/S del disco. Ahora debería estar completamente familiarizado con cómo obtener información hacia y desde una unidad de disco, ya sea utilizando archivos Secuenciales o Vinculados. Experimente con estos sistemas hasta que se sienta cómodo, ya que son básicos para muchas aplicaciones que querrá probar.



Índice de Contenido | Capítulo anterior | Siguiente capítulo