Revision pausada del Día 3 y 4, y correciones breves de otros Días.

This commit is contained in:
jota 2022-01-13 12:21:44 -03:00
parent 8c972f8398
commit cc10cd9624
5 changed files with 167 additions and 172 deletions

View File

@ -24,15 +24,18 @@ el byte de botón codifica en cada uno de sus ocho bits el estado de ocho "boton
numerando los bits de derecha a izquierda, y de 0 a 7, las teclas correspondientes (y los botones de NES) son
* 0: Ctrl (botón A)
* 1: Alt (botón B)
* 2: Shift (botón de selección)
* 3: Esc (botón de inicio)
* 4: Arriba
* 5: Abajo
* 6: Izquierda
* 7: Derecha
+ <table>
+ <tr><th>bit 7</th><th>bit 6</th><th>bit 5</th><th>bit 4</th><th>bit 3</th><th>bit 2</th><th>bit 1</th><th>bit 0</th></tr>
+ <tr><td>Derecha</td><td>Izquierda</td><td>Abajo</td><td>Arriba</td><td>Esc ("Start" o iniciar))</td><td>Shift ("Select" o seleccionar)</td><td>Alt (botón B)</td><td>Ctrl (botón A)</td></tr>
+ </table>
& * 0: Ctrl (botón A)
& * 1: Alt (botón B)
& * 2: Shift (botón "Select" o seleccionar)
& * 3: Esc (botón "Start" o iniciar)
& * 4: Arriba
& * 5: Abajo
& * 6: Izquierda
& * 7: Derecha
codificar los estados de los botones de esta manera nos permite presionar y leer muchas de estas teclas al mismo tiempo.
@ -121,7 +124,7 @@ ahora, ¿cómo podemos realizar diferentes acciones dependiendo de la tecla que
en primer lugar, tenemos que hacer que nuestro programa sepa qué tecla se ha pulsado para que pueda actuar en consecuencia.
para ello, veamos algunas instrucciones uxntales nuevas.
para ello, veamos algunas instrucciones uxntal nuevas.
# instrucciones de comparación y lógica
@ -160,7 +163,7 @@ AND2, ORA2, EOR2 funcionarán de la misma manera, pero con cortos en lugar de by
### AND
lo siguiente empujará hacia abajo en la pila una bandera que indica si el byte tecla está entre 30 y 39 inclusive, usando 01 para representar 'verdadero', y 00 para representar 'falso0:
lo siguiente empujará hacia abajo en la pila una bandera que indica si el byte tecla está entre 30 y 39 inclusive, usando 01 para representar 'verdadero', y 00 para representar 'falso':
```
.Controlador/tecla DEI ( lee la tecla y la introduce en la pila )
@ -217,7 +220,7 @@ sólo cuando ambas banderas sean falsas, la bandera resultante será falsa.
### EOR
un EOR exclusivo es una operación lógica que tiene un resultado de verdadero sólo cuando una u otra entrada es verdadera. si ambas entradas son verdaderas, o si ambas entradas son falsas, el resultado es falso.
un "exclusive-OR", o también "o-exclusivo", es una operación lógica que tiene un resultado de verdadero sólo cuando una u otra entrada es verdadera. si ambas entradas son verdaderas, o si ambas entradas son falsas, el resultado es falso.
basándose en este comportamiento, esta instrucción puede utilizarse para invertir el valor de una bandera utilizando un valor especial en el que el/los bit(s) que queremos invertir se pongan a 1. este tipo de valores se llaman máscaras.
@ -261,12 +264,12 @@ ok, ahora nuestros programas pueden identificar y almacenar en banderas si un va
## instrucciones para saltos
* JMP: salto incondicional a la dirección de la pila ( direc -- )
* JCN: salto condicional: toma una dirección y un valor de la pila, y si el valor no es 00, salta a la dirección; en caso contrario continúa con la siguiente instrucción ( valor direc -- )
* JMP: "jump" o salto incondicional a la dirección de la pila ( direc -- )
* JCN: "conditional jump" o salto condicional: toma una dirección y un valor de la pila, y si el valor no es 00, salta a la dirección; en caso contrario continúa con la siguiente instrucción ( valor direc -- )
en modo byte, las direcciones que utilizan estas instrucciones son de un byte.
estas direcciones de un byte son relativas y con signo: indican cuántos bytes hay que saltar en la memoria principal desde la posición actual del contador de programa, ya sea hacia delante (positivo) o hacia atrás (negativo). el rango de estas direcciones relativas es de -128 a 127 inclusive.
estas direcciones de un byte son relativas y contienen signos: indican cuántos bytes hay que saltar en la memoria principal desde la posición actual del contador de programa, ya sea hacia delante (positivo) o hacia atrás (negativo). el rango de estas direcciones relativas es de -128 a 127 inclusive.
en modo corto, las direcciones que toman estas instrucciones son absolutas (es decir, de dos bytes de longitud), pero el valor que toma JCN para decidir sigue siendo un byte.
@ -278,8 +281,8 @@ en los días anteriores ya hablamos de algunas de ellas; esta es una recapitulac
* dirección literal en la página cero: .etiqueta (un byte)
* dirección literal en memoria principal: ;label (un corto)
* Dirección literal relativa en la memoria principal: ,label (un byte)
* dirección literal en la memoria principal: :label (un byte)
* dirección literal relativa en la memoria principal: ,label (un byte)
* dirección cruda ("raw") en la memoria principal: :label (un byte)
para definir las etiquetas, utilizamos:
@ -316,9 +319,9 @@ la siguiente subrutina en-controlador ilustra el uso de los saltos, dibujando nu
( establece la dirección del sprite )
;cuadrado .Pantalla/direc DEO2
( dibujar el sprite en el fondo )
( dibuja el sprite en el fondo )
( usando el color 1 para el contorno )
#01 .Pantalla /sprite DEO
#01 .Pantalla/sprite DEO
&fin
BRK
@ -332,7 +335,7 @@ estas direcciones relativas, de un byte, son utilizadas por JCN o JMP.
## saltos condicionales
el siguiente código ilustra el uso de muchas condiciones: el color del sprite cambia en consecuencia si se pulsan las teclas 1, 2 o 3.
el siguiente código ilustra el uso de muchas condiciones: el color del sprite cambia según se pulsen las teclas 1, 2 o 3.
```
@en-controlador
@ -379,7 +382,7 @@ observe cómo las condiciones se escriben una tras otra: siempre que una bandera
también note que este código no está optimizado para el tamaño o la velocidad, sino para la legibilidad.
estaría en tí, por ejemplo, realizar una aritmética con el valor de la tecla que se pulsó para calcular el color a asignar al sprite - ¡podrías inspirarte en tu macro PRINT-DIGIT del día 1!
estaría en tí, por ejemplo, realizar una aritmética con el valor de la tecla que se pulsó para calcular el color a asignar al sprite - ¡podrías inspirarte en tu macro IMPRIMIR-DIGITO del día 1!
# manipulación de la pila
@ -387,14 +390,14 @@ hasta ahora hemos estado usando la pila como un lugar para almacenar operandos d
## instrucciones de pila
uxntal tiene seis instrucciones que actúan sobre los elementos de la pila más cercanos a la parte superior:
uxntal tiene seis instrucciones que actúan sobre los elementos de la pila más cercanos a la parte superior:g
* POP: Eliminar el elemento superior de la pila ( a -- )
* DUP: Duplicar; empujar una copia del elemento superior ( a -- a a )
* SWP: Intercambiar; cambiar el orden de los dos primeros elementos de la pila ( a b -- b a )
* NIP: Elimina el segundo elemento superior de la pila ( a b -- b )
* OVR: "Over" o encima; empuja una copia del segundo elemento superior ( a b -- a b a )
* ROT: Rotar; reordenar los tres primeros elementos de la pila de forma que el tercero esté ahora en la parte superior ( a b c -- b c a )
* POP: eliminar el elemento superior de la pila ( a -- )
* DUP: duplicar; empujar una copia del elemento superior ( a -- a a )
* SWP: "swap" o intercambiar; cambiar el orden de los dos primeros elementos de la pila ( a b -- b a )
* NIP: elimina el segundo elemento superior de la pila ( a b -- b )
* OVR: "over" o encima; empuja una copia del segundo elemento superior ( a b -- a b a )
* ROT: rotar; reordenar los tres primeros elementos de la pila de forma que el tercero esté ahora en la parte superior ( a b c -- b c a )
en modo corto, POP2, DUP2, SWP2, NIP2, OVR2 y ROT2 realizan las mismas acciones pero utilizando cortos en lugar de bytes.
@ -456,7 +459,7 @@ ahora la pila se ve así:
bandera1 tecla <- arriba
```
finalmente podemos proceder a la comparación y al AND
finalmente podemos proceder a la comparación y al AND:
```
#3a LTH ( ¿es menor que 3a? empuja la bandera en la pila )
@ -488,15 +491,15 @@ en el caso que acabamos de discutir la entrada es la tecla que se presiona, pero
esto implica que podríamos escribir la rutina como una macro:
```
ASCII-DIGIT { DUP #2f GTH SWP #3a LTH AND } ( byte -- bandera )
%?DIGITO-ASCII { DUP #2f GTH SWP #3a LTH AND } ( byte -- bandera )
```
y utilizarla con el byte que queramos:
```
#30 ?ASCII-DIGIT ( empuja 01 hacia abajo en la pila )
#20 ?ASCII-DIGIT ( empuja 00 hacia abajo en la pila )
.Controlador/tecla DEI ?ASCII-DIGIT ( empuja la bandera correspondiente a la pila )
#30 ?DIGITO-ASCII ( empuja 01 hacia abajo en la pila )
#20 ?DIGITO-ASCII ( empuja 00 hacia abajo en la pila )
.Controlador/tecla DEI ?DIGITO-ASCII ( empuja la bandera correspondiente a la pila )
```
### duplicados para los condicionales
@ -573,9 +576,9 @@ conoce las máscaras AND a nivel de bits.
una máscara AND es un valor especial que utilizaremos para mantener o perder bits específicos de otro valor dado, como el byte del botón del controlador.
en nuestra máscara AND, pondremos como 1 los bits en las posiciones en las que queramos mantener el valor de los bits de entrada. las posiciones en las que los bits de la máscara sean 0 se convertirán en 0 en la entrada.
en nuestra máscara AND, estableceremos como 1 los bits en las posiciones en las que queramos mantener el valor de los bits de entrada. las posiciones en las que los bits de la máscara sean 0 se convertirán en 0 en la entrada.
por ejemplo, digamos que queremos ver si el bit número 4, que corresponde al botón "arriba", está encendido o apagado, independientemente del estado de los otros botones.
por ejemplo, digamos que queremos ver si el bit número 4, que corresponde al botón Arriba, está encendido o apagado, independientemente del estado de los otros botones.
nuestra máscara AND tendrá un 1 en el bit número 4 (de derecha a izquierda, y empezando por el 0), y 0 en el resto:
@ -592,7 +595,7 @@ AND 0001 0000 ( máscara )
0000 0000 ( resultado )
```
¿qué ocurre si se pulsa el botón de arriba?
¿qué ocurre si se pulsa el botón Arriba?
```
0001 0000 ( botón )
@ -601,7 +604,7 @@ AND 0001 0000 ( máscara )
0001 0000 ( resultado )
```
¿y si se pulsan tanto Up como Ctrl?
¿y si se pulsan tanto Arriba como Ctrl?
```
0001 0001 ( botón )
@ -626,7 +629,7 @@ el siguiente programa uxntal permite dibujar utilizando las teclas de las flecha
las flechas mueven la posición de un sprite, y al pulsar Ctrl mientras se mueve lo dibujará con los colores inversos en relleno y trazo.
observa el uso de las máscaras AND, los saltos condicionales y algunas operaciones de apilamiento.
observa el uso de las máscaras AND, los saltos condicionales y algunas operaciones de la pila.
```
( dibujar-con-teclado.tal )
@ -659,12 +662,12 @@ BRK
&contorno
#01 .Pantalla/sprite DEO ( dibujar contorno )
,&comprobar-filas JMP ( continuar con la comprobación de las filas )
,&comprobar-flechas JMP ( continuar con la comprobación de las flechas )
&relleno
#04 .Pantalla/sprite DEO ( dibujar relleno )
&comprobar-filas
&comprobar-flechas
( usar el byte del botón de la pila )
DUP #10 AND ( aislar el bit 4, correspondiente a Arriba )
,&arriba JCN ( saltar si no es 0 )
@ -682,7 +685,7 @@ BRK
POP
BRK
&abajo
.Pantalla/y DEI2 #0008 ADD2 .Pantalla/y DEO2 ( incremento y )
.Pantalla/y DEI2 #0008 ADD2 .Pantalla/y DEO2 ( incrementa y )
POP
BRK
&izquierda
@ -690,7 +693,7 @@ BRK
POP
BRK
&derecha
.Pantalla/x DEI2 #0008 ADD2 .Pantalla/x DEO2 ( incremento x )
.Pantalla/x DEI2 #0008 ADD2 .Pantalla/x DEO2 ( incrementa x )
POP
BRK
BRK
@ -710,22 +713,22 @@ algunas posibilidades para que practiques:
recuerde que .Pantalla/x es una dirección literal en la página cero, es decir, empuja un byte correspondiente a la dirección de la sub-etiqueta Pantalla/x :)
# posibilidades de práctica
# practica posibilidades
¡aquí tienes otras ideas para que practiques con lo que hemos tratado hoy!
¡aquí tienes otras ideas para que practiques con lo que hemos cubierto hoy!
* dibujar un controlador virtual que muestre cuáles de sus botones, mapeados a teclas del teclado, están siendo presionados
* crear una especie de máquina de escribir que dibuje diferentes símbolos y mueva el cursor de dibujo dependiendo de la tecla que se haya pulsado
* dibujar un personaje que cambie su estado según la tecla que se haya pulsado. ¿tal vez utilizar múltiples fichas para dibujarlo?
* crea un simple tablero de tres en raya para dos jugadores: una tecla dibuja una X, otra dibuja una O, y las flechas permiten elegir la casilla a dibujar.
* dibujar un personaje que cambie su estado según la tecla que se haya pulsado. ¿tal vez utilizar múltiples tiles para dibujarlo?
* crea un simple tablero de tres-en-raya para dos jugadores: una tecla dibuja una X, otra dibuja una O, y las flechas permiten elegir la casilla a dibujar.
¡ten en cuenta que para un movimiento interactivo suave puede ser mejor utilizar el vector de pantalla que se llama 60 veces por segundo!
¡ten en cuenta que para un suave movimiento interactivo puede ser mejor utilizar el vector de pantalla que se llama 60 veces por segundo!
¡lo cubriremos en profundidad en el próximo día del tutorial!
# instrucciones del día 3
estas son todas las instrucciones uxntales de las que hemos hablado hoy
¡estas son todas las instrucciones uxntal de las que hemos hablado hoy!
## instrucciones de comparación
@ -747,17 +750,16 @@ estas son todas las instrucciones uxntales de las que hemos hablado hoy
## pila
* POP: Quitar el elemento superior de la pila ( a -- )
* DUP: Duplicar; empujar una copia del elemento superior ( a -- a a )
* SWP: Intercambio; cambia el orden de los dos primeros elementos de la pila ( a b -- b a )
* OVR: "Over" o encima; empuja una copia del segundo elemento superior ( a b -- a b a )
* ROT: Rotar; reordenar los tres primeros elementos de la pila de forma que el tercero esté ahora en la parte superior ( a b c -- b c a )
* POP: eliminar el elemento superior de la pila ( a -- )
* DUP: duplicar; empujar una copia del elemento superior ( a -- a a )
* SWP: "swap" o intercambiar; cambiar el orden de los dos primeros elementos de la pila ( a b -- b a )
* NIP: elimina el segundo elemento superior de la pila ( a b -- b )
* OVR: "over" o encima; empuja una copia del segundo elemento superior ( a b -- a b a )
* ROT: rotar; reordenar los tres primeros elementos de la pila de forma que el tercero esté ahora en la parte superior ( a b c -- b c a )
# día 4
en el tutorial uxn día 4 cubrimos el uso del vector de pantalla para crear animaciones, ya sean interactivas o no.
=> ./tutorial_de_uxn_día_4.gmi {tutorial de uxn día 4}
en el {tutorial de uxn día 4} cubrimos el uso del vector de pantalla para crear animaciones, ya sean interactivas o no.
¡también exploramos las posibilidades de usar "variables" en uxntal que pueden ayudarnos a crear programas más elaborados!

View File

@ -4,7 +4,7 @@
aquí hablamos del bucle de animación del ordenador varvara, a través de su vector de dispositivo de pantalla.
también hablamos del uso de la memoria del programa como un espacio para datos usando "variables". esto nos permite guardar y recuperar datos durante el tiempo de ejecución de nuestros programas, y puede ahorrarnos complejas luchas en la pila :)
también hablamos del uso de la memoria del programa como un espacio para datos usando "variables". esto nos permite guardar y recuperar datos durante el tiempo de ejecución de nuestros programas, y puede ahorrarnos manejos complejos en la pila :)
# el vector pantalla
@ -14,9 +14,7 @@ discutimos el dispositivo de pantalla de varvara en el día 2, pero nos saltamos
|20 @Pantalla [ &vector $2 &ancho $2 &alto $2 &pad $2 &x $2 &y $2 &direc $2 &pixel $1 &sprite $1 ]
```
ahora que ya tenemos el concepto de vectores de dispositivos en el tutorial de uxn día 3, ¡vamos a entrar de lleno en cómo usar el de la pantalla!
=> ./tutorial_de_uxn_día_3.gmi {tutorial de uxn día 3}
ahora que ya tenemos el concepto de vectores de dispositivos en el {tutorial de uxn día 3}, ¡vamos a entrar de lleno en cómo usar el de la pantalla!
## asignación
@ -25,7 +23,8 @@ la siguiente línea de uxntal asignaría la dirección absoluta de la etiqueta e
```
;en-cuadro .Pantalla/vector DEO2
```
uxn saltará a la ubicación de la etiqueta a un ritmo de 60 veces por segundo: podemos utilizar la subrutina bajo en-cuadro para cambiar el contenido de la pantalla, generando animación, y/o también podemos utilizarla para otros propósitos relacionados con la temporización.
uxn saltará a la ubicación de la etiqueta a una frecuencia de 60 veces por segundo: podemos utilizar la subrutina bajo en-cuadro para cambiar el contenido de la pantalla, generando animación, y/o también podemos utilizarla para otros propósitos relacionados con la temporización.
## una línea que crece
@ -40,7 +39,7 @@ el siguiente programa demuestra un uso básico pero potente del vector pantalla:
( init )
|0100
( establecer colores del sistema )
( establecer los colores del sistema )
#2ce9 .Sistema/r DEO2
#01c0 .Sistema/g DEO2
#2ce5 .Sistema/b DEO2
@ -49,7 +48,7 @@ el siguiente programa demuestra un uso básico pero potente del vector pantalla:
#0008 .Pantalla/x DEO2
#0008 .Pantalla/y DEO2
( establecer vector de pantalla )
( establecer el vector de pantalla )
;en-cuadro .Pantalla/vector DEO2
BRK
@ -72,10 +71,10 @@ aquí, el código para incrementar Pantalla/x es llamado dentro de la subrutina
estos son algunos cambios para que los pruebes y practiques:
* ¿cómo harías que la línea creciera en vertical? y en diagonal?
* ¿cómo harías que la línea creciera en vertical? ¿y en diagonal?
* ¿cómo harías que la línea creciera en sentido contrario?
* ¿Cómo harías que la línea fuera punteada?
* ¿Cómo harías que la línea dejara de crecer en una determinada posición? (¡recuerda los saltos condicionales!)
* ¿cómo harías que la línea fuera punteada?
* ¿cómo harías que la línea dejara de crecer en una determinada posición? (¡recuerda los saltos condicionales!)
* ¿cómo dibujarías utilizando un sprite en lugar de un píxel?
# variables
@ -84,9 +83,9 @@ estos son algunos cambios para que los pruebes y practiques:
merece señalar que muchas de estas posibilidades requieren formas de almacenar y recuperar datos entre fotogramas.
en el ejemplo anterior, estamos usando los puertos de pantalla para las coordenadas x e y como una forma de almacenar las coordenadas del pixel.
en el ejemplo anterior, estamos usando los puertos de pantalla para las coordenadas x e `y` como una forma de almacenar las coordenadas del pixel.
pero ¿qué sucede cuando queremos dibujar diferentes objetos, cada uno con su propio conjunto de coordenadas y otras características que pueden cambiar con el tiempo?
pero, ¿qué sucede cuando queremos dibujar diferentes objetos, cada uno con su propio conjunto de coordenadas y otras características que pueden cambiar con el tiempo?
¡podemos utilizar etiquetas en la memoria del programa para conseguirlo!
@ -104,7 +103,7 @@ sin embargo, no hemos utilizado los datos directamente; hemos enviado su direcci
### etiquetas
podríamos utilizar un sistema similar para almacenar, por ejemplo, las coordenadas x e y en lugar de los datos del sprite:
podríamos utilizar un sistema similar para almacenar, por ejemplo, las coordenadas x e `y` en lugar de los datos del sprite:
```
@pixel-x 0008
@ -117,8 +116,8 @@ o si no quisiéramos iniciarlas aquí, podríamos definirlas de la siguiente man
@pixel-x $2
@pixel-y $2
```
recuerda que $2 crea un pad relativo de dos bytes: esto hace que pixel-y sea una etiqueta para una dirección en memoria dos bytes después de pixel-x. y cualquier código posterior ocurrirá dos bytes después de pixel-y.
recuerda que $2 crea un pad relativo de dos bytes: esto hace que píxel-y sea una etiqueta para una dirección en memoria dos bytes después de pixel-x. y cualquier código posterior ocurrirá dos bytes después de píxel-y.
también podríamos usar etiquetas y sub-etiquetas, de manera muy similar a como definimos los dispositivos y sus puertos:
@ -132,8 +131,8 @@ también podríamos usar etiquetas y sub-etiquetas, de manera muy similar a como
aquí están las dos instrucciones que nos ayudarían:
* LDA: carga y empuja hacia abajo en la pila el valor en la dirección absoluta dada ( dirección -- valor )
* STA: almacena en la dirección absoluta dada el valor dado ( dirección valor -- )
* LDA: "load", carga y empuja hacia abajo en la pila el valor en la dirección absoluta dada ( dirección -- valor )
* STA: "store", almacena en la dirección absoluta dada el valor dado ( dirección valor -- )
como ya hemos comentado, una dirección absoluta siempre tendrá una longitud de dos bytes.
@ -189,7 +188,7 @@ las variables con dirección absoluta funcionan bien para los casos en los que q
sin embargo, uxn tiene un mecanismo mejor para esos casos: ¡la página cero!
como recordará, la página cero consiste en las primeras 256 direcciones de la memoria del programa. normalmente, un programa comienza en la dirección 0100, que es la siguiente dirección después de la página cero.
como recordarás, la página cero consiste en las primeras 256 direcciones de la memoria del programa. normalmente, un programa comienza en la dirección 0100, que es la siguiente dirección después de la página cero.
podemos referirnos a cualquiera de las 256 direcciones de la página cero utilizando un solo byte, en lugar de los dos bytes que se necesitan para las direcciones absolutas.
@ -212,8 +211,8 @@ para referirnos a ellas, utilizaríamos la runa punto (.) para las direcciones l
las instrucciones para cargar (leer) y almacenar (escribir) desde y hacia la página cero son:
* LDZ: carga y empuja hacia abajo en la pila el valor en la dirección de la página cero dada ( dirección -- valor )
* STZ: almacena en la dirección de la página cero el valor dado ( dirección del valor -- )
* LDZ: "load", carga y empuja hacia abajo en la pila el valor en la dirección de la página cero dada ( dirección -- valor )
* STZ: "store", almacena en la dirección de la página cero el valor dado ( dirección del valor -- )
en estas instrucciones, la dirección siempre será de un byte.
@ -221,7 +220,7 @@ en el modo corto, LDZ2 cargará un corto desde la dirección dada, y STZ2 almace
### ejemplos
el siguiente ejemplo consiste en la misma línea que crece, pero ahora utilizando la página cero para almacenar las coordenadas x e y del píxel en lugar de los puertos x e y de la pantalla.
el siguiente ejemplo consiste en la misma línea que crece, pero ahora utilizando la página cero para almacenar las coordenadas x e `y` del píxel en lugar de los puertos x e `y` de la pantalla.
en este caso el programa es más largo, pero puede ser visto como una buena plantilla para tener otras líneas que se comporten de diferentes maneras:
@ -238,7 +237,7 @@ en este caso el programa es más largo, pero puede ser visto como una buena plan
( init )
|0100
( establecer colores del sistema )
( establecer los colores del sistema )
#2ce9 .Sistema/r DEO2
#01c0 .Sistema/g DEO2
#2ce5 .Sistema/b DEO2
@ -247,7 +246,7 @@ en este caso el programa es más largo, pero puede ser visto como una buena plan
#0008 .pixel/x STZ2
#0008 .pixel/y STZ2
( establecer vector de pantalla )
( establecer el vector de pantalla )
;en-cuadro .Pantalla/vector DEO2
BRK
@ -266,9 +265,9 @@ BRK
notemos el uso de la runa literal de dirección de página cero (.) para referirse a la etiqueta .pixel.
además, observe que en el caso de .pixel la dirección se refiere a la página cero, a la que se accede con LDZ/STZ, y en el caso de .Pantalla la dirección se refiere al espacio de direcciones entrada/salida (i/o), al que se accede con DEO/DEI.
además, observe que en el caso de .pixel la dirección se refiere a la página cero, a la que se accede con LDZ/STZ, y en el caso de .Pantalla la dirección se refiere al espacio de direcciones entrada/salida (i/o), al que se accede con DEI/DEO.
### un poco de práctica en la pila
### un poco de práctica de manipulación en la pila
nota que las siguientes instrucciones también incrementarían .pixel/x, pero estableciendo su dirección sólo una vez:
@ -283,7 +282,7 @@ esta línea de código contiene la misma cantidad de bytes que la anterior.
una posible desventaja es que podría ser menos legible. pero una posible ventaja es que podría convertirse en una macro:
```
( incrementar un short desde la página cero )
( incrementar un corto desde la página cero )
%PC-INC2 { DUP LDZ2 INC2 ROT STZ2 } ( pc-dirección -- )
```
@ -293,14 +292,14 @@ otra posibilidad que tenemos en uxn y que podría ser más apropiada para las "v
de forma similar a las variables de la página cero, para direccionar estas variables sólo necesitamos un byte.
sin embargo, como estas direcciones se dan como offsets relativos y con signo, sólo se pueden alcanzar si están dentro de los 256 bytes que rodean a la instrucción que las carga o almacena.
sin embargo, como estas direcciones se dan como desfases ("offsets") relativos y con signo, sólo se pueden alcanzar si están dentro de los 256 bytes que rodean a la instrucción que las carga o almacena.
### instrucciones: LDR, STR
las instrucciones para trabajar de esta manera son:
* LDR: carga y empuja hacia abajo en la pila el valor en la dirección relativa dada ( dirección -- valor )
* STR: almacena en la dirección relativa dada el valor dado ( dirección valor -- )
* LDR: "load", carga y empuja hacia abajo en la pila el valor en la dirección relativa dada ( dirección -- valor )
* STR: "store", almacena en la dirección relativa dada el valor dado ( dirección valor -- )
similar a LDZ y STZ, en estas instrucciones la dirección siempre será de un byte.
@ -326,9 +325,9 @@ BRK
@pixel [ &x $2 &y $2 ]
```
nótese el uso de la runa coma (,) para indicar que es una dirección relativa; uxnasm calcula el offset requerido asumiendo que será utilizado en la siguiente instrucción.
nótese el uso de la runa coma (,) para indicar que es una dirección relativa; uxnasm calcula el desfase requerido asumiendo que será utilizado en la siguiente instrucción.
en este caso realmente no podemos duplicar ese offset como hicimos anteriormente con la dirección de página cero, porque es específica de la posición en el código en que fue escrita.
en este caso realmente no podemos duplicar ese desfase como hicimos anteriormente con la dirección de página cero, porque es específica de la posición en el código en que fue escrita.
si declaráramos estas variables como sub-etiquetas de en-cuadro, el código quedaría como sigue:
@ -338,13 +337,13 @@ si declaráramos estas variables como sub-etiquetas de en-cuadro, el código que
,&pixel-x LDR2 .Pantalla/x DEO2
,&pixel-y LDR2 .Pantalla/y DEO2
( dibujar un pixel en el fondo con el color 1 )
( dibujar un píxel en el fondo con el color 1 )
#01 .Pantalla/pixel DEO
( incrementa pixel/x )
( incrementa píxel/x )
,&pixel-x LDR2 INC2 ,&pixel-x STR2
BRK
( variables locales en-cuadro )
( variables locales de en-cuadro )
&pixel-x $2 &pixel-y $2
```
@ -376,7 +375,7 @@ eso daría como resultado un sprite que se mueve y que además deja un rastro:
### sin rastro
ok, eso puede ser útil en algunos casos, pero ¿cómo podemos evitar dejar el rastro?
ok, eso puede ser útil en algunos casos, pero, ¿cómo podemos evitar dejar el rastro?
una posible forma de conseguirlo sería siguiendo este orden de operaciones dentro de la subrutina en-cuadro:
@ -410,7 +409,7 @@ el siguiente programa ilustra los puntos anteriores, haciendo que nuestro cuadra
( init )
|0100
( establecer colores del sistema )
( establecer los colores del sistema )
#2ce9 .Sistema/r DEO2
#01c0 .Sistema/g DEO2
#2ce5 .Sistema/b DEO2
@ -421,7 +420,7 @@ el siguiente programa ilustra los puntos anteriores, haciendo que nuestro cuadra
( fijar la dirección del sprite )
;cuadrado .Pantalla/direc DEO2
( establecer vector de pantalla )
( establecer el vector de pantalla )
;en-cuadro .Pantalla/vector DEO2
BRK
@ -448,7 +447,7 @@ BRK
nítido, ¿no? :)
como esto es sólo un ejemplo para ilustrar un punto, hay algunas cosas que podrían ser optimizadas para hacer nuestro programa más pequeño, y hay algunas cosas que podrían ser útiles pero fueron omitidas. por ejemplo, no hay un valor inicial para la coordenada x, o la coordenada y no se utiliza.
como esto es sólo un ejemplo para ilustrar un punto, hay algunas cosas que podrían ser optimizadas para hacer nuestro programa más pequeño, y hay algunas cosas que podrían ser útiles pero fueron omitidas. por ejemplo, no hay un valor inicial para la coordenada x, o la coordenada `y` no se utiliza.
### posibilidades adicionales
@ -475,7 +474,7 @@ aquí hay algunas preguntas para que reflexiones y pruebes:
## cambio de posición interactivo
cuando usamos el vector controlador, estamos actuando en base a un cambio en el/los botón/es o tecla/s que fueron presionados o liberados. esto puede ser muy útil para algunas aplicaciones.
cuando usamos el vector controlador, estamos actuando en base a un cambio en el/los botón/es o tecla/s que fueron presionados o soltados. esto puede ser muy útil para algunas aplicaciones.
pero, ¿cómo podemos tratar de hacer una acción continua cuando una tecla se mantiene presionada?
@ -487,11 +486,9 @@ en algunos sistemas operativos, si mantenemos una tecla pulsada, ésta dispara e
el siguiente programa nos permite controlar la posición horizontal de nuestro cuadrado mediante las teclas de dirección.
=> ./img/screencap_uxn-moving-square.gif animado que muestra un cuadrado moviéndose horizontalmente en la pantalla, aparentemente controlado por un humano.
=> ./img/screencap_uxn-moving-square.gif animación que muestra un cuadrado moviéndose horizontalmente en la pantalla, aparentemente controlado por un humano.
¡nótese las similitudes entre el programa anterior, y lo que cubrimos en el tutorial de uxn del día 3!
=> ./tutorial_de_uxn_día_3.gmi {tutorial de uxn día 3}
¡nótese las similitudes entre el programa anterior, y lo que cubrimos en el {tutorial de uxn día 3}!
```
( hola-sprite-enmovimiento.tal )
@ -511,7 +508,7 @@ el siguiente programa nos permite controlar la posición horizontal de nuestro c
( init )
|0100
( establecer colores del sistema )
( establecer los colores del sistema )
#2ce9 .Sistema/r DEO2
#01c0 .Sistema/g DEO2
#2ce5 .Sistema/b DEO2
@ -522,7 +519,7 @@ el siguiente programa nos permite controlar la posición horizontal de nuestro c
( fijar la dirección del sprite )
;cuadrado .Pantalla/direc DEO2
( establecer vector de pantalla )
( establecer el vector de pantalla )
;en-cuadro .Pantalla/vector DEO2
BRK
@ -624,31 +621,31 @@ podemos aplicar esas macros después de incrementar o decrementar. por ejemplo:
otra estrategia de animación consistiría en cambiar el sprite que se dibuja en una posición determinada.
podrías tener una secuencia de sprites/marcos y animarlos ejecutándolos en secuencia
¡podrías tener una secuencia de sprites/fotogramas y animarlos ejecutándolos en secuencia!
## los fotogramas
a efectos prácticos te recomendaría tener un número de fotogramas correspondiente a una potencia de dos, como 2, 4, 8, 16, 32, etc.
para efectos prácticos te recomendaría tener un número de fotogramas correspondiente a una potencia de dos, como 2, 4, 8, 16, 32, etc.
por ejemplo, lo siguiente es una secuencia de ocho sprites de 1bpp que corresponden a una línea diagonal que se mueve desde abajo a la derecha hasta arriba a la izquierda:
```
@animación
&fotograma0 00 00 00 00 01 03
&fotograma1 00 00 00 01 03 06 0c
@animacion
&fotograma0 00 00 00 00 00 00 01 03
&fotograma1 00 00 00 00 01 03 06 0c
&fotograma2 00 00 01 03 06 0c 18 30
&fotograma3 01 03 06 0c 18 30 60 c0
&fotograma4 03 06 0c 18 30 60 c0 80
&fotograma5 0c 18 30 60 c0 80 00 00
&fotograma6 30 60 c0 80 00 00 00
&fotograma7 c0 80 00 00 00 00 00
&fotograma6 30 60 c0 80 00 00 00 00
&fotograma7 c0 80 00 00 00 00 00 00
```
nótese que cada fotograma consta de 8 bytes. eso implica que hay un desplazamiento de 8 bytes entre las direcciones correspondientes a cada subetiqueta.
nótese que cada fotograma consta de 8 bytes. eso implica que hay un desfase de 8 bytes entre las direcciones correspondientes a cada subetiqueta.
por ejemplo, la dirección de &fotograma1 sería 8 bytes más que la dirección de &fotograma0.
los fotogramas que utilizas también podrían estar compuestos por sprites de 2bpp. en ese caso, el desplazamiento entre fotogramas sería de 16 en decimal (10 en hexadecimal) bytes.
los fotogramas que utilizas también podrían estar compuestos por sprites de 2bpp. en ese caso, el desfase entre fotogramas sería de 16 en decimal (10 en hexadecimal) bytes.
## conteo de fotogramas
@ -658,17 +655,18 @@ para tener una animación compuesta por esos fotogramas necesitamos cambiar la d
una forma de conseguirlo es teniendo una "variable global" en la página cero que cuente los fotogramas del programa. además, tendríamos que tener ese conteo acotado en un rango correspondiente a la cantidad de fotogramas de nuestra animación.
ya sabemos cómo hacer la primera parte, y más o menos sabemos cómo hacer la segunda
¡ya sabemos cómo hacer la primera parte, y más o menos sabemos cómo hacer la segunda!
### cargar, incrementar y almacenar la cuenta de fotogramas
en la página cero declaramos la etiqueta para nuestro cuentafotogramas. utilizaremos la abreviación "cuentaftg" para ayudar a la legibilidad:
en la página cero declaramos la etiqueta para nuestro cuentafotogramas.
```
( página cero )
|0000
@cuentaftg $1
```
y en la subrutina en-cuadro lo incrementamos:
```
@ -711,9 +709,7 @@ podríamos definir esta operación de módulo rápido como una macro para hacer
%8MOD { #07 AND } ( byte -- byte%8 )
```
si esto no te ha quedado muy claro, te recomiendo que vuelvas a mirar el tutorial de uxn del día 3, en particular la discusión de las operaciones lógicas.
=> ./tutorial_de_uxn_día_3.gmi {tutorial de uxn día 3}
si esto no te ha quedado muy claro, te recomiendo que vuelvas a mirar el {tutorial de uxn día 3}, en particular la discusión de las operaciones lógicas.
## aritmética de punteros
@ -721,32 +717,32 @@ si esto no te ha quedado muy claro, te recomiendo que vuelvas a mirar el tutoria
podríamos usar varios saltos condicionales, o podríamos usar una forma más divertida que se puede llamar aritmética de punteros :)
observa que la subetiqueta para el primer fotograma (fotograma0) de nuestra animación tiene la misma dirección que la etiqueta para toda la animación. y, como ya hemos mencionado, el siguiente fotograma (fotograma1) comienza 8 bytes después.
observa que la subetiqueta para el primer fotograma (fotograma0) de nuestra animación tiene la misma dirección que la etiqueta para toda la animación. y, como ya mencionamos, el siguiente fotograma (fotograma1) comienza 8 bytes después.
la subetiqueta de cada fotograma siguiente está 8 bytes después de la anterior.
la subetiqueta para cada fotograma siguiente está 8 bytes después de la anterior.
o, otra forma de verlo:
* el fotograma 0 es 0 bytes después de la etiqueta de animación
* El fotograma 1 es 8 bytes después de la etiqueta de animación
* El fotograma 2 es de 16 bytes después de la etiqueta de animación
* El fotograma 3 es de 24 bytes después de la etiqueta de animación
* el fotograma0 esta 0 bytes después de la etiqueta de animación
* el fotograma1 esta 8 bytes después de la etiqueta de animación
* el fotograma2 esta 16 bytes después de la etiqueta de animación
* el fotograma3 esta 24 bytes después de la etiqueta de animación
* y así sucesivamente
generalizando, ¡el fotogramaN esta (N veces 8) bytes después de la etiqueta de animación!
esto significa que si obtenemos la dirección absoluta de la etiqueta de animación, y le añadimos (N veces 8) bytes, obtendremos la dirección absoluta del fotogramaN :)
esta cantidad de bytes que separa cada subetiqueta se llama offset.
la cantidad de bytes que separa cada subetiqueta se llama "offset" o desfase.
### calculando el offset
### calculando el desfase
después de aplicar el módulo 8 a nuestro cuentafotogramas podemos multiplicarlo por 8 para obtener el offset respecto a la etiqueta de la animación:
después de aplicar el módulo 8 a nuestro cuentafotogramas podemos multiplicarlo por 8 para obtener el desfase respecto a la etiqueta de la animación:
```
.cuentaftg LDZ ( cargar cuentafotograma )
8MOD ( aplicar el módulo 8 para obtener la secuencia entre 0 y 7 )
#08 MUL ( multiplicar por 8 para obtener el desplazamiento )
#08 MUL ( multiplicar por 8 para obtener el desfase )
```
### de byte a corto
@ -755,7 +751,7 @@ nota que hasta ahora hemos estado trabajando con bytes, y todo ha ido bien.
sin embargo, ¡las direcciones absolutas son cortos!
esto significa que tenemos que convertir nuestro offset en un short para poder añadirlo a la dirección de los datos de la animación.
esto significa que tenemos que convertir nuestro desfase en un corto para poder añadirlo a la dirección de los datos de la animación.
una forma de hacerlo es con esta macro que añade un 00 antes del elemento superior de la pila:
@ -768,30 +764,30 @@ nuestro código quedaría de la siguiente manera
```
.cuentaftg LDZ ( cargar cuentafotograma )
8MOD ( aplicar el módulo 8 para obtener la secuencia entre 0 y 7 )
#08 MUL ( multiplicar por 8 para obtener el desplazamiento )
#08 MUL ( multiplicar por 8 para obtener el desfase )
A-CORTO ( convertir a corto )
```
otra forma, menos clara pero bastante divertida (y algo más corta en memoria de programa), consistiría en pulsar el 00 antes de que ocurra cualquier otra cosa:
otra forma, menos clara pero bastante divertida (y algo más corta en memoria de programa), consistiría en empujar el 00 antes de que ocurra cualquier otra cosa:
```
#00 ( empujar el byte alto del offset )
#00 ( empujar el byte alto del desfase )
.cuentaftg LDZ ( cargar cuentafotograma )
8MOD ( aplicar el módulo 8 para obtener la secuencia entre 0 y 7 )
#08 MUL ( multiplicar por 8 para obtener el offset )
#08 MUL ( multiplicar por 8 para obtener el desfase )
```
### añadiendo el offset
### añadiendo el desfase
añadir este offset a la dirección de nuestra animación es comparativamente sencillo:
añadir este desfase a la dirección de nuestra animación es comparativamente sencillo:
```
.cuentaftg LDZ ( cargar cuentafotogramas )
8MOD ( aplicar el módulo 8 para obtener la secuencia entre 0 y 7 )
#08 MUL ( multiplicar por 8 para obtener el desplazamiento )
#08 MUL ( multiplicar por 8 para obtener el desfase )
A-CORTO ( convertir a corto )
;animacion ( obtener la dirección de la animación )
ADD2 ( añadir el desplazamiento a la dirección )
ADD2 ( añadir el desfase a la dirección )
```
y entonces podríamos enviar eso al puerto Pantalla/direc:
@ -837,19 +833,19 @@ la sección "borrar el sprite" no es realmente necesaria en este caso debido a l
( init )
|0100
( set system colors )
( establecer los colores del sistema )
#2ce9 .Sistema/r DEO2
#01c0 .Sistema/g DEO2
#2ce5 .Sistema/b DEO2
( fijar Pantalla/x y y a la mitad de la pantalla menos 4 )
( fijar Pantalla/x e `y` a la mitad de la pantalla, menos 4 )
.Pantalla/ancho DEI2 MITAD2 #0004 SUB2 .Pantalla/x DEO2
.Pantalla/alto DEI2 MITAD2 #0004 SUB2 .Pantalla/y DEO2
( establecer la dirección del sprite )
;animación .Pantalla/direc DEO2
;animacion .Pantalla/direc DEO2
( establecer vector de pantalla )
( establecer el vector de pantalla )
;en-cuadro .Pantalla/vector DEO2
BRK
@ -865,10 +861,10 @@ BRK
( 2: actualizar la dirección del sprite )
.cuentaftg LDZ ( cargar cuentafotograma )
8MOD ( aplicar el módulo 8 para obtener la secuencia entre 0 y 7 )
#08 MUL ( multiplicar por 8 para obtener el desplazamiento )
TO-SHORT ( convertir a corto )
;animation ( obtener la dirección de la animación )
ADD2 ( añadir el offset a la dirección )
#08 MUL ( multiplicar por 8 para obtener el desfase )
A-CORTO ( convertir a corto )
;animacion ( obtener la dirección de la animación )
ADD2 ( añadir el desfase a la dirección )
.Pantalla/direc DEO2 ( establecer la dirección calculada )
( dibujar sprite en el primer plano con el color 2 y 3 )
@ -877,25 +873,25 @@ BRK
( datos del sprite )
@animacion
&fotograma0 00 00 00 00 01 03
&fotograma1 00 00 00 01 03 06 0c
&fotograma0 00 00 00 00 00 00 01 03
&fotograma1 00 00 00 00 01 03 06 0c
&fotograma2 00 00 01 03 06 0c 18 30
&fotograma3 01 03 06 0c 18 30 60 c0
&fotograma4 03 06 0c 18 30 60 c0 80
&fotograma5 0c 18 30 60 c0 80 00 00
&fotograma6 30 60 c0 80 00 00 00
&fotograma7 c0 80 00 00 00 00 00
&fotograma6 30 60 c0 80 00 00 00 00
&fotograma7 c0 80 00 00 00 00 00 00
```
no era tan complicado, ¿verdad? :) este ejemplo incluye muchos conceptos que merecen ser estudiados, ¡así que te invito a leerlo con atención!
para algunas posibilidades de diversión, te invito a dibujar el tile varias veces en diferentes lugares y posiblemente con diferentes modos de rotación! eso puede generar animaciones más interesantes!
para algunas posibilidad divertidas, ¡te invito a dibujar el tile varias veces en diferentes lugares y posiblemente con diferentes modos de rotación! ¡eso puede generar animaciones más interesantes!
o, mejor aún, ¡diseña y utiliza tus propios sprites!
## ¡más despacio!
hasta ahora, todo lo que hemos estado haciendo ha sucedido a 60 cuadros por segundo, ¡eso puede ser demasiado rápido para algunas aplicaciones!
hasta ahora, todo lo que hemos estado haciendo ha sucedido a 60 fotogramas por segundo, ¡eso puede ser demasiado rápido para algunas aplicaciones!
afortunadamente, podemos usar algo de aritmética simple con nuestro cuentafotograma para desacelerar sus efectos.
@ -916,10 +912,10 @@ podemos utilizar estas macros para dividir la frecuencia en nuestro código:
.cuentaftg LDZ ( cargar cuentafotograma )
CUARTO ( dividir entre 4 la frecuencia )
8MOD ( aplicar el módulo 8 para obtener la secuencia entre 0 y 7 )
#08 MUL ( multiplicar por 8 para obtener el desplazamiento )
#08 MUL ( multiplicar por 8 para obtener el desfase )
A-CORTO ( convertir a corto )
;animacion ( obtener la dirección de la animación )
ADD2 ( añadir el offset a la dirección )
ADD2 ( añadir el desfase a la dirección )
.Pantalla/direc DEO2 ( establecer la dirección calculada )
```
@ -929,11 +925,11 @@ ah, ¡mucho mejor!
## potencias de dos no
ten en cuenta que si quieres dividir la frecuencia a números que no son potencias de 2, podrías empezar a ver algunos glitches aproximadamente cada 4 segundos: esto se debe a que el cuentafotograma se sobrepasa y no da una buena secuencia de resultados para esos divisores.
ten en cuenta que si quieres dividir la frecuencia a números que no son potencias de 2, podrías empezar a ver algunas fallas ("glitches") aproximadamente cada 4 segundos: esto se debe a que el cuentafotograma se sobrepasa y no da una buena secuencia de resultados para esos divisores.
esto también puede ocurrir si tienes una animación que consta de un número de fotogramas que no es una potencia de 2, y utilizas una operación MOD normal para calcular el desplazamiento al fotograma correspondiente.
esto también puede ocurrir si tienes una animación que consta de un número de fotogramas que no es una potencia de 2, y utilizas una operación MOD normal para calcular el desfase al fotograma correspondiente.
la solución más sencilla para estos problemas sería utilizar un número de fotogramas de tamaño reducido que sólo causara esos fallos de sobreflujo aproximadamente cada 18 minutos.
la solución más sencilla para estos problemas sería utilizar un número de fotogramas de pequeño tamaño que sólo causara esos fallos de sobreflujo aproximadamente cada 18 minutos.
tendrías que adaptar el programa para que funcione con ese tamaño de cuentafotograma - ¡siento y pienso que es un buen ejercicio!
@ -954,9 +950,7 @@ en modo corto, estas instrucciones cargan o almacenan cortos desde o hacia la me
# día 5
en el tutorial de uxn día 5 introducimos el dispositivo de ratón varvara para explorar más interacciones posibles, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo de mantenimiento.
=> ./tutorial_de_uxn_día_5.gmi {tutorial de uxn día 5}
en el {tutorial de uxn día 5} introducimos el dispositivo de ratón varvara para explorar más interacciones posibles, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
¡también discutimos posibles estructuras para crear bucles y programas más complejos utilizando estos recursos!

View File

@ -1,6 +1,6 @@
# tutorial de uxn: día 5, el ratón y chucherías de uxntal
esta es la quinta sección del {tutorial de uxn}! aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo de retención.
esta es la quinta sección del {tutorial de uxn}! aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
también discutimos posibles estructuras para crear bucles y programas más complejos utilizando estos recursos.

View File

@ -852,7 +852,7 @@ para el movimiento de la pelota, seguiremos la misma estructura que antes:
se vería algo como lo siguiente, y podría sentarse a lo largo de los procedimientos equivalentes para las palas dentro de la subrutina en-cuadro:
```
( dentro de en-marco )
( dentro de en-cuadro )
( borrar pelota )
COLOR-BORRAR ;dibuja-pelota JSR2
@ -1363,10 +1363,10 @@ aquí está todo el código que hemos escrito hoy:
BRK
```
## en-marco
## en-cuadro
```
@en-marco ( -> )
@en-cuadro ( -> )
( borrar palas )
.izquierda/x LDZ2 .izquierda/y LDZ2 COLOR-BORRAR ;dibuja-pala JSR2
.derecha/x LDZ2 .derecha/y LDZ2 COLOR-BORRAR ;dibuja-pala JSR2

