cursos:ensamblador:rutinas_save_load

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
cursos:ensamblador:rutinas_save_load [06-01-2024 16:53] – [Convirtiendo datos en cinta] sromerocursos:ensamblador:rutinas_save_load [19-01-2024 11:58] (actual) sromero
Línea 8: Línea 8:
 ===== Formato de los datos en cinta ===== ===== Formato de los datos en cinta =====
  
- Supongamos que, desde BASIC, salvamos un bloque de datos en cinta con el comando SAVE. Lo primero que nos interesa conocer es el **formato** o **estructura de los datos** almacenados en la cinta, es decir, ¿qué se guarda realmente en la cinta (en formato de audio) cuando hacemos un SAVE?+ Supongamos que, desde BASIC, salvamos un bloque de datos en cinta con el comando SAVE. Lo primero que nos interesa conocer es el **formato** o **estructura de los datos** almacenados en la cinta, es decir, ¿qué se guarda realmente en la cinta (en formato de audio) cuando hacemos un ''SAVE''?
  
- Un SAVE produce 2 bloques de datos en la cinta:+ Un ''SAVE'' produce 2 bloques de datos en la cinta:
  
 \\  \\ 
Línea 45: Línea 45:
 |< 70% 20% 20% 60% >| |< 70% 20% 20% 60% >|
 ^ Byte ^ Longitud ^ Descripción ^ ^ Byte ^ Longitud ^ Descripción ^
-| 0 | 1 | Byte Flag ($00 ó $FF) |+| 0 | 1 | Byte Flag ($00 ó $ff) |
 | 1 | 1 | Tipo de bloque (0-3)| | 1 | 1 | Tipo de bloque (0-3)|
 | 2 | 10 | Nombre de fichero (rellenado con espacios en blanco) | | 2 | 10 | Nombre de fichero (rellenado con espacios en blanco) |
Línea 55: Línea 55:
  Pasemos a describir los diferentes campos de la cabecera:  Pasemos a describir los diferentes campos de la cabecera:
  
- El byte de flag (Byte 0) y el de Checksum (byte 18) no forman parte exactamente de la cabecera, sino del bloque cargado en sí mismo (también están presente cuando cargamos datos y no cabeceras), pero se han incluído dentro de la tabla para hacerla de lectura más sencilla. Puede decirse que el byte-flag es el byte prefijo de todo bloque de datos (considerando una cabecera de 17 bytes como un bloque de datos) y el checksum es el byte sufijo de ese mismo bloque. Concretamente, el valor de Byte-Flag es de $00 para bloques de cabecera y $FF para bloques de datos.+ El byte de flag (Byte 0) y el de Checksum (byte 18) no forman parte exactamente de la cabecera, sino del bloque cargado en sí mismo (también están presente cuando cargamos datos y no cabeceras), pero se han incluído dentro de la tabla para hacerla de lectura más sencilla. Puede decirse que el byte-flag es el byte prefijo de todo bloque de datos (considerando una cabecera de 17 bytes como un bloque de datos) y el checksum es el byte sufijo de ese mismo bloque. Concretamente, el valor de Byte-Flag es de $00 para bloques de cabecera y $ff para bloques de datos.
  
  El byte de tipo de bloque indica qué datos se van a cargar a continuación, según los siguientes valores:  El byte de tipo de bloque indica qué datos se van a cargar a continuación, según los siguientes valores:
Línea 105: Línea 105:
 </code> </code>
  
- Así pues, la rutina de la ROM del Spectrum se encarga (tanto al grabar como al leer) de codificar pulsos de diferentes duraciones para almacenar los ceros y unos de forma consecutiva. Nosotros aprovecharemos (como veremos a continuación) dicha rutina para cargar o salvar bloques de datos a nuestro antojo sin tener que programar esas temporizaciones y lecturas/escrituras a la cinta. Para nosotros será tan sencillo como cargar los valores adecuados en ciertos registros y realizar un CALL. No obstante, para los más curiosos, al final de este capítulo tenéis un enlace a las rutinas de la ROM adecuadamente comentadas de "The Complete Spectrum ROM Disassembly", por el Ian Logan y Frank O'Hara (publicado en 1983).+ Así pues, la rutina de la ROM del Spectrum se encarga (tanto al grabar como al leer) de codificar pulsos de diferentes duraciones para almacenar los ceros y unos de forma consecutiva. Nosotros aprovecharemos (como veremos a continuación) dicha rutina para cargar o salvar bloques de datos a nuestro antojo sin tener que programar esas temporizaciones y lecturas/escrituras a la cinta. Para nosotros será tan sencillo como cargar los valores adecuados en ciertos registros y realizar un ''call''. No obstante, para los más curiosos, al final de este capítulo tenéis un enlace a las rutinas de la ROM adecuadamente comentadas de "The Complete Spectrum ROM Disassembly", por el Ian Logan y Frank O'Hara (publicado en 1983).
  
  El nivel más bajo al que necesitamos llegar es el siguiente:  El nivel más bajo al que necesitamos llegar es el siguiente:
Línea 116: Línea 116:
  
    * Cada bloque tiene la siguiente estructura lógica (formato de los datos DENTRO de un bloque):    * Cada bloque tiene la siguiente estructura lógica (formato de los datos DENTRO de un bloque):
-      * Flag byte, con un valor de $00 para bloques de cabecera o $FF para bloques de datos.+      * Flag byte, con un valor de $00 para bloques de cabecera o $ff para bloques de datos.
       * Los datos en sí mismos: 17 bytes para cabeceras, o la longitud concreta de los datos para los bloques de datos.       * Los datos en sí mismos: 17 bytes para cabeceras, o la longitud concreta de los datos para los bloques de datos.
-      * Un byte de checksum, calculado de forma que haciendo un XOR de todos los bytes juntos, incluyendo el flag Byte, produzca $00.+      * Un byte de checksum, calculado de forma que haciendo un ''XOR'' de todos los bytes juntos, incluyendo el flag Byte, produzca $00.
  
  Resumiendo:  Resumiendo:
Línea 128: Línea 128:
    * Los 1s y los 0s se almacenan en cinta como pulsos de duraciones concretas.    * Los 1s y los 0s se almacenan en cinta como pulsos de duraciones concretas.
    * Las rutinas de la ROM nos permiten leer y escribir en cinta bloques de datos, realizando ellas la temporización adecuada para convertir nuestros "datos en memoria" en "pulsos" o viceversa sin complicación por nuestra parte.    * Las rutinas de la ROM nos permiten leer y escribir en cinta bloques de datos, realizando ellas la temporización adecuada para convertir nuestros "datos en memoria" en "pulsos" o viceversa sin complicación por nuestra parte.
