cursos:ensamblador:teclado

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:teclado [17-01-2024 15:43] – [Ejemplo práctico: leyendo el teclado] sromerocursos:ensamblador:teclado [22-01-2024 08:01] (actual) – [Redefinicion de teclas] sromero
Línea 12: Línea 12:
  La ROM dispone de diferentes rutinas para la lectura del teclado y el tratamiento de scancodes (por ejemplo, conversión a ASCII, guardar la última tecla pulsada en una variable de sistema, etc).  La ROM dispone de diferentes rutinas para la lectura del teclado y el tratamiento de scancodes (por ejemplo, conversión a ASCII, guardar la última tecla pulsada en una variable de sistema, etc).
  
- Como veremos en la entrega dedicada a las Interrupciones del procesador, ciertas rutinas de servicio (ISR), en concreto ''RST $38'', son llamadas regularmente por el procesador en el modo de interrupciones 1. Estas rutinas son utilizadas por el intérprete de BASIC, por ejemplo, pero pueden ser utilizadas por nosotros siempre y cuando no cambiemos del modo de Interrupción 1 (por defecto) al modo de Interrupción 2 (un modo que nos permite programar nuestras propias rutinas ISR personalizadas).+ Como veremos en la entrega dedicada a las Interrupciones del procesador, ciertas rutinas de servicio (ISR), en concreto ''rst $38'', son llamadas regularmente por el procesador en el modo de interrupciones 1. Estas rutinas son utilizadas por el intérprete de BASIC, por ejemplo, pero pueden ser utilizadas por nosotros siempre y cuando no cambiemos del modo de Interrupción 1 (por defecto) al modo de Interrupción 2 (un modo que nos permite programar nuestras propias rutinas ISR personalizadas).
  
- Estando en modo 1, la ROM lee regularmente el teclado y actualiza ciertas variables del sistema como ''LAST_K'' (variable ubicada en la dirección de memoria $5C08 ó 23560), que contiene el código ASCII de la última tecla que se haya pulsado. La tecla pulsada permanece en dicha variable del sistema incluso aunque ya no esté siendo pulsada. La rutina de la ROM ya nos asegura una correcta gestión de los microrebotes del teclado y su conversión a un ASCII válido.+ Estando en modo 1, la ROM lee regularmente el teclado y actualiza ciertas variables del sistema como ''LAST_K'' (variable ubicada en la dirección de memoria $5c08 ó 23560), que contiene el código ASCII de la última tecla que se haya pulsado. La tecla pulsada permanece en dicha variable del sistema incluso aunque ya no esté siendo pulsada. La rutina de la ROM ya nos asegura una correcta gestión de los microrebotes del teclado y su conversión a un ASCII válido.
  
- Mientras estemos en modo de interrupciones IM1 (el modo en que arranca el Spectrum), podemos hacer uso de ''LAST_K'' si lo consideramos conveniente, ya que como se ha comentado, la Rutina de Interrupciones por defecto del Spectrum se ejecutará regularmente y actualizará su valor.+ Mientras estemos en modo de interrupciones im1 (el modo en que arranca el Spectrum), podemos hacer uso de ''LAST_K'' si lo consideramos conveniente, ya que como se ha comentado, la Rutina de Interrupciones por defecto del Spectrum se ejecutará regularmente y actualizará su valor.
  
- No obstante, no es lo normal utilizar las rutinas de teclado de la ROM en juegos, puesto que en la mayoría de ellos necesitaremos entrar en el modo 2 de Interrupciones, en el cual no se ejecuta RST $38 y por lo tanto no se actualizan variables como ''LAST_K''. Además, es posible que nuestro programa tenga que hacer uso de la zona de memoria en que las rutinas de la ROM guardan los datos de las teclas leídas (de 23552 a 23560), lo que no haría factible el uso de estas rutinas (ni siquiera llamando a RST $38) a menos que preservemos el contenido de esta zona de memoria y de otros registros del procesador antes de volver a a IM1, llamar a RST $38, y saltar de nuevo a IM 2. Seguramente todo este proceso es totalmente innecesario en un juego si éste ya dispone de rutinas para leer el teclado y podemos aprovecharlas.+ No obstante, no es lo normal utilizar las rutinas de teclado de la ROM en juegos, puesto que en la mayoría de ellos necesitaremos entrar en el modo 2 de Interrupciones, en el cual no se ejecuta rst $38 y por lo tanto no se actualizan variables como ''LAST_K''. Además, es posible que nuestro programa tenga que hacer uso de la zona de memoria en que las rutinas de la ROM guardan los datos de las teclas leídas (de 23552 a 23560), lo que no haría factible el uso de estas rutinas (ni siquiera llamando a rst $38) a menos que preservemos el contenido de esta zona de memoria y de otros registros del procesador antes de volver a a im1, llamar a rst $38, y saltar de nuevo a im 2. Seguramente todo este proceso es totalmente innecesario en un juego si éste ya dispone de rutinas para leer el teclado y podemos aprovecharlas.
  
  En la sección de ficheros se incluye un listado de las rutinas de la ROM desensambladas y comentadas, obtenidas del libro "//The Complete Spectrum ROM Disassembly//". Estas rutinas incluyen funciones de lectura de scancodes y decodificación de los mismos para convertirlos en ASCIIs. Podemos aprovecharlas en programas que no requieran precisión con el teclado (por ejemplo, para aplicaciones en lugar de para juegos).  En la sección de ficheros se incluye un listado de las rutinas de la ROM desensambladas y comentadas, obtenidas del libro "//The Complete Spectrum ROM Disassembly//". Estas rutinas incluyen funciones de lectura de scancodes y decodificación de los mismos para convertirlos en ASCIIs. Podemos aprovecharlas en programas que no requieran precisión con el teclado (por ejemplo, para aplicaciones en lugar de para juegos).
Línea 31: Línea 31:
 ===== El teclado a nivel hardware ===== ===== El teclado a nivel hardware =====
  
-El teclado del Spectrum es una matriz de 40 pulsadores (40 teclas) que proporcionan al microprocesador, a través de las líneas de Entrada/Salida, para diferentes filas, un valor de 8 bits en el rango 0-255, donde cada bit indica el estado de una determinada tecla. Estrictamente hablando, la encargada de la lectura del teclado (como de otros periféricos) es realmente la ULA, pero para nosotros esto es transparente y podremos utilizar las funciones estándar de IO del microprocesador Z80 para conocer el estado del teclado. Para leer el estado de cada una de las teclas del teclado (0 = pulsada, 1 = no pulsada), debemos obtener el estado del puerto $FE.+El teclado del Spectrum es una matriz de 40 pulsadores (40 teclas) que proporcionan al microprocesador, a través de las líneas de Entrada/Salida, para diferentes filas, un valor de 8 bits en el rango 0-255, donde cada bit indica el estado de una determinada tecla. Estrictamente hablando, la encargada de la lectura del teclado (como de otros periféricos) es realmente la ULA, pero para nosotros esto es transparente y podremos utilizar las funciones estándar de IO del microprocesador Z80 para conocer el estado del teclado. Para leer el estado de cada una de las teclas del teclado (0 = pulsada, 1 = no pulsada), debemos obtener el estado del puerto $fe.
  
- La pregunta en este momento debe de ser: si $FE es el puerto de lectura del teclado, y el Z80A es un microprocesador con un bus de datos de 8 bits, ¿cómo leemos el estado de 40 teclas en un registro de 8 bits?+ La pregunta en este momento debe de ser: si $fe es el puerto de lectura del teclado, y el Z80A es un microprocesador con un bus de datos de 8 bits, ¿cómo leemos el estado de 40 teclas en un registro de 8 bits?
  
  La respuesta es: organizando el teclado en filas de teclas y seleccionando qué fila leer mediante el registro B.  La respuesta es: organizando el teclado en filas de teclas y seleccionando qué fila leer mediante el registro B.
Línea 57: Línea 57:
  
 <code basic> <code basic>
-5  REM Mostrando el estado de la fila 1-5 del teclado ($F7FE)+5  REM Mostrando el estado de la fila 1-5 del teclado ($f7fe)
 10 LET puerto=63486 10 LET puerto=63486
 20 LET V=IN puerto: PRINT AT 20,0; V ; "  " : GO TO 20 20 LET V=IN puerto: PRINT AT 20,0; V ; "  " : GO TO 20
Línea 63: Línea 63:
  
  Este ejemplo lee (en un bucle infinito) una de las filas del teclado, concretamente la fila de las teclas del 1 al 5. Esta fila tiene sus  Este ejemplo lee (en un bucle infinito) una de las filas del teclado, concretamente la fila de las teclas del 1 al 5. Esta fila tiene sus
-diferentes bits de estado conectados al puerto 63486 ($F7FEh), y como podéis suponer, mediante la instrucción ''IN'' de BASIC realizamos la+diferentes bits de estado conectados al puerto 63486 ($f7feh), y como podéis suponer, mediante la instrucción ''IN'' de BASIC realizamos la
 misma función que con su equivalente ensamblador: consultar el valor contenido en dicho puerto. misma función que con su equivalente ensamblador: consultar el valor contenido en dicho puerto.
  
- El valor $FE se corresponde con el puerto del teclado, mientras que $F7 se corresponde con 11110111 en binario, donde el cero selecciona la fila concreta del teclado que queremos leer, en este caso, la fila de teclas del 1 al 5.+ El valor $fe se corresponde con el puerto del teclado, mientras que $f7 se corresponde con 11110111 en binario, donde el cero selecciona la fila concreta del teclado que queremos leer, en este caso, la fila de teclas del 1 al 5.
  
  Por defecto, sin pulsar ninguna tecla, los diferentes bits del valor leído en dicho puerto estarán a 1. Cuando pulsamos una tecla, el valor del bit correspondiente a dicha tecla aparecerá como 0, y soltándola volverá a su valor 1 original.  Por defecto, sin pulsar ninguna tecla, los diferentes bits del valor leído en dicho puerto estarán a 1. Cuando pulsamos una tecla, el valor del bit correspondiente a dicha tecla aparecerá como 0, y soltándola volverá a su valor 1 original.
Línea 74: Línea 74:
  Si no hay ninguna tecla pulsada, los 5 bits más bajos del byte que hay en el puerto estarán todos a 1, mientras que si se pulsa alguna de las teclas del 1 al 5, el bit correspondiente a dicha tecla pasará a estado 0. Nosotros podemos leer el estado del puerto y saber, mirando los unos y los ceros, si las teclas están pulsadas o no. Los 3 bits más altos del byte debemos ignorarlos para este propósito, ya que no tienen relación alguna con el teclado (son los bits de acceso al cassette, a la unidad de cinta y al altavoz del Spectrum).  Si no hay ninguna tecla pulsada, los 5 bits más bajos del byte que hay en el puerto estarán todos a 1, mientras que si se pulsa alguna de las teclas del 1 al 5, el bit correspondiente a dicha tecla pasará a estado 0. Nosotros podemos leer el estado del puerto y saber, mirando los unos y los ceros, si las teclas están pulsadas o no. Los 3 bits más altos del byte debemos ignorarlos para este propósito, ya que no tienen relación alguna con el teclado (son los bits de acceso al cassette, a la unidad de cinta y al altavoz del Spectrum).
  
- Así, por ejemplo, leyendo del puerto 63486 ($F7FE) obtenemos un byte cuyos 5 últimos bits tienen como significado el estado de cada una de las teclas de la semifila del "1" al "5".+ Así, por ejemplo, leyendo del puerto 63486 ($f7fe) obtenemos un byte cuyos 5 últimos bits tienen como significado el estado de cada una de las teclas de la semifila del "1" al "5".
  
 \\  \\ 
Línea 87: Línea 87:
 |< 50% >| |< 50% >|
 ^ Puerto ^ Teclas ^ ^ Puerto ^ Teclas ^
-| 65278d ($FEFE) | de CAPS SHIFT a V | +| 65278d ($fefe) | de CAPS SHIFT a V | 
-| 65022d ($FDFE) | de A a G | +| 65022d ($fdfe) | de A a G | 
-| 64510d ($FBFE) | de Q a T | +| 64510d ($fbfe) | de Q a T | 
-| 63486d ($F7FE) | de 1 a 5 (y JOYSTICK 1) | +| 63486d ($f7fe) | de 1 a 5 (y JOYSTICK 1) | 
-| 61438d ($EFFE) | de 6 a 0 (y JOYSTICK 2) | +| 61438d ($effe) | de 6 a 0 (y JOYSTICK 2) | 
-| 57342d ($DFFE) | de P a Y | +| 57342d ($dffe) | de P a Y | 
-| 49150d ($BFFE) | de ENTER a H | +| 49150d ($bffe) | de ENTER a H | 
-| 32766d ($7FFE) | de (space) a B |+| 32766d ($7ffe) | de (space) a B |
 \\  \\ 
  
