Ordinateur fait maison de la carte AON

Récemment, plusieurs articles sur les ordinateurs faits maison créés à partir de divers composants non standard sont parus sur Habré. J'ai également décidé de parler de mon ordinateur, créé en 1993. Dans le sillage de l'enthousiasme général pour sinclair, je voulais avoir un ordinateur 8 bits complètement original basé sur z80 et, en plus, créer un logiciel pour celui-ci, à partir du système d'exploitation et se terminant par des jouets. Ce qui en est sorti, lu sous la coupe.

La première question qui s'est posée lors de la création de votre ordinateur était la question de l'architecture. J'ai décidé qu'il serait assez compact, basé sur le processeur z80, sans afficher d'image sur un téléviseur, mais avec un écran de texte LCD, un clavier assez grand, une sortie audio sous la forme d'un tweeter à un seul ton (standard à cette époque pour la plupart des ordinateurs) et un port RS232 pour la connexion à d'autres ordinateurs à des fins de programmation et de débogage.

Cependant, un problème est survenu pour obtenir une carte de circuit imprimé pour un circuit entièrement original, car en 1993, les Chinois n'avaient pas encore produit de cartes pour le monde entier, et il était très coûteux de commander le développement et la production à l'usine. Et puis j'ai tourné mon attention vers les tableaux à partir desquels les ID d'appelant ont été créés - les ID d'appelant automatiques. Ils étaient en vente sur le marché Mitinsky, avaient la possibilité d'installer les composants dont j'avais besoin, mais devaient être améliorés. En vente, il y avait plusieurs variétés de ces cartes de circuits imprimés dont, si ma mémoire est bonne, j'ai choisi une carte appelée "Rus".

Permettez-moi de vous rappeler pour les jeunes lecteurs ce qu'était AON. C'était un téléphone avec numérotation par bouton (à propos, à l'époque, c'était plutôt cool, car la plupart des téléphones étaient avec un disque tournant), composé de 12 boutons et d'un indicateur à 9 segments et 7 segments allumé sur lequel le numéro de téléphone était affiché, si il a été possible de déterminer et quelques autres informations. La carte AON contenait un processeur z80, un port parallèle 58055, un circuit décodeur, une minuterie 58053, une ROM de 32 kilo-octets (avec effacement ultraviolet), une RAM statique de 8 kilo-octets, la partie analogique connectée à la ligne téléphonique et, éventuellement, autre chose, ce que j'ai oublié au cours des dernières années.

