Introduccion
Érase una vez, cuando todo era grande, y yo era pequeño, leí el libro de Wojciechowski "Electronic Toys", ansioso por dar vida a los dispositivos descritos en él. Entonces, en el año 2008 ya distante, de varias decenas de relés electromagnéticos, se ensambló una ALU de 4 bits ( RCVM1 - Relay Digital Computing Machine - versión 1 ) capaz de sumar y restar. Y luego pensé, ¿y si ensamblo un número significativamente mayor de relés y construyo una computadora de relevos completa? Tomó solo 8 años ensamblar lentamente el relé aquí y allá hasta el número requerido, y comencé a crear.
Permítame presentarle su proyecto para crear una segunda versión de una computadora de retransmisión digital, cuyo nombre en código es "BrainfuckPC", una computadora de 16 bits con arquitectura Von Neumann y un conjunto de instrucciones para el lenguaje Brainfuck. El trabajo de diseño se ha completado, y estoy en el proceso de hacer este monstruo.

1 Especificaciones
- Ancho del bus de direcciones: 16 bits
- Direccionamiento: palabra por palabra, 16 bit / palabra
- Capacidad de memoria: 64 Kiloslov (128KB)
- Ancho del bus de datos: 16 bits
- Espacio de direcciones unificadas para código y datos (arquitectura de Von Neumann)
- Frecuencia de reloj (diseño): 100 Hz, 1 instrucción / ciclo
- Conjunto de instrucciones: Brainfuck ++
- Número de relés (diseño): 792
- Relés usados: interruptores de láminas, RES55 (1p), RES64 (1z)
Detalles enrollados
Principio general de trabajo
Considere la estructura generalizada de una computadora:

