Comment trouver un bug dans un microprocesseur sorti il ​​y a trente-cinq ans

K1801VM1A


C'est difficile à croire, mais parfois les erreurs dans les processeurs vivent essentiellement plus longtemps que les processeurs eux-mêmes. Récemment, j'ai été convaincu de cela par l'exemple du microprocesseur 16 bits 1801BM1A , sur la base duquel la famille d'ordinateurs domestiques BK-0010 / 11M a été créée en URSS à un moment donné. A propos de cette famille sur Habré a écrit à plusieurs reprises.


La période de la vie active de BeKashek tombe à la fin des années 80 - au début des années 90 du siècle dernier. Au cours de ces années, grâce aux efforts de nombreux passionnés, ainsi que de groupes de membres de cercle et de coopérateurs, la gamme principale de programmes d'application de la Colombie-Britannique a été développée: jeux, utilitaires, divers "DOS" (systèmes d'exploitation de disque). Parallèlement au développement des logiciels, des périphériques ont été créés sous lesquels leur logiciel système a été écrit. En général, l'écosystème de ces ordinateurs de type PDP 16 bits s'est développé selon des principes similaires, comme, par exemple, les premières architectures ouvertes 8 bits basées sur Intel 8080 et le bus S-100 se sont développées. Plus tard, alors que nous nous éloignons du rôle utilitaire du CD, le centre de la programmation s'est déplacé vers la démoscène.


Le volume de logiciels pour la Colombie-Britannique peut être estimé en visitant des sites publics contenant des collections de programmes . Bien sûr, en comparaison, par exemple, avec le ZX-Spectrum, ce volume est beaucoup plus modeste. Néanmoins, même un tel volume, semble-t-il, aurait dû être suffisant pour contourner tous les coins et recoins imaginables du code machine. Est-il possible de trouver quelque chose d'inhabituel dans le comportement du processeur, après plus de trente ans de pratique dans son utilisation? Il s'est avéré - oui! Ceci sera discuté ci-dessous.


Il est peut-être logique de raconter cette histoire par ordre chronologique. Tout d'abord, je dois d'emblée noter que je ne suis pas du tout un «programmeur d'expérience», ni par profession, ni par appartenance à une cohorte de passionnés de la Colombie-Britannique, à propos desquels j'ai écrit plus haut. Je suis venu en Colombie-Britannique de manière détournée, en partie par nostalgie des passe-temps de l'enfance et de la jeunesse (électronique analogique et numérique, magazine Young Technician , UT-88 et autres métiers et imperfections), et en partie par mon intérêt pour l'architecture et le système de commande PDP-11 . Je n'ai pas BK "dans le matériel" et j'exécute généralement des programmes pour BK et le débogue dans l'émulateur bkemu sur une tablette pour Android.


Il y a quelque temps, je me suis intéressé au programme Kaléidoscope, écrit par Li-Chen Wang-a . Le programme a été écrit en code machine en 1976, pour un microprocesseur Intel 8080 dans le cadre d'un ordinateur Altair 8800 avec un adaptateur graphique Cromemco Dazzler . Je voulais analyser en détail l'algorithme Li-Chen Wang-a et, en même temps, le porter sur le BC. Je dois dire que le désir de porter le Kaléidoscope en Colombie-Britannique a été exprimé plus tôt parmi les démoscéniseurs, et il y a même eu des tentatives d'analyse de l'algorithme, mais ils ont échoué.


Dans mon prochain article, je vais probablement analyser cet algorithme en détail (et pour les impatients, je posterai un lien vers les sources du Kaléidoscope multiplateforme sous libSDL en C). Pour l'avenir, il suffira d'indiquer que le problème a été résolu et que le kaléidoscope a été porté avec succès en Colombie-Britannique. De plus, la génération de son a été ajoutée à l'algorithme sur le CD, et, comme l'image et le son sont générés par le même code, nous pouvons dire que l'image elle-même sonne (toute la démo tient dans moins de 256 octets de code machine, et, J'espère qu'il sera présenté au public au CAFe Demoparty 2019 à Kazan fin octobre).