Le clavier à 12 boutons et l'indicateur disponible sur l'ID de l'appelant ne me convenaient pas catégoriquement, car ils ne pouvaient normalement pas saisir d'informations ni les afficher (en particulier des lettres). Par conséquent, il a été décidé d'utiliser un clavier maison de 40 boutons et un écran LCD texte de 24 caractères et 2 lignes, qui sont ensuite apparus en vente. Pour connecter le clavier et l'écran LCD, il a fallu modifier le schéma AON. La première chose que j'ai faite a été de jeter toute la partie analogique associée à la ligne téléphonique, ou plutôt, je ne l'ai tout simplement pas scellée. Dans le même temps, les jambes de sortie du décodeur, qui sélectionnaient l'indicateur de décharge et les jambes sur le port parallèle 58055, ont été libérées. L'écran LCD nécessitait 4 lignes pour transmettre les informations, mais pour le clavier, il fallait utiliser un décodeur.Étant donné que 40 boutons du clavier étaient disposés dans une matrice de 5 rangées de 8 pièces, il a été décidé de connecter ces 8 boutons au décodeur afin qu'ils puissent être numérisés en fournissant différentes combinaisons de trois lignes à l'entrée du décodeur et en lisant 5 valeurs des rangées de boutons à l'aide du KR580VB55. Ainsi, le code de numérisation du bouton enfoncé sur le clavier avait une taille d'un octet, où les trois premiers bits déterminaient la colonne dans laquelle le bouton était enfoncé et les 5 bits restants indiqués dans quelle ligne ce bouton (ou plusieurs boutons à la fois) était enfoncé . De plus, j'ai considéré que 8 kilo-octets de RAM ne suffiraient pas et je l'ai remplacé par 32 kilo-octets. Dans ce cas, j'ai dû ressouder quelques pistes sur la carte de circuit imprimé, heureusement, les boîtiers de RAM de 8 et 32 ​​kilo-octets étaient presque identiques en brochage. De cette façon,J'ai obtenu 32 kilo-octets de ROM et 32 ​​kilo-octets de RAM (je me souviens que le z80 peut adresser un maximum de 64 kilo-octets, donc j'ai utilisé l'espace d'adressage au maximum). De plus, deux lignes supplémentaires de 58055 sont allées au port série RS232, qui est nécessaire pour se connecter à un autre ordinateur. J'ai mis toute cette économie dans le boîtier du testeur. Le résultat est cette conception:

image

Une fois le matériel terminé, il était temps de créer un logiciel. Ici, il convient de noter que le processus de sa création n'a pas du tout regardé à quoi il ressemble aujourd'hui. Premièrement, la majeure partie a été écrite en assembleur z80 (bien qu'à cette époque presque tous les programmes pour de tels systèmes étaient écrits en assembleur, enfin, sauf pour BASIC). Pour la compilation de l'assembleur à la première étape, mon ami m'a aidé, qui avait un ordinateur Profi - un clone sinclair, mais avec TR-DOS à bord. Ensuite, j'ai commencé à utiliser mon PC IBM, qui était OS / 2, qui exécutait MS-DOS dans une fenêtre distincte, qui, à son tour, exécutait l'émulateur TR-DOS, dans lequel la compilation avait lieu. Je dois dire que lorsque le logiciel s'est considérablement développé, le processus de compilation et d'assemblage a pris dix minutes. Le deuxième problème étaitqu'aucun outil de débogage n'existait et, par conséquent, il était nécessaire de tout télécharger à chaque fois sur mon ordinateur fait maison et de vérifier comment cela fonctionne (la première chose à faire était un programme pour travailler RS232 à 9600 bits par seconde pour le téléchargement). Et enfin, il faut dire qu'après avoir débogué l'image ROM, il fallait l'écrire sur cette ROM elle-même, après avoir effacé ce qui y était déjà écrit. L'effacement a été effectué à l'aide d'une lampe ultraviolette pour bronzer à travers une fenêtre spéciale dans le boîtier du microcircuit, qui a ensuite été recouverte d'un papier adhésif noir spécial, qui sert à sceller le trou sur le côté d'une disquette de 5 pouces pour la protéger de l'écriture. De plus, comme je n'avais pas de programmeur, pour écrire une nouvelle version du logiciel sur ROM, chaque fois que je devais aller chez mon ami à l'autre bout de Moscou,qui avait ce programmeur. Ici, il est nécessaire de clarifier la question, comment était-il possible de déboguer l'image ROM sans la charger dans cette ROM? Il y avait une adresse de base pour cela, que tous mes logiciels utilisaient, décalant les adresses de 32 kilo-octets. Autrement dit, une nouvelle image ROM a été chargée dans la RAM et déboguée là-bas, et après le débogage, l'adresse de base a été définie sur zéro, tout a été compilé à nouveau, et je suis allé à un ami pour écrire une nouvelle version sur ROM.tout a de nouveau été compilé et je suis allé voir un ami pour écrire une nouvelle version en ROM.tout a de nouveau été compilé et je suis allé voir un ami pour écrire une nouvelle version en ROM.

Lorsque le processus de "codage" - "débogage" - "firmware" a été débogué, la question s'est posée d'écrire un système d'exploitation. Le système d'exploitation devait prendre en charge la saisie au clavier, afficher les informations sur un écran LCD, prendre en charge la sortie de différents sons et faire tout cela en parallèle, si possible, c'est-à-dire être multitâche. Pour tout cela, l'architecture suivante a été choisie - il y avait trois types de tâches dans le système d'exploitation: plusieurs tâches en temps réel avec la plus haute priorité, une tâche utilisateur qui interagissait avec la personne elle-même et des tâches d'arrière-plan qui fonctionnaient lorsque le processeur était inactif. J'ai raccroché les tâches avec la priorité la plus élevée sur l'interruption, qui a été générée par le temporisateur KR580VI53 10 fois par seconde. Il faut dire que dans Caller ID, des interruptions ont été générées 400 fois par seconde, car il était nécessaire de mettre à jour l'indicateur très souvent afin deafin qu'une personne ne remarque pas le scintillement. En plus de mettre à jour l'indicateur en interruptions, le clavier a été interrogé pour la recherche de la touche enfoncée. Une interruption si fréquente dans AON a conduit au fait que la plupart du temps du processeur a été consacré à des interruptions, et je voulais que mon ordinateur fasse autre chose d'utile. Depuis que j'ai installé un écran LCD comme dispositif d'affichage d'informations, qui avait sa propre mémoire et n'avait pas besoin d'une mise à jour dynamique, la nécessité d'une telle fréquence d'interruption n'était plus nécessaire. Il a été établi expérimentalement que 10 interruptions par seconde suffisent pour interroger le clavier.que la majeure partie du temps du processeur était en fait consacrée aux interruptions, et je voulais que mon ordinateur fasse autre chose d’utile. Depuis que j'ai installé un écran LCD comme dispositif d'affichage d'informations, qui avait sa propre mémoire et n'avait pas besoin d'une mise à jour dynamique, la nécessité d'une telle fréquence d'interruption n'était plus nécessaire. Il a été établi expérimentalement que 10 interruptions par seconde suffisent pour interroger le clavier.que la majeure partie du temps du processeur était en fait consacrée aux interruptions, et je voulais que mon ordinateur fasse autre chose d’utile. Depuis que j'ai installé un écran LCD comme dispositif d'affichage d'informations, qui avait sa propre mémoire et n'avait pas besoin d'une mise à jour dynamique, la nécessité d'une telle fréquence d'interruption n'était plus nécessaire. Il a été établi expérimentalement que 10 interruptions par seconde suffisent pour interroger le clavier.

Ainsi, des tâches en temps réel ont été lancées à chaque interruption et ont placé de nouvelles informations dans une file d'attente d'événements spéciale. Les événements étaient de plusieurs types et contenaient des informations correspondant au type d'événement, par exemple, l'événement «bouton pressé» contenait un code de balayage. En fait, l'une des tâches prioritaires qui ont démarré à chaque interruption était d'interroger le clavier et de supprimer par programme le rebond des contacts. En plus de cette tâche, il y avait également des tâches prioritaires - des minuteries que la tâche utilisateur pouvait définir et qui, après une heure spécifiée, mettaient en file d'attente l'événement correspondant, il y avait des alarmes qui fonctionnaient à une certaine heure, horloge et calendrier, et il y avait aussi une tâche qui jouait de la musique avec programmation KR580VI53, et l'entrée de celui-ci a été alimentée en données sous forme de notes. De cette façon,la tâche de l'utilisateur pourrait simplement commencer à jouer de la musique et faire d'autres choses.

Un travail utile sur mon ordinateur a été effectué par une tâche utilisateur pilotée par les événements. Une vue typique d'une telle tâche ressemblait à:

while(true) {
  Event e;

  GetEvent(e);

  /* process event */
}


Ici, la fonction GetEvent (e) a attendu que l'événement apparaisse dans la file d'attente et, lorsqu'elle est apparue, a rempli la structure Event. Il est clair que, selon un certain événement, le programme pourrait quitter une boucle infinie et transférer le contrôle au moniteur système, qui a lancé les tâches utilisateur. Étant donné que les événements de la tâche utilisateur étaient généralement traités rapidement, le programme attendait qu'un nouvel événement apparaisse dans la procédure GetEvent (e). Afin d'utiliser en quelque sorte cette attente, des tâches d'arrière-plan ont été introduites que le programme utilisateur pouvait exécuter et qui fonctionnaient indépendamment. C'est-à-dire que lorsqu'une interruption de la minuterie se produit, les tâches en temps réel ont d'abord été accomplies en plaçant des événements dans la file d'attente, puis après l'interruption, la tâche utilisateur a traité tous les événements de la file d'attente, et le temps restant jusqu'à la prochaine interruption a été accordé aux tâches d'arrière-plan.Aujourd'hui, un tel schéma semble naturel, mais en 1993, il était très progressif.

Il y avait un autre problème lié au fait que l'écran LCD ne pouvait pas afficher les lettres russes. Cela est dû au fait que de tels indicateurs viennent d'apparaître sur notre marché et que personne ne les a spécifiquement russifiés. Naturellement, il n'y avait pas de bibliothèques pour travailler avec elles, mais il n'y avait qu'une spécification et une description des commandes. Par conséquent, tout le travail sur l'initialisation et son utilisation devait être écrit à partir de zéro. J'ai résolu le problème de la russification comme suit: une procédure spéciale a été écrite, dont l'entrée était une chaîne avec du texte russe qui devait être affichée. Cette procédure a remplacé toutes les lettres russes similaires au latin par des lettres latines correspondantes, et celles qui étaient impossibles à remplacer ont été créées à la volée à l'aide d'images personnalisées pouvant être téléchargées sur l'écran LCD. Ça devrait être notéqu'il y avait huit images de ces utilisateurs et que, par conséquent, dans le texte russe, il ne pouvait y avoir plus de huit lettres, dont les analogues n'étaient pas dans l'alphabet latin. Mais en général, c'était suffisant. Une autre occasion amusante que j'ai utilisée était que si vous changez les images utilisateur pour un personnage, vous obtenez une animation amusante. J'ai utilisé cette opportunité dans le jeu des sapeurs, dont je parlerai ci-dessous, où le drapeau au-dessus de la mine a flotté dans le vent et la bombe explose.J'ai utilisé cette opportunité dans le jeu des sapeurs, dont je parlerai ci-dessous, où le drapeau au-dessus de la mine a flotté dans le vent et la bombe explose.J'ai utilisé cette opportunité dans le jeu des sapeurs, dont je parlerai ci-dessous, où le drapeau au-dessus de la mine trouvée flotte dans le vent et la bombe explose.

Je vais maintenant vous parler des tâches utilisateur que j'ai créées pour mon ordinateur. Quand j'ai commencé à les créer, j'ai vite réalisé que les écrire en assembleur, comme tout le monde le faisait à l'époque pour des systèmes comme sinclair, est assez triste. Depuis que j'ai programmé C sur un PC IBM, je me suis demandé s'il était possible de programmer sur C et sur mon ordinateur. Après quelques recherches, j'ai trouvé un compilateur du langage C pour TR-DOS, d'ailleurs, dans sa version classique K&R. Ce compilateur était plutôt primitif, par exemple, il ne vérifiait pas si le nombre de paramètres passés à la procédure correspondait à leur nombre réel, sans parler de vérifier leurs types. Mais si je pouvais utiliser ce compilateur pour mon ordinateur, ce serait un énorme progrès. Le problème était de savoir comment adapter le code reçu par ce compilateur pour mon ordinateur.J'y suis allé de la manière classique, que nous avons déjà oubliée, et en 1993 ils s'en souvenaient encore. Cette méthode consistait à compiler le code source non pas directement dans le fichier objet, mais dans le code source de l'assembleur. Ainsi, il était seulement nécessaire d'écrire des macros qui permettraient d'appeler les procédures assembleur compilées à partir du code et vice versa, avec le transfert correct des paramètres, ce qui était fait. L'utilisation de ce compilateur, en plus de la commodité de travailler avec du code, a fourni un autre grand avantage - il est devenu possible de travailler avec la multiplication / division entière (je me souviens que le z80 n'a pas de commandes de multiplication et de division entières), et aussi (lo and behold!), La possibilité de travailler avec des nombres point flottant. Cependant, pour cela, j'ai dû faire face à la bibliothèque attachée au compilateur,car toutes les opérations mathématiques après compilation ont été effectuées comme un appel à cette bibliothèque. Le problème était que cette bibliothèque utilisait des variables temporaires que le compilateur plaçait dans le modèle de mémoire spécifique à TR-DOS, ce qui, bien sûr, ne correspondait pas du tout au modèle de mémoire de mon ordinateur. J'ai dû chercher toutes ces variables temporaires et les refaire pour des adresses qui correspondent à ma RAM. Mais en bonus, j'ai eu beaucoup de fonctions standard comme le sinus et le cosinus, que j'ai utilisées dans mes tâches, dont je parlerai ci-dessous.J'ai dû chercher toutes ces variables temporaires et les refaire pour des adresses qui correspondent à ma RAM. Mais en bonus, j'ai eu beaucoup de fonctions standard comme le sinus et le cosinus, que j'ai utilisées dans mes tâches, dont je parlerai ci-dessous.J'ai dû chercher toutes ces variables temporaires et les refaire pour des adresses qui correspondent à ma RAM. Mais en bonus, j'ai eu beaucoup de fonctions standard comme le sinus et le cosinus, que j'ai utilisées dans mes tâches, dont je parlerai ci-dessous.

Le premier programme créé à l'aide du compilateur C était un programme pour vérifier le bon fonctionnement de la RAM. Ce programme a parcouru toute la RAM, écrit, puis lu divers modèles et comparé le résultat. De plus, l'ensemble du processus a été affiché sur l'écran LCD, ce qui a également confirmé le bon fonctionnement des procédures qui lui sont associées. Il est clair que ce n'était qu'un test du stylo avant d'écrire des programmes plus intéressants. La prochaine chose que j'ai faite a été de créer un éditeur hexadécimal pour modifier le contenu de la RAM. Cet éditeur possédait déjà des possibilités assez larges, comprenant non seulement la visualisation et l'édition de cellules de mémoire, mais également la recherche d'octets intéressants dans la RAM. En particulier, il est devenu possible d'écrire de petits programmes directement en RAM dans des codes machine. Pour tester les capacités sonores de votre ordinateur,J'ai créé un programme comme une «boîte à musique» qui jouait diverses mélodies (je me souviens que les mélodies étaient enregistrées sous forme de notes). En outre, un programme pour le jeu «taureaux et vaches» a été écrit, où une personne a été invitée à deviner un nombre aléatoire à quatre chiffres conçu par un ordinateur (oui, j'ai également créé un générateur de nombres aléatoires). Dans ce programme, j'ai dû créer une liste déroulante avec un historique des numéros déjà entrés, car il était impossible d'afficher une liste particulièrement longue sur deux lignes. Le programme suivant créé était un «sapeur» classique sur un champ 16x16. Comme je n'avais que deux lignes à ma disposition, j'ai fait défiler, ajouter l'accompagnement musical et l'animation d'un drapeau flottant au vent et exploser des bombes. De plus, pour la méditation, j'ai fait un programme qui montrait des vers rampant dans une direction aléatoire,en utilisant la possibilité de télécharger des images personnalisées à l'écran. Eh bien, et où sans le tic-tac-toe classique? J'y ai testé l'algorithme minimax, c'est-à-dire que l'ordinateur a calculé (assez rapidement) toutes les options et n'a jamais perdu. Étant donné que mon système d'exploitation prend en charge les alarmes, l'heure et un calendrier, j'ai créé un programme utilisateur qui définit l'heure, la date et plusieurs alarmes qui, lorsqu'elles atteignent l'heure définie, jouent différentes mélodies. Et enfin, la couronne de création dans mon ordinateur est un programme pour calculer la trajectoire du mouvement dans le problème de deux corps gravitationnels. Autrement dit, pour une position initiale et une vitesse données du corps, ainsi que la masse du centre d'attraction,le problème de l'intégration numérique d'un système de deux équations différentielles ordinaires non linéaires du deuxième ordre avec une étape d'intégration donnée a été résolu. Pour cela, j'ai ajouté une procédure qui intégrait numériquement ces équations. Toutes les variables étaient au format à virgule flottante double. Ici, je souligne une fois de plus que dans le processeur z80, il n'y a pas seulement un support matériel pour travailler avec virgule flottante, mais aussi la multiplication / division habituelle des entiers, tout a été fait par programmation. Cette intégration a fonctionné assez lentement, environ une étape par seconde, mais cela a fonctionné!mais aussi la multiplication / division habituelle des entiers, tout a été fait par programmation. Cette intégration a fonctionné assez lentement, environ une étape par seconde, mais cela a fonctionné!mais aussi la multiplication / division habituelle des entiers, tout a été fait par programmation. Cette intégration a fonctionné assez lentement, environ une étape par seconde, mais cela a fonctionné!

Ce que je voulais toujours implémenter, mais cela n'a pas fonctionné - tout d'abord, l'allocation / désallocation dynamique de la mémoire afin que les ressources de chaque tâche puissent être gérées de manière flexible. De plus, l'enregistrement / la lecture sur bande n'a pas été mis en œuvre, comme cela a été fait dans le Sinclair. Mais dans l'ensemble, j'étais satisfait de ce que j'ai réussi à faire. Je souligne que tout ce qui précède était dans une ROM de 32 kilo-octets - la taille actuelle d'un e-mail pas si grand.

Vous pouvez regarder mon ordinateur en action ici:




Et téléchargez son logiciel ici

All Articles