lunes, 26 de febrero de 2024

Estructuras de control: implementación del IF

 La J1s tiene una sola instrucción de salto condicional: 0branch direccion.

Es una instrucción simple: si el tope del stack es cero, la ejecución sigue en la dirección indicada. En cualquier caso, el tope del stack es descartado.

Por otra parte, Forth tiene el IF-ELSE-THEN. Si el tope del stack es distinto de cero, se ejecutan las instrucciones entre el IF y el ELSE.  Si el stack es cero, se ejecutan las instrucciones entre el ELSE y el THEN. Por supuesto, el bloque else es opcional.

La instrucción IF siempre remueve el tope del stack.

Veamos, por ejemplo, la definición de la función lógica NOT: si el tope del stack es cero, se reemplaza por un uno. En caso contrario, se reemplaza con cero.

: not if 0 else 1 then ;

La implementación del IF-THEN-ELSE es

0branch bloque-else
    ... instrucciones caso Verdadero
    jmp outside
bloque-else:
    ... instrucciones caso Falso
outside:          ; Siguiente instrucción


que para este ejemplo sería

Dir  Código   Instrucción
03b1 23b4     0branch b-else   ; Comienza NOT
03b2 8000     0                ; Coloca un cero en el stack
03b3 03b5     jmp b-then
         b-else:
03b4 8001     1                ; Coloca un uno en el stack.
         b-then: 
03b5 608c     ret              ; Retorno (fin de la implementación)

El IF sólo puede ser usado en la definición de una palabra; no en forma interactiva. Por lo tanto, el interprete se encuentra con ella mientras está en modo compilación, sin saber que viene por delante. En esta fase, el compilador va generando las instrucciones de máquina en memoria. Una vez terminada la compilación, el código será ingresado al diccionario Forth.

Al ver el IF, el compilador genera una instrucción 0branch 0, dado que aun no se conoce la dirección de destino.

Cuando encuentra un ELSE, inserta un jmp 0 para saltar sobre las instrucciones que vienen a continuación.

Al encontrarse con ELSE/THEN, el compilador busca atrás en memoria la instrucción 0branch 0 y la parcha con la dirección de la próxima instrucción. Si encuentra un jmp 0, también lo parcha con la misma dirección.

Asi podemos compilar el IF-ELSE-THEN sin necesidad de variables intermedias.


sábado, 24 de febrero de 2024

Probando el kernel

Objetivos

El kernel ha crecido y ahora debo ser frugal en lo que agrego o dejo fuera. Al parecer ya está completo; la única manera de saberlo es escribir aplicaciones prácticas del mundo real.

Empezare por lo básico: ejercitar la aritmética y las estructuras de control, como este pequeño programa que calcula la secuencia de Collantz para un valor dado inicial en el stack:

: collantz
  dup .
  begin
    dup 1 and
    if
        dup dup 1 + + +
    else
        1 rshift
    then
    dup .
    dup 1 =
  until
  drop
  ; 

Probando en el emulador

 >900 collantz
 900 450 225 676 338 169 508 254 127 382 191 574 287 862 431 1294 647 1942 971 2914 1457 4372 2186 1093 3280 1640 820 410 205 616 308 154 77 232 116 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1

Le toma 1 minuto calcular e imprimir todas las secuencias desde 2 hasta 32.767.

lunes, 19 de febrero de 2024

Un computador desde cero

 

Tenía 12 años en 1968 cuando apareció este artículo en la Mecánica Popular. Algún día yo también construiría mi propio computador. Nada más cool.

Luego entre a estudiar Ingeniería. Ese algún día se sentía un poco más cerca.

Pasaron los años, me jubile y con mucho tiempo libre, me dije: Ahora es ese día.

Mi punto de partida es una tarjeta FPGA, la IceSugar 1.5, elegida por contar con un toolkit open-source y por evitarme el drama de diseñar PCB, montar y soldar componentes. 

El diseño de la CPU está basada en la J1, con arquitectura de stack minimalista, lo que nos lleva naturalmente a Forth, un lenguaje basado en stack enfocado a microprocesadores.

¿Que tenemos hasta ahora?
  • El diseño de la CPU en Verilog.
  • Un ensamblador (escrito en Python, corre en PC).
  • Un emulador (escrito en Python, corre en PC).
  • Una implementación de Forth escrita en Assembler J1 y Forth.

El proyecto está en su fase final. El interprete Forth funciona y lo que falta por completar se puede hacer programando en Forth.