-   * Sólo necesitaríamos escribir una rutina propia de carga (que detecte pulsos, temporice, etc) si quisiéramos programar nuestra propia carga, por ejemplo para cargar a diferente velocidad que el Spectrum (ultracargas), que cargue de dispositivos externos (puerto de joystick, algún pin concreto del bus de expansión, etc.) o para ejecutar código mientras cargamos el programa (minijuegos durante la carga, contadores de carga, etc). Para el resto de casos, bastará con usar mediante CALL las rutinas de la ROM.+   * Sólo necesitaríamos escribir una rutina propia de carga (que detecte pulsos, temporice, etc) si quisiéramos programar nuestra propia carga, por ejemplo para cargar a diferente velocidad que el Spectrum (ultracargas), que cargue de dispositivos externos (puerto de joystick, algún pin concreto del bus de expansión, etc.) o para ejecutar código mientras cargamos el programa (minijuegos durante la carga, contadores de carga, etc). Para el resto de casos, bastará con usar mediante call las rutinas de la ROM.
  
 \\  \\ 
 ===== Ejemplo de volcado de un SAVE ===== ===== Ejemplo de volcado de un SAVE =====
  
- En la FAQ de comp.sys.sinclair y WorldOfSpectrum tenemos un ejemplo muy interesante que muestra el formato lógico de los datos grabados con un SAVE en cinta. Supongamos el siguiente comando BASIC:+ En la FAQ de comp.sys.sinclair y WorldOfSpectrum tenemos un ejemplo muy interesante que muestra el formato lógico de los datos grabados con un ''SAVE'' en cinta. Supongamos el siguiente comando BASIC:
  
 <code> <code>
Línea 139: Línea 139:
 </code> </code>
    
- Este comando BASIC salvaría (SAVE), un total de 2 bytes (2) de datos (CODE), empezando en 0 (0) a cinta. En resumen, salvaría el contenido de la dirección de memoria 0x0000 0x0001 en cinta. Esto produciría los siguientes datos en cinta:+ Este comando BASIC salvaría (SAVE), un total de 2 bytes (2) de datos (CODE), empezando en 0 (0) a cinta. En resumen, salvaría el contenido de la dirección de memoria $0000 $0001 en cinta. Esto produciría los siguientes datos en cinta:
  
 <code> <code>
Línea 173: Línea 173:
 | ff | f3 af | a3 | | ff | f3 af | a3 |
  
- En este caso el byte flag es 0xFF (bloque de tipo "datos"), al cual siguen los 2 bytes tomados de la ROM y grabados a cinta (0x0000 0x0001) y el checksum (0xA3).+ En este caso el byte flag es $FF (bloque de tipo "datos"), al cual siguen los 2 bytes tomados de la ROM y grabados a cinta ($0000 $0001) y el checksum ($A3).
  
 \\  \\ 
Línea 189: Línea 189:
 | IX | Dirección inicio de memoria donde almacenar los datos que se van a cargar. | | IX | Dirección inicio de memoria donde almacenar los datos que se van a cargar. |
 | DE | Longitud del bloque de datos a cargar. | | DE | Longitud del bloque de datos a cargar. |
-| A | Flag Byte, normalmente 0x00 para cargar cabeceras o 0xFF (255) para cargar datos. |+| A | Flag Byte, normalmente $00 para cargar cabeceras o $FF (255) para cargar datos. |
 | CF (CarryFlag) | 1=LOAD, 0=VERIFY | | CF (CarryFlag) | 1=LOAD, 0=VERIFY |
  
Línea 198: Línea 198:
    * "D BREAK - CONT repeats" (se pulsó la tecla BREAK).    * "D BREAK - CONT repeats" (se pulsó la tecla BREAK).
  
- Recuerda que puedes activar el CARRY FLAG con la instruccion "SCF(Set Carry Flag) y ponerlo a cero con un simple "AND A".+ Recuerda que puedes activar el CARRY FLAG con la instruccion ''SCF'' (Set Carry Flag) y ponerlo a cero con un simple ''and a''.
  
- Veamos 2 ejemplos, el primero cargaría una pantalla gráfica sobre la videomemoria (el equivalente de un LOAD "" SCREEN$) siempre y cuando la pantalla se haya grabado sin cabecera:+ Veamos 2 ejemplos, el primero cargaría una pantalla gráfica sobre la videomemoria (el equivalente de un ''LOAD "" SCREEN$'') siempre y cuando la pantalla se haya grabado sin cabecera:
  
 <code z80> <code z80>
-   SCF                ; Set Carry Flag -> CF=1 -> LOAD +    scf                   ; Set Carry Flag -> CF=1 -> LOAD 
-   LD A255          ; A = 0xFF (cargar datos) +    ld a$ff             ; A = $FF (cargar datos) 
-   LD IX, 16384       ; Destino del load = 16384 +    ld ix, 16384          ; Destino del load = 16384 
-   LD DE, 6912        ; Tamaño a cargar = 6912 +    ld de, 6912           ; Tamaño a cargar = 6912 bytes 
-   CALL 1366          ; Llamamos a la rutina de carga+    call 1366             ; Llamamos a la rutina de carga
 </code> </code>
  
Línea 213: Línea 213:
  
 <code z80> <code z80>
-   SCF               ; Set Carry Flag (LOAD) +    scf                  ; Set Carry Flag (LOAD) 
-   LD A255      ; A = 0xFF (cargar datos) +    ld a$ff            ; A = $FF (cargar datos) 
-   LD IX, 32768      ; Destino de la carga +    ld ix, 32768         ; Destino de la carga 
-   LD DE, 12000      ; Nuestro "programa" ocupa 12000 bytes. +    ld de, 12000         ; Nuestro "programa" ocupa 12000 bytes. 
-   CALL 0556        ; Recordemos que 0556h = 1366d +    call $0556           ; Recordemos que 0556h = 1366d 
-   JP 32768          ; Saltamos al programa código máquina cargado+    jp 32768             ; Saltamos al programa código máquina cargado
 </code> </code>
  
Línea 224: Línea 224:
 ==== Rutina de SAVE de la ROM ==== ==== Rutina de SAVE de la ROM ====
    
- La rutina SAVE de la ROM tiene unos parámetros muy similares a la de LOAD, y está alojada en 1218d (04c2h):+ La rutina ''SAVE'' de la ROM tiene unos parámetros muy similares a la de ''LOAD'', y está alojada en 1218d (04c2h):
  
 |< 70% 20% 80% >| |< 70% 20% 80% >|
Línea 230: Línea 230:
 | IX | Dirección inicio de memoria de los datos que se van a grabar. | | IX | Dirección inicio de memoria de los datos que se van a grabar. |
 | DE | Longitud del bloque de datos a grabar (se grabarán los datos desde IX a IX+DE). | | DE | Longitud del bloque de datos a grabar (se grabarán los datos desde IX a IX+DE). |