Figura 1: Estructura de computadora generalizada
El elemento central es el sumador, y no simple, sino con transferencia paralela. Por qué esto es necesario: lo contaré un poco más abajo.
El programa y los datos se almacenan en un bloque de memoria. El acceso a ellos se lleva a cabo en la dirección registrada en el registro de instrucciones IP, o en el registro de direcciones AP, en función de lo que ahora queremos leer: datos en la dirección especificada en el AP, o la instrucción registrada en la dirección IP.
Para operar esta cinta de Turing (y el lenguaje de programación Brainfuck la identifica con precisión), necesitamos poder realizar una de tres acciones:
- Cambie el valor en la celda de datos actual, es decir, realice operaciones Agregar / Sub. En Brainfuck, el valor en la celda solo se puede cambiar en uno, es decir +1 o -1. Pero tener un sumador completo, es un pecado no colapsar cadenas largas +++++++++++++ (------------) en una sola operación AP + = N ( AP- = N) acelerando significativamente el proceso cálculos (tampoco olvide convertir [-] (o [+]) en * AP = 0);
- Cambiar el número de la celda de datos actualmente seleccionada. Es decir, caminando por la memoria de datos (AP ++, AP--);
- Cambiar el número de la instrucción actual. Primero, después de cada instrucción, necesitamos aumentar el valor en el registro IP en uno. En segundo lugar, cambie este valor si hay ramas en el código (de forma predeterminada para organizar bucles). Solo hay un indicador de control: Z. En consecuencia, hay comandos JumpIfZero y JumpIfNotZero.
En total, debemos poder suministrar a una entrada del sumador el valor de cualquiera de los siguientes tres bloques: registro AP, registro IP, bus de datos. Haremos esto a través de un registro temporal, en el que guardaremos uno de los valores requeridos, conectando el deseado usando claves de 16 bits.
En la segunda entrada del sumador, enviaremos un número por el cual uno de estos valores debería cambiar a más o menos. Debido al ancho limitado de la instrucción, solo puede cambiarla por un número de + -12 bits. Sin embargo, para Brainfuck esto es más que suficiente ("suficiente para todos", sí).
Tomaremos estos 12 bits del registro de comandos, en presencia de dichos comandos es natural, porque algunos equipos no usan el sumador en absoluto. No olvide que los números negativos se servirán en el código aumentado, con la presentación de un extra. entrada de transferencia de unidad (es decir, será A + invB + 1)
El resultado del cálculo se carga inmediatamente donde lo obtuvimos. Debido al registro temporal, podemos hacer esto sin dolor.
Se pueden encontrar más detalles (incluso diría que aburridos) sobre la arquitectura en este video:
Conjunto de instrucciones
Después de dibujar un diagrama esquemático general capaz de implementar 8 instrucciones básicas de Brainfuck, me di cuenta de que tiene un potencial mucho mayor. Por lo tanto, desarrollé un conjunto más amplio de instrucciones que es compatible con Brainfuck, pero requiere compilar cada instrucción Brainfuck de origen en una instrucción de computadora de 16 bits.
Descripción general de las instrucciones
Todas las instrucciones son de 16 bits. Formado de varias partes.
- Bits 15, 14, 13 - determina la clase de instrucción
- Bit 12 - Bit de firma para instrucciones de firma
- Bits 11-0: contienen los 12 bits inferiores del int-a firmado. Los 4 bits más significativos se forman según el valor del 12º bit.
Tabla de instrucciones
Manual de instrucciones | Opcode | Operación | Equivalente de Brainfuck | Descripción |
---|
agregar m16 | 0X XX | AP ← AP + m16 | '+' (Repetir m16 veces) | Agrega la base al valor actual de la celda seleccionada |
sub m16 | 1X XX | AP ← AP - m16 | '-' (Repite m16 veces) | En consecuencia, resta la base de |
ada m16 | 2X XX | AP ← AP + m16 | '>' (Repite m16 veces) | Aumenta el valor de la dirección. |
anuncios m16 | 3X XX | AP ← AP - m16 | '<' (Repetir m16 veces) | Disminuye el valor de la dirección. |
jz m16 | 4X XX | (* AP == 0)? IP ← IP + m16: IP ← IP | '[' | Vaya a IP + m16 si el valor de la celda actual es cero |
jz m16 | 5X XX | (* AP == 0)? IP ← IP - m16: IP ← IP | No | Vaya a IP - m16 si el valor de la celda actual es cero |
jnz m16 | 6X XX | (* AP! = 0)? IP ← IP + m16: IP ← IP | No | Vaya a IP + m16 si el valor de la celda actual no es cero |
jnz m16 | 7X XX | (* AP! = 0)? IP ← IP - m16: IP ← IP | ']' | Vaya a IP - m16 si el valor de la celda actual no es cero |
y m16 | 8X XX | AP ← AP Y m16 | No | Lógico Y con un número positivo. |
y m16 | 9X XX | AP ← AP Y m16 | No | Lógico Y con un número negativo (alguien más debe formar los 4 bits altos) |
o m16 | aX XX | AP ← AP O m16 | No | O lógico con constante positiva |
o m16 | bX XX | AP ← AP O m16 | No | O lógico con constante negativa |
en | c0 00 | * AP ← CIN | ',' | Lea un personaje m8 de la consola. Si el búfer de entrada está vacío, espere. |
fuera | c0 01 | COUT ← * AP | '.' | Imprimir personaje m8 a la consola |
clr.ap | d0 01 | AP ← 0 | No | Borrar AP registro. El comando permite combinación |
clr.ip | d0 02 | IP ← 0 | No | Claro registro de IP. El comando permite combinación |
clr.dp | d0 04 | * AP ← 0 | '[+]' o '[-]' | Borrar la celda de memoria. El comando permite combinación |
set.ap | d0 10 | AP ← * AP | No | Escribir el valor actual en el registro AP |
set.ip | d0 20 | IP ← * AP | No | Escribir el valor actual en el registro IP |
get.ap | d1 00 | * AP ← AP | No | Leer el valor actual del registro AP |
get.ip | d2 00 | * AP ← IP | No | Leer el valor actual del registro IP |
mode.b8 | e1 00 | | No | Activación de 8 bits (1) |
mode.b16 | e2 00 | | No | Activación de 16 bits |
detener | f0 00 | | No | Detener la máquina |
- AP - Registro de dirección
- IP - Instrucciones Registrarse
- * AP: ubicación de memoria actual
- CIN - Entrada de consola
- COUT - Salida de consola
- Cuando se activa el modo de 8 bits, el sumador continúa funcionando en modo de 16 bits. Sin embargo, las instrucciones condicionales (es decir, probar el valor de la celda de memoria actual para la igualdad a cero) se convierte en 8 bits. ( AP y 0x00FF == 0)? y ( AP & 0x00FF! = 0)? La entrada y salida de la consola hasta ahora decidió dejar siempre 8 bits. ¿No está en Unicode para imprimir al final?
En este video, hablé en detalle (pero poco entendido) sobre lo que hace cada instrucción y a qué instrucciones brainfuck corresponde:
Sumador paralelo
Las computadoras de retransmisión deben ser no solo de retransmisión, sino también rápidas. Como cualquier otra computadora, la mía también será una máquina síncrona, equipada con un generador de reloj. Naturalmente, me gustaría no perder los ciclos del reloj e intentar ajustar cada operación en un ciclo; es decir, para los bordes ascendentes y descendentes del generador síncrono, puedo cargar un nuevo comando y ejecutarlo. Al mismo tiempo, es deseable que todos los comandos se ejecuten durante el mismo período de tiempo.
Cada relé tiene un cierto retraso en la operación y liberación, que tomaremos por 1 unidad de tiempo convencional (cu) Si usamos el relé RES22, 1u.e. será igual a 12-15 ms (informativo), RES64 - 1.3 ms (informativo). La operación más costosa (y más frecuente) en mi automóvil es la sumadora.
Por sí solo, es bastante simple y rápido, pero "hay una advertencia" que radica en el método de cálculo y transmisión de la señal de transferencia.