View File

@ -24,6 +24,10 @@ the button byte encodes in each of its eight bits the state of eight different "
numbering the bits from right to left, and from 0 to 7, the corresponding keys (and NES buttons) are:
+ <table>
+ <tr><th>bit 7</th><th>bit 6</th><th>bit 5</th><th>bit 4</th><th>bit 3</th><th>bit 2</th><th>bit 1</th><th>bit 0</th></tr>
+ <tr><td>Right</td><td>Left</td><td>Down</td><td>Up</td><td>Esc (Start)</td><td>Shift (Select)</td><td>Alt (B)</td><td>Ctrl (A)</td></tr>
+ </table>
& * 0: Ctrl (button A)
& * 1: Alt (button B)
& * 2: Shift (Select button)
@ -33,11 +37,6 @@ numbering the bits from right to left, and from 0 to 7, the corresponding keys (
& * 6: Left
& * 7: Right
+ <table>
+ <tr><th>bit 7</th><th>bit 6</th><th>bit 5</th><th>bit 4</th><th>bit 3</th><th>bit 2</th><th>bit 1</th><th>bit 0</th></tr>
+ <tr><td>Right</td><td>Left</td><td>Down</td><td>Up</td><td>Esc (Start)</td><td>Shift (Select)</td><td>Alt (B)</td><td>Ctrl (A)</td></tr>
+ </table>
enconding the states of the buttons in this way allows us to press and read many of these keys at the same time.
## the key byte
@ -164,7 +163,7 @@ AND2, ORA2, EOR2 will work in the same way, but with shorts instead of bytes.
### AND
the following will push down into the stack a flag that indicates if the key byte is between 30 and 39 inclusive, using 01 to represent 'true', and 00 to represent 'false0:
the following will push down into the stack a flag that indicates if the key byte is between 30 and 39 inclusive, using 01 to represent 'true', and 00 to represent 'false':
```
.Controller/key DEI ( read key and push into the stack )
@ -393,12 +392,12 @@ so far we have been using the stack as a place to store operands of instructions
uxntal has six instructions that act upon elements in the stack closer to the top:
* POP: Remove top element from the stack ( a -- )
* DUP: Duplicate; push a copy of the top element ( a -- a a )
* SWP: Swap; change the order of the top two elements of the stack ( a b -- b a )
* NIP: Remove the top second element of the stack ( a b -- b )
* OVR: Over; push a copy of the second top element ( a b -- a b a )
* ROT: Rotate; reorder the top three elements of the stack so that the third one is now at the top ( a b c -- b c a )
* POP: remove top element from the stack ( a -- )
* DUP: duplicate; push a copy of the top element ( a -- a a )
* SWP: swap; change the order of the top two elements of the stack ( a b -- b a )
* NIP: remove the top second element of the stack ( a b -- b )
* OVR: over; push a copy of the second top element ( a b -- a b a )
* ROT: rotate; reorder the top three elements of the stack so that the third one is now at the top ( a b c -- b c a )
in short mode, POP2, DUP2, SWP2, NIP2, OVR2 and ROT2 perform the same actions but using shorts instead of bytes.
@ -460,7 +459,7 @@ now the stack looks like this:
flag1 key <- top
```
finally we can proceed with the comparison and the AND
finally we can proceed with the comparison and the AND:
```
#3a LTH ( is it less than 3a? push flag into the stack )