Présentation
Il était une fois, quand tout était grand et que j'étais petit, j'ai lu le livre de Wojciechowski, Radio-electronic Toys, désireux de donner vie aux appareils qui y sont décrits. Ainsi, au cours de l'année 2008, déjà lointaine, sur plusieurs dizaines de relais électromagnétiques, une ALU 4 bits ( RCVM1 - Machine à calculer numérique à relais - version 1 ) a été assemblée capable d'ajouter et de soustraire. Et puis j'ai pensé - et si j'assemblais un nombre beaucoup plus grand de relais et construisais un ordinateur relais à part entière? Il n'a fallu que 8 ans pour assembler lentement le relais ici et là jusqu'au nombre requis, et j'ai commencé à créer.
Permettez-moi de vous présenter votre projet de création d'une deuxième version d'un ordinateur relais numérique, nommé "BrainfuckPC" - un ordinateur 16 bits avec l'architecture Von Neumann et un ensemble d'instructions pour le langage Brainfuck. Le travail de conception est terminé et je suis en train de fabriquer ce monstre.

1 Spécifications
- Largeur du bus d'adresse: 16 bits
- Adressage: mot par mot, 16 bits / mot
- Capacité de mémoire: 64 kiloslov (128 Ko)
- Largeur du bus de données: 16 bits
- Espace d'adressage unifié pour le code et les données (architecture Von Neumann)
- Fréquence d'horloge (conception): 100 Hz, 1 instruction / cycle
- Jeu d'instructions: Brainfuck ++
- Nombre de relais (conception): 792
- Relais utilisés: interrupteurs reed, RES55 (1p), RES64 (1z)
Détails roulés
Principe général de travail
Considérez la structure généralisée d'un ordinateur:

Figure 1: Structure informatique généralisée
L'élément central est l'additionneur, et pas simple, mais avec transfert parallèle. Pourquoi cela est nécessaire - je dirai un peu ci-dessous.
Le programme et les données sont stockés dans un bloc mémoire. Leur accès se fait à l'adresse enregistrée dans le registre d'instructions IP ou dans le registre d'adresses AP, en fonction de ce que nous voulons maintenant lire - des données à l'adresse spécifiée dans l'AP ou l'instruction enregistrée à l'adresse IP.
Pour utiliser cette bande de Turing (et le langage de programmation Brainfuck l'identifie précisément), nous devons être en mesure d'effectuer l'une des trois actions suivantes:
- Modifiez la valeur dans la cellule de données actuelle, c'est-à-dire effectuez des opérations Ajouter / Sous Dans Brainfuck, la valeur dans la cellule ne peut être modifiée que par un, c'est-à-dire +1 ou -1. Mais avoir un additionneur à part entière, c'est un péché de ne pas réduire les longues chaînes +++++++++++++ (------------) en une seule opération AP + = N ( AP- = N), ce qui accélère considérablement le processus calculs. (n'oubliez pas non plus de transformer [-] (ou [+]) en * AP = 0);
- Modifiez le numéro de la cellule de données actuellement sélectionnée. C'est-à-dire, parcourir la mémoire de données (AP ++, AP--);
- Modifiez le numéro de l'instruction en cours. Tout d'abord, après chaque instruction, nous devons augmenter la valeur du registre IP d'une unité. Deuxièmement, modifiez cette valeur s'il y a des branches dans le code (par défaut pour l'organisation des boucles). Il n'y a qu'un seul indicateur de contrôle - Z. Par conséquent, il existe des commandes JumpIfZero et JumpIfNotZero.
Au total, nous devons être en mesure de fournir à une entrée de l'additionneur la valeur de l'un des trois blocs suivants - registre AP, registre IP, bus DATA. Nous le ferons à travers un registre temporaire, dans lequel nous enregistrerons l'une des valeurs requises, en connectant celle souhaitée à l'aide de clés 16 bits.
À la deuxième entrée de l'additionneur, nous soumettrons un nombre par lequel l'une de ces valeurs devrait passer à plus ou moins. En raison de la largeur limitée de l'instruction, vous ne pouvez la modifier que par un nombre + -12 bits. Cependant, pour Brainfuck, c'est plus que suffisant ("assez pour tout le monde", oui).
Nous prendrons ces 12 bits du registre des commandes, en présence de telles commandes c'est naturel, car une partie des commandes n'utilise pas du tout l'additionneur. N'oubliez pas que les nombres négatifs seront servis dans le code augmenté, avec dépôt pour extra. entrée de transfert d'unité (c'est-à-dire sera A + invB + 1)
Le résultat du calcul est immédiatement chargé à l'endroit où nous l'avons obtenu. En raison du registre temporaire, nous pouvons le faire sans douleur.
Plus de détails (je dirais même ennuyeux) sur l'architecture peuvent être trouvés dans cette vidéo:
Jeu d'instructions
Après avoir dessiné un diagramme schématique général capable de mettre en œuvre 8 instructions de base de Brainfuck, j'ai réalisé qu'il avait un potentiel beaucoup plus grand. Par conséquent, j'ai développé un ensemble d'instructions plus large qui est compatible avec Brainfuck, mais nécessite la compilation de chaque instruction Brainfuck source en une instruction informatique 16 bits.
Description générale des instructions
Toutes les instructions sont en 16 bits. Formé de plusieurs parties.
- Bits 15, 14, 13 - déterminent la classe d'enseignement
- Bit 12 - Bit de signe pour les instructions de signe
- Bits 11-0 - contiennent les 12 bits inférieurs de l'int-a signé. Les 4 bits les plus significatifs sont formés en fonction de la valeur du 12e bit.
Table d'instructions
Manuel d'instructions | Opcode | Fonctionnement | Équivalent de Brainfuck | La description |
---|
ajouter m16 | 0X XX | AP ← AP + m16 | '+' (Répéter m16 fois) | Ajoute la base à la valeur actuelle de la cellule sélectionnée |
sous m16 | 1X XX | AP ← AP - m16 | '-' (Répéter m16 fois) | En conséquence, il soustrait la base de |
ada m16 | 2X XX | AP ← AP + m16 | '>' (Répétez m16 fois) | Augmente la valeur de l'adresse |
annonces m16 | 3X XX | AP ← AP - m16 | '<' (Répéter m16 fois) | Diminue la valeur d'adresse. |
jz m16 | 4X XX | (* AP == 0)? IP ← IP + m16: IP ← IP | «[» | Passez à IP + m16 si la valeur de la cellule actuelle est nulle |
jz m16 | 5X XX | (* AP == 0)? IP ← IP - m16: IP ← IP | Non | Passez à IP - m16 si la valeur de la cellule actuelle est nulle |
jnz m16 | 6X XX | (* AP! = 0)? IP ← IP + m16: IP ← IP | Non | Passez à IP + m16 si la valeur de la cellule actuelle n'est pas nulle |
jnz m16 | 7X XX | (* AP! = 0)? IP ← IP - m16: IP ← IP | ']' | Passez à IP - m16 si la valeur de la cellule actuelle n'est pas nulle |
et m16 | 8X XX | AP ← AP ET m16 | Non | ET logique avec un nombre positif |
et m16 | 9X XX | AP ← AP ET m16 | Non | ET logique avec un nombre négatif (quelqu'un d'autre doit former les 4 bits supérieurs) |
ou m16 | aX XX | AP ← AP OU m16 | Non | OU logique avec constante positive |
ou m16 | bX XX | AP ← AP OU m16 | Non | OU logique avec constante négative |
dans | c0 00 | * AP ← CIN | ',' | Lisez un caractère m8 dans la console. Si le tampon d'entrée est vide, attendez-le. |
dehors | c0 01 | COUT ← * AP | "." | Imprimer le caractère m8 sur la console |
clr.ap | d0 01 | AP ← 0 | Non | Effacer le registre AP. La commande permet la combinaison |
clr.ip | d0 02 | IP ← 0 | Non | Effacer le registre IP. La commande permet la combinaison |
clr.dp | d0 04 | * AP ← 0 | «[+]» ou «[-]» | Effacer la cellule mémoire. La commande permet la combinaison |
set.ap | d0 10 | AP ← * AP | Non | Écrire la valeur actuelle dans le registre AP |
set.ip | d0 20 | IP ← * AP | Non | Écrire la valeur actuelle dans le registre IP |
get.ap | d1 00 | * AP ← AP | Non | Lire la valeur actuelle du registre AP |
get.ip | d2 00 | * AP ← IP | Non | Lire la valeur actuelle du registre IP |
mode.b8 | e1 00 | | Non | Activation 8 bits (1) |
mode.b16 | e2 00 | | Non | Activation 16 bits |
arrêter | f0 00 | | Non | Arrêter la machine |
- AP - Registre d'adresses
- IP - Registre des instructions
- * AP - Emplacement actuel de la mémoire
- CIN - Entrée console
- COUT - Sortie console
- Lorsque le mode 8 bits est activé, l'additionneur continue de fonctionner en mode 16 bits. Cependant, les instructions conditionnelles (à savoir, tester la valeur de la cellule de mémoire actuelle pour une égalité à zéro) deviennent 8 bits. ( AP & 0x00FF == 0)? et ( AP & 0x00FF! = 0)? L'entrée et la sortie de la console ont jusqu'à présent décidé de toujours laisser 8 bits. Pas en Unicode pour imprimer à la fin?
Dans cette vidéo, j'ai parlé en détail (mais peu compris) de ce que fait chaque instruction et à quelles instructions de brainfuck elle correspond:
Additionneur parallèle
Les ordinateurs relais doivent être non seulement relais, mais aussi rapides. Comme tout autre ordinateur, le mien sera également une machine synchrone, équipée d'un générateur d'horloge. Naturellement, je ne voudrais pas gaspiller les cycles d'horloge et essayer d'adapter chaque opération en un cycle - c'est-à-dire que pour les fronts montant et descendant du générateur synchrone, je peux charger une nouvelle commande et l'exécuter. En même temps, il est souhaitable que toutes les commandes soient exécutées pendant la même période de temps.
Chaque relais a un certain retard de fonctionnement et de libération, que nous prendrons pour 1 unité de temps conventionnelle (cu). Si nous utilisons le relais RES22, 1u.e. sera égal à 12-15 ms (informatif), RES64 - 1,3 ms (informatif). L'opération la plus chère (et la plus fréquente) dans ma voiture est l'additionneur.
En soi, c'est assez simple et rapide, mais "il y a une mise en garde" qui réside dans la méthode de calcul et de transmission du signal de transfert.

Figure 2: additionneur de transfert série.
Au départ, j'avais prévu d'utiliser un additionneur de port séquentiel. Dans un tel additionneur, chaque décharge ultérieure dépend de l'état du signal de transfert de décharge de l'actuel. En conséquence, la durée de l'opération de calcul fluctuera entre 2 cu - N * 2 cu, où N est le nombre de chiffres. Par conséquent, un additionneur de report séquentiel de 16 bits aura un retard maximum de 32 cu
Les additionneurs de portage parallèle offrent des performances maximales. Il leur manque les processus de propagation des transferts de décharge en décharge. Dans chaque catégorie, les valeurs de sortie sont générées simultanément:

Figure 3: additionneur de port parallèle
La possibilité de construire un additionneur avec les propriétés indiquées est basée sur la reproduction des fonctions de somme et de transfert, qui ne dépendent que des valeurs des termes, quel que soit l'emplacement de la décharge dans la grille de décharge. Le hic, c'est que le schéma de transfert parallèle lui-même devient plus compliqué à chaque décharge ultérieure. Ici, voyez ce qui se passe:

Figure 4: (qui aurait dû être sous la forme de formules LaTeX, mais pas) L'équation pour le calcul du signal de transfert pour les bits. O Where - au niveau du bit et, - OU au niveau du bit
Par conséquent, l'implémentation de la migration parallèle est assez coûteuse. Cependant, on peut noter que la prochaine décharge contient l'équation pour calculer la précédente (il devrait y avoir un mème «ok ??» avec Nicolas Cage), donc, en principe, il suffira de faire un schéma de calcul de transfert uniquement pour la sortie senior, et de collecter le reste, en fournissant conclusion des résultats intermédiaires.

Figure 5: Diagramme complet d'un additionneur parallèle 16 bits
Dans la figure 5, les deux premières colonnes sont les additionneurs eux-mêmes. Viennent ensuite les blocs 2AND et 2OR, qui forment les valeurs intermédiaires de h et k, qui sont illustrées à la figure 4. Leur présence m'a incité à étendre la liste des commandes avec les opérations logiques d'addition et de multiplication, pour lesquelles je n'ai besoin que d'ajouter quelques verrous et le microcode correspondant.
Tout le reste est constitué de blocs 5AND basés sur 4 relais RES64, qui peuvent être soudés afin qu'un module puisse être utilisé, par exemple, 2AND + 3AND. Pour ces blocs, chaque étape logique ET est émise via une diode, ce qui vous permet de collecter des signaux de transfert intermédiaires.
Temps de propagation du signal estimé: les additionneurs font face à 1 cu, à ce moment les signaux sont générés aux sorties des blocs 2AND / 2OR, puis 1 cu - par multiplication en blocs 5AND, l'addition logique sur diodes, n'introduit pas de retard. Eh bien, le dernier dépensé pour recalculer l'additionneur.
Total 3 cu contre 32, ou pas plus de 4,5 ms pour l'additionneur.
Registres
Il y a quatre registres spécialisés 16 bits dans la machine. Pas de RON. Seulement des liens serrés, seulement du hardcore! Il se compose de bascules D, chaque bascule D est un module séparé sur 4 relais RES55 avec le circuit suivant:

Figure 6: Diagramme schématique du module de bascule D. Quelque part il y a encore un connecteur, mais ici ce n'est pas important, car tout est signé.
Les données arrivent à l'entrée Données, dont le relais détermine où ira le signal de synchronisation - pour réinitialiser le déclencheur, ou pour l'installer (dont deux autres relais sont responsables, l'un avec verrouillage automatique). Le quatrième relais obtient la sortie de commutation Q. Une caractéristique très utile.
Carte mémoire

Figure 7: Carte mémoire. Dimensions de la carte 315x200 mm
Un élément très complexe et important, bien que le circuit de mémoire lui-même soit une petite partie du remplissage total du bloc. La tâche de cette carte est, premièrement, de transporter 64 kiloslovos de la mémoire totale des programmes et des données. Il est assemblé sur la base de deux puces de cache de 64 Ko. L'entrée d'adresse via les circuits de protection et le commutateur est connectée au bus d'adresse de l'ordinateur et, du côté du bus de données, à un système complexe de tampon d'entrée et de pilote de sortie, également avec le commutateur. Pour la lecture et l'écriture dans la mémoire, deux lignes W / R et Sync sont responsables. Le premier choisit ce que nous ferons, le second - le fera réellement.
Et bien que cette synchronisation elle-même ne soit pas là, la carte mémoire vit naturellement sa propre vie. Sur le rendu, vous pouvez voir deux matrices LED 16x16. Cet écran affiche une zone de mémoire. Une sorte de VideoRAM, déterminée par programme, soit dit en passant. Interroge la puce mémoire et contrôle la sortie du microcontrôleur Atmega1280.
Pour sim, les tâches du microcontrôleur ne s'arrêtent pas là. L'entrée et la sortie de la console s'y accrochent. Où il sortira - je n'ai pas encore décidé, donc le convertisseur USB-série pour une console régulière et ESp8266 pour le Wi-Fi sont divorcés sur la carte. Selon ce dernier, dans les plans les plus urgents d'avoir une page Web avec la possibilité de télécharger des programmes pour l'ordinateur dans la mémoire et la console elle-même. Oui, les tâches de MK comprennent également le chargement initial du programme dans la RAM, pour lequel il a un accès complet à la RAM, ainsi qu'une petite entrée EEPROM 1 Mbit pour stocker les programmes.

Figure 8: Diagramme schématique d'une carte mémoire. Microcontrôleur et schémas fonctionnels non représentés
Bloc logique
Je ne sais pas comment il finira par chercher. La dernière version est présente sur le circuit informatique général, mais je ne l'aime pas. Très probablement, je ferai un séquenceur à 12 étages et à l'aide de touches, j'enverrai des signaux à des blocs individuels.

Figure 9: Tout autour des blocs 16 bits est un bloc logique
La construction
La conception de la machine est modulaire, cadre de bloc. Le KDPV montre clairement comment sera localisé le remplissage de la machine. Mais tout d'abord:
Module
L'élément de base de l'ordinateur est un module de 60x44 mm, avec un connecteur à 16 broches, portant 4 relais, leur faisceau et 4 LED pour indiquer:

Figure 10: modèle 3D du module
Modules de différents types:
- Additionneur 1 bit avec transfert - 16 pièces;
- Module 5AND pour circuit de transfert parallèle - 32 pièces;
- Module D-flip-flop - 64 pièces par registre, plus un peu de logique;
- Module 4x2AND_SW, pour organiser les verrous. Il n'y a que 4 relais de fermeture;
- Module 4x2AND, pour organiser les verrous. Il y a 3 relais sur 4 avec un contact inverseur. Sur 4 relais, il n'y avait pas assez de broche de sortie;
- Le module est une diode, 8 diodes D226D. Pour organiser un OU à entrées multiples
- Le module universel 2AND / 2OR, vous permet de créer 2AND-NOT, 2OR-NOT, 4AND, 4AND-NOT, 4OR, 4OR-NOT et toute combinaison. Basé sur 4 relais avec contacts de commutation et points communs;
Étant donné que, même si j'ai proposé un bloc de logique de contrôle, déjà rejeté, je ne connais pas le nombre exact de modules de chaque type. Je vais le découvrir sur la route. Le nombre estimé de modules est de 192 pièces.
Bloquer
Nous prenons une carte 150x200mm, soudons 32 connecteurs avec 16 broches, mais pas simples, mais pour envelopper et installer nos modules dessus dans une matrice 8x4, obtenant un tel bloc:

Figure 11: Bloc
Dans ma voiture, il y aura 6 blocs de ce type - deux blocs par additionneur, deux blocs par registre et deux blocs par logique. Je gratte les navets sur quelques blocs de verrous supplémentaires, mais s'ils le sont, ils sont plats et soudés
L'installation enveloppante a été choisie parce que: premièrement, les circuits de chaque carte de base, bien qu'ils soient connus à l'avance, peuvent changer et sont sujets à des erreurs. Deuxièmement, en principe, il est impossible de séparer correctement le bloc logique la première fois, et si tout est clair pour le bloc de registre et que vous pouvez vous tromper avec, par exemple, une ligne de synchronisation, vous devrez refaire la logique mille et une fois. Ce sera beaucoup mieux si vous collectez progressivement chaque composant du bloc logique. Troisièmement, un facteur purement mécanique - il est physiquement impossible de séparer ces blocs sur une carte à deux couches :) Les pneus 16 bits divergent dans de nombreuses directions, qui se croisent à plusieurs reprises.
Au total, chaque unité contient 32 modules, avec un nombre total de relais de 128 pièces. La puissance de chaque unité est de 5V 2A.
Ordinateur
Sur un grand châssis, dimensions de 640x480 mm (en fait un peu plus, mais le nombre est beau) il y a six blocs relais et une carte mémoire:

Figure 12: Emplacement des blocs de machine
L'ensemble de l'ordinateur est inséré dans un cadre en bois en bois précieux, avec façade et arrière en verre.
Fabrication
Malgré la date actuelle, le projet existe bel et bien :-) Et il n'est pas au stade le plus actif, mais toujours en cours de fabrication.
Relais
Je les ai. En grand nombre, mais le problème est qu'il y en a trois cents ou plus d'un millier de stock - un relais de 27 volts et 5 volts RES55 peut ne pas être suffisant pour moi. Je ne peux pas enfin estimer l'ampleur de la catastrophe, mais je pense que la prochaine fois que je collecterai cette machine infernale, le problème disparaîtra en raison de la reconstitution de l'extérieur.

Figure 13: Réserves de relais. 800 pièces de relais - nouvelles, saisies avec succès sur le marché de la radio Mitsa pour un sou
L'une des sources de réapprovisionnement est les cartes de relais DAC provenant des alimentations de laboratoire. En voici:

Figure 14: Cartes d’alimentations de type PSU achetées sur le marché de la radio (non, je ne suis pas
Cartes de circuits imprimés
J'ai décidé de faire toutes les cartes de circuits imprimés moi-même. J'ai serré 300 dollars aux Chinois et depuis 4 mois, je fais le travail de recouvrir les blancs avec de la résine photosensible, translucide, de graver, de recouvrir avec un masque de soudure, de développer, de percer et de fraiser.

Figure 15: Panneaux gravés de différents types
Je fais des planches en plaques, 9 modules sur une plaque 200x150mm. Gravé 30 plaques et collé sur l'application d'un masque de soudure. Je ne commencerai en aucune façon. Le masque de soudage de mon FSR-8000 est bleu, à deux composants et je l'ai déjà traité auparavant.
Les plaques 200x150 mm n'ont pas été choisies par hasard - nous les avons sur le marché de la radio, dans un endroit secret, elles se vendent de manière stable depuis de nombreuses années, et tout mon appareil est adapté à ce format.
En un mot, j'ai commencé à appliquer une résine photosensible (MPF-VSC de Diazonium) à l'aide d'une plastifieuse et ce ne sont que des miracles. La qualité du collage a considérablement augmenté.
Il faudra ensuite découper et percer ces planches, pour lesquelles j'ai même une fraise 3D.

Figure 16: Fraiseuse 3D DIY chinoise 2020CNC
Je l'ai pris pour un modeste 175 dollars exclusivement pour l'électronique. Il suffit de percer et de fraiser des planches, et je regarde déjà des ensembles de vis à billes + rails pour machines 3D. Prêt à acheter un peu cher, mais à assembler vous-même quand il commence à être nécessaire - c'est tout.
:
Les programmes
, . ( ) 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

Les références
openSource. :
- https://github.com/radiolok/RelayComputer2 — .
- https://github.com/radiolok/RelayComputer2/blob/master/roadmap.md , .
- https://hackaday.io/project/18599-brainfuck-relay-computer . GT.
- https://github.com/radiolok/bfutils .