-| A | Flag Byte, 0x00 para grabar cabeceras o 0xFF (255) para grabar datos. |+| A | Flag Byte, $00 para grabar cabeceras o $FF (255) para grabar datos. |
 | CF (CarryFlag) | 0 (SAVE) | | CF (CarryFlag) | 0 (SAVE) |
  
Línea 242: Línea 242:
  En ocasiones, podemos ignorar el bloque de cabecera totalmente, sobre todo cuando sabemos qué vamos a cargar desde cinta, qué destino tiene, y qué tamaño tiene, y lo especificamos directamente en nuestro programa ASM. En ese caso, podemos cargar la cabecera con el CARRY FLAG a cero (verify), con lo cual la leemos pero no la almacenamos en memoria, y después cargar los valores adecuados en IX, DE, A, etc, poner el CF a 1, y cargar los datos que vienen tras la cabecera.  En ocasiones, podemos ignorar el bloque de cabecera totalmente, sobre todo cuando sabemos qué vamos a cargar desde cinta, qué destino tiene, y qué tamaño tiene, y lo especificamos directamente en nuestro programa ASM. En ese caso, podemos cargar la cabecera con el CARRY FLAG a cero (verify), con lo cual la leemos pero no la almacenamos en memoria, y después cargar los valores adecuados en IX, DE, A, etc, poner el CF a 1, y cargar los datos que vienen tras la cabecera.
  
- Supongamos que grabamos un bloque de datos, gráficos, una pantalla o música en cinta usando SAVE, rutinas de la ROM, o desde un emulador o herramienta cruzada de PC. Supongamos que sabemos el tamaño exacto en cinta de dichos datos, y no necesitamos leer y analizar la cabecera para cargarlos. En tal caso, podemos ejecutar código como el siguiente:+ Supongamos que grabamos un bloque de datos, gráficos, una pantalla o música en cinta usando ''SAVE'', rutinas de la ROM, o desde un emulador o herramienta cruzada de PC. Supongamos que sabemos el tamaño exacto en cinta de dichos datos, y no necesitamos leer y analizar la cabecera para cargarlos. En tal caso, podemos ejecutar código como el siguiente:
  
 <code z80> <code z80>
-  AND A                           ; CF = 0 (verify) +    and a                           ; CF = 0 (verify) 
-  CALL 1366                       ; Cargamos e ignoramos la cabecera+    call 1366                       ; Cargamos e ignoramos la cabecera
  
-  SCF                             ; Set Carry Flag -> CF=1 -> LOAD +    scf                             ; Set Carry Flag -> CF=1 -> LOAD 
-  LD A255                       ; A = 0xFF (cargar datos) +    ld a$ff                       ; A = $FF (cargar datos) 
-  LD IX, direccion_destino        ; Destino del load +    ld ix, direccion_destino        ; Destino del load 
-  LD DE, tamaño_a_cargar          ; Tamaño a cargar +    ld de, tamaño_a_cargar          ; Tamaño a cargar 
-  CALL 1366                       ; Llamamos a la rutina de carga+    call 1366                       ; Llamamos a la rutina de carga
 </code> </code>
  
Línea 266: Línea 266:
  Lo primero que necesitamos saber es, ¿cómo convertimos nuestros datos (gráficos, pantalla de carga, números, tablas precalculadas, sprites, música, etc) en datos cargables desde las rutinas que hemos visto? Hay múltiples formas de hacerlo.   Lo primero que necesitamos saber es, ¿cómo convertimos nuestros datos (gráficos, pantalla de carga, números, tablas precalculadas, sprites, música, etc) en datos cargables desde las rutinas que hemos visto? Hay múltiples formas de hacerlo. 
  
- Para empezar, podemos hacerlo desde el mismo BASIC del Spectrum, usando el comando SAVE: esto nos permitirá grabar datos de memoria en cinta:+ Para empezar, podemos hacerlo desde el mismo BASIC del Spectrum, usando el comando ''SAVE'': esto nos permitirá grabar datos de memoria en cinta:
  
 <code basic> <code basic>
Línea 272: Línea 272:
 </code> </code>
  
- En la mayoría de los casos, muchos de nosotros programamos hoy en sistemas PC usando compiladores cruzados, ensambladores cruzados y emuladores, por lo que normalmente lo que nos interesará es obtener ficheros TAP para poder concatenarlos con nuestros cargadores o programas. + En la mayoría de los casos, muchos de nosotros programamos hoy en sistemas PC usando compiladores cruzados, ensambladores cruzados y emuladores, por lo que normalmente lo que nos interesará es obtener ficheros TAP para poder concatenarlos con nuestros cargadores o programas.
  
- Supongamos que estamos programando un juego que, nada más acabar, lo primero que hace es cargar desde cinta los datos del nivel actual (gráficos, mapeado, etc). Esto implica que cuando programemos el juego, tendremos por un lado el código, que nos proporcionará un fichero TAP (por ejemplo) listo para ejecutar. A ese fichero TAP tendremos que concatenarle los datos de los diferentes niveles (o gráficos, o los datos que necesitemos). + Supongamos que estamos programando un juego que, nada más acabar, lo primero que hace es cargar desde cinta los datos del nivel actual (gráficos, mapeado, etc). Esto implica que cuando programemos el juego, tendremos por un lado el código, que nos proporcionará un fichero TAP (por ejemplo) listo para ejecutar. A ese fichero TAP tendremos que concatenarle los datos de los diferentes niveles (o gráficos, o los datos que necesitemos).
  
- Así, nuestro "programa.asm(código fuente) se convierte en "programa.bintras el proceso de ensamblado, y finalmente obtenemos un "programa.tap(o .tzx) listo para cargar en un Spectrum. + Así, nuestro ''programa.asm'' (código fuente) se convierte en ''programa.bin'' tras el proceso de ensamblado, y finalmente obtenemos un ''programa.tap'' (o .tzx) listo para cargar en un Spectrum.
  
  Pero en dicho TAP o TZX tenemos que añadir (al final del mismo) los datos que el programa espera cargar. Imaginemos que estos datos son una pantalla gráfica (.scr) de 6912 bytes. Tendremos un fichero "pantalla.scr", y tenemos que introducirlo dentro de nuestro fichero TAP, al final, tras el código del programa, para que cuando este sea ejecutado, lo siguiente que cargue desde cinta nuestro programa sea dicha pantalla SCR.  Pero en dicho TAP o TZX tenemos que añadir (al final del mismo) los datos que el programa espera cargar. Imaginemos que estos datos son una pantalla gráfica (.scr) de 6912 bytes. Tendremos un fichero "pantalla.scr", y tenemos que introducirlo dentro de nuestro fichero TAP, al final, tras el código del programa, para que cuando este sea ejecutado, lo siguiente que cargue desde cinta nuestro programa sea dicha pantalla SCR.