Figura 2: sumador de transferencia en serie.
Inicialmente, planeé usar un sumador de acarreo secuencial. En tal sumador, cada descarga posterior depende del estado de la señal de transferencia de descarga actual. Como resultado, la duración de la operación de cálculo fluctuará entre 2 cu - N * 2 cu, donde N es el número de dígitos. Como resultado, un sumador de acarreo secuencial de 16 bits tendrá un retraso máximo de 32 pies cúbicos
Los sumadores de transporte en paralelo ofrecen el máximo rendimiento. Carecen de los procesos de propagación de transferencias de alta a alta. En cada categoría, los valores de salida se generan simultáneamente:

Figura 3: sumador de transporte paralelo
La capacidad de construir un sumador con las propiedades indicadas se basa en la reproducción de las funciones de suma y transferencia, que dependen solo de los valores de los términos, independientemente de la ubicación de la descarga en la cuadrícula de descarga. El problema es que el esquema de transferencia paralela se vuelve más complicado con cada descarga posterior. Aquí, mira lo que sucede:

Figura 4: (que debería haber sido en forma de fórmulas LaTeX, pero no) La ecuación para calcular la señal de transferencia para los bits. Donde - bit a bit Y, - bit a bit O
Como resultado, implementar la migración paralela es bastante costoso. Sin embargo, se puede observar que la próxima descarga contiene la ecuación para calcular la anterior (debería haber un meme "¿está bien?" Con Nicolas Cage), por lo tanto, en principio, será suficiente hacer un esquema de cálculo de transferencia solo para la descarga principal, y recolectar el resto de ella, proporcionando conclusión de resultados intermedios.

Figura 5: Diagrama completo de un sumador paralelo de 16 bits
En la Figura 5, las dos primeras columnas son los sumadores mismos. Luego están los bloques 2AND y 2OR, que forman valores intermedios de h y k, que se muestran en la Figura 4. Su presencia me llevó a expandir la lista de comandos con operaciones lógicas de suma y multiplicación, para lo cual solo necesito agregar un par de pestillos y el microcódigo correspondiente.
Todo lo demás son bloques 5AND basados en 4 relés RES64, que pueden soldarse para que un módulo pueda usarse, por ejemplo, 2AND + 3AND. Para estos bloques, cada paso AND lógico se emite a través de un diodo, que le permite recopilar señales de transferencia intermedias.
Tiempo estimado de propagación de la señal: los sumadores hacen frente a 1 cu, en este momento las señales se generan en las salidas de los bloques 2AND / 2OR, luego 1 cu - por multiplicación en bloques 5AND, la adición lógica en diodos, no introduce retraso. Bueno el ultimo gastado en recalcular el sumador.
Total 3 cu versus 32, o no más de 4.5 ms para el sumador.
Registros
Hay cuatro registros especializados de 16 bits en la máquina. Sin RON ¡Solo encuadernación apretada, solo hardcore! Consiste en D-flip-flops, cada D-flip-flop es un módulo separado en 4 relés RES55 con el siguiente circuito:

Figura 6: Diagrama esquemático del módulo D-flip-flop. En algún lugar todavía hay un conector, pero aquí no es importante, porque todo está firmado.
Los datos llegan a la entrada de datos, cuyo relé determina a dónde irá la señal de sincronización: para restablecer el disparador o instalarlo (de los cuales son responsables dos relés más, uno con autobloqueo). El cuarto relé obtiene la salida de conmutación Q. Una característica muy útil.
Tablero de memoria