Ayant fini d'écrire et de déboguer mon programme dans l'émulateur, je me suis tourné vers Damir ("Adamych") Nasyrov (il est l'un des organisateurs de CAFe Demoparty et une personne très connue parmi les demosceners) avec une demande de vérifier l'exécution du programme sur un vrai BC. J'étais particulièrement intéressé par la reproduction du son, car les timings dans l'émulateur pouvaient différer des timings sur du matériel réel. Imaginez ma déception quand Damir m'a informé qu'il y avait une image sur un vrai BC, mais qu'il n'y avait pas de son!


Les nuits suivantes ont été passées à essayer de soustraire de la documentation du système sur le BK-0011M et le schéma de circuit , où pourrait-il y avoir une erreur avec le son. Le son dans le BC est organisé de manière très simple: le 6e bit du registre d'E / S avec l'adresse octale 177716 (registre de contrôle du magnétophone) est émis via un tampon vers un haut-parleur piézoélectrique (bip). En plus de la 6e catégorie, les bits 2 et 5 du même registre sont connectés au convertisseur numérique-analogique le plus simple avec 4 résistances. Depuis la sortie de ce convertisseur, le son peut aller vers le magnétophone. Tout est extrêmement clair et logique, mais il n'y avait pas de son têtu sur un vrai BK, quelles que soient les combinaisons de masques de bits que j'ai essayé d'appliquer à la sortie de données de ce registre. En parallèle, tous les émulateurs BK que je connaissais ont été installés et testés - et le son a fonctionné dans tout le monde!


À un moment donné, j'ai même presque réussi à convaincre Damir que son BK était défectueux, mais le comportement a été répété sur un autre BK-0011M en direct, ainsi que sur le BK-0010. J'ai manqué d'idées, et les habitants de la chaîne de télégramme sur le thème BC, eux aussi, n'ont rien pu dire ... Cependant, l'incident a aidé, comme d'habitude. Au cours d'une des expériences, Damir a lancé une démo sur l'émulateur pour s'assurer qu'il y a du son dans l'émulateur. Et ici, il a réussi à remarquer que non seulement il y a du son dans l'émulateur, mais pas sur le BC, mais aussi les images dans l'émulateur et sur le BC live sont différentes! Ici, je dois vous rappeler que dans mon programme, l'image et le son sont générés par le même code. En conséquence, pendant tout ce temps, je cherchais une raison au mauvais endroit: la raison était dans le code qui générait les données pour le contenu de l'écran.


Damir m'a envoyé une capture d'écran et il est devenu clair que l'algorithme produit des octets avec un contenu nul des 4 bits les plus élevés et, par coïncidence, ces bits ont été émis vers le son (c'est-à-dire toujours des zéros). Cependant, la raison pour laquelle l'algorithme s'est comporté de cette façon est restée vague. C'est la place dans le code (assembleur macro11 de PDP-11, registres r0-r5 renommés!):


; renamed registers a = %0 b = %1 c = %2 d = %3 e = %4 h = %5 ... ... asr b ; sets CF bic #177760, b bis b, c bis (h)+, c ; screen address in c movb (c), a ; get a byte from screen RAM bcc 1$ ; check CF bic #177760, a ; keep bits 0-3, clear rest bisb d, a ; fill bits 4-7 br 2$ 1$: bic #177417, a ; keep bits 4-7, clear rest bisb e, a ; fill bits 0-3 2$: ... ... 

Pour une raison quelconque, sur un vrai BC, un saut conditionnel à la marque de 1 $ a toujours été effectué. Autrement dit, l'instruction bcc a toujours perçu le drapeau de report comme réinitialisé, bien que l'instruction de décalage ASR puisse définir ce drapeau sur 0 ou 1. Comment cela pourrait-il être, car selon la documentation du processeur, ni BIC, ni BIS, ni MOVB devrait affecter le drapeau de transport?!


De plus, dans tous les émulateurs (qui ont été écrits selon la documentation du processeur!) C'est ainsi: ces instructions ne touchent pas le drapeau C.Il est devenu clair que le vrai processeur 1801BM1A ne fonctionne pas dans ce cas selon la documentation. Reste à le confirmer.


Pour commencer, une solution rapide évidente:


  ... asr b ; sets CF mfps -(sp) ; store PSW on stack bic #177760, b bis b, c bis (h)+, c ; screen address in c movb (c), a ; get a byte from screen RAM mtps (sp)+ ; restore PSW from stack bcc 1$ ; check CF ... 

L'enregistrement des drapeaux sur la pile immédiatement après l'instruction de décalage et leur restauration avant le saut conditionnel ont immédiatement résolu le problème, ce qui a montré que j'étais sur la bonne voie. Reste à resserrer le "cercle des suspects". Pour tester l'hypothèse, un tel test synthétique a d'abord été écrit (les registres n'ont pas été renommés ici; l'initialisation a été omise pour ne pas encombrer le code; emt 64 est une interruption de programme pour imprimer une ligne):


  ... mov #1, r1 jsr pc, test clr r1 jsr pc, test halt test: mov #40000, r2 ; r2 points to screen RAM mov #dummy, r5 ; r5 points to dummy = 200 ; *** begin *** asr r1 ; affects CF bic #177760, r1 bis r1, r2 bis (r5)+, r2 movb (r2), r0 ; *** end *** jsr pc, prt rts pc prt: mov #msg1, r0 bcs l1 mov #msg2, r0 l1: emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ dummy: .word 200 ... 

Et le test ... n'a pas fonctionné! Programme imprimé à l'écran


Flag CF set
Drapeau CF effacé