Línea 286: Línea 286:
 </code> </code>
  
- Este fichero de 2 bytes de tamaño (inicio_rom.bin, por ejemplo), guardado en una cinta tendría el formato que vimos anteriormente: 2 bloques (cabecera y datos)+ Este fichero de 2 bytes de tamaño (''inicio_rom.bin'', por ejemplo), guardado en una cinta tendría el formato que vimos anteriormente: 2 bloques (cabecera y datos)
  
 <code> <code>
-00 03 52 4f 4d 20 20 20 20 20 20 20 02 00 00 00 00 80 f1 +00 03 52 4f 4d 20 20 20 20 20 20 20 02 00 00 00 00 80 f1
  
 + +
Línea 298: Línea 298:
  Observamos que hay 2 bloques de cinta de 19 y 4 bytes de datos, que conforman un SAVE de nuestros 2 bytes. Pues un fichero TAP con estos datos sería, sencillamente, el escribir estos 2 bloques en un fichero anteponiendo a cada bloque el tamaño a cargar:  Observamos que hay 2 bloques de cinta de 19 y 4 bytes de datos, que conforman un SAVE de nuestros 2 bytes. Pues un fichero TAP con estos datos sería, sencillamente, el escribir estos 2 bloques en un fichero anteponiendo a cada bloque el tamaño a cargar:
  
-  
 <code> <code>
-13 00 00 03 52 4f 4d 20 20 20 20 20 20 20 02 00 00 00 00 80 f1 +13 00 00 03 52 4f 4d 20 20 20 20 20 20 20 02 00 00 00 00 80 f1
  
 + +
Línea 324: Línea 323:
 </code> </code>
  
- Sabemos cómo podemos obtener nuestro programa en formato TAP: cogemos el código fuente, lo compilamos, y o bien obtenemos un TAP directamente (**pasmo <nowiki>--</nowiki>tapbas**), o bien obtenemos un BIN que convertimos con BIN2TAP. Pero ... ¿cómo convertimos nuestro "graficos.bin""pantalla_carga.bin""musica.bino cualquier otro fichero de datos en crudo? No podemos usar el BIN2TAP original porque éste añade un cargador BASIC al principio del programa... hay múltiples soluciones, pero la más sencilla es utilizar un ensamblador como **pasmo**.+ Sabemos cómo podemos obtener nuestro programa en formato TAP: cogemos el código fuente, lo compilamos, y o bien obtenemos un TAP directamente (''pasmo <nowiki>--</nowiki>tapbas''), o bien obtenemos un BIN que convertimos con BIN2TAP. Pero ... ¿cómo convertimos nuestro ''graficos.bin''''pantalla_carga.bin''''musica.bin'' o cualquier otro fichero de datos en crudo? No podemos usar el BIN2TAP original porque éste añade un cargador BASIC al principio del programa... hay múltiples soluciones, pero la más sencilla es utilizar un ensamblador como Pasmo.
  
- Para convertir un fichero .bin en un fichero tap sin cabecera, creamos un pequeño programa ASM (rom.asm) como el siguiente:+ Para convertir un fichero .bin en un fichero tap sin cabecera, creamos un pequeño programa ASM (''rom.asm'') como el siguiente:
  
 <code> <code>
Línea 332: Línea 331:
 </code> </code>
  
- A continuación, "ensamblamos" ese programa con PASMO indicando que queremos que nos genere un TAP sin cabecera BASIC:+ A continuación, "ensamblamos" ese programa con Pasmo indicando que queremos que nos genere un TAP sin cabecera BASIC:
  
 <code> <code>
Línea 338: Línea 337:
 </code> </code>
  
- Con esto, obtendremos un fichero "rom.tapcon el contenido de rom.bin, y sin cargador BASIC, listo para utilizar.+ Con esto, obtendremos un fichero ''rom.tap'' con el contenido de ''rom.bin'', y sin cargador BASIC, listo para utilizar.
  
 \\  \\ 
Línea 357: Línea 356:
 </code> </code>
  
- Ahora ya tenemos una pantalla SCR guardada en formato TAP (en cinta). Nótese cómo podríamos cargar este TAP desde BASIC con un //LOAD "" CODE 16384,6912//, y aparecería la imagen en pantalla.+ Ahora ya tenemos una pantalla SCR guardada en formato TAP (en cinta). Nótese cómo podríamos cargar este TAP desde BASIC con un ''LOAD "" CODE 16384,6912'', y aparecería la imagen en pantalla.
  
  Lo siguiente que necesitamos es el programa propiamente dicho, el cual hará la carga de la pantalla en videomemoria:  Lo siguiente que necesitamos es el programa propiamente dicho, el cual hará la carga de la pantalla en videomemoria:
Línea 367: Línea 366:
 ;---------------------------------------------------------------------- ;----------------------------------------------------------------------
  
-  ORG 32000+    ORG 32000
  
-  AND A                           ; CF = 0 (verify) +    and a                           ; CF = 0 (verify) 
-  CALL 1366                       ; Cargamos e ignoramos la cabecera+    call 1366                       ; Cargamos e ignoramos la cabecera
  
-  SCF                             ; Set Carry Flag -> CF=1 -> LOAD +    scf                             ; Set Carry Flag -> CF=1 -> LOAD 
-  LD A255                       ; A = 0xFF (cargar datos) +    ld a$ff                       ; A = $FF (cargar datos) 
-  LD IX, 16384                    ; Destino del load = 16384 +    ld ix, 16384                    ; Destino del load = 16384 
-  LD DE, 6912                     ; Tamaño a cargar = 6912 +    ld de, 6912                     ; Tamaño a cargar = 6912 bytes 
-  CALL 1366                       ; Llamamos a la rutina de carga+    call 1366                       ; Llamamos a la rutina de carga
  
-  RET+    ret
  
-END 32000+    END 32000
 </code> </code>
  
  Al respecto del código fuente, como habréis notado, realizamos 2 llamadas a la rutina de la ROM. La primera carga (pero no almacena en ningún sitio) el primer bloque de datos existente (la cabecera de la pantalla de carga). La rutina de la ROM ignorará esta carga porque el CARRY FLAG está a cero (0=VERIFY). La segunda llamada a 1366 realizará la carga de los datos propiamente dichos. Al cargarlos sobre la dirección de destino 16384 (la dirección de la videoram), veremos cómo se van cargando sobre la pantalla directamente desde la cinta.  Al respecto del código fuente, como habréis notado, realizamos 2 llamadas a la rutina de la ROM. La primera carga (pero no almacena en ningún sitio) el primer bloque de datos existente (la cabecera de la pantalla de carga). La rutina de la ROM ignorará esta carga porque el CARRY FLAG está a cero (0=VERIFY). La segunda llamada a 1366 realizará la carga de los datos propiamente dichos. Al cargarlos sobre la dirección de destino 16384 (la dirección de la videoram), veremos cómo se van cargando sobre la pantalla directamente desde la cinta.
  