Línea 104: Línea 104:
 |< 70% >| |< 70% >|
 ^ Puerto ^ Bits: ^ D4 ^ D3 ^ D2 ^ D1 ^ D0 ^ ^ Puerto ^ Bits: ^ D4 ^ D3 ^ D2 ^ D1 ^ D0 ^
-| 65278d ($FEFE) | Teclas: | "V" | "C" | "X" | "Z" | CAPS | +| 65278d ($fefe) | Teclas: | "V" | "C" | "X" | "Z" | CAPS | 
-| 65022d ($FDFE) | Teclas: | "G" | "F" | "D" | "S" | "A"+| 65022d ($fdfe) | Teclas: | "G" | "F" | "D" | "S" | "A"
-| 64510d ($FBFE) | Teclas: | "T" | "R" | "E" | "W" | "Q"+| 64510d ($fbfe) | Teclas: | "T" | "R" | "E" | "W" | "Q"
-| 63486d ($F7FE) | Teclas: | "5" | "4" | "3" | "2" | "1"+| 63486d ($f7fe) | Teclas: | "5" | "4" | "3" | "2" | "1"
-| 61438d ($EFFE) | Teclas: | "6" | "7" | "8" | "9" | "0"+| 61438d ($effe) | Teclas: | "6" | "7" | "8" | "9" | "0"
-| 57342d ($DFFE) | Teclas: | "Y" | "U" | "I" | "O" | "P"+| 57342d ($dffe) | Teclas: | "Y" | "U" | "I" | "O" | "P"
-| 49150d ($BFFE) | Teclas: | "H" | "J" | "K" | "L" | ENTER | +| 49150d ($bffe) | Teclas: | "H" | "J" | "K" | "L" | ENTER | 
-| 32766d ($7FFE) | Teclas: | "B" | "N" | "M" | SYMB | SPACE |+| 32766d ($7ffe) | Teclas: | "B" | "N" | "M" | SYMB | SPACE |
 ^ SINCLAIR 1 y 2\\ (las mismas teclas 0-9): ^ ^ ^ ^ ^ ^ ^ ^ SINCLAIR 1 y 2\\ (las mismas teclas 0-9): ^ ^ ^ ^ ^ ^ ^
-| 61438d ($EFFE) | SINCL1 | LEFT | RIGHT | DOWN | UP | FIRE | +| 61438d ($effe) | SINCL1 | LEFT | RIGHT | DOWN | UP | FIRE | 
-| 63486d ($F7FE) | SINCL2 | FIRE | DOWN | UP | RIGHT | LEFT |+| 63486d ($f7fe) | SINCL2 | FIRE | DOWN | UP | RIGHT | LEFT |
 \\  \\ 
  
- Como puede verse en la tabla, la parte baja de los 16 bits del puerto representan siempre $FE (254d), el puerto al que está conectado el teclado.+ Como puede verse en la tabla, la parte baja de los 16 bits del puerto representan siempre $fe (254d), el puerto al que está conectado el teclado.
  
  La parte alta es, la única que varía según la semifila a leer, y su valor consiste, como hemos visto, en la puesta a cero de la semifila deseada, teniendo en cuenta que cada semifila de teclas está conectada a uno de los bits del bus de direcciones:  La parte alta es, la única que varía según la semifila a leer, y su valor consiste, como hemos visto, en la puesta a cero de la semifila deseada, teniendo en cuenta que cada semifila de teclas está conectada a uno de los bits del bus de direcciones:
Línea 123: Línea 123:
 |< 70% >| |< 70% >|
 ^ FILA DE TECLAS ^ LINEA BUS ^ VALOR ^ VALOR BINARIO ^ ^ FILA DE TECLAS ^ LINEA BUS ^ VALOR ^ VALOR BINARIO ^
-| CAPSSHIFT a V | A8 | $FE | 1 1 1 1 1 1 1 0 | +| CAPSSHIFT a V | A8 | $fe | 1 1 1 1 1 1 1 0 | 
-| A-G | A9 | $FD | 1 1 1 1 1 1 0 1 | +| A-G | A9 | $fd | 1 1 1 1 1 1 0 1 | 
-| Q-T | A10 | $FB | 1 1 1 1 1 0 1 1 | +| Q-T | A10 | $fb | 1 1 1 1 1 0 1 1 | 
-| 1-5 | A11 | $F7 | 1 1 1 1 0 1 1 1 | +| 1-5 | A11 | $f7 | 1 1 1 1 0 1 1 1 | 
-| 6-0 | A12 | $EF | 1 1 1 0 1 1 1 1 | +| 6-0 | A12 | $ef | 1 1 1 0 1 1 1 1 | 
-| Y-P | A13 | $DF | 1 1 0 1 1 1 1 1 | +| Y-P | A13 | $df | 1 1 0 1 1 1 1 1 | 
-| H-ENTER | A14 | $BF | 1 0 1 1 1 1 1 1 | +| H-ENTER | A14 | $bf | 1 0 1 1 1 1 1 1 | 
-| B-SPACE | A15 | $7F | 0 1 1 1 1 1 1 1 |+| B-SPACE | A15 | $7f | 0 1 1 1 1 1 1 1 |
  
  Así, al mandar estos valores en la lectura de puerto (en la parte alta del mismo), lo que hacemos realmente es seleccionar cuál de las líneas del bus de direcciones (cada una de ellas conectada a una fila del teclado) queremos leer.  Así, al mandar estos valores en la lectura de puerto (en la parte alta del mismo), lo que hacemos realmente es seleccionar cuál de las líneas del bus de direcciones (cada una de ellas conectada a una fila del teclado) queremos leer.
  
- En resumen: es posible obtener el estado de una tecla determinada leyendo de un puerto de Entrada / Salida del microprocesador. Este puerto de 16 bits se compone poniendo en su parte alta el valor de la semifila de teclado a leer (todo "1"s excepto un "0" en la semifila de interés, según la tabla vista anteriormente), y poniendo en su parte baja el valor $FE. El ''IN'' de dicho puerto nos proporcionará un valor de 8 bits cuyos 5 últimos bits indicarán el estado de las 5 teclas de la semifila seleccionada (1=no pulsada, 0=pulsada).+ En resumen: es posible obtener el estado de una tecla determinada leyendo de un puerto de Entrada / Salida del microprocesador. Este puerto de 16 bits se compone poniendo en su parte alta el valor de la semifila de teclado a leer (todo "1"s excepto un "0" en la semifila de interés, según la tabla vista anteriormente), y poniendo en su parte baja el valor $fe. El ''IN'' de dicho puerto nos proporcionará un valor de 8 bits cuyos 5 últimos bits indicarán el estado de las 5 teclas de la semifila seleccionada (1=no pulsada, 0=pulsada).
  
 (Nótese que es posible leer el estado de 2 o más semifilas simultáneamente haciendo 0 a la vez el valor de los 2 bits del byte alto del puerto. El resultado obtenido será un AND del estado de los bits de todas las semifilas leídas). (Nótese que es posible leer el estado de 2 o más semifilas simultáneamente haciendo 0 a la vez el valor de los 2 bits del byte alto del puerto. El resultado obtenido será un AND del estado de los bits de todas las semifilas leídas).
Línea 148: Línea 148:
  
 bucle: bucle:
-    LD BC, $DFFE         ; Semifila "P" a "Y" +    ld bc, $dffe         ; Semifila "P" a "Y" 
-    IN A, (C)            ; Leemos el puerto +    in a, (c)            ; Leemos el puerto 
-    BIT 0,             ; Testeamos el bit 0 +    bit 0,             ; Testeamos el bit 0 
-    JR Z, salir          ; Si esta a 0 (pulsado) salir. +    jr z, salir          ; Si esta a 0 (pulsado) salir. 
-    JR bucle             ; Si no (a 1, no pulsado) repetimos+    jr bucle             ; Si no (a 1, no pulsado) repetimos
  
 salir: salir:
-    RET+    ret
  
     END 50000     END 50000
Línea 162: Línea 162:
  De nuevo ensamblamos nuestro programa con ''pasmo <nowiki>--</nowiki>tapbas keyb1.asm keyb1.tap'', y lo cargamos en el Spectrum o en un emulador.  De nuevo ensamblamos nuestro programa con ''pasmo <nowiki>--</nowiki>tapbas keyb1.asm keyb1.tap'', y lo cargamos en el Spectrum o en un emulador.
  
- Efectivamente, el programa se mantendrá en un bucle infinito hasta que se ponga a cero el bit 0 del puerto $DFFE, que se corresponde con el estado de la tecla "P". Al pulsar esa tecla, la comparación hecha con BIT hará que el Zero Flag se active y el ''JR Z'' saldrá de dicho bucle, retornando al BASIC.+ Efectivamente, el programa se mantendrá en un bucle infinito hasta que se ponga a cero el bit 0 del puerto $dffe, que se corresponde con el estado de la tecla "P". Al pulsar esa tecla, la comparación hecha con BIT hará que el Zero Flag se active y el ''JR Z'' saldrá de dicho bucle, retornando al BASIC.
  
  En ocasiones puede ser más recomendable la utilización de ''IN'' en su formato alternativo. Recordemos que tenemos 2 opcodes para IN, con 2 formas diferentes y equivalentes de especificar el puerto:  En ocasiones puede ser más recomendable la utilización de ''IN'' en su formato alternativo. Recordemos que tenemos 2 opcodes para IN, con 2 formas diferentes y equivalentes de especificar el puerto:
Línea 168: Línea 168:
 <code z80> <code z80>
 ; Forma 1 ; Forma 1
-LD BC, $FFFE +ld bc, $fffe 
-IN A, (C)       ; A = Lectura de puerto $FFFE+in a, (c)       ; A = Lectura de puerto $fffe
  
 ; Forma 2 ; Forma 2
-LD A, $FF +ld a, $ff 
-IN A, ($FE)     ; A = Lectura de puerto $FFFE+in a, ($fe)     ; A = Lectura de puerto $fffe
 </code> </code>
  
Línea 183: Línea 183:
  
 bucle: bucle:
-    LD A, $DF            ; Semifila "P" a "Y" +    ld a, $df            ; Semifila "P" a "Y" 
-    IN A, ($FE)          ; Leemos el puerto +    in a, ($fe)          ; Leemos el puerto 
-    BIT 0,             ; Testeamos el bit 0 +    bit 0,             ; Testeamos el bit 0 
-    JR Z, salir          ; Si esta a 0 (pulsado) salir. +    jr z, salir          ; Si esta a 0 (pulsado) salir. 
-    JR bucle             ; Si no (a 1, no pulsado) repetimos+    jr bucle             ; Si no (a 1, no pulsado) repetimos
  
 salir: salir:
-    RET+    ret
  
     END 50000     END 50000
Línea 209: Línea 209:
  Ambas rutinas se basan en el hecho de que, realmente, es posible leer más de una semifila del teclado simultáneamente. Como ya vimos, el valor que mandamos como byte alto del puerto tiene a valor 0 el bit que representa a la línea de datos que queremos leer.  Ambas rutinas se basan en el hecho de que, realmente, es posible leer más de una semifila del teclado simultáneamente. Como ya vimos, el valor que mandamos como byte alto del puerto tiene a valor 0 el bit que representa a la línea de datos que queremos leer.
  
- Pero como vamos a ver, podemos leer más de una línea simultáneamente, poniendo a cero tantos bits como deseemos en la parte alta del puerto. En estos ejemplos, con el ''XOR A'' (que equivale a ''LD A, 0'' dado que un ''XOR'' de un registro con sí mismo es cero) dejamos a 0 todo el byte alto con lo que leemos la información de todas las semifilas simultáneamente.+ Pero como vamos a ver, podemos leer más de una línea simultáneamente, poniendo a cero tantos bits como deseemos en la parte alta del puerto. En estos ejemplos, con el ''xor a'' (que equivale a ''ld a, 0'' dado que un ''XOR'' de un registro con sí mismo es cero) dejamos a 0 todo el byte alto con lo que leemos la información de todas las semifilas simultáneamente.
  
  Este tipo de "multilectura" no nos permite saber de forma exacta qué tecla ha sido pulsada. Por ejemplo, si intentamos leer simultaneamente las semifilas 1-5 y Q-T, el bit 0 del resultado valdrá "0" (tecla pulsada) si se pulsa "1", se pulsa "Q", o se pulsan ambas.  Este tipo de "multilectura" no nos permite saber de forma exacta qué tecla ha sido pulsada. Por ejemplo, si intentamos leer simultaneamente las semifilas 1-5 y Q-T, el bit 0 del resultado valdrá "0" (tecla pulsada) si se pulsa "1", se pulsa "Q", o se pulsan ambas.