Figura 7: Tarjeta de memoria. Dimensiones de la placa 315x200 mm
Un elemento muy complejo e importante, aunque el circuito de memoria en sí mismo es una pequeña parte del llenado total del bloque. La tarea de esta placa es, en primer lugar, transportar 64 kiloslovos de la memoria total de programas y datos. Se ensambla sobre la base de dos chips de caché de 64 Kbytes. La entrada de dirección a través de los circuitos de protección y el conmutador está conectada al bus de direcciones de la computadora y, en el lado del bus de datos, un complejo sistema de buffer de entrada y controlador de salida, también con el conmutador. Para leer y escribir en la memoria, dos líneas W / R y Sync son responsables. El primero elige lo que haremos, el segundo, en realidad lo hará.
Y aunque esta Sincronización en sí no está allí, la tarjeta de memoria vive naturalmente su propia vida. En el render, puede ver dos matrices LED de 16x16. Esta pantalla muestra un área de memoria. Una especie de VideoRAM, determinado por programación, por cierto. Interroga el chip de memoria y controla la salida del microcontrolador Atmega1280.
Para sim, las tareas del microcontrolador no terminan allí. La entrada y la salida de la consola se cuelgan. Dónde se emitirá: aún no lo he decidido, por lo tanto, el convertidor de serie USB para una consola normal y el ESp8266 para Wi-Fi están divorciados en el tablero. Según este último, en los planes más urgentes para tener una página web con la capacidad de descargar programas para la computadora en la memoria y la consola misma. Sí, las tareas de MK también incluyen la carga inicial del programa en la RAM, para lo cual tiene acceso completo a la RAM, así como una pequeña entrada EEPROM de 1 Mbit para almacenar programas.

Figura 8: Diagrama esquemático de una tarjeta de memoria. Microcontrolador y diagramas de bloques no mostrados
Bloque lógico
No tengo idea de cómo terminará luciendo. La última versión está presente en el circuito informático general, pero no me gusta. Lo más probable es que haga un secuenciador de 12 etapas y con la ayuda de teclas enviaré señales a bloques individuales.

Figura 9: Todo alrededor de bloques de 16 bits es un bloque lógico
Construcción
El diseño de la máquina es modular, marco de bloque. El KDPV muestra claramente cómo se ubicará el llenado de la máquina. Pero lo primero es lo primero:
Modulo
El elemento básico de la computadora es un módulo de 60x44 mm, con un conector de 16 pines, que transporta 4 relés, su arnés y 4 LED para indicar:

Figura 10: modelo 3D del módulo
Módulos de varios tipos:
- Sumador de 1 bit con transferencia - 16 piezas;
- Módulo 5AND para circuito de transferencia en paralelo - 32 piezas;
- Módulo D-flip-flop: 64 piezas por registro, más un poco de lógica;
- Módulo 4x2AND_SW, para organizar pestillos. Solo hay 4 relés de cierre;
- Módulo 4x2AND, para organizar pestillos. Hay 3 de 4 relés con un contacto de cambio. En 4 relés no había suficiente pin de salida;
- El módulo es un diodo, 8 diodos D226D. Para organizar un OR de entrada múltiple
- El módulo universal 2AND / 2OR, le permite crear 2AND-NOT, 2OR-NOT, 4AND, 4AND-NOT, 4OR, 4OR-NOT y cualquier combinación. Basado en 4 relés con contactos de conmutación y puntos comunes;
Como yo, aunque se me ocurrió un bloque de lógica de control, ya rechazado, no sé el número exacto de módulos de cada tipo. Lo resolveré en el camino. El número estimado de módulos es de 192 piezas.
Bloque
Tomamos una placa de 150x200 mm, soldamos 32 conectores con 16 pines, pero no simples, sino para envolver e instalar nuestros módulos en una matriz de 8x4, obteniendo dicho bloque:

Figura 11: Bloque
En mi automóvil habrá 6 de esos bloques: dos bloques por sumador, dos bloques por registro y dos bloques por lógica. Rasco los nabos sobre un par de bloques más de pestillos, pero si lo son, entonces son planos y soldados
La instalación envolvente se eligió porque: en primer lugar, la circuitería de cada placa base, aunque se conoce de antemano, puede cambiar y está sujeta a errores. En segundo lugar, en principio, es imposible separar correctamente el bloque lógico la primera vez, y si todo está claro para el bloque de registro y puede cometer un error, por ejemplo, con una línea de sincronización, tendrá que rehacer la lógica mil y una veces. Será mucho mejor si reúne cada componente del bloque lógico gradualmente. En tercer lugar, un factor puramente mecánico: es físicamente imposible separar estos bloques en una placa de dos capas :) Los autobuses de 16 bits que se cruzan entre sí divergen repetidamente en todas las direcciones.
En total, cada unidad contiene 32 módulos, con un número total de relés de 128 piezas. La potencia de cada unidad es de 5V 2A.
Computadora
En un marco grande, dimensiones de 640x480 mm (de hecho, un poco más, pero el número es hermoso) hay seis bloques de relés y una placa de memoria:

Figura 12: Ubicación de los bloques de la máquina
Toda la computadora se inserta en un marco de madera hecho de madera preciosa, con vidrio frontal y posterior.
Fabricación
A pesar de la fecha actual, el proyecto en realidad existe :-) Y no se encuentra en la etapa más activa, pero aún está en proceso de fabricación.
Relé
Los tengo En grandes cantidades, pero el problema es que hay trescientos de más de mil existencias; un relé de 27 voltios y RES55 de 5 voltios puede no ser suficiente para mí. Finalmente no puedo estimar la magnitud del desastre, pero creo que la próxima vez que recoja esta máquina infernal, el problema desaparecerá debido a la reposición desde el exterior.

Figura 13: Reservas de relé. 800 piezas de retransmisión: nuevas, incautadas con éxito en el mercado de radio Mitsa por un centavo
Una de las fuentes de reabastecimiento son las tarjetas de relé DAC de fuentes de alimentación de laboratorio. Aquí están estos:

Figura 14: Placas de fuentes de alimentación de tipo PSU compradas en el mercado de la radio (no, no estoy
Placas de circuito impreso
Decidí hacer todas las placas de circuito impreso yo mismo. Aseguré 300 dólares a los chinos y durante 4 meses he estado haciendo eso cubriendo los espacios en blanco con fotorresistencia, brillando, grabando, cubriendo con una máscara de soldadura, desarrollando, perforando.

Figura 15: paneles grabados de varios tipos
Hago tableros en placas, 9 módulos en una placa de 200x150 mm. Grabó 30 placas y se pegó al aplicar una máscara de soldadura. No comenzaré de ninguna manera. La máscara de soldadura de mi FSR-8000 es azul, de dos componentes y ya la he tratado antes.
Las placas de 200x150 mm no se eligieron por casualidad: las tenemos en el mercado de la radio, en un lugar secreto, se han estado vendiendo de manera estable durante muchos años, y todo mi dispositivo está diseñado para este formato.
En una palabra, comencé a aplicar fotorresistencia (MPF-VSC de Diazonium) usando un laminador y estos son solo milagros. La calidad del encolado ha crecido significativamente.
Entonces será necesario cortar y perforar estas tablas, para lo cual incluso tengo una fresa 3D.

Figura 16: Fresadora 3D DIY China 2020CNC
Lo tomé por unos modestos 175 dólares exclusivamente para electrónica. Es suficiente para perforar y fresar tablas, y ya estoy mirando juegos de tornillos de bola + rieles para máquinas 3D. Listo para comprar un poco caro, pero para armarlo usted mismo cuando comience a ser necesario, eso es todo.
:
Programas
, . ( ) Elf. , ( ). //TODO — , .
: . , . . Segmentation Fault!
, . — . leBrainfuck , .
, , Brainfuck . +-<>, [-] . , . , .
. 8 . :

— 10 . LLVM 0,9 . Intel Vtune Amplifier 120 10 .
. , 3 brainfuck-. 100 50 347 — .. , ! , , . .
, , ,
.
-6 , , . — , . — . - — 30-40 - 6 .
????777

Referencias
openSource. :
- https://github.com/radiolok/RelayComputer2 : un repositorio con diagramas esquemáticos y diseños de PCB. Un enlace al repositorio de firmware de la placa de memoria que agregaré más tarde
- https://github.com/radiolok/RelayComputer2/blob/master/roadmap.md Anotaré por separado esta página con la hoja de ruta del proyecto en la que se registran los cambios clave.
- https://hackaday.io/project/18599-brainfuck-relay-computer en esta página publico informes detallados sobre lo que se ha hecho. Según el conjunto de masa crítica, se convertirán en un artículo sobre GT.
- https://github.com/radiolok/bfutils compilador y emulador.