- Ensamblamos nuestro programa con "**pasmo <nowiki>--</nowiki>tapbas loadscr.asm loadscr.tap**" y tendremos lo siguiente:+ Ensamblamos nuestro programa con ''pasmo <nowiki>--</nowiki>tapbas loadscr.asm loadscr.tap'' y tendremos lo siguiente:
  
-   * Un TAP (loadscr.tap) con nuestro programa (pero que no tiene datos después de él). +   * Un TAP (''loadscr.tap'') con nuestro programa (pero que no tiene datos después de él). 
-   * Un TAP (zxcolumns.tap) con los datos gráficos (en este caso, una pantalla completa de 6912 bytes).+   * Un TAP (''zxcolumns.tap'') con los datos gráficos (en este caso, una pantalla completa de 6912 bytes).
  
- Si cargamos en el Spectrum, o en un emulador, el fichero loadscr.tap, nos encontraríamos con que intenta cargar los datos desde cinta, pero no hay datos almacenados tras el programa. Para solucionarlo, concatenamos los 2 TAPs (con cat en Linux o copy en Windows/DOS):+ Si cargamos en el Spectrum, o en un emulador, el fichero ''loadscr.tap'', nos encontraríamos con que intenta cargar los datos desde cinta, pero no hay datos almacenados tras el programa. Para solucionarlo, concatenamos los 2 TAPs (con cat en Linux o copy en Windows/DOS):
  
 <code> <code>
Línea 396: Línea 395:
 </code> </code>
  
- Ahora sí, cargando "programa.tapen el emulador, cargaremos nuestro programa, el cual llama a la rutina de la ROM para cargar los datos que van después del programa (la pantalla de carga) en videomemoria. Si lo probáis en un emulador, recordad deshabilitar las opciones de carga rápida o carga instantánea si queréis ver el efecto de la carga.+ Ahora sí, cargando ''programa.tap'' en el emulador, cargaremos nuestro programa, el cual llama a la rutina de la ROM para cargar los datos que van después del programa (la pantalla de carga) en videomemoria. Si lo probáis en un emulador, recordad deshabilitar las opciones de carga rápida o carga instantánea si queréis ver el efecto de la carga.
  
 \\  \\ 
Línea 406: Línea 405:
  Un apunte: tanto en el caso de la carga, como de la grabación de datos, recordad que las rutinas de la ROM no indican al usuario que debe pulsar PLAY o REC, por lo que debemos indicar al usuario cuándo debe pulsar PLAY o REC dentro de nuestros programas o juegos. Incluso, cuando acabemos de cargar los datos relativos a nuestro juego, resulta conveniente indicarle al usuario cuándo debe detener la cinta (especialmente en juegos multicarga) e insertar los segundos de "espacio" que creamos convenientes entre bloques.  Un apunte: tanto en el caso de la carga, como de la grabación de datos, recordad que las rutinas de la ROM no indican al usuario que debe pulsar PLAY o REC, por lo que debemos indicar al usuario cuándo debe pulsar PLAY o REC dentro de nuestros programas o juegos. Incluso, cuando acabemos de cargar los datos relativos a nuestro juego, resulta conveniente indicarle al usuario cuándo debe detener la cinta (especialmente en juegos multicarga) e insertar los segundos de "espacio" que creamos convenientes entre bloques.
  
- Recordad que en este ejemplo hemos cargado 6912 bytes de un fichero SCR directamente sobre la videoRAM, pero nada nos impide cargar ficheros de cualquier otro tamaño, con cualquier otro contenido (sprites, fondos, datos, mapeados) sobre cualquier lugar de la memoria (asegurándonos primero que no hay nada en el lugar destino de la carga, como código, la pila, u otros datos o variables).  + Recordad que en este ejemplo hemos cargado 6912 bytes de un fichero SCR directamente sobre la videoRAM, pero nada nos impide cargar ficheros de cualquier otro tamaño, con cualquier otro contenido (sprites, fondos, datos, mapeados) sobre cualquier lugar de la memoria (asegurándonos primero que no hay nada en el lugar destino de la carga, como código, la pila, u otros datos o variables). 
-  + 
- Así pues, de la misma forma que hemos cargado una pantalla SCR, podemos organizar los gráficos y mapeados de nuestro juego en 1 "bloque de datos" por nivel, cargar los datos del nivel 1 tras acabar la carga de nuestro programa, y sobreescribir estos gráficos y mapeados "en memoria" con los de los diferentes niveles según vaya avanzando el jugador. En otras palabras, podemos hacer un juego multicarga que nos permita tener más sprites, pantallas o gráficos disponibles para cada nivel, que los que tendríamos disponibles si cargamos todos los datos de todos los niveles del juego, ya que usamos toda la memoria para cada nivel, en lugar de dividirla en espacio para los diferentes niveles. A cambio, el usuario tendrá que cargar desde cinta las diferentes fases conforme avanza, y rebobinar para cargar los datos del "Nivel 1" cuando deba empezar una nueva partida.+ De la misma forma que hemos cargado una pantalla SCR, podemos organizar los gráficos y mapeados de nuestro juego en 1 "bloque de datos" por nivel, cargar los datos del nivel 1 tras acabar la carga de nuestro programa, y sobreescribir estos gráficos y mapeados "en memoria" con los de los diferentes niveles según vaya avanzando el jugador. En otras palabras, podemos hacer un juego multicarga que nos permita tener más sprites, pantallas o gráficos disponibles para cada nivel, que los que tendríamos disponibles si cargamos todos los datos de todos los niveles del juego, ya que usamos toda la memoria para cada nivel, en lugar de dividirla en espacio para los diferentes niveles. A cambio, el usuario tendrá que cargar desde cinta las diferentes fases conforme avanza, y rebobinar para cargar los datos del "Nivel 1" cuando deba empezar una nueva partida.
  
  
Línea 414: Línea 413:
 ===== La rutina LD-BYTES (Load) ===== ===== La rutina LD-BYTES (Load) =====
  
