Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
cursos:ensamblador:teclado [17-01-2024 13:42] – sromero | cursos: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 '' | + | Como veremos en la entrega dedicada a las Interrupciones del procesador, ciertas rutinas de servicio (ISR), en concreto '' |
- | | + | |
- | | + | |
- | 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, | + | 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 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//" | 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//" | ||
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, | + | El teclado del Spectrum es una matriz de 40 pulsadores (40 teclas) que proporcionan al microprocesador, |
- | 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 ; " | 20 LET V=IN puerto: PRINT AT 20,0; V ; " | ||
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 '' | + | diferentes bits de estado conectados al puerto 63486 ($f7feh), y como podéis suponer, mediante la instrucción '' |
misma función que con su equivalente ensamblador: | misma función que con su equivalente ensamblador: | ||
- | 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 " | + | 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 " |
\\ | \\ | ||
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: | " | + | | 65278d ($fefe) | Teclas: | " |
- | | 65022d ($FDFE) | Teclas: | " | + | | 65022d ($fdfe) | Teclas: | " |
- | | 64510d ($FBFE) | Teclas: | " | + | | 64510d ($fbfe) | Teclas: | " |
- | | 63486d ($F7FE) | Teclas: | " | + | | 63486d ($f7fe) | Teclas: | " |
- | | 61438d ($EFFE) | Teclas: | " | + | | 61438d ($effe) | Teclas: | " |
- | | 57342d ($DFFE) | Teclas: | " | + | | 57342d ($dffe) | Teclas: | " |
- | | 49150d ($BFFE) | Teclas: | " | + | | 49150d ($bffe) | Teclas: | " |
- | | 32766d ($7FFE) | Teclas: | " | + | | 32766d ($7ffe) | Teclas: | " |
^ 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 " | + | 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 " |
(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: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
salir: | salir: | ||
- | | + | |
END 50000 | END 50000 | ||
Línea 162: | Línea 162: | ||
De nuevo ensamblamos nuestro programa con '' | De nuevo ensamblamos nuestro programa con '' | ||
- | | + | |
En ocasiones puede ser más recomendable la utilización de '' | En ocasiones puede ser más recomendable la utilización de '' | ||
Línea 168: | Línea 168: | ||
<code z80> | <code z80> | ||
; Forma 1 | ; Forma 1 | ||
- | LD BC, FFFEh | + | ld bc, $fffe |
- | IN A, (C) ; A = Lectura de puerto | + | in a, (c) ; A = Lectura de puerto |
; Forma 2 | ; Forma 2 | ||
- | LD A, FFh | + | ld a, $ff |
- | IN A, (FEh) ; A = Lectura de puerto | + | in a, ($fe) ; A = Lectura de puerto |
</ | </ | ||
Línea 183: | Línea 183: | ||
bucle: | bucle: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
salir: | salir: | ||
- | | + | |
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, | + | Pero como vamos a ver, podemos leer más de una línea simultáneamente, |
Este tipo de " | Este tipo de " | ||
Línea 239: | Línea 239: | ||
; | ; | ||
Wait_For_Keys_Pressed: | Wait_For_Keys_Pressed: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | ; Si A=0 => ZF = 1 => no hay tecla pulsada |
- | | + | ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada |
+ | | ||
+ | | ||
; | ; | ||
Línea 251: | Línea 253: | ||
; | ; | ||
Wait_For_Keys_Released: | Wait_For_Keys_Released: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | ; Si A=0 => ZF = 1 => no hay tecla pulsada |
- | | + | ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada |
+ | | ||
+ | | ||
</ | </ | ||
Línea 264: | Línea 268: | ||
; | ; | ||
Wait_For_Keys_Pressed: | Wait_For_Keys_Pressed: | ||
- | | + | |
wait_for_keypressed_loop: | wait_for_keypressed_loop: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | ; Si A=0 => ZF = 1 => no hay tecla pulsada |
- | | + | ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada |
- | | + | |
+ | | ||
+ | | ||
; | ; | ||
Wait_For_Keys_Released: | Wait_For_Keys_Released: | ||
- | | + | |
wait_for_no_pressedkey_loop: | wait_for_no_pressedkey_loop: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | ; Si A=0 => ZF = 1 => no hay tecla pulsada |
- | | + | ; Si A!=0 => ZF = 0 => hay alguna tecla pulsada |
- | | + | |
+ | | ||
+ | | ||
</ | </ | ||
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: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ; (podríamos haber usado "AND %00000001" | + | ; (podríamos haber usado "and %00000001" |
- | | + | |
- | | + | |
Control_no_up: | Control_no_up: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
Control_no_down: | Control_no_down: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
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 | ||
- | | + | |
- | | + | |
- | | + | |
- | ; (podríamos haber usado "AND %00000010" | + | ; (podríamos haber usado "and %00000010" |
- | | + | |
- | | + | |
Control_no_left: | Control_no_left: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
Control_no_fire: | Control_no_fire: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Estado de cada tecla. | ; Estado de cada tecla. | ||
Línea 386: | Línea 393: | ||
\\ | \\ | ||
- | // | + | // |
| | ||
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: | ||
- | | + | |
- | | + | |
NXHALF: | NXHALF: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
KLOOP: | KLOOP: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
NPRESS: | NPRESS: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 445: | Línea 452: | ||
<code z80> | <code z80> | ||
;; Pedimos tecla ARRIBA | ;; Pedimos tecla ARRIBA | ||
- | | + | |
- | | + | |
Pedir_Arriba: | Pedir_Arriba: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;; Pedimos siguiente tecla (ABAJO) | ;; Pedimos siguiente tecla (ABAJO) | ||
- | | + | |
- | | + | |
Pedir_Abajo: | Pedir_Abajo: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;;; 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 " | ; Visualizando los scancodes de las teclas codificadas con " | ||
- | ORG 50000 | + | |
Bucle_entrada: | Bucle_entrada: | ||
- | | + | call Wait_For_Key |
Pedir_Tecla: | Pedir_Tecla: | ||
- | | + | call Find_Key |
- | JR NZ, Pedir_Tecla | + | jr nz, Pedir_Tecla |
- | INC D | + | inc d |
- | JR Z, Pedir_Tecla | + | jr z, Pedir_Tecla |
- | DEC D | + | dec d |
- | LD A, D ; Guardamos en A copia del resultado | + | ld a, d ; Guardamos en A copia del resultado |
- | | + | cp $21 ; Comprobamos si A == 21h (enter) |
- | RET Z ; Si no lo es, repetir | + | ret z ; Si no lo es, repetir |
- | | + | call PrintHex |
- | | + | call PrintSpace |
- | | + | call Wait_For_No_Key |
- | JR Pedir_Tecla | + | |
- | ; ($21 pulsado) haga el RET Z a BASIC | + | ; ($21 pulsado) haga el ret z a BASIC |
INCLUDE " | INCLUDE " | ||
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): | ||
+ | |||
+ | \\ | ||
+ | {{ : | ||
+ | \\ | ||
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 | tecla_arriba | ||
tecla_abajo | tecla_abajo | ||
- | tecla_izq | + | tecla_izq |
tecla_der | tecla_der | ||
tecla_disp | tecla_disp | ||
Línea 587: | Línea 602: | ||
; | ; | ||
Scancode2Ascii: | Scancode2Ascii: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; 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: | ||
- | | + | |
- | | + | |
- | ; | + | ; |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
SC2Ascii_Found: | SC2Ascii_Found: | ||
- | | + | |
- | | + | |
- | | + | |
SC2Ascii_Exit: | SC2Ascii_Exit: | ||
- | | + | |
- | | + | |
- | | + | |
; 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 " | DEFB " | ||
</ | </ | ||
Línea 645: | Línea 660: | ||
ORG 50000 | ORG 50000 | ||
- | | + | |
START: | START: | ||
- | | + | |
chequear_teclas: | chequear_teclas: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; En este punto D es un scancode valido | ; En este punto D es un scancode valido | ||
- | | + | |
; 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. | ||
- | | + | |
- | | + | |
INCLUDE " | INCLUDE " | ||
Línea 699: | Línea 714: | ||
ORG 33500 | ORG 33500 | ||
- | | + | |
- | | + | |
bucle: | 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 | + | tecla_izq |
tecla_der | tecla_der | ||
tecla_arriba | tecla_arriba | ||
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) |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; | ; | ||
Línea 772: | Línea 787: | ||
; | ; | ||
Redefine_Key: | Redefine_Key: | ||
- | | + | |
- | | + | |
- | | + | |
wait_for_scan_loop: | wait_for_scan_loop: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
redef_key_NO_ENTER: | redef_key_NO_ENTER: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
redef_key_NO_SPACE: | redef_key_NO_SPACE: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
redef_key_NO_CAPSSHIFT: | redef_key_NO_CAPSSHIFT: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
redef_key_NO_SYMBOLSHIFT: | redef_key_NO_SYMBOLSHIFT: | ||
; Si llegamos aqui no era tecla especial. | ; Si llegamos aqui no era tecla especial. | ||
- | | + | |
- | | + | |
redef_key_end: | redef_key_end: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
redef_key_enter DB " | redef_key_enter DB " | ||
Línea 850: | Línea 865: | ||
\\ | \\ | ||
+ | |||
+ | \\ | ||
+ | ==== UDGs para las teclas especiales ==== | ||
+ | |||
+ | Si en lugar de imprimir las cadenas " | ||
+ | |||
+ | Nuestro compañero //Juan Antonio Rubio// nos proporciona los siguientes UDGs que podemos " | ||
+ | |||
+ | <code z80> | ||
+ | DB $10, | ||
+ | DB $60, | ||
+ | DB $05, | ||
+ | DB $00, | ||
+ | </ | ||
+ | |||
+ | Los cuales tienen el siguiente aspecto: | ||
+ | |||
+ | \\ | ||
+ | {{ : | ||
+ | \\ | ||
\\ | \\ | ||
Línea 857: | Línea 892: | ||
<code z80> | <code z80> | ||
- | tecla_izq | + | tecla_izq |
tecla_der | tecla_der | ||
tecla_arriba | tecla_arriba | ||
Línea 880: | Línea 915: | ||
; | ; | ||
Check_Key: | Check_Key: | ||
- | | + | |
- | | + | |
; 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 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
CKHiFind: | CKHiFind: | ||
- | | + | |
- | | + | |
- | | + | |
CKNXKey: | CKNXKey: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 916: | Línea 951: | ||
<code z80> | <code z80> | ||
Comprobar_tecla_izquierda: | Comprobar_tecla_izquierda: | ||
- | | + | |
- | | + | |
- | | + | |
(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: | ||
- | | + | |
- | | + | |
- | | + | |
(acciones a realizar si se pulso der) | (acciones a realizar si se pulso der) | ||
Línea 940: | Línea 975: | ||
ORG 50000 | ORG 50000 | ||
- | | + | |
Imprimir_Valor: | Imprimir_Valor: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
Bucle: | Bucle: | ||
Comprobar_tecla_mas: | Comprobar_tecla_mas: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
Comprobar_tecla_menos: | Comprobar_tecla_menos: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Variables de teclas | ; Variables de teclas | ||
Línea 1008: | Línea 1043: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
; (...) | ; (...) | ||
; Mas adelante en el programa | ; Mas adelante en el programa | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; etc... | ; etc... | ||
Línea 1045: | Línea 1080: | ||
; | ; | ||
Leer_Teclado_Empaquetado: | Leer_Teclado_Empaquetado: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ; Usando A podríamos usar "OR %00001000" | + | ; Usando A podríamos usar "or %00001000" |
tecl_izq_notpressed: | tecl_izq_notpressed: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
tecl_der_notpressed: | tecl_der_notpressed: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
tecl_arr_notpressed: | tecl_arr_notpressed: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
tecl_aba_notpressed: | tecl_aba_notpressed: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
tecl_fire_notpressed: | tecl_fire_notpressed: | ||
; Podriamos añadir codigo para disparo 2 | ; Podriamos añadir codigo para disparo 2 | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
La rutina simplemente apunta HL a la primera de las teclas y llama a '' | La rutina simplemente apunta HL a la primera de las teclas y llama a '' | ||
- | | + | |
| | ||
Línea 1102: | Línea 1137: | ||
ORG 33500 | ORG 33500 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Bucle del programa, lee nuestras teclas e imprime primero la | ; Bucle del programa, lee nuestras teclas e imprime primero la | ||
; " | ; " | ||
bucle: | bucle: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; 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 | + | tecla_izq |
tecla_der | tecla_der | ||
tecla_arriba | tecla_arriba | ||
Línea 1195: | Línea 1230: | ||
ORG 33500 | ORG 33500 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Bucle del programa, lee nuestras teclas e imprime primero la | ; Bucle del programa, lee nuestras teclas e imprime primero la | ||
; " | ; " | ||
bucle: | bucle: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; 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 | + | p1_puerto_disp |
p1_tecla_disp | p1_tecla_disp | ||
- | p1_puerto_izq | + | p1_puerto_izq |
p1_tecla_izq | p1_tecla_izq | ||
- | p1_puerto_der | + | p1_puerto_der |
p1_tecla_der | p1_tecla_der | ||
- | p1_puerto_arriba | + | p1_puerto_arriba |
p1_tecla_arriba | p1_tecla_arriba | ||
- | p1_puerto_abajo | + | p1_puerto_abajo |
p1_tecla_abajo | p1_tecla_abajo | ||
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: ' | + | ; Ejemplo: ' |
; p1_tecla_izq = 2 (%00000010) | ; p1_tecla_izq = 2 (%00000010) | ||
; Llama a " | ; Llama a " | ||
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) |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; | ; | ||
Línea 1312: | Línea 1347: | ||
; SALIDA: | ; SALIDA: | ||
; E = PUERTO (parte alta) correspondiente a esa SEMIFILA | ; E = PUERTO (parte alta) correspondiente a esa SEMIFILA | ||
- | ; Ejemplo: ' | + | ; Ejemplo: ' |
; E = 2 (%00000010) | ; E = 2 (%00000010) | ||
; | ; | ||
Línea 1318: | Línea 1353: | ||
; | ; | ||
Scancode_To_Port_Key: | Scancode_To_Port_Key: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
ConvScn_loop1: | ConvScn_loop1: | ||
- | | + | |
- | | + | |
- | | + | |
ConvScn_tecla: | ConvScn_tecla: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
ConvScn_loop2 | ConvScn_loop2 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; | ; | ||
Línea 1352: | Línea 1387: | ||
; | ; | ||
Leer_Teclado_SSSTTT: | Leer_Teclado_SSSTTT: | ||
- | | + | |
- | | + | |
- | | + | |
tecl_sssttt_loop: | tecl_sssttt_loop: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
tecl_sssttt_nopulsada: | tecl_sssttt_nopulsada: | ||
- | | + | |
; (carry OFF no pulsada/ | ; (carry OFF no pulsada/ | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;;; 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 | + | p1_puerto_disp |
p1_tecla_disp | p1_tecla_disp | ||
- | p1_puerto_izq | + | p1_puerto_izq |
p1_tecla_izq | p1_tecla_izq | ||
- | p1_puerto_der | + | p1_puerto_der |
p1_tecla_der | p1_tecla_der | ||
- | p1_puerto_arriba | + | p1_puerto_arriba |
p1_tecla_arriba | p1_tecla_arriba | ||
- | p1_puerto_abajo | + | p1_puerto_abajo |
p1_tecla_abajo | p1_tecla_abajo | ||
Línea 1426: | Línea 1461: | ||
Ahora, en el bucle principal del programa, usaremos '' | Ahora, en el bucle principal del programa, usaremos '' | ||
- | Esta rutina lo que hace es un bucle de N iteraciones (siendo N el valor de '' | + | Esta rutina lo que hace es un bucle de N iteraciones (siendo N el valor de '' |
\\ | \\ | ||
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 | + | p1_puerto_pause |
p1_tecla_pause | p1_tecla_pause | ||
- | p1_puerto_disp2 | + | p1_puerto_disp2 |
p1_tecla_disp2 | p1_tecla_disp2 | ||
- | p1_puerto_disp | + | p1_puerto_disp |
p1_tecla_disp | p1_tecla_disp | ||
- | p1_puerto_izq | + | p1_puerto_izq |
p1_tecla_izq | p1_tecla_izq | ||
- | p1_puerto_der | + | p1_puerto_der |
p1_tecla_der | p1_tecla_der | ||
- | p1_puerto_arriba | + | p1_puerto_arriba |
p1_tecla_arriba | p1_tecla_arriba | ||
- | p1_puerto_abajo | + | p1_puerto_abajo |
p1_tecla_abajo | p1_tecla_abajo | ||
Línea 1520: | Línea 1555: | ||
</ | </ | ||
- | //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 | + | //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 |
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" | 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" | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | Si queremos utilizar la comprobación por valor, o simplemente vamos a saltar con '' | + | Si queremos utilizar la comprobación por valor, o simplemente vamos a saltar con '' |
\\ | \\ | ||
Línea 1547: | Línea 1582: | ||
</ | </ | ||
- | 3.- Para los casos en los cuales queramos comprobar sólo el bit 0 de una semifila, podemos ahorrarnos la sentencia BIT utilizando | + | 3.- Para los casos en los cuales queramos comprobar sólo el bit 0 de una semifila, podemos ahorrarnos la sentencia BIT utilizando |
<code z80> | <code z80> | ||
; Ejemplo: leyendo la tecla espacio (bit 0) | ; Ejemplo: leyendo la tecla espacio (bit 0) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1591: | Línea 1626: | ||
EsperaSoltar: | EsperaSoltar: | ||
in a,(254) | in a,(254) | ||
- | and 00011111b | + | and %00011111 |
- | cp 00011111b | + | cp %00011111 |
jr nz, | jr nz, | ||
EsperaPulsar: | EsperaPulsar: | ||
in a,(254) | in a,(254) | ||
- | and 00011111b | + | and %00011111 |
- | cp 00011111b | + | cp %00011111 |
jr z, | jr z, | ||
Línea 1626: | Línea 1661: | ||
Bucle: | Bucle: | ||
- | EsperaSoltar: | + | EsperaSoltar: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;Hacer pausa AQUI | ;Hacer pausa AQUI | ||
- | EsperaPulsar: | + | EsperaPulsar: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Hacer pausa AQUI | ; Hacer pausa AQUI | ||
;Se registra la pulsacion... | ;Se registra la pulsacion... | ||
- | | + | |
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 " | actualizar la matriz con las teclas " | ||
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, | + | 910 IF t(i, |
REM si alguna esta seleccionada, | REM si alguna esta seleccionada, | ||
una misma columna. Miramos si hay una tercera en la misma fila | una misma columna. Miramos si hay una tercera en la misma fila |