Fig.1: Ordinateur relais BrainfuckPC en arrière-plan de son auteurPoursuivant la glorieuse tradition du résumé annuel de mes projets informatiques les plus fous, je vous présente le troisième et
dernier article sur le projet informatique de relais BrainfuckPC.
Dans les séries passées:
Après dix ans de rêveries et de réflexions, plus de deux ans de travail et d'assemblage sans hâte, je peux affirmer avec confiance que le projet informatique relais a eu lieu. Malgré le fait que l'ordinateur est inutile d'un point de vue pratique, et se bloque également régulièrement, il est devenu le point de départ pour les prochains cyber-projets, non moins fous.
Sous le cutter se trouvent des blocs de relais qui sonnent, les calculs de relais les plus rapides au monde, des enveloppements, des indicateurs de vide et bien plus encore.
Langage de programmation Brainfuck
Le langage de programmation brainfuck est peut-être le langage de programmation ésotérique le plus populaire au monde. Et en même temps, le vrai
Turing est un bourbier complet . Seulement 8 instructions sur lesquelles vous pouvez écrire n'importe quoi, mais pour très longtemps.
Par exemple, il m'a fallu trois jours pour écrire et déboguer le programme de division 355/113, qui imprime 6 décimales sur le terminal.
Figure 2: instructions de langage brainfuckLa syntaxe entière du langage est construite autour de la RAM pour 30 000 cellules de mémoire, avec une capacité de 8 bits.
- Avec deux instructions + et -, nous modifions la valeur de la cellule de données actuelle d'une unité vers le haut ou vers le bas.
- Avec deux instructions < et >, nous modifions le pointeur sur la cellule de données en cours, se déplaçant ainsi vers la gauche ou la droite dans la mémoire.
- Deux autres instructions [ et ] - nous permettent d'organiser les boucles. Tout à l'intérieur des supports est le corps de la boucle. Boucles imbriquées autorisées. La logique de l'instruction est simple - si la valeur de la cellule de données actuelle n'est pas égale à zéro - nous allons effectuer une itération de la boucle, si elle est égale, puis sortir de la boucle.
- Les deux dernières instructions . et , - vous permet d'afficher la valeur de la cellule actuelle dans la console, ou entrez sa RAM. L'interactivité est ainsi réalisée.
Oui, c'est plus que suffisant pour écrire n'importe quel programme. L'existence de compilateurs C
dans brainfuck semble le suggérer. Mais la densité du code est inexistante. Pour effectuer des opérations simples, telles que l'ajout des valeurs de deux cellules de mémoire, vous devez exécuter des centaines d'instructions brainfuck.
brainfuck ++
Essayons d'augmenter la densité du code au moins un peu. Lorsque vous étudiez des programmes écrits dans cette langue, vous pouvez faire attention à ce qu'ils consistent pour la plupart en séquences des mêmes instructions
+ - <> . Cela conduit beaucoup à l'idée de plier la séquence de ces instructions en une seule et d'obtenir une petite augmentation de la productivité, qui d'un programme à l'autre peut atteindre des dizaines de pour cent, et donner une augmentation multiple de la vitesse. Par exemple, nous remplaçons 10 opérations d'incrémentation par une opération +10. 20 opérations de déplacement du pointeur vers la droite de l'opération> 20 et ainsi de suite.
Figure 3: instructions de langage brainfuck ++De la théorie à la pratique
Comme vous le comprenez, on ne peut pas simplement prendre et écrire dans le langage du brainfuck l'opération Rb = Ra + Rb, où Ra et Rb sont des cellules de mémoire. Tout ce que nous pouvons faire est de changer le contenu d'une cellule en une constante et de vérifier si elle est nulle. Par conséquent, pour additionner les deux nombres, tout ce qui nous reste à faire est de faire +1 pour la cellule Rb et -1 pour la cellule Ra, jusqu'à ce que le contenu de la cellule Ra devienne nul. Nous écrivons ceci sous la forme d'un code en C:
void addMov(Memory &mem, uint16_t RbPos) { while (*mem) { mem += RbPos; (*mem)++; mem -= RbPos; (*mem)--; } }
Par conséquent, l'ancienne valeur apparaîtra dans la cellule RbPos plus ce qu'elle était à l'adresse source. classe Memory - un conteneur avec 65k cellules entières. Sa propriété principale est que le débordement de la valeur du pointeur le ramènera au début du tableau. Comme dans mon vrai matériel.
L'inconvénient de la fonction décrite est la perte de la valeur d'origine - elle sera remise à zéro. Ajoutez une autre variable Rc pour l'enregistrer:
void addCpy(Memory &mem, uint16_t RbPos, uint16_t RcPos) { while (*mem) { mem += RbPos; (*mem)++; mem -= RbPos; (*mem)--; mem += RcPos; (*mem)++; mem -= RcPos; } }
Par conséquent, le terme copié se trouvera dans la cellule RcPos. Eh bien, dans le cas où il y avait autrefois zéro.
Puisque la notation que j'utilise ressemble beaucoup à brainfuck ++, nous réécrivons simplement notre fonction en caractères bfpp, en prenant RbPos pour 4 et RcPos pour 5 comme exemple:
[
>>>>
+
<<<<
-
>>>>>
+
<<<<<
]
Après avoir décrit toutes les primitives, vous pouvez commencer à les combiner en structures plus complexes et obtenir le programme des fonctionnalités nécessaires. En conséquence, vous pouvez obtenir un programme qui divise 355 par 113 (ou tout autre nombre les uns sur les autres sur 16 bits)
Programme en virgule flottante class Memory { public: Memory() { memset(m_mem, 0, sizeof(m_mem)); memPtr = 0; } Memory& operator += (uint16_t ptr) { memPtr += ptr; return *this; } Memory& operator -= (uint16_t ptr) { memPtr -= ptr; return *this; } uint16_t& operator [] (uint16_t ptr) { return this->m_mem[ptr]; } Memory& operator = (uint16_t ptr) { memPtr = ptr; return *this; } uint16_t & operator * () { return m_mem[memPtr]; } Memory& operator ++ () { memPtr++; return *this; } Memory& operator -- () { memPtr--; return *this; } private: uint16_t memPtr; uint16_t m_mem[65536]; }; void calcPi() { Memory mem; *mem = 22; mem += 1; *mem = 7; while (*mem) { mem += 1; (*mem)++; mem -= 1; (*mem)--; mem += 2; (*mem)++; mem -= 2; }
Architecture de l'ordinateur relais
L'élément central du processeur de relais est un additionneur complet 16 bits avec report parallèle. Deux registres lui sont connectés en entrée. TMP est le registre temporaire dans lequel l'ancienne valeur est placée, et CMD est le registre de commande dans lequel l'instruction et la constante par lesquelles l'ancienne valeur sera modifiée sont stockées.
Par conséquent, je peux effectuer des opérations brainfuck ++ optimisées, et en même temps obtenir des sauts conditionnels complets - Jump If Zero et Jump If Not Zero à n'importe quel côté du programme.
Le résultat de l'opération de sommation peut être téléchargé soit vers l'un des registres de contexte - AP - avec le numéro de la cellule de données courante, soit IP - avec le numéro de l'instruction courante. De plus, le résultat peut être téléchargé dans la cellule RAM actuelle, s'il s'agit d'instructions
+ et
-
Fig. 4: Architecture de l'ordinateur relais en fonctionnement. L'étape de chargement de la nouvelle instruction est remplacée par l'étape de son exécution.Tout d'abord, nous devons calculer le numéro de la prochaine instruction - c'est-à-dire effectuer une opération IP ++. Pour ce faire, une est ajoutée à l'ancienne valeur du registre IP, le résultat est réécrit dans le registre IP et l'instruction suivante est chargée à cette nouvelle adresse, dans le registre CMD.
La deuxième étape est l'exécution de l'instruction nouvellement chargée. S'il fonctionne avec l'additionneur, le processus de son exécution ressemble au processus de chargement d'une nouvelle instruction - l'ancienne valeur est dans le registre temporaire, nous ajoutons la constante se trouvant dans les bits inférieurs du registre CMD et réécrivons le résultat dans le registre ou la cellule de données actuelle.
Ainsi, l'instruction est exécutée en une seule fois du générateur d'horloge. Sur un front descendant, nous chargeons l'instruction suivante, sur une augmentation - nous l'exécutons.
pas un bug, mais une fonctionnalitéEt ici, une caractéristique a été révélée. Après avoir allumé l'ordinateur, le premier front du générateur d'horloge augmentera et donc - nous devrons exécuter l'instruction en cours, que personne n'a encore chargée dans le registre CMD - il y a des zéros.
Suivez les instructions vides et ... faites IP ++!
Par conséquent, la cellule de mémoire zéro du programme contient zéro et ne sera jamais exécutée. La première instruction chargée à partir de la mémoire sera l'instruction à 0x0001.
Jeu d'instructions
Fig.5: Jeu d'instructions de l'ordinateur relaisLes instructions sont de 16 bits, où les 4 bits de poids fort sont responsables du type d'instruction et les 12 bits de poids faible sont la charge utile. Dans la plupart des cas, c'est une constante.
- Instruction NOP - ignorée.
- L'instruction CTRLIO est une instruction spéciale dont le comportement est codé par le masque de bits de la charge utile. Tout d'abord, il implémente des commandes pour écrire sur la console et lire à partir de la console (en modes synchrones ou asynchrones). Deuxièmement, il vous permet de définir le mode de fonctionnement 16 bits ou 8 bits de la machine. Et troisièmement, à l'aide de l'instruction CTRLIO.HALT, vous pouvez arrêter la machine. Le plus drôle, c'est que les morceaux de masque
non bloquant. Vous pouvez les définir au moins en une seule fois, mais le comportement de la machine ne sera pas défini. - L'instruction ADD est une opération de cellule de données. Modifie la valeur de la cellule par la valeur de la constante. Dans ce cas, le bit 12 est un bit signé et est copié dans les bits 13-15. Par conséquent, l'instruction 0x2ffe se transforme en l'opération * AP + = 0x0ffe et l'instruction 0x3ffe se transforme en * AP + = 0xfffe. L'opération de soustraction est remplacée par l'addition d'un nombre négatif.
- Instruction ADA - implémente l'opération AP + = const et vous permet de naviguer dans la mémoire.
- Les instructions JZ et JNZ sont conditionnelles. Selon le drapeau Z, vous pouvez soit sauter quelques instructions en avant ou en arrière, soit rester en place. Selon le mode de fonctionnement de la machine - 16 ou 8 bits, l'état du drapeau Z est déterminé soit par l'octet de données le moins significatif soit par le mot entier.
Spécifications techniques
BrainfuckPC est un ordinateur 16 bits avec un processeur de relais Reed, une architecture Von Neumann et un ensemble d'instructions Brainfuck ++
- Nombre total de relais: 578 pièces
- Le nombre total d'éléments logiques: 157 pièces
- Largeur du bus d'adresse: 16 bits
- Adressage: mot par mot
- RAM: 128 Ko (64 Kslov)
- Largeur du bus de données: 16bit / 8bit
- Fréquence d'horloge (actuelle / maximale): 25 Hz / 40 Hz
- Consommation électrique: 70W
- Dimensions hors tout: 110kh650kh140mm
- Poids: 15kg
Au départ, on supposait que l'ordinateur fonctionnerait à des fréquences allant jusqu'à 100 Hz ... Et ce - pendant une minute - 4 octaves de piano. Malheureusement, les premiers tests ont montré que 40 Hz est le plafond, mais il y en a beaucoup pour le circuit de relais. d'autant plus lorsque la synchronisation externe est nécessaire pour appliquer deux impulsions par cycle - en raison des particularités du circuit de synchronisation avec un signal externe. 80Hz pour la musique, c'est déjà quelque chose.
Composition informatique
Fig. 6: Composants principaux de l'ordinateur relais.Examinons de plus près l'ordinateur. La quasi-totalité du volume de la machine est occupée par des processeurs relais. Pour le moment, tout tient dans cinq blocs, mais il y a de la place pour six - donc si vous le voulez vraiment, plus tard la fonctionnalité du processeur peut être étendue.
Chacun de ces blocs contient 32 modules, dans chaque module il y a 3 ou 4 relais Reed RES55 et RES64. L'alimentation de chaque unité est de 5 V, 3 A.
Fig. 7: Un ensemble de blocs et de modules d'un processeur de relais, prêt à être installé sur un châssis.Chaque module est unifié. Connecteur 60x44 mm, 16 broches. Lors de l'assemblage des blocs logiques, j'ai inséré le module requis dans un emplacement libre et flashé les connexions.
Fig. 8: Les modules à bascule D sont vérifiés pour leur fonctionnement.Rangée centrale - blocs additionneurs et blocs de registres. Au-dessus et au-dessous d'eux se trouvent des verrous 16 bits basés sur RES43, qui commutent le flux de données entre les blocs. Toutes les données tournent ici.
La ligne du bas est la ligne des blocs logiques du processeur. Maintenant, deux blocs sont partiellement remplis, mais si vous le souhaitez vraiment, il est plus que possible de modifier et d'étendre les fonctionnalités en raison de l'espace libre.
Fig. 9: Le cadre est assemblé à partir d'une feuille d'aluminium de 2 mm, sous découpe laser. Sur la photo - cadre déjà soudé et apprêté, prêt pour la peinture.La partie supérieure est indicatrice. Sur la gauche se trouve le bloc d'état de la machine - les indicateurs basés sur l'IV-6 affichent le numéro de la cellule mémoire actuelle et la nuit de l'instruction actuelle, l'instruction elle-même et le compteur général des instructions exécutées. Ce dernier est très utile, car si l'émulateur, par exemple, dit que jusqu'au premier caractère de la console, vous devez exécuter 30 mille instructions, le compteur indiquera clairement où se trouve la machine maintenant et quand elle finira de compter.
Fig. 10: La vue finale de la zone d'indicateur. Dans le processus de fabrication.Sur la droite se trouve la carte mémoire - l'élément le plus controversé de la machine. Bien que je pense que l'ordinateur est toujours relais, le processeur est définitivement 100% relais. La périphérie est plus moderne. En particulier, la RAM est une puce de mémoire statique. Mais presque tous les créateurs modernes d'ordinateurs relais le font aussi.
Fig.11: Programmateur. 16 lignes d'adresse, 16 lignes de données, lignes d'alimentation, de terre et de lecture. Total 36 contacts.Étant donné que la mémoire des programmes et des données est partagée, quelqu'un ou quelque chose, chaque fois que vous allumez l'ordinateur, doit charger le programme dans la RAM. Cette tâche est attribuée au programmeur. Pour le moment, le programmeur est situé sur la carte mémoire elle-même. Maintenant, il a exactement deux tâches.
- Téléchargez le programme dans la RAM, car chaque fois que vous mettez sous tension pour le faire manuellement à l'aide des interrupteurs à bascule, c'est une paresse banale, bien que cette possibilité soit présente.
- Surveillez l'état d'une certaine région de mémoire et affichez-la sur une matrice LED 32x16.
Cela n'affecte pas le processeur, et pour voir en temps réel ce qui se passe dans la RAM est très utile lors du débogage. Par la suite, lorsque le programmateur est externe, le panneau LED servira à l'un des modules indicateurs. Il connaît déjà l'adresse, il reste à lui donner les données d'entrée.
Fig. 12: Schéma fonctionnel des périphériques du processeur.Ainsi, dans un avenir proche, les circuits des périphériques du processeur ressembleront. Seules les puces de mémoire et les circuits d'adaptation de signal avec le circuit de relais resteront sur la carte mémoire.
Grâce au connecteur de programmation à 36 broches, vous pouvez connecter le programmateur et télécharger le firmware sur l'ordinateur. En plus du programmeur, ayant le convertisseur d'interface nécessaire, vous pouvez utiliser n'importe quel autre appareil. Au moins un lecteur de bande perforée (en passant, j'en ai un, avec un punch punch et même une bobine de bande), au moins un panneau avec des interrupteurs à bascule.
En conséquence, la logique de relais fournit une certaine interface et le convertisseur d'interface peut être quelconque. Par ailleurs, le connecteur d'interface parallèle sera compatible avec LPT ...
Démonstration du travail et de l'état actuel
Tout d'abord, le programme Hello World de l'article wikipedia a été exécuté sur l'ordinateur.
Le code source est le suivant:
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
------.--------.>+.>.
Grâce au panneau LED, vous pouvez voir clairement comment les données changent:
Bien qu'à une fréquence de 25 Hz, il soit difficile de garder une trace de ce qui se passe dans la RAM.
Une tâche plus utile et pratique consiste à calculer les signes du nombre Pi après la virgule décimale. Il est clair que les ordinateurs modernes ont résolu ce problème
jusqu'à 31,4 billions de caractères . Mais le fait même que BrainfuckPC soit capable d'effectuer cette opération suggère que l'ordinateur relais n'est pas 100% inutile, mais seulement 99,9.
Tout d'abord, j'ai trouvé un
algorithme de calcul prêt à l'emploi
écrit en brainfuck .
> ++++ (4 digits)
[<+>>>>>>>>++++++++++<<<<<<<-]>+++++[<+++++++++>-]+>>>>>>+[<<+++[>>[-<]<[>]<-]>>
[>+>]<[<]>]>[[->>>>+<<<<]>>>+++>-]<[<<<<]<<<<<<<<+[->>>>>>>>>>>>[<+[->>>>+<<<<]>
>>>>]<<<<[>>>>>[<<<<+>>>>-]<<<<<-[<<++++++++++>>-]>>>[<<[<+<<+>>>-]<[>+<-]<++<<+
>>>>>>-]<<[-]<<-<[->>+<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>+<<<-[>>+<<-]<]<<<<+>>>>>>>
>[-]>[<<<+>>>-]<<++++++++++<[->>+<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>+>[<<+<+>>>-]<<<
<+<+>>[-[-[-[-[-[-[-[-[-<->[-<+<->>]]]]]]]]]]<[+++++[<<<++++++++<++++++++>>>>-]<
<<<+<->>>>[>+<<<+++++++++<->>>-]<<<<<[>>+<<-]+<[->-<]>[>>.<<<<[+.[-]]>>-]>[>>.<<
-]>[-]>[-]>>>[>>[<<<<<<<<+>>>>>>>>-]<<-]]>>[-]<<<[-]<<<<<<<<]++++++++++.
Un problème - bien qu'il soit dit que ce programme est beaucoup plus rapide que certains autres programmes, il calcule toujours le caractère suivant, il est extrêmement lent.
Fig. 13: Temps nécessaire pour sortir N chiffres de Pi après le point décimal.4 décimales devront attendre près d'une heure et demie ...
Fig.14: - Pi = 3! - C'est impoli!Cependant, même deux caractères n'ont pas vraiment pu être déduits; à la place, l'ordinateur a déclaré que Pi avait 4 ans et a terminé le travail.
Fig. 15: Il sait clairement à propos de la blague qu'en vertu de la loi martiale, pi peut aller jusqu'à quatre.J'ai décidé d'aller dans l'autre sens et j'ai écrit une calculatrice de fraction
. Précision - 6 décimales! C'est le résultat le plus précis pour les fractions avec des nombres de taille adéquate.
Après trois nuits blanches, j'ai écrit un programme sur brainfuck, capable de diviser deux nombres et de produire le résultat avec une virgule flottante sur le terminal. Le verdict de l'émulateur est le suivant - il faudra 60 000 instructions à exécuter. Au dernier, 10 mille par signe:
Fig. 16: Le temps nécessaire pour sortir la prochaine décimale lors du calcul de la fraction.À quelle vitesse les prochaines valeurs apparaîtront-elles? Je dois dire très rapidement par rapport au programme précédent!
Mais le bonheur a été de courte durée - l'ordinateur a commencé à échouer en mode 16 bits. Les diagnostics ont montré que la carte mémoire dupe - elle définit constamment le 13e bit. Je vais faire une nouvelle carte mémoire et tout passera, mais pour l'instant je me limiterai à une fraction
deux décimales et mode de fonctionnement 8 bits. Plus important encore, il ne nécessite que 1600 instructions à suivre! À une fréquence de 25 Hz, c'est un peu plus d'une minute.
À plusieurs reprises et avec un coup de sifflet, l'ordinateur fait face à la tâche.
À suivre ...
Maintenant, sur l'ordinateur, vous pouvez exécuter des programmes qui ne nécessitent pas d'entrée utilisateur. Jusqu'à présent, je n'ai pas complètement foiré l'instruction CTRLIO.CIN :) Et je ne vais pas le faire de sitôt. L'ordinateur est actuellement terminé à 98%. Et après deux ans de travail, de nombreux projets se sont accumulés qui attendent le moment où je m'occuperai d'eux.
Par conséquent, je passe à d'autres projets
Tout d'abord, il s'agit d'un ordinateur à tube basé sur des décatrons commutateurs. J'ai déjà à la fois un coup de poing et les décatrons eux-mêmes (bien que la plupart du temps A101 - l'ordinateur sortira encore plus lentement que le relais sur eux - nous avons besoin d'A103). Même 700 tubes à vide sont déjà disponibles et bien plus encore ...

J'ai préparé une mémoire pour cela -
16 morceaux de cubes de mémoire intégrés pour 128 mots de 16 bits chacun. A l'intérieur - plaques de ferrite multi-trous, une sorte de branche mémoire sur des anneaux de ferrite.
Je n’oublie pas non plus la pneumonie - mon ami Anton est engagé dans la nature. expériences, mais plus sur la prochaine fois.
... laissant les imperfections suivantes. Je vais résoudre une partie du problème pour le festival fin mai, une partie - non:
- Une nouvelle carte mémoire sur laquelle seules les puces RAM et leur faisceau sont installés. Il y a un circuit imprimé pour la carte mémoire, le circuit imprimé n'a pas encore été divorcé. À la maison, ce sera trop paresseux pour le faire (un bidirectionnel assez dense), donc j'inclurai cette carte dans la commande lorsque je commanderai des cartes pour quelques autres projets - une horloge mécanique sur un relais et un pneumoscope.
- Avec la nouvelle carte mémoire, des indicateurs de numérotation, du matériel d'affichage de terminal normal et une logique indépendante pour la mise à jour du panneau LED viendront.
- Le programmeur, ou plutôt, le développement de firmware pour cela. En général, si vous avez une ancienne carte mémoire, elle est redondante, mais comme le connecteur de programmation est disponible, vous pouvez déjà charger le programme avec.
- La logique du timing. Ici, je suis complètement paresseux, car il y a littéralement 3 modules logiques. Je vais certainement le faire pour le festival fin mai.
- Instruction de lecture depuis la console. Il est lié à la logique du timing (en fonctionnement synchrone, l'ordinateur doit arrêter le fonctionnement et attendre que les données arrivent).
- Envoyez une demande au Livre Guinness des records ... En tant que processeur de relais le plus rapide et en même temps le plus lent à lire. 16 milliFlops n'est pas à vous de «rentrer un manteau de fourrure en slip» (d'après les commentaires sur youtube).

Toute la documentation sur l'ordinateur relais est dans le
référentiel sur GitHub , et vous pouvez surveiller son état sur n'importe quel réseau social en utilisant les liens de mon profil.
UPD: J'ai refusé de participer au festival.
Et pourtant - du 25 au 26 mai, à Moscou, sur le territoire de la Bread Factory, se tiendra le premier festival de productions artisanales et de culture DIY Antifactory . J'y serai présent avec un ordinateur relais et j'apporterai aussi un contrôleur de relais pour auto-arrosage . L'entrée à l'événement est gratuite, vous serez donc à Moscou ces jours-ci - ne manquez pas la chance de voir mon monstre relais en direct. Si je l'apporte sain et sauf, je vais certainement le démontrer au travail.