- A continuación podemos ver el código desensamblado de la rutina LD-BYTES ($0556), la que estamos utilizando para la carga de datos desde cinta. Es una rutina muy interesante y disponer de su código fuente puede tener 2 usos directos.+ A continuación podemos ver el código desensamblado de la rutina ''LD-BYTES'' ($0556), la que estamos utilizando para la carga de datos desde cinta. Es una rutina muy interesante y disponer de su código fuente puede tener 2 usos directos.
  
  El primero es poder comprender de forma exácta cómo funciona la carga de datos desde cinta y los tiempos que se manejan en dicha carga. El segundo es el de reproducir la rutina en nuestro programa y añadir funciones adicionales como un contador de carga o incluso algún tipo de minijuego durante la misma.  El primero es poder comprender de forma exácta cómo funciona la carga de datos desde cinta y los tiempos que se manejan en dicha carga. El segundo es el de reproducir la rutina en nuestro programa y añadir funciones adicionales como un contador de carga o incluso algún tipo de minijuego durante la misma.
  
- El código comentado está extraído del documento "The Complete Spectrum ROM Disassembly", de Ian Logan y Frank O'Hara.+ El código comentado está extraído del documento "//The Complete Spectrum ROM Disassembly//", de Ian Logan y Frank O'Hara.
  
-<code z80>+ <code z80>
 ; THE 'LD-BYTES' SUBROUTINE ; THE 'LD-BYTES' SUBROUTINE
 ; This subroutine is called to LOAD the header information (from 07BE) ; This subroutine is called to LOAD the header information (from 07BE)
 ; and later LOAD, or VERIFY, an actual block of data (from 0802). ; and later LOAD, or VERIFY, an actual block of data (from 0802).
 0556 LD-BYTES: 0556 LD-BYTES:
-                  INC                     ; This resets the zero flag. (D +                  inc                     ; This resets the zero flag. (D 
-                                            ; cannot hold +FF.) +                                            ; cannot hold $FF.) 
-                  EX    AF,A'F            ; The A register holds +00 for a +                  ex    afaf            ; The Aregister holds $00 for 
-                                            ; header and +FF for a block of+                                            ; header and $FF for a block of
                                             ; data.                                             ; data.
                                             ; The carry flag is reset for                                             ; The carry flag is reset for
                                             ; VERIFYing and set for                                             ; VERIFYing and set for
                                             ; LOADing.                                             ; LOADing.
-                  DEC                     ; Restore D to its original value.+                  dec                     ; Restore D to its original value.
  
-                  DI                        ; The maskable interrupt is now+                  di                        ; The maskable interrupt is now
                                             ; disabled.                                             ; disabled.
-                  LD    A,+0F               ; The border is made WHITE. +                  ld    a,$0f               ; The border is made WHITE. 
-                  OUT   (+FE),A +                  out   ($fe),a 
-                  LD    HL,+053F            ; Preload the machine stack +                  ld    hl,$053f            ; Preload the machine stack 
-                  PUSH  HL                  ; with the address - SA/LD-RET+                  push  hl                  ; with the address - SA/LD-ret
-                  IN    A,(+FE)             ; Make an initial read of port '254' +                  in    a,($fe)             ; Make an initial read of port '254' 
-                  RRA                       ; Rotate the byte obtained but +                  rra                       ; Rotate the byte obtained but 
-                  AND   +20                 ; keep only the EAR bit, +                  and   $20                 ; keep only the EAR bit, 
-                  OR    +02                 ; Signal 'RED' border. +                  or    $02                 ; Signal 'RED' border. 
-                  LD    C,                ; Store the value in the C register. - +                  ld    c,                ; Store the value in the C register. - 
-                                            ; (+22 for 'off' and +02 for 'on'+                                            ; ($22 for 'off' and $02 for 'on'
                                             ; - the present EAR state.)                                             ; - the present EAR state.)
-                  CP                      ; Set the zero flag.+                  cp                      ; Set the zero flag.
  
 ; The first stage of reading a tape involves showing that a pulsing ; The first stage of reading a tape involves showing that a pulsing
 ; signal actually exist (i.e. 'On/off' or 'off/on' edges.) ; signal actually exist (i.e. 'On/off' or 'off/on' edges.)
  
-056B LD-BREAK     RET   NZ                  ; Return if the BREAK key is+056B LD-BREAK     ret   nz                  ; Return if the BREAK key is
                                             ; being pressed.                                             ; being pressed.
-056C LD-START     CALL  05E7,LD-EDGE-1      ; Return with the carry flag reset +056C LD-START     call  05E7,LD-EDGE-1      ; Return with the carry flag reset 
-                  JR    NC,056B,LD-BREAK    ; if there is no 'edge' within+                  jr    nc,056b,LD-BREAK    ; if there is no 'edge' within
                                             ; approx. 14,000 T states. But if                                             ; approx. 14,000 T states. But if
                                             ; an 'edge' is found the border                                             ; an 'edge' is found the border
Línea 464: Línea 463:
 ; that the signal is still pulsing. ; that the signal is still pulsing.
  
-                  LD    HL,+0415            ; The length of this waiting +                  ld    hl,$0415            ; The length of this waiting 
-0574 LD-WAIT      DJNZ  0574,LD-WAIT        ; period will be almost one +0574 LD-WAIT      djnz  0574,LD-WAIT        ; period will be almost one 
-                  DEC   HL                  ; second in duration. +                  dec   hl                  ; second in duration. 
-                  LD    A,H +                  ld    a,h 
-                  OR    L +                  or    l 
-                  JR    NZ,0574,LD-WAIT +                  jr    nz,0574,LD-WAIT 
-                  CALL  05E3,LD-EDGE-2      ; Continue only if two edges are +                  call  05E3,LD-EDGE-2      ; Continue only if two edges are 
-                  JR    NC,056B,LD-BREAK    ; found within the allowed time+                  jr    nc,056b,LD-BREAK    ; found within the allowed time
                                             ; period.                                             ; period.
  
 ; Now accept only a 'leader signal'. ; Now accept only a 'leader signal'.
  
-0580 LD-LEADER    LD    B,+9C               ; The timing constant, +0580 LD-LEADER    ld    b,$9c               ; The timing constant, 
-                  CALL  05E3,LD-EDGE-2      ; Continue only if two edges are +                  call  05E3,LD-EDGE-2      ; Continue only if two edges are 
-                  JR    NC,056B,LD-BREAK    ; found within the allowed time+                  jr    nc,056B,LD-BREAK    ; found within the allowed time
                                             ; period.                                             ; period.
-                  LD    A,+C6               ; However the edges must have +                  ld    a,$c6               ; However the edges must have 
-                  CP                      ; been found within about +                  cp                      ; been found within about 
-                  JR    NC,056C,LD-START    ; 3,000 T states of each other +                  jr    nc,056c,LD-START    ; 3,000 T states of each other 
-                  INC                     ; Count the pair of edges in the H +                  inc                     ; Count the pair of edges in the H 
-                  JR    NZ,0580,LD-LEADER   ; register until '256' pairs have+                  jr    nz,0580,LD-LEADER   ; register until '256' pairs have
                                             ; been found.                                             ; been found.
  
 ; After the leader come the 'off' and 'on' part's of the sync pulse. ; After the leader come the 'off' and 'on' part's of the sync pulse.
  