Línea 239: Línea 239:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Wait_For_Keys_Pressed: Wait_For_Keys_Pressed:
-    XOR A                        ; A = 0 +    xor a                     ; A = 0 => leer todas las semifilas 
-    IN A, ($FE+    in a, ($fe              ; Leer del puerto del teclado 
-    OR 224 +    or %11100000              ; Poner a 1 los 3 bits más altos 
-    INC +    inc a                     ; Comprobamos el estado del teclado con: A=A+1.  
-    JR Z, Wait_For_Keys_Pressed +                              ; Si A=0 => ZF = 1 => no hay tecla pulsada 
-    RET+                              ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada 
 +    jr z, Wait_For_Keys_Pressed 
 +    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 251: Línea 253:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Wait_For_Keys_Released: Wait_For_Keys_Released:
-    XOR +    xor a                     ; = 0 => leer todas las semifilas 
-    IN A, ($FE+    in a, ($fe              ; Leer del puerto del teclado 
-    OR 224 +    or %11100000              ; Poner a 1 los 3 bits más altos 
-    INC +    inc a                     ; Comprobamos el estado del teclado con: A=A+1.  
-    JR NZ, Wait_For_Keys_Released +                              ; Si A=0 => ZF = 1 => no hay tecla pulsada 
-    RET+                              ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada 
 +    jr nz, Wait_For_Keys_Released 
 +    ret
 </code> </code>
  
Línea 264: Línea 268:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Wait_For_Keys_Pressed: Wait_For_Keys_Pressed:
-    PUSH AF+    push af
 wait_for_keypressed_loop: wait_for_keypressed_loop:
-    XOR A                        ; A = 0 +    xor a                     ; A = 0 => leer todas las semifilas 
-    IN A, ($FE+    in a, ($fe              ; Leer del puerto del teclado 
-    OR 224 +    or %11100000              ; Poner a 1 los 3 bits más altos 
-    INC +    inc a                     ; Comprobamos el estado del teclado con: A=A+1.  
-    JR Z, wait_for_keypressed_loop +                              ; Si A=0 => ZF = 1 => no hay tecla pulsada 
-    POP AF +                              ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada 
-    RET+    jr z, wait_for_keypressed_loop 
 +    pop af 
 +    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Wait_For_Keys_Released: Wait_For_Keys_Released:
-    PUSH AF+    push af
 wait_for_no_pressedkey_loop: wait_for_no_pressedkey_loop:
-    XOR +    xor a                     ; = 0 => leer todas las semifilas 
-    IN A, ($FE+    in a, ($fe              ; Leer del puerto del teclado 
-    OR 224 +    or %11100000              ; Poner a 1 los 3 bits más altos 
-    INC +    inc a                     ; Comprobamos el estado del teclado con: A=A+1.  
-    JR NZ, wait_for_no_pressedkey_loop +                              ; Si A=0 => ZF = 1 => no hay tecla pulsada 
-    POP AF +                              ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada 
-    RET +    jr nz, wait_for_no_pressedkey_loop 
 +    pop af 
 +    ret
 </code> </code>
  
Línea 300: Línea 307:
 ; Lee el estado de O, P, Q, A, ESPACIO. ; Lee el estado de O, P, Q, A, ESPACIO.
 Leer_Teclado: Leer_Teclado:
-    PUSH AF +    push af 
-    PUSH BC +    push bc 
-    PUSH HL+    push hl
  
-    LD HL, estado_tecla_arriba +    ld hl, estado_tecla_arriba 
-    LD (HL), 0                 ; marcamos estado_tecla_arriba como no pulsada+    ld (hl), 0                 ; marcamos estado_tecla_arriba como no pulsada
  
-    LD BC, $FBFE +    ld bc, $fbfe 
-    IN A, (C+    in a, (c
-    BIT 0,                   ; Leemos la tecla Q +    bit 0,                   ; Leemos la tecla Q 
-                               ; (podríamos haber usado "AND %00000001"+                               ; (podríamos haber usado "and %00000001"
-    JR NZ, Control_no_up       ; No pulsada, saltamos para no cambiar valor 0 +    jr nz, Control_no_up       ; No pulsada, saltamos para no cambiar valor 0 
-    LD (HL), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1+    ld (hl), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1
 Control_no_up: Control_no_up:
  
-    LD HL, estado_tecla_abajo +    ld hl, estado_tecla_abajo 
-    LD (HL), 0                 ; marcamos estado_tecla_abajo como no pulsada +    ld (hl), 0                 ; marcamos estado_tecla_abajo como no pulsada 
-    LD BC, $FDFE +    ld bc, $fdfe 
-    IN A, (C+    in a, (c
-    BIT 0,                   ; Leemos la tecla A +    bit 0,                   ; Leemos la tecla A 
-    JR NZ, Control_no_down     ; No pulsada, saltamos para no cambiar valor 0 +    jr nz, Control_no_down     ; No pulsada, saltamos para no cambiar valor 0 
-    LD (HL), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1+    ld (hl), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1
 Control_no_down: Control_no_down:
  
-    LD HL, estado_tecla_derecha +    ld hl, estado_tecla_derecha 
-    LD (HL), 0                 ; marcamos estado_tecla_derecha como no pulsada +    ld (hl), 0                 ; marcamos estado_tecla_derecha como no pulsada 
-    LD BC, $DFFE +    ld bc, $dffe 
-    IN A, (C+    in a, (c
-    BIT 0,                   ; Leemos la tecla P (aqui no usar AND) +    bit 0,                   ; Leemos la tecla P (aqui no usar AND) 
-    JR NZ, Control_no_right    ; No pulsada +    jr nz, Control_no_right    ; No pulsada 
-    LD (HL), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1+    ld (hl), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1
 Control_no_right: Control_no_right:
                                ; O y P en misma fila, no leer puerto otra vez                                ; O y P en misma fila, no leer puerto otra vez
-    LD HL, estado_tecla_izquierda +    ld hl, estado_tecla_izquierda 
-    LD (HL), 0 +    ld (hl), 0 
-    BIT 1,                   ; Tecla O +    bit 1,                   ; Tecla O 
-                               ; (podríamos haber usado "AND %00000010"+                               ; (podríamos haber usado "and %00000010"
-    JR NZ, Control_no_left     ; No pulsada, saltamos para no cambiar valor 0 +    jr nz, Control_no_left     ; No pulsada, saltamos para no cambiar valor 0 
-    LD (HL), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1+    ld (hl), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1
 Control_no_left: Control_no_left:
  
-    LD HL, estado_tecla_disp +    ld hl, estado_tecla_disp 
-    LD (HL), 0 +    ld (hl), 0 
-    LD BC, $7FFE +    ld bc, $7ffe 
-    IN A, (C+    in a, (c
-    BIT 0,                   ; Tecla Espacio +    bit 0,                   ; Tecla Espacio 
-    JR NZ, Control_no_fire     ; No pulsada, saltamos para no cambiar valor 0 +    jr nz, Control_no_fire     ; No pulsada, saltamos para no cambiar valor 0 
-    LD (HL), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1+    ld (hl), 1                 ; Pulsada, ponemos a 1 el bit 0 => (HL) = 1
 Control_no_fire: Control_no_fire:
  
-    POP HL +    pop hl 
-    POP BC +    pop bc 
-    POP AF +    pop af 
-    RET+    ret
  
 ; Estado de cada tecla.  0 = no pulsada, 1 = pulsada ; Estado de cada tecla.  0 = no pulsada, 1 = pulsada
Línea 386: Línea 393:
 \\  \\ 
  
- //David Webb// nos ofrece el siguiente conjunto de rutinas para este propósito. Existen bastantes posibilidades de realizar esta tarea (tablas con las semifilas y bits y sus correspondientes en ASCII, modificación en tiempo real de los opcodes que hacen los testeos, elegir entre un conjunto de combinaciones de teclas predeterminadas, etc), pero la que nos muestra David Webb es elegante y sencilla de utilizar.+ //David Webb//, en su libro //Lenguaje máquina avanzado para el ZX Spectrum//, nos ofrece el siguiente conjunto de rutinas para este propósito. Existen bastantes posibilidades de realizar esta tarea (tablas con las semifilas y bits y sus correspondientes en ASCII, modificación en tiempo real de los opcodes que hacen los testeos, elegir entre un conjunto de combinaciones de teclas predeterminadas, etc), pero la que nos muestra David Webb es elegante y sencilla de utilizar.
  
  Consiste en escanear el teclado completo y, al detectar la pulsación de una tecla, codificar la semifila y el bit donde se han detectado en un mismo byte, utilizando los 3 bits más bajos para "el bit de la tecla pulsada" y los 3 siguientes para "la semifila (puerto)" en que se ha detectado la pulsación.  Consiste en escanear el teclado completo y, al detectar la pulsación de una tecla, codificar la semifila y el bit donde se han detectado en un mismo byte, utilizando los 3 bits más bajos para "el bit de la tecla pulsada" y los 3 siguientes para "la semifila (puerto)" en que se ha detectado la pulsación.
Línea 402: Línea 409:
 ; Así, el valor devuelto nos indica la semifila a leer y el bit a testear. ; Así, el valor devuelto nos indica la semifila a leer y el bit a testear.
 ; ;
-; El registro D valdrá 255 ($FF) si no hay ninguna tecla pulsada.+; El registro D valdrá 255 ($ff) si no hay ninguna tecla pulsada.
 ; ;
 ; Flags: ZF 0: Más de una tecla pulsada ; Flags: ZF 0: Más de una tecla pulsada
Línea 408: Línea 415:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Find_Key: Find_Key:
-    LD DE, $FF2F         ; Valor inicial "ninguna tecla" +    ld de, $ff2f         ; Valor inicial "ninguna tecla" 
-    LD BC, $FEFE         ; Puerto+    ld bc, $fefe         ; Puerto
  
 NXHALF: NXHALF:
-    IN A, (C+    in a, (c
-    CPL +    cpl 
-    AND $1F +    and %00011111 
-    JR Z, NPRESS         ; Saltar si ninguna tecla pulsada+    jr z, NPRESS         ; Saltar si ninguna tecla pulsada
  
-    INC D                ; Comprobamos si hay más de 1 tecla pulsada +    inc d                ; Comprobamos si hay más de 1 tecla pulsada 
-    RET NZ               ; Si es así volver con Z a 0+    ret nz               ; Si es así volver con Z a 0
  
-    LD H             ; Cálculo del valor de la tecla +    ld h             ; Cálculo del valor de la tecla 
-    LD AE+    ld ae
  
 KLOOP: KLOOP:
-    SUB +    sub 
-    SRL H +    srl h 
-    JR NC, KLOOP+    jr nc, KLOOP
  
-    RET NZ               ; Comprobar si más de una tecla pulsada+    ret nz               ; Comprobar si más de una tecla pulsada
  
-    LD D             ; Guardar valor de tecla en D+    ld d             ; Guardar valor de tecla en D
  
 NPRESS:                  ; Comprobar el resto de semifilas NPRESS:                  ; Comprobar el resto de semifilas
-    DEC E +    dec e 
-    RLC B +    rlc b 
-    JR C, NXHALF         ; Repetimos escaneo para otra semifila+    jr c, NXHALF         ; Repetimos escaneo para otra semifila
  
-    CP A                 ; Ponemos flag a zero +    cp a                 ; Ponemos flag a zero 
-    RET Z                ; Volvemos+    ret z                ; Volvemos
 </code> </code>
  
Línea 445: Línea 452:
 <code z80> <code z80>
     ;; Pedimos tecla ARRIBA     ;; Pedimos tecla ARRIBA
-    CALL Imprimir_Texto_Pulse_Arriba +    call Imprimir_Texto_Pulse_Arriba 
-    CALL Wait_For_Keys_Released     ; Esperamos teclado libre+    call Wait_For_Keys_Released     ; Esperamos teclado libre
  
 Pedir_Arriba: Pedir_Arriba:
  
-    CALL Find_Key                   ; Llamamos a la rutina +    call Find_Key                   ; Llamamos a la rutina 
-    JR NZ, Pedir_Arriba             ; Repetir si la tecla no es válida +    jr nz, Pedir_Arriba             ; Repetir si la tecla no es válida 
-    INC D +    inc d 
-    JR Z, Pedir_Arriba              ; Repetir si no se pulsó ninguna tecla +    jr z, Pedir_Arriba              ; Repetir si no se pulsó ninguna tecla 
-    DEC D+    dec d
  
-    LD AD +    ld ad 
-    LD (tecla_arriba), A+    ld (tecla_arriba), a
  
     ;; Pedimos siguiente tecla (ABAJO)     ;; Pedimos siguiente tecla (ABAJO)
-    CALL Imprimir_Texto_Pulse_Abajo +    call Imprimir_Texto_Pulse_Abajo 
-    CALL Wait_For_Keys_Released     ; Esperamos teclado libre+    call Wait_For_Keys_Released     ; Esperamos teclado libre
  
 Pedir_Abajo: Pedir_Abajo:
  
-    CALL Find_Key                   ; Llamamos a la rutina +    call Find_Key                   ; Llamamos a la rutina 
-    JR NZ, Pedir_Abajo              ; Repetir si la tecla no es válida +    jr nz, Pedir_Abajo              ; Repetir si la tecla no es válida 
-    INC D +    inc d 
-    JR Z, Pedir_Abajo               ; Repetir si no se pulsó ninguna tecla +    jr z, Pedir_Abajo               ; Repetir si no se pulsó ninguna tecla 
-    DEC D+    dec d
  
-    LD AD +    ld ad 
-    LD (tecla_abajo), A+    ld (tecla_abajo), a
  
     ;;; Repetir el mismo código para IZQ, DERECHA, DISPARO, etc.     ;;; Repetir el mismo código para IZQ, DERECHA, DISPARO, etc.
Línea 485: Línea 492:
 ; Visualizando los scancodes de las teclas codificadas con "Find_Key" ; Visualizando los scancodes de las teclas codificadas con "Find_Key"
  
-   ORG 50000+    ORG 50000
  
 Bucle_entrada: Bucle_entrada:
-   CALL Wait_For_Key+    call Wait_For_Key
  
  
 Pedir_Tecla: Pedir_Tecla:
-   CALL Find_Key                   ; Llamamos a la rutina+    call Find_Key                   ; Llamamos a la rutina
  
-   JR NZ, Pedir_Tecla              ; Repetir si la tecla no es valida +    jr nz, Pedir_Tecla              ; Repetir si la tecla no es valida 
-   INC D +    inc d 
-   JR Z, Pedir_Tecla               ; Repetir si no se pulsa ninguna tecla +    jr z, Pedir_Tecla               ; Repetir si no se pulsa ninguna tecla 
-   DEC D+    dec d
  
-   LD A                        ; Guardamos en A copia del resultado+    ld a                        ; Guardamos en A copia del resultado
  
-   CP $21                          ; Comprobamos si A == 21h (enter) +    cp $21                          ; Comprobamos si A == 21h (enter) 
-   RET Z                           ; Si no lo es, repetir+    ret z                           ; Si no lo es, repetir
  
-   CALL PrintHex                   ; Imprimimos el scancode hex en pantalla+    call PrintHex                   ; Imprimimos el scancode hex en pantalla
  
-   CALL PrintSpace                 ; Espacio para separar+    call PrintSpace                 ; Espacio para separar
  
-   CALL Wait_For_No_Key            ; Esperamos a que el usuario SUELTE la tecla +    call Wait_For_No_Key            ; Esperamos a que el usuario SUELTE la tecla 
-   JR Pedir_Tecla                  ; Repetir hasta que arriba un ENTER +    jr Pedir_Tecla                  ; Repetir hasta que arriba un ENTER 
-                                   ; ($21 pulsado) haga el RET Z a BASIC+                                   ; ($21 pulsado) haga el ret z a BASIC
  
     INCLUDE "utils.asm"     INCLUDE "utils.asm"
Línea 526: Línea 533:
  Los scancodes asociados a las diferentes teclas son:  Los scancodes asociados a las diferentes teclas son:
  
 +\\ 
 |< 80% >| |< 80% >|
 ^ Teclas: ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 0 ^ ^ Teclas: ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 0 ^
-^ Scancodes: | $24 | $1C | $14 | $0C | $04 | $03 | $0B | $13 | $1B | $23 |+^ Scancodes: | $24 | $1c | $14 | $0c | $04 | $03 | $0b | $13 | $1b | $23 |
  
 |< 80% >| |< 80% >|
 ^ Teclas: ^ Q ^ W ^ E ^ R ^ T ^ Y ^ U ^ I ^ O ^ P ^ ^ Teclas: ^ Q ^ W ^ E ^ R ^ T ^ Y ^ U ^ I ^ O ^ P ^
-^ Scancodes: | $25 | $1D | $15 | $0D | $05 | $02 | $0A | $12 | $1A | $22 |+^ Scancodes: | $25 | $1d | $15 | $0d | $05 | $02 | $0a | $12 | $1a | $22 |
  
 |< 80% >| |< 80% >|
 ^ Teclas: ^ A ^ S ^ D ^ F ^ G ^ H ^ J ^ K ^ L ^ ENTER ^ ^ Teclas: ^ A ^ S ^ D ^ F ^ G ^ H ^ J ^ K ^ L ^ ENTER ^
-^ Scancodes: | $26 | $1E | $16 | $0E | $06 | $01 | $09 | $11 | $19 | $21 |+^ Scancodes: | $26 | $1e | $16 | $0e | $06 | $01 | $09 | $11 | $19 | $21 |
  
 |< 80% >| |< 80% >|
 ^ Teclas: ^ CAPS ^ Z ^ X ^ C ^ V ^ B ^ N ^ M ^ SYMB ^ SPACE ^ ^ Teclas: ^ CAPS ^ Z ^ X ^ C ^ V ^ B ^ N ^ M ^ SYMB ^ SPACE ^
-^ Scancodes: | $27 | $1F | $17 | $0F | $07 | $00 | $08 | $10 | $18 | $20 |+^ Scancodes: | $27 | $1f | $17 | $0f | $07 | $00 | $08 | $10 | $18 | $20 | 
 +\\  
 + 
 + O, en forma visual sobre un teclado de 48K, extraído del libro //Mastering Machine Code on your ZX Spectrum// (los valores numéricos están en formato hexadecimal pese a no llevar prefijo ni sufijo): 
 + 
 +\\  
 +{{ :cursos:ensamblador:scancodes_gomas.jpg }} 
 +\\ 
  
  Estos valores nos serán necesarios si queremos establecer unos scancodes por defecto para las teclas del programa, de forma que si el usuario no las redefine, tengan unos valores de comprobación determinados para la rutina de chequeo que veremos a continuación.  Estos valores nos serán necesarios si queremos establecer unos scancodes por defecto para las teclas del programa, de forma que si el usuario no las redefine, tengan unos valores de comprobación determinados para la rutina de chequeo que veremos a continuación.
Línea 558: Línea 573:
 tecla_arriba   DEFB  $25 tecla_arriba   DEFB  $25
 tecla_abajo    DEFB  $26 tecla_abajo    DEFB  $26
-tecla_izq      DEFB  $1A+tecla_izq      DEFB  $1a
 tecla_der      DEFB  $22 tecla_der      DEFB  $22
 tecla_disp     DEFB  $20 tecla_disp     DEFB  $20
Línea 587: Línea 602:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Scancode2Ascii: Scancode2Ascii:
-    PUSH HL +    push hl 
-    PUSH BC+    push bc
  
-    LD HL, 0 +    ld hl, 0 
-    LD BC, TABLA_Scancode2ASCII +    ld bc, TABLA_Scancode2ASCII 
-    ADD HLBC                    ; HL apunta al inicio de la tabla+    add hlbc                    ; HL apunta al inicio de la tabla
  
     ; buscamos en la tabla un max de 40 veces por el codigo     ; buscamos en la tabla un max de 40 veces por el codigo
     ; le sumamos 40 a HL, leemos el valor de (HL) y ret A     ; le sumamos 40 a HL, leemos el valor de (HL) y ret A
 SC2Ascii_1: SC2Ascii_1:
-    LD A, (HL)                   ; leemos un byte de la tabla +    ld a, (hl)                   ; leemos un byte de la tabla 
-    CP "1                      ; Si es "1fin de la rutina (porque en +    cp '1                      ; Si es '1' (caracter) fin de la rutina (porque 
-                                 ; (la tabla habriamos llegado a los ASCIIs) +                                 ; en la tabla habriamos llegado a los ASCIIs) 
-    JR Z, SC2Ascii_Exit          ; (y es condicion de forzado de salida) +    jr z, SC2Ascii_Exit          ; (y es condicion de forzado de salida) 
-    INC HL                       ; incrementamos puntero de HL +    inc hl                       ; incrementamos puntero de HL 
-    CP D                         ; comparamos si A==D (nuestro scancode) +    cp d                         ; comparamos si A==D (nuestro scancode) 
-    JR NZ, SC2Ascii_1+    jr nz, SC2Ascii_1
  
 SC2Ascii_Found: SC2Ascii_Found:
-    LD BC, 39                    ; Sumamos 39(+INC HL=40) para ir a la +    ld bc, 39                    ; Sumamos 39(+inc hl=40) para ir a la 
-    ADD HLBC                   ; seccion de la tabla con el codigo ASCII +    add hlbc                   ; seccion de la tabla con el codigo ASCII 
-    LD A, (HL)                   ; leemos el codigo ASCII de esa tabla+    ld a, (hl)                   ; leemos el codigo ASCII de esa tabla
  
 SC2Ascii_Exit: SC2Ascii_Exit:
-    POP BC +    pop bc 
-    POP HL +    pop hl 
-    RET+    ret
  
     ; 40 scancodes seguidos de sus ASCIIs equivalentes     ; 40 scancodes seguidos de sus ASCIIs equivalentes
 TABLA_Scancode2ASCII: TABLA_Scancode2ASCII:
-    DEFB $24, $1C, $14, $0C, $04, $03, $0B, $13, $1B, $23 +    DEFB $24, $1c, $14, $0c, $04, $03, $0b, $13, $1b, $23 
-    DEFB $25, $1D, $15, $0D, $05, $02, $0A, $12, $1A, $22 +    DEFB $25, $1d, $15, $0d, $05, $02, $0a, $12, $1a, $22 
-    DEFB $26, $1E, $16, $0E, $06, $01, $09, $11, $19, $21 +    DEFB $26, $1e, $16, $0e, $06, $01, $09, $11, $19, $21 
-    DEFB $27, $1F, $17, $0F, $07, $00, $08, $10, $18, $20+    DEFB $27, $1f, $17, $0f, $07, $00, $08, $10, $18, $20
     DEFB "1234567890QWERTYUIOPASDFGHJKLecZXCVBNMys"     DEFB "1234567890QWERTYUIOPASDFGHJKLecZXCVBNMys"
 </code> </code>
Línea 645: Línea 660:
     ORG 50000     ORG 50000
  
-    CALL CLS+    call CLS
  
 START: START:
  
-    CALL Wait_For_No_Key+    call Wait_For_No_Key
  
 chequear_teclas: chequear_teclas:
-    CALL Find_Key                   ; Llamamos a la rutina +    call Find_Key                   ; Llamamos a la rutina 
-    JR NZ, chequear_teclas          ; Repetir si la tecla no es válida +    jr nz, chequear_teclas          ; Repetir si la tecla no es válida 
-    INC D +    inc d 
-    JR Z, chequear_teclas           ; Repetir si no se pulsó ninguna tecla +    jr z, chequear_teclas           ; Repetir si no se pulsó ninguna tecla 
-    DEC D+    dec d
  
     ; En este punto D es un scancode valido     ; En este punto D es un scancode valido
-    CALL Scancode2Ascii+    call Scancode2Ascii
  
     ; En este punto A contiene el ASCII del scancode en D     ; En este punto A contiene el ASCII del scancode en D
     ; lo imprimimos por pantalla con rst 16.     ; lo imprimimos por pantalla con rst 16.
-    RST 16+    rst 16
  
-    JR START                        ; vuelta a empezar+    jr START                        ; vuelta a empezar
  
     INCLUDE "utils.asm"     INCLUDE "utils.asm"
Línea 699: Línea 714:
     ORG 33500     ORG 33500
  
-    CALL CLS +    call CLS 
-    CALL Redefinir_Teclas+    call Redefinir_Teclas
  
 bucle: bucle:
-    JR bucle+    jr bucle
  
 ; Mensajes del programa ; Mensajes del programa
Línea 713: Línea 728:
  
 ; Teclas por defecto si no se redefine: O P Q A SPACE ; Teclas por defecto si no se redefine: O P Q A SPACE
-tecla_izq      DEFB  $1A+tecla_izq      DEFB  $1a
 tecla_der      DEFB  $22 tecla_der      DEFB  $22
 tecla_arriba   DEFB  $25 tecla_arriba   DEFB  $25
Línea 730: Línea 745:
 Redefinir_Teclas: Redefinir_Teclas:
     ; Los siguientes textos se podrian haber impreso tambien usando un bucle     ; Los siguientes textos se podrian haber impreso tambien usando un bucle
-    ; con INC DE (avanzar cadena) e INC HL (avanzar tecla a escribir) +    ; con inc de (avanzar cadena) e inc hl (avanzar tecla a escribir) 
-    LD DE, msg_izq +    ld de, msg_izq 
-    CALL PrintString              ; Imprimir mensaje "Izquierda?" +    call PrintString              ; Imprimir mensaje "Izquierda?" 
-    CALL Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) +    call Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) 
-    LD HL, tecla_izq              ; Apuntamos HL a la variable tecla_izq +    ld hl, tecla_izq              ; Apuntamos HL a la variable tecla_izq 
-    LD (HL), A+    ld (hl), a
  
-    LD DE, msg_der                ; Siguiente mensaje: "Derecha?" +    ld de, msg_der                ; Siguiente mensaje: "Derecha?" 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) +    call Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) 
-    LD HL, tecla_der +    ld hl, tecla_der 
-    LD (HL),                    ; Guardamos tecla pulsada+    ld (hl),                    ; Guardamos tecla pulsada
  
-    LD DE, msg_arriba             ; Repetimos con ARRIBA +    ld de, msg_arriba             ; Repetimos con ARRIBA 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key +    call Redefine_Key 
-    LD HL, tecla_arriba +    ld hl, tecla_arriba 
-    LD (HL), A+    ld (hl), a
  
-    LD DE, msg_abajo              ; Repetimos con ABAJO +    ld de, msg_abajo              ; Repetimos con ABAJO 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key +    call Redefine_Key 
-    LD HL, tecla_abajo +    ld hl, tecla_abajo 
-    LD (HL), A+    ld (hl), a
  
-    LD DE, msg_disp               ; Repetimos con DISPARO +    ld de, msg_disp               ; Repetimos con DISPARO 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key +    call Redefine_Key 
-    LD HL, tecla_disp +    ld hl, tecla_disp 
-    LD (HL), A +    ld (hl), a 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 772: Línea 787:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Redefine_Key: Redefine_Key:
-    PUSH DE +    push de 
-    PUSH HL +    push hl 
-    CALL Wait_For_No_Key+    call Wait_For_No_Key
  
 wait_for_scan_loop: wait_for_scan_loop:
-    CALL Find_Key +    call Find_Key 
-    JR NZ, wait_for_scan_loop          ; Mas de una tecla leida, repetir +    jr nz, wait_for_scan_loop          ; Mas de una tecla leida, repetir 
-    LD AD +    ld ad 
-    CP $FF                             ; si A es $FF => ninguna tecla pulsada +    cp $ff                             ; si A es $ff => ninguna tecla pulsada 
-    JR Z, wait_for_scan_loop           ; Repetimos hasta que A != $FF +    jr z, wait_for_scan_loop           ; Repetimos hasta que A != $ff 
-    LD H                           ; Nos hacemos copia de D en H +    ld h                           ; Nos hacemos copia de D en H 
-    CALL Scancode2Ascii                ; Convertir D (scancode) en A (ASCII)+    call Scancode2Ascii                ; Convertir D (scancode) en A (ASCII)
  
-    CP 'e'                             ; ¿Es 'e'? Imprimir "ENTER" +    cp 'e'                             ; ¿Es 'e'? Imprimir "ENTER" 
-    JR NZ, redef_key_NO_ENTER +    jr nz, redef_key_NO_ENTER 
-    LD DE, redef_key_enter +    ld de, redef_key_enter 
-    CALL PrintString +    call PrintString 
-    JR redef_key_end                   ; Impreso texto, salimos+    jr redef_key_end                   ; Impreso texto, salimos
 redef_key_NO_ENTER: redef_key_NO_ENTER:
  
-    CP 's'                             ; ¿Es 's'? Imprimir "SPACE" +    cp 's'                             ; ¿Es 's'? Imprimir "SPACE" 
-    JR NZ, redef_key_NO_SPACE +    jr nz, redef_key_NO_SPACE 
-    LD DE, redef_key_space +    ld de, redef_key_space 
-    CALL PrintString +    call PrintString 
-    JR redef_key_end+    jr redef_key_end
 redef_key_NO_SPACE: redef_key_NO_SPACE:
  
-    CP 'c'                             ; ¿Es 'c'? Imprimir "CS" +    cp 'c'                             ; ¿Es 'c'? Imprimir "CS" 
-    JR NZ, redef_key_NO_CAPSSHIFT +    jr nz, redef_key_NO_CAPSSHIFT 
-    LD DE, redef_key_cs +    ld de, redef_key_cs 
-    CALL PrintString +    call PrintString 
-    JR redef_key_end+    jr redef_key_end
 redef_key_NO_CAPSSHIFT: redef_key_NO_CAPSSHIFT:
  
-    CP 'y'                             ; ¿Es 'y'? Imprimir "SS" +    cp 'y'                             ; ¿Es 'y'? Imprimir "SS" 
-    JR NZ, redef_key_NO_SYMBOLSHIFT +    jr nz, redef_key_NO_SYMBOLSHIFT 
-    LD DE, redef_key_ss +    ld de, redef_key_ss 
-    CALL PrintString +    call PrintString 
-    JR redef_key_end+    jr redef_key_end
 redef_key_NO_SYMBOLSHIFT: redef_key_NO_SYMBOLSHIFT:
                                        ; Si llegamos aqui no era tecla especial.                                        ; Si llegamos aqui no era tecla especial.
-    RST 16                             ; Ninguna tecla especial => Print ASCII +    rst 16                             ; Ninguna tecla especial => Print ASCII 
-    LD AD+    ld ad
  
 redef_key_end: redef_key_end:
-    LD A                           ; Recuperamos scancode +    ld a                           ; Recuperamos scancode 
-    CALL PrintCR                       ; Imprimir retorno de carro+    call PrintCR                       ; Imprimir retorno de carro
  
-    POP HL +    pop hl 
-    POP DE +    pop de 
-    RET                                ; Volver con registros preservados+    ret                                ; Volver con registros preservados
  
 redef_key_enter DB "ENTER", _EOS redef_key_enter DB "ENTER", _EOS
Línea 850: Línea 865:
 \\  \\ 
  
 +
 +\\ 
 +==== UDGs para las teclas especiales ====
 +
 +Si en lugar de imprimir las cadenas "ENTER", "SPACE", "SS" y "CS" (como se hace en el ejemplo anterior) queremos imprimir unos caracteres con símbolos compactos para las teclas, podemos utilizar UDGs para la tabla de Scancode2Ascii.
 +
 +Nuestro compañero //Juan Antonio Rubio// nos proporciona los siguientes UDGs que podemos "pokear" en la dirección adecuada para utilizarlos con los código de carácter que deseemos:
 +
 +<code z80>
 +    DB $10,$28,$44,$C6,$28,$28,$38,$00 ; Caps Shift
 +    DB $60,$80,$46,$28,$C4,$02,$0C,$00 ; Symbol Shift
 +    DB $05,$05,$25,$5D,$81,$5E,$20,$00 ; Enter
 +    DB $00,$00,$00,$00,$82,$82,$FE,$00 ; Espacio
 +</code>
 +
 +Los cuales tienen el siguiente aspecto:
 +
 +\\ 
 +{{ :cursos:ensamblador:udgs_teclas.png?106 }}
 +\\ 
  
 \\  \\ 
Línea 857: Línea 892:
  
 <code z80> <code z80>
-tecla_izq     DEFB  $1A       ; O+tecla_izq     DEFB  $1a       ; O
 tecla_der     DEFB  $22       ; P tecla_der     DEFB  $22       ; P
 tecla_arriba  DEFB  $25       ; Q tecla_arriba  DEFB  $25       ; Q
Línea 880: Línea 915:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Check_Key: Check_Key:
-    PUSH BC +    push bc 
-    LD C            ; Copia de A+    ld c            ; Copia de A
  
                         ; Operaciones para extraer la semifila                         ; Operaciones para extraer la semifila
                         ; y la tecla de A (00SSSTTT), para leer                         ; y la tecla de A (00SSSTTT), para leer
                         ; el puerto y chequear el bit adecuados                         ; el puerto y chequear el bit adecuados
-    AND 7 +    and %00000111       ; Nos quedamos con la tecla (bit) 
-    INC A +    inc a 
-    LD B            ; B = 16 - (num. linea direccion) +    ld b            ; B = 16 - (num. linea direccion) 
-    SRL C +    srl c 
-    SRL C +    srl c 
-    SRL C +    srl c 
-    LD A, 5 +    ld a, 5 
-    SUB C +    sub c 
-    LD C            ; C = (semifila + 1)+    ld c            ; C = (semifila + 1)
  
-    LD A, $FE+    ld a, $fe
  
 CKHiFind:               ; Calcular el octeto de mayor peso del puerto CKHiFind:               ; Calcular el octeto de mayor peso del puerto
-    RRCA +    rrca 
-    DJNZ CKHiFind +    djnz CKHiFind 
-    IN A, ($FE)         ; Leemos la semifila+    in a, ($fe)         ; Leemos la semifila
  
 CKNXKey: CKNXKey:
-    RRA +    rra 
-    DEC C +    dec c 
-    JR NZ, CKNXKey      ; Ponemos el bit de tecla en el CF +    jr nz, CKNXKey      ; Ponemos el bit de tecla en el CF 
-    POP BC+    pop bc
  
-    RET+    ret
 </code> </code>
  
Línea 916: Línea 951:
 <code z80> <code z80>
 Comprobar_tecla_izquierda: Comprobar_tecla_izquierda:
-    LD A, (teclaizq) +    ld a, (teclaizq) 
-    CALL Check_Key +    call Check_Key 
-    JR C, izq_no_pulsada            ; Carry = 1, tecla no pulsada+    jr c, izq_no_pulsada            ; Carry = 1, tecla no pulsada
  
     (acciones a realizar si se pulso izq)     (acciones a realizar si se pulso izq)
Línea 925: Línea 960:
  
 Comprobar_tecla_derecha: Comprobar_tecla_derecha:
-    LD A, (teclader) +    ld a, (teclader) 
-    CALL Check_Key +    call Check_Key 
-    JR C, der_no_pulsada            ; Carry = 1, tecla no pulsada+    jr c, der_no_pulsada            ; Carry = 1, tecla no pulsada
  
     (acciones a realizar si se pulso der)     (acciones a realizar si se pulso der)
Línea 940: Línea 975:
     ORG 50000     ORG 50000
  
-    CALL CLS+    call CLS
 Imprimir_Valor: Imprimir_Valor:
-    LD A, (valor)                   ; Guardamos en A copia del resultado +    ld a, (valor)                   ; Guardamos en A copia del resultado 
-    LD B, 0 +    ld b, 0 
-    LD C                        ; BC = A (B=0, C=A) +    ld c                        ; BC = A (B=0, C=A) 
-    CALL PrintNum                   ; Imprimimos el valor en pantalla +    call PrintNum                   ; Imprimimos el valor en pantalla 
-    CALL PrintSpace+    call PrintSpace
  
-    CALL Wait_For_No_Key            ; Esperamos a que se suelte la tecla+    call Wait_For_No_Key            ; Esperamos a que se suelte la tecla
  
 Bucle: Bucle:
  
 Comprobar_tecla_mas: Comprobar_tecla_mas:
-    LD A, (tecla_mas) +    ld a, (tecla_mas) 
-    CALL Check_Key+    call Check_Key
  
-    JR C, Comprobar_tecla_menos     ; Carry = 1, tecla_mas no pulsada+    jr c, Comprobar_tecla_menos     ; Carry = 1, tecla_mas no pulsada
  
-    LD HL, valor +    ld hl, valor 
-    INC (HL+    inc (hl
-    JR Imprimir_Valor+    jr Imprimir_Valor
  
 Comprobar_tecla_menos: Comprobar_tecla_menos:
-    LD A, (tecla_menos) +    ld a, (tecla_menos) 
-    CALL Check_Key +    call Check_Key 
-    JR C, Bucle                     ; Carry = 1, tecla_menos no pulsada+    jr c, Bucle                     ; Carry = 1, tecla_menos no pulsada
  
-    LD HL, valor +    ld hl, valor 
-    DEC (HL)+    dec (hl)
  
-    JP Imprimir_Valor+    jp Imprimir_Valor
  
 ; Variables de teclas ; Variables de teclas
Línea 1008: Línea 1043:
  
 <code z80> <code z80>
-    CALL Leer_Teclado_Empaquetado +    call Leer_Teclado_Empaquetado 
-    LD (estado_teclas), a+    ld (estado_teclas), a
  
     ; (...)     ; (...)
  
     ; Mas adelante en el programa     ; Mas adelante en el programa
-    LD A, (estado_teclas)+    ld a, (estado_teclas)
  
-    BIT 4, A +    bit 4, a 
-    CALL NZ, Disparo_Pulsado+    call nz, Disparo_Pulsado
  
-    BIT 1, A +    bit 1, a 
-    CALL NZ, Salto_Pulsado+    call nz, Salto_Pulsado
  
     ; etc...     ; etc...
Línea 1045: Línea 1080:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Leer_Teclado_Empaquetado: Leer_Teclado_Empaquetado:
-    PUSH DE +    push de 
-    LD D, 0                       ; D = 0+    ld d, 0                       ; D = 0
  
-    LD HL, tecla_izq              ; Apuntamos HL a la primera de las teclas (izq)+    ld hl, tecla_izq              ; Apuntamos HL a la primera de las teclas (izq)
  
-    LD A, (HL)                    ; leemos su valor +    ld a, (hl)                    ; leemos su valor 
-    CALL Check_Key +    call Check_Key 
-    JR C, tecl_izq_notpressed +    jr c, tecl_izq_notpressed 
-    SET 3,                      ; Si pulsada, ponemos bit 3 a 1. +    set 3,                      ; Si pulsada, ponemos bit 3 a 1. 
-                                  ; Usando A podríamos usar "OR %00001000"+                                  ; Usando A podríamos usar "or %00001000"
 tecl_izq_notpressed: tecl_izq_notpressed:
-    INC HL                        ; INC HL a siguiente tecla en memoria (der) +    inc hl                        ; inc hl a siguiente tecla en memoria (der) 
-    LD A, (HL)                    ; leemos su valor +    ld a, (hl)                    ; leemos su valor 
-    CALL Check_Key +    call Check_Key 
-    JR C, tecl_der_notpressed +    jr c, tecl_der_notpressed 
-    SET 2,                      ; Si pulsada, ponemos bit 2 a 1.+    set 2,                      ; Si pulsada, ponemos bit 2 a 1.
  
 tecl_der_notpressed: tecl_der_notpressed:
-    INC HL                        ; apuntamos HL a siguiente tecla (arriba) +    inc hl                        ; apuntamos HL a siguiente tecla (arriba) 
-    LD A, (HL)                    ; leemos su valor +    ld a, (hl)                    ; leemos su valor 
-    CALL Check_Key +    call Check_Key 
-    JR C, tecl_arr_notpressed +    jr c, tecl_arr_notpressed 
-    SET 1,                      ; Si pulsada, ponemos bit 1 a 1.+    set 1,                      ; Si pulsada, ponemos bit 1 a 1.
  
 tecl_arr_notpressed: tecl_arr_notpressed:
-    INC HL                        ; apuntamos HL a siguiente tecla (abajo) +    inc hl                        ; apuntamos HL a siguiente tecla (abajo) 
-    LD A, (HL)                    ; leemos su valor +    ld a, (hl)                    ; leemos su valor 
-    CALL Check_Key +    call Check_Key 
-    JR C, tecl_aba_notpressed +    jr c, tecl_aba_notpressed 
-    SET 0,                      ; Si pulsada, ponemos bit 0 a 1.+    set 0,                      ; Si pulsada, ponemos bit 0 a 1.
  
 tecl_aba_notpressed: tecl_aba_notpressed:
-    INC HL                        ; apuntamos HL a siguiente tecla (disparo) +    inc hl                        ; apuntamos HL a siguiente tecla (disparo) 
-    LD A, (HL)                    ; leemos su valorprimera +    ld a, (hl)                    ; leemos su valorprimera 
-    CALL Check_Key +    call Check_Key 
-    JR C, tecl_fire_notpressed +    jr c, tecl_fire_notpressed 
-    SET 4,                      ; Si pulsada, ponemos bit 4 a 1.+    set 4,                      ; Si pulsada, ponemos bit 4 a 1.
  
 tecl_fire_notpressed: tecl_fire_notpressed:
                                   ; Podriamos añadir codigo para disparo 2                                   ; Podriamos añadir codigo para disparo 2
-    LD AD +    ld ad 
-    POP DE +    pop de 
-    RET                           ; Devolvemos en A el estado de las teclas+    ret                           ; Devolvemos en A el estado de las teclas
 </code> </code>
  
  La rutina simplemente apunta HL a la primera de las teclas y llama a ''Check_Key'' para leer su estado. Si está a 1, establece a 1 el bit 3 del registro D. Si está a 0, salta a comprobar la siguiente tecla.  La rutina simplemente apunta HL a la primera de las teclas y llama a ''Check_Key'' para leer su estado. Si está a 1, establece a 1 el bit 3 del registro D. Si está a 0, salta a comprobar la siguiente tecla.
  
- Utilizamos ''INC HL'' para saltar a la siguiente tecla porque las variables ''tecla_*'' están seguidas en memoria, por lo que podemos saltar de una a otra con INC o DEC.+ Utilizamos ''inc hl'' para saltar a la siguiente tecla porque las variables ''tecla_*'' están seguidas en memoria, por lo que podemos saltar de una a otra con INC o DEC.
  
  Repetimos el proceso con las 5 teclas (podríamos añadir más chequeos para teclas adicionales después de comprobar el disparo) y antes de salir copiamos el valor de D en A para devolver el resultado en el acumulador.  Repetimos el proceso con las 5 teclas (podríamos añadir más chequeos para teclas adicionales después de comprobar el disparo) y antes de salir copiamos el valor de D en A para devolver el resultado en el acumulador.
Línea 1102: Línea 1137:
     ORG 33500     ORG 33500
  
-    CALL CLS +    call CLS 
-    CALL Redefinir_Teclas +    call Redefinir_Teclas 
-    CALL CLS +    call CLS 
-    CALL Wait_For_No_Key          ; Esperar a que no haya teclas pulsadas+    call Wait_For_No_Key          ; Esperar a que no haya teclas pulsadas
  
     ; Bucle del programa, lee nuestras teclas e imprime primero la     ; Bucle del programa, lee nuestras teclas e imprime primero la
     ; "leyenda" de las teclas y luego el byte de estado de teclado:     ; "leyenda" de las teclas y luego el byte de estado de teclado:
 bucle: bucle:
-    LD DE, 0 +    ld de, 0 
-    CALL CursorAt                 ; Nos vamos a (0,0) +    call CursorAt                 ; Nos vamos a (0,0) 
-    LD DE, msg_keys +    ld de, msg_keys 
-    CALL PrintString              ; Imprimimos mensaje "*<>^v"+    call PrintString              ; Imprimimos mensaje "*<>^v"
  
-    CALL Leer_Teclado_Empaquetado +    call Leer_Teclado_Empaquetado 
-    CALL PrintBin                 ; Imprimimos estado teclas (A) en binario+    call PrintBin                 ; Imprimimos estado teclas (A) en binario
  
-    JR bucle                      ; Repetir hasta reset+    jr bucle                      ; Repetir hasta reset
  
 ; Mensajes del programa ; Mensajes del programa
Línea 1129: Línea 1164:
  
 ; Teclas por defecto si no se redefine: O P Q A SPACE ; Teclas por defecto si no se redefine: O P Q A SPACE
-tecla_izq      DEFB  $1A+tecla_izq      DEFB  $1a
 tecla_der      DEFB  $22 tecla_der      DEFB  $22
 tecla_arriba   DEFB  $25 tecla_arriba   DEFB  $25
Línea 1195: Línea 1230:
     ORG 33500     ORG 33500
  
-    CALL CLS +    call CLS 
-    CALL Redefinir_Teclas_SSSTTT  ; Redefinir teclado +    call Redefinir_Teclas_SSSTTT  ; Redefinir teclado 
-    CALL Wait_For_No_Key          ; Esperar a que no haya teclas pulsadas +    call Wait_For_No_Key          ; Esperar a que no haya teclas pulsadas 
-    CALL CLS+    call CLS
  
     ; Bucle del programa, lee nuestras teclas e imprime primero la     ; Bucle del programa, lee nuestras teclas e imprime primero la
     ; "leyenda" de las teclas y luego el byte de estado de teclado:     ; "leyenda" de las teclas y luego el byte de estado de teclado:
 bucle: bucle:
-    LD DE, 0 +    ld de, 0 
-    CALL CursorAt                 ; Nos vamos a (0,0) +    call CursorAt                 ; Nos vamos a (0,0) 
-    LD DE, msg_keys +    ld de, msg_keys 
-    CALL PrintString              ; Imprimimos mensaje "*<>^v"+    call PrintString              ; Imprimimos mensaje "*<>^v"
  
-    CALL Leer_Teclado_SSSTTT +    call Leer_Teclado_SSSTTT 
-    CALL PrintBin                 ; Imprimimos estado teclas (A) en binario+    call PrintBin                 ; Imprimimos estado teclas (A) en binario
  
-    JR bucle                      ; Repetir hasta reset+    jr bucle                      ; Repetir hasta reset
  
 ; Mensajes del programa ; Mensajes del programa
Línea 1225: Línea 1260:
 ; que aparezcan en los bits del byte de estado ; que aparezcan en los bits del byte de estado
 teclas_player_1: teclas_player_1:
-p1_puerto_disp       DEFB  $7F      ; Semifila ' ' = puerto $FEFE+p1_puerto_disp       DEFB  $7f      ; Semifila ' ' = puerto $fefe
 p1_tecla_disp        DEFB  $01      ; Tecla ' ' = bit 1 p1_tecla_disp        DEFB  $01      ; Tecla ' ' = bit 1
-p1_puerto_izq        DEFB  $DF      ; Semifila 'O' = puerto $DFFE+p1_puerto_izq        DEFB  $df      ; Semifila 'O' = puerto $dfFE
 p1_tecla_izq         DEFB  $02      ; Tecla 'O' = bit 2 p1_tecla_izq         DEFB  $02      ; Tecla 'O' = bit 2
-p1_puerto_der        DEFB  $DF      ; Semifila 'P' = puerto $DFFE+p1_puerto_der        DEFB  $df      ; Semifila 'P' = puerto $dfFE
 p1_tecla_der         DEFB  $01      ; Tecla 'P' = bit 1 p1_tecla_der         DEFB  $01      ; Tecla 'P' = bit 1
-p1_puerto_arriba     DEFB  $FB      ; Semifila 'Q' = puerto $FBFE+p1_puerto_arriba     DEFB  $fb      ; Semifila 'Q' = puerto $fbFE
 p1_tecla_arriba      DEFB  $01      ; Tecla 'Q' = bit 1 p1_tecla_arriba      DEFB  $01      ; Tecla 'Q' = bit 1
-p1_puerto_abajo      DEFB  $FD      ; Semifila 'A' = puerto $FDFE+p1_puerto_abajo      DEFB  $fd      ; Semifila 'A' = puerto $fdFE
 p1_tecla_abajo       DEFB  $01      ; Tecla 'A' = bit 1 p1_tecla_abajo       DEFB  $01      ; Tecla 'A' = bit 1
  
Línea 1246: Línea 1281:
 ; La semifila se guarda como puerto a leer  y la tecla como ; La semifila se guarda como puerto a leer  y la tecla como
 ; el bit (posición) de esa tecla en la respuesta. ; el bit (posición) de esa tecla en la respuesta.
-; Ejemplo: 'O' = p1_puerto_izq = $DF+; Ejemplo: 'O' = p1_puerto_izq = $df
 ;                p1_tecla_izq = 2 (%00000010) ;                p1_tecla_izq = 2 (%00000010)
 ; Llama a "Redefine_Key" para mostrar el mensaje y pedir la tecla. ; Llama a "Redefine_Key" para mostrar el mensaje y pedir la tecla.
Línea 1256: Línea 1291:
 Redefinir_Teclas_SSSTTT: Redefinir_Teclas_SSSTTT:
     ; Los siguientes textos se podrian haber impreso tambien usando un bucle     ; Los siguientes textos se podrian haber impreso tambien usando un bucle
-    ; con INC DE (avanzar cadena) e INC HL (avanzar tecla a escribir) +    ; con inc de (avanzar cadena) e inc hl (avanzar tecla a escribir) 
-    LD DE, msg_izq +    ld de, msg_izq 
-    CALL PrintString              ; Imprimir mensaje "Izquierda?" +    call PrintString              ; Imprimir mensaje "Izquierda?" 
-    CALL Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) +    call Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) 
-    CALL Scancode_To_Port_Key +    call Scancode_To_Port_Key 
-    LD HL, p1_puerto_izq          ; Apuntamos HL a la p1_puerto_izq +    ld hl, p1_puerto_izq          ; Apuntamos HL a la p1_puerto_izq 
-    LD (HL),                    ; Guardamos la semifila +    ld (hl),                    ; Guardamos la semifila 
-    INC HL                        ; Incrementamos HL => apuntamos a p1_tecla_x +    inc hl                        ; Incrementamos HL => apuntamos a p1_tecla_x 
-    LD (HL),                    ; Guardamos la tecla+    ld (hl),                    ; Guardamos la tecla
  
-    LD DE, msg_der                ; Siguiente mensaje: "Derecha?" +    ld de, msg_der                ; Siguiente mensaje: "Derecha?" 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) +    call Redefine_Key             ; Esperar pulsacion (e imprimir ASCII) 
-    CALL Scancode_To_Port_Key +    call Scancode_To_Port_Key 
-    LD HL, p1_puerto_der          ; Apuntamos HL a la p1_puerto_X +    ld hl, p1_puerto_der          ; Apuntamos HL a la p1_puerto_X 
-    LD (HL),                    ; Guardamos la semifila +    ld (hl),                    ; Guardamos la semifila 
-    INC HL                        ; Incrementamos HL => apuntamos a p1_tecla_x +    inc hl                        ; Incrementamos HL => apuntamos a p1_tecla_x 
-    LD (HL),                    ; Guardamos la tecla+    ld (hl),                    ; Guardamos la tecla
  
-    LD DE, msg_arriba             ; Repetimos con ARRIBA +    ld de, msg_arriba             ; Repetimos con ARRIBA 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key +    call Redefine_Key 
-    CALL Scancode_To_Port_Key +    call Scancode_To_Port_Key 
-    LD HL, p1_puerto_arriba       ; Apuntamos HL a la p1_puerto_X +    ld hl, p1_puerto_arriba       ; Apuntamos HL a la p1_puerto_X 
-    LD (HL),                    ; Guardamos la semifila +    ld (hl),                    ; Guardamos la semifila 
-    INC HL                        ; Incrementamos HL => apuntamos a p1_tecla_x +    inc hl                        ; Incrementamos HL => apuntamos a p1_tecla_x 
-    LD (HL),                    ; Guardamos la tecla+    ld (hl),                    ; Guardamos la tecla
  
-    LD DE, msg_abajo              ; Repetimos con ABAJO +    ld de, msg_abajo              ; Repetimos con ABAJO 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key +    call Redefine_Key 
-    CALL Scancode_To_Port_Key +    call Scancode_To_Port_Key 
-    LD HL, p1_puerto_abajo        ; Apuntamos HL a la p1_puerto_X +    ld hl, p1_puerto_abajo        ; Apuntamos HL a la p1_puerto_X 
-    LD (HL),                    ; Guardamos la semifila +    ld (hl),                    ; Guardamos la semifila 
-    INC HL                        ; Incrementamos HL => apuntamos a p1_tecla_x +    inc hl                        ; Incrementamos HL => apuntamos a p1_tecla_x 
-    LD (HL),                    ; Guardamos la tecla+    ld (hl),                    ; Guardamos la tecla
  
-    LD DE, msg_disp               ; Repetimos con DISPARO +    ld de, msg_disp               ; Repetimos con DISPARO 
-    CALL PrintString +    call PrintString 
-    CALL Redefine_Key +    call Redefine_Key 
-    CALL Scancode_To_Port_Key +    call Scancode_To_Port_Key 
-    LD HL, p1_puerto_disp         ; Apuntamos HL a la p1_puerto_X +    ld hl, p1_puerto_disp         ; Apuntamos HL a la p1_puerto_X 
-    LD (HL),                    ; Guardamos la semifila +    ld (hl),                    ; Guardamos la semifila 
-    INC HL                        ; Incrementamos HL => apuntamos a p1_tecla_x +    inc hl                        ; Incrementamos HL => apuntamos a p1_tecla_x 
-    LD (HL),                    ; Guardamos la tecla +    ld (hl),                    ; Guardamos la tecla 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 1312: Línea 1347:
 ; SALIDA:  D = NUMERO de bit de TECLA. ; SALIDA:  D = NUMERO de bit de TECLA.
 ;          E = PUERTO (parte alta) correspondiente a esa SEMIFILA ;          E = PUERTO (parte alta) correspondiente a esa SEMIFILA
-; Ejemplo: 'O' = D = $DF+; Ejemplo: 'O' = D = $df
 ;                E = 2 (%00000010) ;                E = 2 (%00000010)
 ; ;
Línea 1318: Línea 1353:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Scancode_To_Port_Key: Scancode_To_Port_Key:
-    LD D                 ; Hacer copia de scancode en D +    ld d                 ; Hacer copia de scancode en D 
-    AND $07                  ; Eliminar todos los bits menos 00000SSS +    and %00000111            ; Eliminar todos los bits menos 00000SSS 
-    CPL                      ; Invertir valores (1/0) +    cpl                      ; Invertir valores (1/0) 
-    LD E                 ; E = contador para bucle +    ld e                 ; E = contador para bucle 
-    LD A, $FE                ; Empezamos por primera semifila (determina puerto) +    ld a, $fe                ; Empezamos por primera semifila (determina puerto) 
-    JR Z, ConvScn_tecla      ; Si Z==1 => es primera semifila+    jr z, ConvScn_tecla      ; Si Z==1 => es primera semifila
 ConvScn_loop1: ConvScn_loop1:
-    RLCA                     ; Rotamos A: Siguiente semifila +    rlca                     ; Rotamos A: Siguiente semifila 
-    DEC E +    dec e 
-    JR NZ, ConvScn_loop1     ; Si Z==0 => no es la semifila correcta+    jr nz, ConvScn_loop1     ; Si Z==0 => no es la semifila correcta
 ConvScn_tecla: ConvScn_tecla:
-    LD E                 ; Salvaguardamos semifila (puerto a leer) en E +    ld e                 ; Salvaguardamos semifila (puerto a leer) en E 
-    LD A                 ; Recuperamos A = 00TTTSSS de nuevo +    ld a                 ; Recuperamos A = 00TTTSSS de nuevo 
-    AND $38                  ; Eliminamos todos los valores menos 00TTT000 +    and %00111000            ; Eliminamos todos los valores menos 00TTT000 
-    LD D, $10                ; Inicializamos a la tecla mas interna +    ld d, $10                ; Inicializamos a la tecla mas interna 
-    RET Z                    ; Si Z==1 => es la tecla interna+    ret z                    ; Si Z==1 => es la tecla interna
 ConvScn_loop2 ConvScn_loop2
-    RR D                     ; Rotamos: Siguiente tecla de la semifila +    rr d                     ; Rotamos: Siguiente tecla de la semifila 
-    SUB +    sub 
-    JR NZ, ConvScn_loop2     ; Si Z==0 => NO ES LA TECLA CORRECTA +    jr nz, ConvScn_loop2     ; Si Z==0 => NO ES LA TECLA CORRECTA 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 1352: Línea 1387:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Leer_Teclado_SSSTTT: Leer_Teclado_SSSTTT:
-    LD DE, P1_NUM_TECLAS*256     ; D = 5 (teclas a leer), E = 0 +    ld de, P1_NUM_TECLAS*256     ; D = 5 (teclas a leer), E = 0 
-    LD HL, teclas_player_1       ; 1a tecla (p1_puerto_X) para bit + alto +    ld hl, teclas_player_1       ; 1a tecla (p1_puerto_X) para bit + alto 
-    LD C, $FE                    ; Parte baja puerto teclado+    ld c, $fe                    ; Parte baja puerto teclado
  
 tecl_sssttt_loop: tecl_sssttt_loop:
-    LD B, (HL)                   ; cogemos puerto a leer (parte alta) +    ld b, (hl)                   ; cogemos puerto a leer (parte alta) 
-    INC HL                       ; pasamos al siguiente byte (p1_tecla_X) +    inc hl                       ; pasamos al siguiente byte (p1_tecla_X) 
-    IN A, (C)                    ; leer del puerto de esta tecla +    in a, (c)                    ; leer del puerto de esta tecla 
-    CPL                          ; Ahora: 1 teclas pulsadas, 0 no pulsadas +    cpl                          ; Ahora: 1 teclas pulsadas, 0 no pulsadas 
-    AND $1F                      ; aislamos las teclas +    and %00011111                ; aislamos las teclas 
-    AND (HL)                     ; comparo con la tecla en memoria (carry OFF) +    and (hl)                     ; comparo con la tecla en memoria (carry OFF) 
-    JR Z, tecl_sssttt_nopulsada  ; Si Z == 1 => tecla no pulsada +    jr z, tecl_sssttt_nopulsada  ; Si Z == 1 => tecla no pulsada 
-    SCF                          ; Ponemos Carry = 1 para meterlo en A al rotar+    scf                          ; Ponemos Carry = 1 para meterlo en A al rotar
  
 tecl_sssttt_nopulsada: tecl_sssttt_nopulsada:
-    RL E                         ; meto el valor de la pulsacion de la tecla+    rl e                         ; meto el valor de la pulsacion de la tecla
                                  ; (carry OFF no pulsada/carry ON pulsada)                                  ; (carry OFF no pulsada/carry ON pulsada)
-    INC HL                       ; apunto a siguiente puerto (semifila) +    inc hl                       ; apunto a siguiente puerto (semifila) 
-    DEC D                        ; decrementamos el num. de teclas pendientes por leer +    dec d                        ; decrementamos el num. de teclas pendientes por leer 
-    JR NZ, tecl_sssttt_loop      ; siempre necesita una pulsacion para salir del bucle +    jr nz, tecl_sssttt_loop      ; siempre necesita una pulsacion para salir del bucle 
-    LD A                     ; Recuperamos estado final +    ld a                     ; Recuperamos estado final 
-    LD (p1_teclas_pulsadas),   ; Guardamos en variable el estado de las teclas +    ld (p1_teclas_pulsadas),   ; Guardamos en variable el estado de las teclas 
-    RET                          ; Devolvemos en A el estado de las teclas+    ret                          ; Devolvemos en A el estado de las teclas
  
 ;;; Insertar aqui el codigo de Redefine_Key ;;; Insertar aqui el codigo de Redefine_Key
Línea 1407: Línea 1442:
 ; que aparezcan en los bits ; que aparezcan en los bits
 teclas_player_1: teclas_player_1:
-p1_puerto_disp       DEFB  $7F      ; Semifila ' ' = puerto $FEFE+p1_puerto_disp       DEFB  $7f      ; Semifila ' ' = puerto $fefe
 p1_tecla_disp        DEFB  $01      ; Tecla ' ' = bit 1 p1_tecla_disp        DEFB  $01      ; Tecla ' ' = bit 1
-p1_puerto_izq        DEFB  $DF      ; Semifila 'O' = puerto $DFFE+p1_puerto_izq        DEFB  $df      ; Semifila 'O' = puerto $dfFE
 p1_tecla_izq         DEFB  $02      ; Tecla 'O' = bit 2 p1_tecla_izq         DEFB  $02      ; Tecla 'O' = bit 2
-p1_puerto_der        DEFB  $DF      ; Semifila 'P' = puerto $DFFE+p1_puerto_der        DEFB  $df      ; Semifila 'P' = puerto $dfFE
 p1_tecla_der         DEFB  $01      ; Tecla 'P' = bit 1 p1_tecla_der         DEFB  $01      ; Tecla 'P' = bit 1
-p1_puerto_arriba     DEFB  $FB      ; Semifila 'Q' = puerto $FBFE+p1_puerto_arriba     DEFB  $fb      ; Semifila 'Q' = puerto $fbFE
 p1_tecla_arriba      DEFB  $01      ; Tecla 'Q' = bit 1 p1_tecla_arriba      DEFB  $01      ; Tecla 'Q' = bit 1
-p1_puerto_abajo      DEFB  $FD      ; Semifila 'A' = puerto $FDFE+p1_puerto_abajo      DEFB  $fd      ; Semifila 'A' = puerto $fdFE
 p1_tecla_abajo       DEFB  $01      ; Tecla 'A' = bit 1 p1_tecla_abajo       DEFB  $01      ; Tecla 'A' = bit 1
  
Línea 1426: Línea 1461:
 Ahora, en el bucle principal del programa, usaremos ''Leer_Teclado_SSSTTT'' para que lea las 5 teclas rápidamente, ya que sabemos sus puertos y sus posiciones en el valor leído del puerto, lo cual es muchísimo más óptimo. Ahora, en el bucle principal del programa, usaremos ''Leer_Teclado_SSSTTT'' para que lea las 5 teclas rápidamente, ya que sabemos sus puertos y sus posiciones en el valor leído del puerto, lo cual es muchísimo más óptimo.
  
-Esta rutina lo que hace es un bucle de N iteraciones (siendo N el valor de ''P1_NUM_TECLAS'') y va recorriendo con HL toda la tabla de puertos/teclas para leer el puerto y comprobar el estado de la tecla. Si encuentra la tecla pulsada, pone un 1 en el CARRY FLAG, y si no está pulsada lo deja en 0. A continuación rota con ''RL E'' el registro donde vamos almacenando el estado de las teclas para que entre ese 1 o ese 0 desde la derecha. Este es el motivo por el cual el orden en que definimos las teclas en el bloque de puertos/teclas es importante, ya que la primera tecla se quedará en el BIT ''P1_NUM_TECLAS-1'' por el bucle que estamos realizando.+Esta rutina lo que hace es un bucle de N iteraciones (siendo N el valor de ''P1_NUM_TECLAS'') y va recorriendo con HL toda la tabla de puertos/teclas para leer el puerto y comprobar el estado de la tecla. Si encuentra la tecla pulsada, pone un 1 en el CARRY FLAG, y si no está pulsada lo deja en 0. A continuación rota con ''rl e'' el registro donde vamos almacenando el estado de las teclas para que entre ese 1 o ese 0 desde la derecha. Este es el motivo por el cual el orden en que definimos las teclas en el bloque de puertos/teclas es importante, ya que la primera tecla se quedará en el BIT ''P1_NUM_TECLAS-1'' por el bucle que estamos realizando.
  
 \\  \\ 
Línea 1447: Línea 1482:
 ; que aparezcan en los bits ; que aparezcan en los bits
 teclas_player_1: teclas_player_1:
-p1_puerto_pause      DEFB  $FE      ; Semifila 'C' = puerto $FEFE+p1_puerto_pause      DEFB  $fe      ; Semifila 'C' = puerto $feFE
 p1_tecla_pause       DEFB  $08      ; Tecla 'C' = bit 4 p1_tecla_pause       DEFB  $08      ; Tecla 'C' = bit 4
-p1_puerto_disp2      DEFB  $FE      ; Semifila 'V' = puerto $FEFE+p1_puerto_disp2      DEFB  $fe      ; Semifila 'V' = puerto $feFE
 p1_tecla_disp2       DEFB  $10      ; Tecla 'V' = bit 5 p1_tecla_disp2       DEFB  $10      ; Tecla 'V' = bit 5
-p1_puerto_disp       DEFB  $7F      ; Semifila ' ' = puerto $FEFE+p1_puerto_disp       DEFB  $7f      ; Semifila ' ' = puerto $fefe
 p1_tecla_disp        DEFB  $01      ; Tecla ' ' = bit 1 p1_tecla_disp        DEFB  $01      ; Tecla ' ' = bit 1
-p1_puerto_izq        DEFB  $DF      ; Semifila 'O' = puerto $DFFE+p1_puerto_izq        DEFB  $df      ; Semifila 'O' = puerto $dfFE
 p1_tecla_izq         DEFB  $02      ; Tecla 'O' = bit 2 p1_tecla_izq         DEFB  $02      ; Tecla 'O' = bit 2
-p1_puerto_der        DEFB  $DF      ; Semifila 'P' = puerto $DFFE+p1_puerto_der        DEFB  $df      ; Semifila 'P' = puerto $dfFE
 p1_tecla_der         DEFB  $01      ; Tecla 'P' = bit 1 p1_tecla_der         DEFB  $01      ; Tecla 'P' = bit 1
-p1_puerto_arriba     DEFB  $FB      ; Semifila 'Q' = puerto $FBFE+p1_puerto_arriba     DEFB  $fb      ; Semifila 'Q' = puerto $fbFE
 p1_tecla_arriba      DEFB  $01      ; Tecla 'Q' = bit 1 p1_tecla_arriba      DEFB  $01      ; Tecla 'Q' = bit 1
-p1_puerto_abajo      DEFB  $FD      ; Semifila 'A' = puerto $FDFE+p1_puerto_abajo      DEFB  $fd      ; Semifila 'A' = puerto $fdFE
 p1_tecla_abajo       DEFB  $01      ; Tecla 'A' = bit 1 p1_tecla_abajo       DEFB  $01      ; Tecla 'A' = bit 1
  
Línea 1520: Línea 1555:
 </code> </code>
  
-//Los valores que obtenemos para estas pulsaciones son 189 y 190 (con 191 sin pulsar), lo que significa que los bits desconocidos son nada más y nada menos que XXX = 101. Podremos garantizar que nuestro programa funcionará en todos los Spectrum si comparamos siempre con ambos valores (por ejemplo, para detectar O deberíamos mirar si IN 57342=253 OR IN 57342=189).//+//Los valores que obtenemos para estas pulsaciones son 189 y 190 (con 191 sin pulsar), lo que significa que los bits desconocidos son nada más y nada menos que XXX = 101. Podremos garantizar que nuestro programa funcionará en todos los Spectrum si comparamos siempre con ambos valores (por ejemplo, para detectar O deberíamos mirar si IN 57342=253 or iN 57342=189).//
  
  La solución que Na_th_an nos expone en el párrafo anterior está orientada a la creación de programas en BASIC, dado que la variante "ZX Spectrum" de este lenguaje no dispone de operaciones de testeo de bits, pero en nuestro caso, en ensamblador, la mejor opción para leer una tecla (pongamos "P" en el siguiente ejemplo) sería:  La solución que Na_th_an nos expone en el párrafo anterior está orientada a la creación de programas en BASIC, dado que la variante "ZX Spectrum" de este lenguaje no dispone de operaciones de testeo de bits, pero en nuestro caso, en ensamblador, la mejor opción para leer una tecla (pongamos "P" en el siguiente ejemplo) sería:
  
 <code z80> <code z80>
-    LD A, $DF            ; Semifila "P" a "Y" +    ld a, $df            ; Semifila "P" a "Y" 
-    IN A, ($FE)          ; Leemos el puerto +    in a, ($fe)          ; Leemos el puerto 
-    BIT 0,             ; Testeamos el bit 0 +    bit 0,             ; Testeamos el bit 0 
-    JR Z, pulsado        ; Si esta a 0 (pulsado) salir.+    jr z, pulsado        ; Si esta a 0 (pulsado) salir.
 </code> </code>
  
- Si queremos utilizar la comprobación por valor, o simplemente vamos a saltar con ''OR A'' y luego ''JZ'' / ''JNZ'', podríamos simplemente enmascarar con ''AND %00011111'' el valor de A antes de la comparación, y dejaríamos a cero los bits implicados.+ Si queremos utilizar la comprobación por valor, o simplemente vamos a saltar con ''or a'' y luego ''JZ'' / ''JNZ'', podríamos simplemente enmascarar con ''and %00011111'' el valor de A antes de la comparación, y dejaríamos a cero los bits implicados.
  
 \\  \\ 
Línea 1547: Línea 1582:
 </code> </code>
  
- 3.- Para los casos en los cuales queramos comprobar sólo el bit 0 de una semifila, podemos ahorrarnos la sentencia BIT utilizando RRA para mover el bit b0 al carry flag. ¿La utilidad de esto? Sencillamente que RRA se ejecuta en 4 ciclos de reloj mientras que BIT en 8.+ 3.- Para los casos en los cuales queramos comprobar sólo el bit 0 de una semifila, podemos ahorrarnos la sentencia BIT utilizando rra para mover el bit b0 al carry flag. ¿La utilidad de esto? Sencillamente que rra se ejecuta en 4 ciclos de reloj mientras que BIT en 8.
  
 <code z80> <code z80>
     ; Ejemplo: leyendo la tecla espacio (bit 0)     ; Ejemplo: leyendo la tecla espacio (bit 0)
-    LD A, $7F +    ld a, $7f 
-    IN A, ($FE+    in a, ($fe
-    RRA                    ; pone b0 en el carry flag +    rra                    ; pone b0 en el carry flag 
-    JP NC, key_pressed+    jp nc, key_pressed
 </code> </code>
  
Línea 1591: Línea 1626:
 EsperaSoltar:   xor a EsperaSoltar:   xor a
                 in a,(254)                 in a,(254)
-                and 00011111b +                and %00011111 
-                cp 00011111b+                cp %00011111
                 jr nz,EsperaSoltar                 jr nz,EsperaSoltar
  
 EsperaPulsar:   xor a EsperaPulsar:   xor a
                 in a,(254)                 in a,(254)
-                and 00011111b +                and %00011111 
-                cp 00011111b+                cp %00011111
                 jr z,EsperaPulsar                 jr z,EsperaPulsar
  
Línea 1626: Línea 1661:
  
 Bucle: Bucle:
-EsperaSoltar:   XOR A +EsperaSoltar:   xor a 
-                IN A, (254) +                in a, (254) 
-                AND 00011111B +                and %00011111 
-                CP 00011111B +                cp %00011111 
-                JR NZ, EsperaSoltar+                jr nz, EsperaSoltar
  
                 ;Hacer pausa AQUI                 ;Hacer pausa AQUI
  
-EsperaPulsar:   XOR A +EsperaPulsar:   xor a 
-                IN A, (254) +                in a, (254) 
-                AND 00011111B +                and %00011111 
-                CP 00011111B +                cp %00011111 
-                JR Z, EsperaPulsar+                jr z, EsperaPulsar
  
                 ; Hacer pausa AQUI                 ; Hacer pausa AQUI
  
                 ;Se registra la pulsacion...                 ;Se registra la pulsacion...
-                JR Bucle+                jr Bucle
  
  El efecto que esto tiene sobre el comportamiento de las lecturas es el siguiente:  El efecto que esto tiene sobre el comportamiento de las lecturas es el siguiente:
Línea 1722: Línea 1757:
     120 LET r(n,1)=f: LET r(n,2)=c:     120 LET r(n,1)=f: LET r(n,2)=c:
         REM La guardamos en nuestra matriz de teclas seleccionadas.         REM La guardamos en nuestra matriz de teclas seleccionadas.
-    130 FOR m=1 TO n: LET fil=r(m,1): LET col=r(m,2): GO SUB 900: NEXT m:+    130 FOR m=1 TO n: LET fil=r(m,1): LET col=r(m,2): GO sub 900: NEXT m:
         REM Repasamos la lista de teclas seleccionadas hasta el momento para         REM Repasamos la lista de teclas seleccionadas hasta el momento para
             actualizar la matriz con las teclas "fantasma" que encontremos             actualizar la matriz con las teclas "fantasma" que encontremos
Línea 1728: Línea 1763:
     900 FOR i=1 TO 8:     900 FOR i=1 TO 8:
         REM recorremos todas las teclas de la misma columna que nuestra tecla         REM recorremos todas las teclas de la misma columna que nuestra tecla
-    910 IF t(i,col,1)=1 THEN GO SUB 1000:+    910 IF t(i,col,1)=1 THEN GO sub 1000:
         REM si alguna esta seleccionada, significa que tenemos dos teclas en         REM si alguna esta seleccionada, significa que tenemos dos teclas en
             una misma columna. Miramos si hay una tercera en la misma fila             una misma columna. Miramos si hay una tercera en la misma fila
  • cursos/ensamblador/teclado.1705506182.txt.gz
  • Última modificación: 17-01-2024 15:43
  • por sromero