Bueno, aqui va toda la info que tengo, quien quiera algo que se ponga en contacto conmigo en jgpeiro@gmail.com
Procesador BrainFuck
El lenguaje BrainFuck
Brainfuck (jode cerebros) es un lenguaje de programación esotérico, diseñado por Urban Müller en 1993, con el objetivo de hacer un lenguaje que fuera a la vez muy simple, Turing completo (puede describir cualquier algoritmo) y que requiriese un compilador pequeño. Müller basó Brainfuck en la máquina de Turing.
El juego de instrucciones
Con tan solo 8 instrucciones, el brainfuck se un lenguaje sencillo, que suele crear retos muy interesantes.
Carácter Significado Equivalente en C++
> Incrementa el puntero. ++ptr;
< Decrementa el puntero. --ptr;
+ Incrementa el byte apuntado. ++*ptr;
- Decrementa el byte apuntado. --*ptr;
. Lee el byte apuntado y lo escribe en el puerto de salida. putchar(*ptr);
, Lee el puerto de entrada y lo graba en el byte apuntado. *ptr = getchar();
[ Es condicional, si el byte apuntado es distinto de 0 entra en el bucle. while (*ptr) {
] Es condicional, si el byte apuntado es igual a 0 entra sale del bucle. }
Programa ejemplo
,[>+++<-]>.
Explicare brevemente este programa:
1- Lee el puerto de entrada y lo almacena en la posición de RAM 0.
2- Entra en un bucle( ya que la posición a la que apunta el puntero de datos tiene un valor distinto de 0 )
3- Incrementa el puntero de datos para apuntar a la posición 1.
4- Incrementa 3 veces el valor de la posición 1.
5- Decrementa el puntero de datos para apuntar a la posición 0.
6- Decrementa el valor de la posición 0
7- Si el puntero de daots apunta a un dato distinto de 0 volvera al paso 2, en otro caso pasara al siguiente paso.
8- Incrementa el puntero de datos, para apuntar a la posición 1.
9- Saca el dato al que apunta el puntero de datos por el puerto de salida.
Ahora veamos los nodos mas importantes del circuito en una simulación del mismo programa.
IO_PQ[7:0] es el puerto de salida. Tiene un valor X (indeterminado) hasta el final del programa, que cambia al valor 6.
ALU_DQ[7:0] es el bus de datos, no se puede apreciar bien en el dibujo, pero contiene los datos que entran o salen de la RAM.
RAM_A[3:0] es el bus de direcciones de la RAM.
ROM_A[6:0] es el bus de direcciones de la ROM, que junto con los bits ALU_z y WLC_z forman la completa de la ROM.
ROM_Q[15:12],[11:8],[7:4],[3:0] Son los buses de control de los modulos WLC, IO, ALU y RAM
RAM_CLK es la frecuencia de entrada del circuito, con un valor de 1 MHz.
El compilador
Es necesario transformar cada instrucción brainfuck en 4 micro-instrucciones. Para probar los distintos módulos del hardware se pueden escribir a mano las micro-instrucciones en hexadecimal equivalentes a un pequeño programa brainfuck. Cuando van aumentando el numero de módulos suele ir aumentando el tamaño del programa para probarlos en conjunto. Se hizo necesario crear un pequeño compilador que convierta un programa brainfuck en un conjunto de micro-instrucciones.
El compilador lee el programa brainfuck de un archivo de texto, y devuelve 4 archivos binarios correspondientes a los cuatro módulos del hardware.
El programa ya funciona, pero aun no esta terminado. Aun tengo que añadirle un método para optimizar y reducir el código, para poder variar la ruta de los archivos fuente y destino e incluso para que genere un archivo en formato INTEL HEX de 8 BITS en lugar de un binario puro.
Aquí muestro el código fuente del compilador, que se apoya de una matriz con las equivalencias entre brainfuck y micro-instrucciones.
void main()
{ unsigned int BLOCK;
for( BLOCK = 0 ; BLOCK < 4 ; BLOCK++ )
{ char FSOURCE[] = "c:\BFCODE.txt" ;
file_open( FSOURCE );
unsigned int MODE;
for( MODE = 0 ; MODE < 4 ; MODE++ )
{ unsigned int RR = 0; unsigned int iptr;
for( iptr = 0, RR = 0 ; iptr < 32 ; iptr++ )
{ unsigned int INS;
switch (buff_in[iptr])
{case 'R': RR = 1; break; case '>': INS = 0; break;
case '<': INS = 1; break; case '+': INS = 2; break;
case '-': INS = 3; break; case ',': INS = 4; break;
case '.': INS = 5; break; case '[': INS = 6; break;
case ']': INS = 7; break; default : INS = 8;
}
if (INS <
{ if( buff_in[iptr] != 'R' )
{ unsigned int uC;
for( uC=0 ; uC<4 ; uC++ )
{ unsigned int a =MODE * 128
+ ( iptr - RR ) * 4 + uC * 1 ;
unsigned int b = RR * 512
+MODE* 128 + BLOCK*32 + INS * 4+ uC * 1;
buff_out[a] = INS_HEX
;
}
}
}
}
}
if(BLOCK == 0) file_close( "c:\RAM.txt" );
else if(BLOCK == 1)file_close( "c:\ALU.txt" );
else if(BLOCK == 2)file_close( "c:\IO.txt" );
else if(BLOCK == 3)file_close( "c:\WLC.txt" );
}
return;
}
**********************************
Descripción del Hardware
Esquema de bloques general
La CPU
Formado únicamente por unos 20ICs de la familia 7400 y dos memorias recicladas de teléfonos móviles. Se consigue 128K de memoria de programa, 64K de RAM y una velocidad de ejecución de 250KHz.
Tanto el core como el puerto IO trabajan a una tensión de 3,3V.
Las tecnologías de montaje superficial TSSOP y BGA permiten repartir todos los componentes del circuito en una PCB de 35x50mm.
Cada instrucción BrainFuck esta compuesta de cuatro micro-instrucciones, cada micro-instrucción actúa directamente sobre los distintos módulos.
Memoria ROM
La ROM
La memoria FLASH tiene una capacidad de 32Mbit, con una organización de 2Mx16b. El numero máximo de instrucciones de programa es 128K. Ya que 8 pins de dirección se utilizan para formar una maquina de estados en la misma memoria FLASH, permitiendo ahorrar espacio en la placa a cambio de reducir el numero de instrucciones.
Memoria RAM
La RAM
La memoria RAM, con una capacidad de 64KBytes, también tiene un puntero formado por 4 ICs 74HC193 y un bus de entrada/salida de 8 bits con posibilidad de alta impedancia. Se conecta directamente a otros módulos formando el “camino de datos“.
ALU
La ALU
En un principio se diseño utilizando 2 ICs 74HC181, pero ningún distribuidor los proporcionaba en encapsulados TSSOP y cantidades para prototipos. Se rediseño utilizando de nuevo el 74HC193, que permitía operar leyendo desde la RAM y volver a introducir el dato.
Al mismo tiempo los 74HC193 generan un bit de estado que indica si el dato es igual a 0, necesario para las instrucciones de bucles.
Contador de bucles WHILE
El contador de bucles WHILE
Fue el modulo mas complicado de diseñar, y gracias a la maquina de estados implementada en la FLASH se redujo a 3 ridículos integrados.
Cuando el PC llega a una instrucción ] o [ se lee el bit de estado que genero la ALU y dependiendo de si es 1 o 0 el PC avanzara al siguiente ] o [ de su mismo nivel, es decir, que permite perfectamente bucles anidados.
Puerto de Entrada/Salida
EL puerto de Entrada/Salida
Permite intercambiar datos entre el procesador y el exterior. Son 16 pins, 8 de entrada y 8 de salida.
Permite conectar el procesador a LEDs, sensores o dispositivos SPI.
y por ultimo la simulacion del programa ,[>>[>]+<[-<]<-]
y un par de fotos de un proyecto anterior
__