-058F LD-SYNC      LD    B,+C9               ; The timing constant. +058F LD-SYNC      ld    b,$c9               ; The timing constant. 
-                  CALL  05E7,LD-EDGE-1      ; Every edge is considered until +                  call  05E7,LD-EDGE-1      ; Every edge is considered until 
-                  JR    NC,056B,LD-BREAK    ; two edges are found close +                  jr    nc,056b,LD-BREAK    ; two edges are found close 
-                  LD    A,                ; together - these will be the +                  ld    a,                ; together - these will be the 
-                  CP    +D4                 ; start and finishing edges of +                  CP    $d4                 ; start and finishing edges of 
-                  JR    NC,058F,LD-SYNC     ; the 'off' sync pulse. +                  jr    nc,058f,LD-SYNC     ; the 'off' sync pulse. 
-                  CALL  05E7,LD-EDGE-1      ; The finishing edge of the +                  call  05e7,LD-EDGE-1      ; The finishing edge of the 
-                  RET   NC                  ; 'on' pulse must exist.+                  ret   nc                  ; 'on' pulse must exist.
                                             ; (Return carry flag reset.)                                             ; (Return carry flag reset.)
  
Línea 502: Línea 501:
 ; VERIFied. But the first byte is the type flag. ; VERIFied. But the first byte is the type flag.
  
-                  LD    A,                ; The border colours from now +                  ld    a,                ; The border colours from now 
-                  XOR   +03                 ; on will be BLUE & YELLOW.+                  XOR   $03                 ; on will be BLUE & YELLOW.
  
-                  LD    C,A +                  ld    c,a 
-                  LD    H,+00               ; Initialise the 'parity matching'+                  ld    h,$00               ; Initialise the 'parity matching'
                                             ; byte to zero.                                             ; byte to zero.
-                  LD    B,+B0               ; Set the timing constant for the+                  ld    b,$b0               ; Set the timing constant for the
                                             ; flag byte.                                             ; flag byte.
-                  JR    05C8,LD-MARKER      ; Jump forward into the byte+                  jr    05C8,LD-MARKER      ; Jump forward into the byte
                                             ; LOADING loop.                                             ; LOADING loop.
  
Línea 517: Línea 516:
 ; the last byte is the 'parity' byte. ; the last byte is the 'parity' byte.
  
