From c2bf84a505ccd0d8dbfc4019812f03655846b628 Mon Sep 17 00:00:00 2001 From: maleza Date: Tue, 27 Jul 2021 14:54:55 -0300 Subject: [PATCH] =?UTF-8?q?primer=20intento=20de=20traducci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tutorial_de_uxn.gmo | 118 +++++++ src/tutorial_de_uxn_día_1.gmo | 602 +++++++++++++++++++++++++++++++++ 2 files changed, 720 insertions(+) create mode 100644 src/tutorial_de_uxn.gmo create mode 100644 src/tutorial_de_uxn_día_1.gmo diff --git a/src/tutorial_de_uxn.gmo b/src/tutorial_de_uxn.gmo new file mode 100644 index 0000000..591e9cf --- /dev/null +++ b/src/tutorial_de_uxn.gmo @@ -0,0 +1,118 @@ +# tutorial de uxn + +una guía de inicio para programar la computadora uxn, y un pausado complemento a la documentación oficial. + +=> https://wiki.xxiivv.com/site/uxntal.html uxntal +=> https://wiki.xxiivv.com/site/uxnemu.html uxnemu + +el tutorial está dividido en 8 días (o secciones), ya que puede ser seguido junto al taller. + +(al día de hoy, este es un trabajo en proceso) + + +# día 1 + +en esta primera sección del tutorial vamos a hablar de los aspectos básicos de la computadora uxn, su paradigma de programación, su arquitectura, y por qué podrías queres aprender a programar en ella. + +también vamos a saltar directo a nuestros primeros programas simples para demostrar conceptos fundamentales que desarrollaremos en los días siguientes. + +=> ./uxn_tutorial_day_1.gmi {uxn tutorial day 1} + +# día 2 + +próximamente! + +# índice tentativo + +este índice está aquí y ahora como referencia de la estructura general del tutorial. + +## día 1: aspectos básicos + +* ¿por qué uxn? +* notación {postfix} +* arquitectura de la computadora uxn +* instalación y toolchain +* un hola mundo muy básico +* etiquetas, macros y runas +* un hola mundo mejorado +* imprimir un dígito + +instrucciones nuevas: LIT, DEO, ADD, SUB + +=> https://git.sr.ht/~rabbits/uxn/ uxn repo + +## día 2: la pantalla + +* modo corto +* colores del sistema +* dibujar pixeles +* sprites: formato chr, nasu +* dibujar sprites sprites +* operaciones en la pila +* practica: reoetición manual de un sprite + +instructiones nuevas: DEI, MUL, DIV, SWP, OVR, ROT, DUP, POP + +modo nuevo: modo corto + +=> https://wiki.xxiivv.com/site/nasu.html nasu + +## día 3: interactividad con el teclado + +* vector de controlador +* control de flujo: condicionales, saltos relativos y absolutos +* runas para direcciones +* botón y tecla +* máscaras bitwise +* práctica: mover/cambiar sprite con el teclado + +instrucciones nuevas: EQU, NEQ, JCN, JMP, AND, ORA, EOR, SFT + +## día 4: bucles y animación + +* control de flujo: repetición de un sprite +* vector de pantalla +* variables: página cero, relativas, absolutas +* offsets en direcciones +* timing de animación +* práctica: sprite animado + +instrucciones nuevas: LTH, GTH, STZ, STR, STA, LDZ, LDR, LDA + +## día 5: interactividad con el mouse + +* dispositivo y vector del mouse +* Pila de retorno y modo +* subrutinas: parametros, llamada y retorno +* práctica: sprite como puntero +* práctica: herramienta de dibujo simple + +instrucciones nuevas: STH, JSR + +modo nuevo: modo de retorno + +## día 6: audio + +* el dispositivo de audio +* samples como sprites de audio +* adsr +* pitch +* práctica: pequeño instrumento musical + +## día 7: modo de retención y otros dispositivos + +* modo de retención +* re-escribiendo código con modo de retención +* dispositivo de archivo: guardando y cargando un estado simple +* dispositivo de fecha y hora: leyendo fecha y hora +* práctica: visualización de fecha y hora + +modo nuevo: modo de retención + +## día 8: tiempo de demo + +* comparte lo que has creado :) + +# soporte + +si este tutorial te ha sido de ayuda, considera compartirli y brindarle tu {apoyo} :) diff --git a/src/tutorial_de_uxn_día_1.gmo b/src/tutorial_de_uxn_día_1.gmo new file mode 100644 index 0000000..42101eb --- /dev/null +++ b/src/tutorial_de_uxn_día_1.gmo @@ -0,0 +1,602 @@ +# tutorial uxn: día 1, aspectos básicos + +hola! en esta primera sección del {tutorial uxn} vamos a hablar de los aspectos básicos de la computadora uxn, su paradigma de programación, su arquitectura, y por que puede que quieras aprender a programarla. + +también saltaremos directo a nuestros primeros programas simples para demostrar conceptos fundamentales que desarrollaremos en los próximos días. + +# ¿por qué uxn? + +o primero que nada... qué es uxn? + +> Uxn es una computadora portable de 8 bit capaz de correr herramientas y juegos simples programable en su propio pequeño lenguaje ensamblador. Es también un ámbito de juego donde aprender habilidades básicas de computación. + +=> https://wiki.xxiivv.com/site/uxn.html XXIIVV - uxn + +i invite you to read "why create a smol virtual computer" from the 100R site, as well: + +=> https://100r.co/site/uxn.html 100R - uxn + +osea que, uxn es una computadora virtual (¿por el momento?) que es lo suficientemente simple como para ser emulada por diversas plataformas de computación viejas y nuevas. + +personalmente, veo en ella las siguientes virtudes: + +* hecha para el largo plazo +* hecha para aplicaciones audiovisuales interactivas +* arquitectura y set de instrucciones simple (sólo 32 instrucciones!) +* primero-offline: funciona localmente y sólo necesitas unos pocos archivos de documentación para avanzar +* ámbito de práctica y experimentación de computación dentro de límites +* ya ortada a plataformas de computación actuales y de varios años de antigüedad + +¡todos estos conceotos suenan genial para mí, y espero que para tí también! sin embargo, noto algunos aspectos que pueden hacerla parecer no tan asequible: + +* es programada en un lenguaje ensamblador, uxntal +* utiliza notación {postfija} (alias notación polaca inversa) / está inspirada en máquinas forth + +la idea de este tutorial es explorar estos dos aspectos y revelar cómo trabajan juntos para dar a uxn su poder con una complegidad relativamente baja. + +# notación postfija (y la pila) + +uxn está inspirado por las máquinas forth en que utiliza la recombinación de componentes simples para lograr soluciones apropiadas, y en que es una máquina basada en pila. + +esto implica que está principalmente basada en interacciones con una pila "push down", dónde las operaciines son indicadas mediante la llamada notación postfija. + +> Notación Polaca Reversa (NPR), también conocida como notación postfija polaca o simplemente notación postfija, es una notación matemática en la que los operadores siguen a sus operandos [...] + +=> https://en.wikipedia.org/wiki/Reverse_Polish_notation Reverse Polish notation - Wikipedia + +## suma postfija + +en notación postfija, la suma de nos números sería escrita de la siguiente forma: + +``` 1 48 + +1 48 + +``` + +dónde, leyendo de izquierda a derecha: + +* el número 1 es empujado en la pila +* el número 48 es empujado en la pila +* + toma dos elementos de la parte superior de la pila, los suma, y empuja el resultado en la pila + +the book Starting Forth has some great illustrations of this process of addition: + +=> https://www.forth.com/starting-forth/1-forth-stacks-dictionary/#The_Stack_Forth8217s_Workspace_for_Arithmetic The Stack: Forth’s Workspace for Arithmetic + +## de infija a postfija + +expresiones más complejas en notación infija, que requieren paréntesis o reglas de precedencia de operadores (y un sistema más complejo para codificarlas), pueden ser simplificadas mediante notación postfija. +por ejemplo, la siguiente expresión infija: + +``` (2 + 16)/8 + 48 +(3 + 5)/2 + 48 +``` + +pueden ser escritas en notación postfija como: + +``` 3 5 + 2 / 48 + +3 5 + 2 / 48 + +``` + +también podemos escribirla de muchas otras maneras, por ejemplo: + +``` 48 2 3 5 + / + +48 3 5 + 2 / + +``` + +¡asegúrate de que éstas expresiones funcionan y son equivalentes! sólo debes seguir estas reglas, leyendo de izquierda a derecha: + +* si es un número, empujarlo a la pila +* si es un operador, tomar dos elementos de la parte superior de la pila, aplicar la operación, y empujar el resultado en la pila. + +nota: en el caso de la división, los operandos siguen el mismo orden de izquierda a derecha. 3/2 sería escrito como: + +``` 3 2 / +3 2 / +``` + +irás descubriendo cómo el uso de la pila puede ser muy poderoso ya que ahorra operandos y/o resultados intermedios sin necesidad de que asignemos explicitamente un espacio en memoria para ellos (por ejemplo, mediante el uso de "variables" en otros lenguajes de programación) + +we'll come back to postfija notation and the stack very soon! +¡vamos a volver a la notación postfija y la pila muy pronto! + +# arquitectura de la computadora uxn + +una de las cuestiones de programar una computadora a un nivel bajo de abstracción, como estaremos haciendo con uxn, es que tenemos que conocer y estar atentos a sus funcionamientos internos. + +## 8-bits y hexadecimal + +las palabras binarias de 8 bits, también conocidas como bytes, son los elementos básicos de codificación y manipulación de datos en uxn. + +uxn puede manejar también palabras binarias de 16 bits (2 bytes), también conocidas como cortos, mediante la concatenación de dos bytes consecutivos. vamos a hablar más sobre esto en el segundo día de este tutorial. + +los números en uxn son expresados utilizando el sistema hexadecimal (base 16), en el qhe cada dígito (nibble) va de 0 a 9 y luego de 'a' a 'f' (en minúscula). + +un byte necesita dos dígitos hexadecimales (nibbles) para ser expresado, y un corto necesita cuatro. + +## el cpu uxn + +se ha dicho que el cpu uxn es una remolacha, capaz de ejecutar 32 instrucciones diferentes con tres banderas de modo diferentes. + +cada instrucción junto con sus banderas de modo puede ser codificada en una sola palabra de 8 bits. + +todas estas instrucciones operan sobre elementos en la pila, ya sea tomando de ella sus operandos y/o empujando en ella sus resultados. + +we'll be covering these instructions slowly over this tutorial. +vamos a ir cubriendo lentamente estas instrucciones durante este tutorial. + +## memoria uxn + +la memoria en la computadora uxn consiste en cuatro espacios separados: + +* memoria principal, con 65536 bytes +* memoria de entrada/salida, con 256 bytes dividida en 16 secciines (o dispositivos) de 16 bytes cada uno: 8 bytes para entradas y 8 bytes para salidas. +* pila de trabajo, con 256 bytes +* pila de retorno, con 256 bytes + +cada byte en la memoria principal posee una dirección de 16 bits (2 bytes) de tamaño, mientras que cada byte en la memoria de entrada/salida posee una dirección de 8 bits (1 byte) de tamaño. ambas pueden ser accedidas de manera aleatoria. + +los primeros 256 bytes de la memoria principal constituyen una sección llamada página cero. esta sección puede ser referenciada por 8 bits (1 byte), y su propósito es almacenar datos durante el tiempo de ejecución de la máquina. + +hay tres instrucciones diferentes para interactuar con cada uno de estos espacios de memoria. + +la memoria principal almacena el programa a ser ejecutado, empezando en el byte 257 (dirección 0100 en hexadecimal). también puede almacenar datos. + +las pilas no pueden ser accedidas aleatoriamente; la máquina uxn se ocupa de ellas. + +## ciclo de instrucción + +el cpu uxn lee un byte por vez de la memoria principal. + +el contador de programa es una palabra de 16 bits que indica la dirección del próximo byte a leer. su valor inicial es la dirección 0100 en hexadecimal. + +una vez que el cpu lee un byte, lo decodifica como instrucción y lo ejecuta. + +la instrucción va a implicar normalmente un cambio en la(s) pila(s), y algunas veces también un cambio en el flujo normal del contador de programa: en lugar de apuntar al siguiente byte en memoria, puede ser apuntado a otro lado, "saltando" de un lugar en memoria a otro. + +# instalación y toolchain + +liste? obtengamos el ensamblador uxn (uxnasm) y emulador (uxnemu) de su repositorio git: + +=> https://git.sr.ht/~rabbits/uxn ~rabbits/uxn - sourcehut git + +estas instrucciones son para sistemas basados en linux. + +si necesitas una mano, encuèntranos en #uxn en irc.esper.net :) + +## instalar SDL2 + +para compilar uxnemu, necesitamos instalar la librería SDL2. + +en una terminal en debian/ubuntu, correr: + +``` sudo apt install libsdl2-dev +$ sudo apt install libsdl2-dev +``` + +on en guix: + +``` guix install sdl2 +$ guix install sdl2 +``` + +## obtener y compilar uxn + +obtengamos y compilemos uxnemu y uxnasm: + +``` +$ git clone https://git.sr.ht/~rabbits/uxn +$ cd uxn +$ ./build.sh +``` + +si todo fué bién, verás varios mensajes en la terminal y una pequeña ventana con el título uxn, y una aplicación demo: uxnemu está ahora corriendo una "rom" correspondiendo a esa aplicación. + +## controles uxnemu + +* F1 itera entre diferentes niveles de zoom +* F2 muestra el debugger en pantalla +* F3 toma una captura de pantalla de la ventana + +## usando el toolchain + +verás que luego de compilar uxn, cuentas con tres nuevos archivos ejecutables en el directorio bin/: + +* uxnemu: el emulador +* uxnasm: el ensamblador +* uxncli: un emulador de consola no interactivo + +puedes ajustar tu $PATH para tenerlos disponibles en todos lados. + +la idea es que para correr un programa escrito en uxntal (el lenguaje ensamblador de uxn), primero tienes que ensamblarlo en una "rom", y luego puedes correr esta rom con el emulador. + +por ejemplo, para correr {darena} que se encuentra en projects/examples/demos/ : + +``` + ensambla darena.tal en darena.rom +$ ./bin/uxnasm projects/examples/demos/darena.tal bin/darena.rom + + correr darena.rom +$ ./bin/uxnemu bin/darena.rom +``` + +¡échale una mirada a los demos disponibles! (¡o no, y empecemos a programar los nuestros!) + +# uxntal y un muy básico hola mundo + +uxntal es el lenguaje ensamblador para la máquina uxn. + +estuvimos hablando antes sobre el cpu uxn y las 32 instrucciones que sabe cómo ejecutar, cada una de ellas codificada como una sola palabra de 8 bits (byte). + +ese lenguaje ensamblador uxntal implica que hay una relación uno a uno mapeando de una instrucción escrita en el lenguaje a una palabra de 8 bit correspondiente que el cpu puede interpretar. + +por ejemplo, la instrucción ADD (suma) en uxntal es codificada como un byte con el valor 18 en hexadecimal, y corresponde al siguiente conjunto de de acciones: toma los dos elementos superiores de la pila, los suma, y empuja el resultado a la pila. + +en sistemas de tipo forth podemos ver el siguiente tipo de notación para expresar los operandos que una instrucción toma de la pila, y el(los) resultado(s) que empuja devuelta a la pila: + +``` +ADD ( a b -- a+b ) +``` + +esto significa que ADD tome el primer elemento desde arriba 'b', luego toma el siguiente primer elemento 'a', y empuja devuelta el resultado de sumar a+b. + +ahora que estamos en eso, hay una instrucción complementaria, SUB (resta) (opcode 19), que toma los dos elementos superiores de la pila, los resta, y empuja a la pila el resultado: + +``` +SUB ( a b -- a-b ) +``` + +nota que el orden de los operandos es similar al de la división que discutimos arriba cuando hablamos de notación postfija. + +## un primer programa + +escribamos el siguiente programa en nuestro editor de texto favorito, y guardémoslo como hello.tal: + +``` +( hello.tal ) +|0100 LIT 68 LIT 18 DEO +``` + +ensamblémoslo y corrámoslo: + +``` +$ ./bin/uxnasm hello.tal bin/hello.rom && ./bin/uxnemu bin/hello.rom +``` + +veremos una salida con el siguiente aspecto: + +``` +Assembled bin/hello.rom(5 bytes), 0 labels, 0 macros. +Uxn loaded[bin/hello.rom]. +Device added #00: system, at 0x0000 +Device added #01: console, at 0x0010 +Device added #02: screen, at 0x0020 +Device added #03: audio0, at 0x0030 +Device added #04: audio1, at 0x0040 +Device added #05: audio2, at 0x0050 +Device added #06: audio3, at 0x0060 +Device added #07: ---, at 0x0070 +Device added #08: controller, at 0x0080 +Device added #09: mouse, at 0x0090 +Device added #0a: file, at 0x00a0 +Device added #0b: datetime, at 0x00b0 +Device added #0c: ---, at 0x00c0 +Device added #0d: ---, at 0x00d0 +Device added #0e: ---, at 0x00e0 +Device added #0f: ---, at 0x00f0 +h +``` + +la última 'h' que vemos es la salida de nuestro programa. cambia el 68 a, por ejemplo, 65, y verás una 'e'. + +¿qué es lo que está pasando? + +## una instrucción por vez + +acabamos de correr el siguiente programa en uxntal: + +``` +( hello.tal ) +|0100 LIT 68 LIT 18 DEO +``` + +la primera línea es un comentario: los comentarios son encerrados entre paréntesis y debe haber un espacio entre cada paréntesis y el contenido. de manera similar a otros lenguajes de programación, los comentarios son ignorados por el ensamblador. + +en la segunda linea ocurren varias cosas: + +* |0100 : puede que recuerdes este número de antes - este es el valor inicial del contador de programa; la dirección del primer byte que el cpu lee. usamos esta notación para indicar que lo que esté escrito después será escrito en memoria después de esta dirección. +* LIT : esta aparece dos veces, y es una instrucción uxn con las siguientes acciones: empuja el siguiente valor en memoria a la pila, y hace que el contador de programa saltee ese byte. +* 68 : un número hexadecimal, que corresponde al código ascii del caracter 'h' +* 18 : un número hexadecimal, que corresponde a una dirección de entrada/salida: dispositivo 1 (consola), dirección 8. +* DEO : otra instrucción uxn, que podemos definir como lo siguiente: escribir el byte dado en la dirección de dispositivo dada, ambos tomados de la pila ( byte dirección -- ) + +leyendo el programa de izquierda a derecha, podemos ver el siguiente comportamiento: + +* la instrucción LIT empuja el número 68 a la pila +* la instrucción LIT empuja el número 18 a la pila +* la instrucción DEO toma el elemento superior de la pila (18) y lo usa como dirección de dispositivo +* la instrucción DEO toma el elemento superiir de la pila (68) y lo usa como byte a escribir +* la instrucción DEO escribe el byte a la dirección de dispositivo, dejando la pila vacía + +¿y qué es el dispositivo de entrada/salida con la dirección 18? + +mirando en la tabla de dispositivos de la referencia uxnemu, podemos ver que el dispositivo con la dirección 1 en el nibble superior es la consola (entrada y salida estandard), y que la columna con la dirección 8 corresponde a "escritura". + +=> https://wiki.xxiivv.com/site/uxnemu.html uxnemu + +asique, el dispositivo 18 corresponde a "escribir en consola", o salida estandard. + +¡nuestro programa está enviando el valor hexadecimal 68 (caracter 'h') a la salida estandard! + +puedes ver los valores hexadecimales de los caracteres ascii en la siguiente tabla: + +=> https://wiki.xxiivv.com/site/ascii.html ascii table + +## rom ensamblada + +podemos ver que el ensamblador reporta que nuestro programa es de 5 bytes de tamaño: + +``` +Assembled bin/hello.rom(5 bytes), 0 labels, 0 macros. +``` + +para el curioso (¡como tu!), podemos usar una herramienta como hexdump para ver sus contenidos: + +``` +$ hexdump -C bin/hello.rom +00000000 01 68 01 18 17 |.h...| +00000005 +``` + +01 es el "opcode" correspondiente a LIT, y 17 es el opcode correspondiente a DEO. ¡y ahí están nuestros 68 y 18! + +¡osea, efectivamente, nuestro programa ensamblado presenta una correspondencia uno a uno con las instrucciones que acabamos de escribir! + + +de hecho, podríamos haber escrito nuestro programa con estos números hexadecimales (el código máquina), y hubiera funcionado igual: + +``` +( hello.tal ) +|0100 01 68 01 18 17 ( LIT 68 LIT 18 DEO ) +``` + +tal vez no sea la manera más práctica de programar, pero ciertamente una divertida :) + +puedes encontrar los opcodes de todas las 32 instrucciones en la referencia uxntal + +=> https://wiki.xxiivv.com/site/uxntal.html XXIIVV - uxntal + +## programa hola + +podemos expandir nuestro programa para imprimir más caracteres: + +``` +( hello.tal ) +|0100 LIT 68 LIT 18 DEO ( h ) + LIT 65 LIT 18 DEO ( e ) + LIT 6c LIT 18 DEO ( l ) + LIT 6c LIT 18 DEO ( l ) + LIT 6f LIT 18 DEO ( o ) + LIT 0a LIT 18 DEO ( newline ) +``` + +si lo ensamblamos y corremos, tendremos un 'hello' en nuestra terminal, usando 30 bytes de programa :) + +¿ok, y... te gusta? + +¿parece innecesariamente complejo? + +veremos ahora algunas virtudes de uxntal que hacen escribir y leer código más "confortable". + +# runas, etiquetas, macros + +las runas son caracteres especiales que indican a uxnasm algún pre procesamiento a hacer al ensamblar nuestro programa. + +## runa de pad absoluto + +ya vimos la primera de ellas: | define un pad absoluto: la dirección donde el siguiente elemento escrito será ubicado en memoria. + +si la dirección es de 1 byte de longitud, es asumido que es una dirección de el espacio de entrada/salidao de la página cero. + +si la dirección d¡es de 2 bytes de longitud, es asumido que es una dirección de la memoria principal. + +## runa hex literal + +hablemos de otra: #. + +éste caracter define un "hex literal": es básicamente un atajo para la instrucción LIT. + +usando esta runa, podemos reescribir nuestro primer programa como: + +``` +( hello.tal ) +|0100 #68 #18 DEO +``` + +nota que sólo puedes usar esta runa para escribir los contenidos de uno o dos bytes (dos o cuatro nibbles). + +el siguiente tendría el mismo comportamiento que el programa de arriba, pero usando un byte menos (en la siguiente sección/día veremos por qué) + +``` +( hello.tal ) +|0100 #6818 DEO +``` + +importante: recuerda que esta runa (y las otras con la palabra "literal" en su nombre) es un atajo para la instrucción LIT. esto puede prestarse a confusión en algunos casos :) + +## runa de caracter raw + +ésta es la runa de caracter raw: ' + +nos permite que uxnasm decodifique el valor numérico de un caracter ascii. + +nuestro "programa hello" luciría de la siguiente manera, usando las nuevas runas que acabamos de aprender: + +``` +( hello.tal ) +|0100 LIT 'h #18 DEO + LIT 'e #18 DEO + LIT 'l #18 DEO + LIT 'l #18 DEO + LIT 'o #18 DEO + #0a #18 DEO ( newline ) +``` + +el "raw" en el nombre de esta runa indica que no es literal, por ejemplo que no agrega una instrucción LIT. + +## runas para etiquetas + +incluso ahora que sabemos que #18 corresponde a empujar la dirección de dispositivo escribir en consola en la pila, por legibilidad y para asegurar nuestro código a futuro es una buena práctica asignar una serie de etiquetas que corresponderán a ese dispositivo y sus sub direcciones. + +la runa @ nos permite definir etiquetas, y la runa & nos permite definir sub etiquetas. + +por ejemplo, para el dispositivo de consola, la manera en que verías esto escrito en programas uxn es la siguiente: + +``` +|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] +``` + +podemos ver un pad absokuto a la dirección 10, que asigna lo siguiente a esa dirección. dado que la dirección consiste en un sólo byte, uxnasm asume que es para el espacio de memoria de entrada/salida o la página cero. + +luego vemos la etiqueta @Console: ésta etiqueta va a corresponder a la dirección 10. + +los corchetes son ignorados, pero incluidos por legibilidad. + +luego tenemos varias sub etiquetas, indicadas por la runa &, y pads relativos, indicados por la runa $. ¿cómo los leemos/interpretamos? + +* la sub etiqueta &vector tiene la misma dirección que su etiqueta madre @Console: 10 +* $2 salta dos bytes (podemos leer esto como &vector siendo una dirección a una palabra de dos bytes de longitud) +* la sub etiqueta &read tiene la dirección 12 +* $1 salta un byte (&read sería una dirección para una palabra de 1 byte de longitud) +* la sub etiqueta &pad tiene la dirección 13 +* $5 salta el resto de los bytes del primer grupo de 8 bytes del dispositivo: éstos bytes corresponden a las "entradas" +* la sub etiqueta &write tiene la dirección 18 (¡la que ya conocíamos!) +* $1 salta un byte (&write sería una dirección para una palabra de 1 byte de longitud) +* la subetiqueta &error tiene la dirección 19 + +nada de esto sería traducido a código máquina, pero nos asiste al escribir código uxntal. + +la runa para referirse a una dirección literal en la página cero o el espacio de direcciones de entrada/salida, es . (punto), y una / (barra) nos permite referirnos a una de sus sub etiquetas. + +recuerda: al ser una runa de "dirección literal" va a agregar una instrucción LIT antes de la correspondiente dirección :) + +podemos reescribir nuestro "programa hello world" como sigue: + +``` +( hello.tal ) + +( devices ) +|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] + +( main program ) +|0100 LIT 'h .Console/write DEO + LIT 'e .Console/write DEO + LIT 'l .Console/write DEO + LIT 'l .Console/write DEO + LIT 'o .Console/write DEO + #0a .Console/write DEO ( newline ) +``` + +ahora esto empieza a parecerse más a los ejemplos que puedes encontrar en línea y/o en el repositorio uxn :) + +## macros + +siguiendo con la herencia de forth (?), en uxntal podemos definir nuestras propias "palabras" que nos permiten agrupar y reutilizar instrucciones. + +durante el ensamblado, estos macros son (recursivamente) reemplazados por los contenidos de sus definiciones. + +por ejemplo, podemos ver que el siguiente fragmento de código es repetido varias veces en nuestro programa. + +``` +.Console/write DEO ( equivalent to #18 DEO, or LIT 18 DEO ) +``` + +podemos definir un macro llamado EMIT que tomará de la pila un byte correspondiente a un caracter, y lo imprimirá en la salida estandard. para esto, necesitamos la runa %, y llaves para la definición. + +¡no olvides los espacios! + +``` +( print a character to standard output ) +%EMIT { .Console/write DEO } ( character -- ) +``` + +para llamar a un macro, sólo escribimos su nombre: + +``` +( print character h ) +LIT 'h EMIT +``` + +podemos llamar macros dentro de macros, por ejemplo: + +``` +( print a newline ) +%NL { #0a EMIT } ( -- ) +``` + +# un hello world más idiomático + +usando todos estos macros y runas, nuestro programa puede terminar luciendo como lo siguiente: + +``` +( hello.tal ) +( devices ) +|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] + +( macros ) +( print a character to standard output ) +%EMIT { .Console/write DEO } ( character -- ) +( print a newline ) +%NL { #0a EMIT } ( -- ) + +( main program ) +|0100 LIT 'h EMIT + LIT 'e EMIT + LIT 'l EMIT + LIT 'l EMIT + LIT 'o EMIT + NL +``` + +termina siendo ensamblado en los mismos 30 bytes que los ejemplos de arriba, pero con suerte más legible y mantenible. + +podemos "mejorar" este programa haciendo que un loop imprima los caracteres, pero estudiaremos eso más tarde : + +# ejercicios + +## reubicando EMIT + +en nuestro programa previo, el macro EMIT es llamado justo después de empujar un caracter a la pila. + +¿cómo reescribirías el programa para empujar primero todos los caracteres, y luego "EMIT"ir todos ellos en una secuencia como ésta? + +``` +EMIT EMIT EMIT EMIT EMIT +``` + +## imprimir un dígito + +si miras en la tabla ascii, verás que esl código hexadecimal 30 corresponde al dígito 0, 31 al dígito 1, siguiendo hasta el 39 que corresponde al dígito 9. + +define un macro PRINT-DIGIT que toma un número (del 0 al 9) de la pila, e imprime el correspondiente dígito en la salida estandard. + +``` +%PRINT-DIGIT { } ( number -- ) +``` + +# instrucciones del día 1 + +éstas son las instrucciones que cubrimos hoy: + +* ADD: toma los dos elementos superiores de la pila, los suma, y empuja el resultado ( a b -- a+b ) +* SUB: toma los dos elementos superiores de la pila, los resta, y empuja el resultado ( a b -- a-b ) +* LIT: empuja el siguiente byte en memoria a la pila +* DEO: escribe el byte dado en la dirección de dispositivo dada, tomando ambos de la pila ( byte address -- ) + +# day 2 + +¡mantente al tanto por las siguientes secciones del {tutorial uxn}! + +# apoyo + +si este tutorial te ha resultado de ayuda, considera compartirlo y brindarle tu {apoyo} :) +