Qu'est-ce qui s'est avéré? Il s'est avéré que l'hypothèse initiale selon laquelle le fragment de code entre le début et la fin gâche le drapeau C est fausse et doit être clarifiée. Quelle est la différence entre ce test et le code source? Et le fait que d'autres instructions soient apparues entre le bloc de commandes "suspectes" et le saut conditionnel. N'affecte pas l'indicateur C, mais modifie néanmoins l'état interne du processeur. Par conséquent, le test suivant était le suivant:


  ... mov #1, r1 jsr pc, test clr r1 jsr pc, test halt test: mov #40000, r2 mov #dummy, r5 ; *** begin *** asr r1 ; affects CF bic #177760, r1 bis r1, r2 bis (r5)+, r2 movb (r2), r0 bcc l1 ; *** end *** mov #msg1, r0 emt 64 rts pc l1: mov #msg2, r0 emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ dummy: .word 200 ... 

Et maintenant, ce test a déjà été imprimé sur un vrai BK-0011M:


Drapeau CF effacé
Drapeau CF effacé


Sur l'émulateur, comme précédemment,


Flag CF set
Drapeau CF effacé


En outre, c'est une question de technologie. Au moyen de simplifications progressives, un tel test minimal a été obtenu sur lequel un bug est reproduit (je cite la source entière):


  .title test .psect code .=.+1000 mov #15, r0 emt 63 sec jsr pc, test clc jsr pc, test halt test: movb r0, r0 bcc l1 mov #msg1, r0 emt 64 rts pc l1: mov #msg2, r0 emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ .end 

Sur un vrai BK-0011M, ce test affiche


Drapeau CF effacé
Drapeau CF effacé


C'est-à-dire que l'instruction MOVB qui était directement en face de l'instruction de branchement conditionnel était à blâmer, et l'apparence du premier opérande n'est pas importante. Si, par exemple, NOP est inséré entre MOVB et BCC, le comportement reviendra à celui documenté et le programme imprimera


Flag CF set
Drapeau CF effacé


Cela a permis de formuler une hypothèse affinée (je me cite sur un télégramme):


... Concernant le bug: le comportement semble avoir disparu. Comme j'imagine, MOVB src, dst (à propos, il semble que les opérandes ne soient pas importants), en raison de certaines caractéristiques architecturales, gâche temporairement le drapeau C à l'intérieur du processeur, mais pas fatalement, car le pourcentage semble enregistrer une copie de ce drapeau. Par conséquent, s'il existe entre le MOVB et la branche conditionnelle d'autres commandes (n'affectant pas C), par exemple NOP, le comportement est tel que décrit dans la documentation.

Que s'est-il passé ensuite? De plus, des collègues de la chaîne ont contribué à amener Vyacheslav (@ K1801BM1, l'homme légendaire qui avait précédemment inversé ce processeur au niveau du transistor) à la discussion. La réaction de Vyacheslav (Yuot) quand il a testé le comportement sur un stand avec un vrai 1801BM1A (orthographe et ponctuation préservées):


Stanislav Maslovski:
au moins deux commandes sont nécessaires pour la reproduction
movb et saut conditionnel en C
Eh bien, avant cela, définissez le drapeau C sur un état connu

Yuot:
Le drapeau avec toujours réinitialisé est obtenu

Stanislav Maslovski:
oui
insérez maintenant nop

Yuot:
Maintenant jamais

Yuot:
Alternance 0 1
C'est dommage

Avec l'aide de Vyacheslav, les détails ont été découverts, à savoir que la raison du bug est que, dans le processeur, en plus du PSW, il existe un autre registre 4 bits, qui stocke normalement une copie des drapeaux du PSW. Ce registre est connecté au micrologiciel automatique et les transitions conditionnelles en prennent les valeurs de drapeau. Lors de l'exécution des instructions MVB, SWAB, MFPS avec le registre récepteur, en raison des particularités du traitement de l'extension de signe et en raison d'une erreur dans le microcode, une copie du drapeau C dans ce registre est rejetée et les transitions conditionnelles utilisant ce drapeau ne fonctionnent pas correctement. Cependant, en suivant les instructions ci-dessous, la valeur de registre temporaire est restaurée à partir du PSW. C'est pourquoi, l'insertion de NOP restaure le comportement correct.


En conclusion, je voudrais également remercier les abonnés de la chaîne de télégramme BK0010 / 11M World d' avoir participé à la discussion de ce bug et pour les commentaires faits sur le texte de l'article. La photo de titre de l'article est une gracieuseté de Manwe_SandS . Plus intéressant, Manwe était sur le point de découvrir le même bug, presque en même temps que Damir et moi avions du mal à résoudre le problème du son!


Maintenant, c'est la petite (je plaisante) - mettez tous les émulateurs en ligne avec le comportement réel du processeur. Après tout, le processeur lui-même, hélas, ne peut plus être réparé.


Je terminerai là-dessus. J'espère que c'était intéressant.

Source: https://habr.com/ru/post/fr471020/


All Articles