-05A9 LD-LOOP      EX    AF,A'F'             ; Fetch the flags. +05A9 LD-LOOP      ex    af,af             ; Fetch the flags (ex af, af') 
-                  JR    NZ,05B3,LD-FLAG     ; Jump forward only when+                  jr    nz,05B3,LD-FLAG     ; Jump forward only when
                                             ; handling the first byte.                                             ; handling the first byte.
-                  JR    NC,05BD,LD-VERIFY   ; Jump forward if VERIFYing a+                  jr    nc,05BD,LD-VERIFY   ; Jump forward if VERIFYing a
                                             ; tape.                                             ; tape.
-                  LD    (IX+00),          ; Make the actual LOAD when+                  ld    (ix+00),          ; Make the actual LOAD when
                                             ; required.                                             ; required.
-                  JR    05C2,LD-NEXT        ; Jump forward to LOAD the+                  jr    05C2,LD-NEXT        ; Jump forward to LOAD the
                                             ; next byte.                                             ; next byte.
-05B3 LD-FLAG      RL                      ; Keep the carry flag in a safe+05B3 LD-FLAG      rl                      ; Keep the carry flag in a safe
                                             ; place temporarily.                                             ; place temporarily.
-                  XOR                     ; Return now if the type flag does +                  xor                     ; Return now if the type flag does 
-                  RET   NZ                  ; not match the first byte on the+                  ret   nz                  ; not match the first byte on the
                                             ; tape. (Carry flag reset.)                                             ; tape. (Carry flag reset.)
-                  LD    A,                ; Restore the carry flag now. +                  ld    a,                ; Restore the carry flag now. 
-                  RRA +                  rra 
-                  LD    C,A +                  ld    c,a 
-                  INC   DE                  ; Increase the counter to +                  inc   de                  ; Increase the counter to 
-                  JR    05CA,LD-DEC         ; compensate for its 'decrease'+                  jr    05CA,LD-DEC         ; compensate for its 'decrease'
                                             ; after the jump.                                             ; after the jump.
  
Línea 541: Línea 540:
 ; tested against the original byte. ; tested against the original byte.
  
-05BD LD-VERlFY    LD    A,(IX+00)           ; Fetch the original byte. +05BD LD-VERlFY    ld    a,(ix+00)           ; Fetch the original byte. 
-                  XOR                     ; Match it against the new byte. +                  xor                     ; Match it against the new byte. 
-                  RET   NZ                  ; Return if 'no match'. (Carry+                  ret   nz                  ; Return if 'no match'. (Carry
                                             ; flag reset.)                                             ; flag reset.)
  
 ; A new byte can now be collected from the tape. ; A new byte can now be collected from the tape.
  
-05C2 LD-NEXT      INC   IX                  ; Increase the 'destination'+05C2 LD-NEXT      inc   ix                  ; Increase the 'destination'
-05C4 LD-DEC       DEC   DE                  ; Decrease the 'counter'+05C4 LD-dec       dec   de                  ; Decrease the 'counter'
-                  EX    AF,A'F'             ; Save the flags. +                  ex    af,af             ; Save the flags in af' 
-                  LD    B,+B2               ; Set the timing constant. +                  ld    b,$b2               ; Set the timing constant. 
-05C8 LD-MARKER    LD    L,+01               ; Clear the 'object' register apart+05C8 LD-MARKER    ld    l,$01               ; Clear the 'object' register apart
                                             ; from a 'marker' bit.                                             ; from a 'marker' bit.
  
 ; The 'LD-8-BITS' loop is used to build up a byte in the L register. ; The 'LD-8-BITS' loop is used to build up a byte in the L register.
  
-05CA LD-8-BITS    CALL  05E3,LD-EDGE-2      ; Find the length of the 'off' and +05CA LD-8-BITS    call  05E3,LD-EDGE-2      ; Find the length of the 'off' and 
                                             ; 'on' pulses of the next bit.                                             ; 'on' pulses of the next bit.
-                  RET   NC                  ; Return if the time period is+                  ret   nc                  ; Return if the time period is
                                             ; exceeded. (Carry flag reset.)                                             ; exceeded. (Carry flag reset.)
-                  LD    A,+CB               ; Compare the length against+                  ld    a,$cb               ; Compare the length against
                                             ; approx. 2,400 T states; resetting                                             ; approx. 2,400 T states; resetting
-                  CP                      ; the carry flag for a '0' and+                  cp                      ; the carry flag for a '0' and
                                             ; setting it for a '1'.                                             ; setting it for a '1'.
-                  RL                      ; Include the new bit in the L+                  rl                      ; Include the new bit in the L
                                             ; register.                                             ; register.
-                  LD    B,+B0               ; Set the timing constant for the+                  ld    b,$b0               ; Set the timing constant for the
                                             ; next bit.                                             ; next bit.
-                  JP    NC,05CA,LD-8-BITS   ; Jump back whilst there are still+                  jp    nc,05CA,LD-8-BITS   ; Jump back whilst there are still
                                             ; bits to be fetched.                                             ; bits to be fetched.
  
 ; The 'parity matching' byte has to be updated with each new byte. ; The 'parity matching' byte has to be updated with each new byte.
  
-                  LD    A,                ; Fetch the 'parity matching' +                  ld    a,                ; Fetch the 'parity matching' 
-                  XOR                     ; byte and include the new byte. +                  xor                     ; byte and include the new byte. 
-                  LD    H,                ; Save it once again.+                  ld    h,                ; Save it once again.
 ; Passes round the loop are made until the 'counter' reaches zero.  ; Passes round the loop are made until the 'counter' reaches zero. 
 ; At that point the 'parity matching' byte should be holding zero. ; At that point the 'parity matching' byte should be holding zero.
-                  LD    A,                ; Make a further pass if the DE +                  ld    a,                ; Make a further pass if the DE 
-                  OR                      ; register pair does not hold +                  or                      ; register pair does not hold 
-                  JR    NZ,05A9,LD-LOOP     ; zero. +                  jr    nz,05A9,LD-LOOP     ; zero. 
-                  LD    A,                ; Fetch the 'parity matching'+                  ld    a,                ; Fetch the 'parity matching'
                                             ; byte.                                             ; byte.
-                  CP    +01                 ; Return with the carry flat set +                  CP    $01                 ; Return with the carry flat set 
-                  RET                       ; if the value is zero.+                  ret                       ; if the value is zero.
                                             ; (Carry flag reset if in error.)                                             ; (Carry flag reset if in error.)
  
Línea 600: Línea 599:
 ; is required and LD-EDGE-1 is used to find the time before the next 'edge'. ; is required and LD-EDGE-1 is used to find the time before the next 'edge'.
  
-05E3 LD-EDGE-2    CALL  05E7,LD-EDGE-1      ; In effect call LD-EDGE-1 twice; +05E3 LD-EDGE-2    call  05E7,LD-EDGE-1      ; In effect call LD-EDGE-1 twice; 
-                  RET   NC                  ; returning in between if there+                  ret   nc                  ; returning in between if there
                                             ; is an error.                                             ; is an error.
-05E7 LD-EDGE-1    LD    A,+16               ; Wait 358 T states before +05E7 LD-EDGE-1    ld    a,$16               ; Wait 358 T states before 
-05E9 LD-DELAY     DEC                     ; entering the sampling loop. +05E9 LD-DELAY     dec                     ; entering the sampling loop. 
-                  JR    NZ,05E9,LD-DELAY +                  jr    nz,05E9,LD-DELAY 
-                  AND   A+                  and   a
  
 ; The sampling loop is now entered. The value in the B register is ; The sampling loop is now entered. The value in the B register is
 ; incremented for each pass; 'time-up' is given when B reaches zero. ; incremented for each pass; 'time-up' is given when B reaches zero.
  
-05ED LD-SAMPLE    INC                     ; Count each pass. +05ED LD-SAMPLE    inc                     ; Count each pass. 
-                  RET                     ; Return carry reset & zero set if+                  ret                     ; Return carry reset & zero set if
                                             ; 'time-up'.                                             ; 'time-up'.
-                  LD    A,+7F               ; Read from port +7FFE. +                  ld    a,$7F               ; Read from port $7FFE. 
-                  IN    A,(+FE)             ; i.e. BREAK & EAR. +                  IN    A,($fe)             ; i.e. BREAK & EAR. 
-                  RRA                       ; Shift the byte. +                  rra                       ; Shift the byte. 
-                  RET   NC                  ; Return carry reset & zero reset+                  ret   nc                  ; Return carry reset & zero reset
                                             ; if BREAK was pressed.                                             ; if BREAK was pressed.
-                  XOR                     ; Now test the byte against the +                  xor                     ; Now test the byte against the 
-                  AND   +20                 ; 'last edge-type'; jump back +                  AND   $20                 ; 'last edge-type'; jump back 
-                  JR    Z,05ED,LD-SAMPLE    ; unless it has changed.+                  jr    z,05ED,LD-SAMPLE    ; unless it has changed.
  
 ; A new 'edge' has been found within the time period allowed for the search. ; A new 'edge' has been found within the time period allowed for the search.
 ; So change the border colour and set the carry flag. ; So change the border colour and set the carry flag.
  
-                  LD    A,                ; Change the 'last edge-type' +                  ld    a,                ; Change the 'last edge-type' 
-                  CPL                       ; and border colour. +                  cpl                       ; and border colour. 
-                  LD    C,A +                  ld    c,a 
-                  AND   +07                 ; Keep only the border colour. +                  AND   $07                 ; Keep only the border colour. 
-                  OR    +08                 ; Signal 'MIC off'+                  OR    $08                 ; Signal 'MIC off'
-                  OUT   (+FE),A             ; Change the border colour (RED/+                  OUT   ($fe),A             ; Change the border colour (RED/
                                             ; CYAN or BLUE/YELLOW).                                             ; CYAN or BLUE/YELLOW).
-                  SCF                       ; Signal the successful search +                  scf                       ; Signal the successful search 
-                  RET                       ; before returning.+                  ret                       ; before returning.
  
 ; Note: The LD-EDGE-1 subroutine takes 465 T states, plus an additional 58 T ; Note: The LD-EDGE-1 subroutine takes 465 T states, plus an additional 58 T
Línea 642: Línea 641:
 ; allowance is made for ten additional passes through the sampling loop. ; allowance is made for ten additional passes through the sampling loop.
 ; The search is thereby for the next edge to be found within, roughly, ; The search is thereby for the next edge to be found within, roughly,
-; 1,100 T states (465 10 * 58 overhead). This will prove successful+; 1,100 T states (465 10 * 58 overhead). This will prove successful
 ; for the sync 'off' pulse that comes after the long 'leader pulses'. ; for the sync 'off' pulse that comes after the long 'leader pulses'.
 </code> </code>
 +  
 + 
 \\  \\ 
 ===== Ficheros ===== ===== Ficheros =====
  • cursos/ensamblador/rutinas_save_load.1704559985.txt.gz
  • Última modificación: 06-01-2024 16:53
  • por sromero