
Es ist kaum zu glauben, aber manchmal leben Fehler in den Prozessoren im Wesentlichen länger als die Prozessoren selbst. Kürzlich war ich davon am Beispiel des 16-Bit-Mikroprozessors 1801BM1A überzeugt , auf dessen Grundlage die Haushaltscomputerfamilie BK-0010 / 11M in der UdSSR einst erstellt wurde. Über diese Familie schrieb Habré wiederholt.
Die Periode von BeKasheks aktivem Leben fällt auf das Ende der 80er Jahre - den Beginn der 90er Jahre des letzten Jahrhunderts. In diesen Jahren wurde durch die Bemühungen zahlreicher einzelner Enthusiasten sowie Gruppen von Kreismitgliedern und Mitarbeitern das Hauptangebot an BC-Anwendungsprogrammen entwickelt: Spiele, Dienstprogramme, verschiedene "DOSs" (Festplattenbetriebssysteme). Parallel zur Entwicklung von Software wurden Peripheriegeräte erstellt, unter denen ihre Systemsoftware geschrieben wurde. Im Allgemeinen entwickelte sich das Ökosystem dieser 16-Bit-PDP-ähnlichen Computer nach ähnlichen Prinzipien, wie beispielsweise die frühen offenen 8-Bit-Architekturen, die auf dem Intel 8080 und dem S-100- Bus basieren. Später, als wir uns von der utilitaristischen Rolle der CD entfernen, hat sich der Schwerpunkt der Programmierung auf die Demoszene verlagert.
Das Softwarevolumen für BC kann durch den Besuch öffentlicher Websites mit Programmkollektionen geschätzt werden . Natürlich ist dieses Volumen im Vergleich zum Beispiel mit dem ZX-Spectrum viel bescheidener. Trotzdem sollte selbst ein solches Volumen ausreichen, um alle denkbaren Ecken und Winkel des Maschinencodes zu umgehen. Ist es möglich, nach mehr als dreißigjähriger Erfahrung im Umgang mit dem Prozessor etwas Ungewöhnliches zu finden? Wie sich herausstellte - ja! Dies wird unten diskutiert.
Vielleicht ist es sinnvoll, diese Geschichte in chronologischer Reihenfolge zu erzählen. Zunächst muss ich sofort feststellen, dass ich überhaupt kein „Programmierer mit Erfahrung“ bin, weder beruflich noch einer Kohorte von Enthusiasten des BC, über die ich oben geschrieben habe. Ich kam auf Umwegen nach BC, teils durch Nostalgie nach den Hobbys von Kindheit und Jugend (analoge und digitale Elektronik, das Magazin Young Technician , UT-88 und andere Handwerke und Unvollkommenheiten), teils durch mein Interesse an der Architektur und dem Befehlssystem PDP-11 . Ich habe kein BK "in Hardware" und führe normalerweise Programme für BK aus und debugge es im bkemu- Emulator auf einem Tablet für Android.
Vor einiger Zeit interessierte ich mich für das Kaleidoskop- Programm , das von Li-Chen Wang-a verfasst wurde . Das Programm wurde 1976 in Maschinencode für einen Intel 8080-Mikroprozessor als Teil eines Altair 8800- Computers mit einem Cromemco Dazzler- Grafikadapter geschrieben. Ich wollte den Li-Chen Wang-a-Algorithmus im Detail analysieren und gleichzeitig auf das BC portieren. Ich muss sagen, dass der Wunsch, das Kaleidoskop nach BC zu portieren, früher bei Demoscenern zum Ausdruck gebracht wurde, und es gab sogar Versuche, den Algorithmus zu analysieren, aber sie waren erfolglos.
In meinem nächsten Artikel werde ich diesen Algorithmus wahrscheinlich im Detail analysieren (und für Ungeduldige werde ich unter libSDL in C einen Link zu den Quellen des plattformübergreifenden Kaleidoskops veröffentlichen). Für die Zukunft wird es ausreichen, anzuzeigen, dass das Problem gelöst wurde und das Kaleidoskop erfolgreich nach BC portiert wurde. Darüber hinaus wurde dem Algorithmus auf der CD eine Tonerzeugung hinzugefügt. Da sowohl das Bild als auch der Ton von demselben Code generiert werden, können wir sagen, dass das Bild selbst klingt (die gesamte Demo passt in weniger als 256 Byte Maschinencode und) Ich hoffe, dass es Ende Oktober auf der CAFe Demoparty 2019 in Kasan der Öffentlichkeit vorgestellt wird.
Nachdem ich mein Programm im Emulator fertig geschrieben und debuggt hatte , wandte ich mich an Damir ("Adamych") Nasyrov (er ist einer der Organisatoren von CAFe Demoparty und eine sehr bekannte Person unter den Demoscenern) mit der Bitte, die Programmausführung auf einem echten BC zu überprüfen. Ich war besonders an der Tonwiedergabe interessiert, da die Timings im Emulator von den Timings auf realer Hardware abweichen können. Stellen Sie sich meine Enttäuschung vor, als Damir mir mitteilte, dass es ein Bild auf einem echten BC gibt, aber keinen Ton!
In den nächsten Nächten wurde versucht, von der Systemdokumentation des BK-0011M und dem Schaltplan zu subtrahieren, wo möglicherweise ein Tonfehler aufgetreten ist. Der Ton im BC ist ganz einfach organisiert: Das 6. Bit im E / A-Register mit der Oktaladresse 177716 (Kassettenrekorder-Steuerregister) wird über einen Puffer an einen piezoelektrischen Lautsprecher (Piepser) ausgegeben. Zusätzlich zur 6. Kategorie sind die Bits 2 und 5 desselben Registers mit dem einfachsten Digital-Analog-Wandler mit 4 Widerständen verbunden. Über den Ausgang dieses Konverters kann Ton auf das Tonbandgerät übertragen werden. Alles ist außergewöhnlich klar und logisch, aber auf einem echten BK war kein hartnäckiger Ton zu hören, unabhängig von den Kombinationen von Bitmasken, die ich auf die Datenausgabe in diesem Register anwenden wollte. Parallel dazu wurden alle mir bekannten BK-Emulatoren installiert und getestet - und der Sound funktionierte in allen!
Irgendwann hätte ich es sogar fast geschafft, Damir davon zu überzeugen, dass sein BK fehlerhaft war, aber das Verhalten wurde auf einem anderen Live-BK-0011M sowie auf BK-0010 wiederholt. Mir gingen die Ideen aus, und auch die Bewohner des Telegrammkanals zum Thema BC konnten nichts sagen ... Der Vorfall half jedoch wie üblich. Während eines der Experimente startete Damir eine Demo auf dem Emulator, um sicherzustellen, dass der Emulator Ton enthält. Und hier bemerkte er, dass nicht nur der Emulator, sondern auch der BC Ton enthält, sondern auch die Bilder im Emulator und im Live-BC unterschiedlich sind! Hier muss ich Sie daran erinnern, dass in meinem Programm sowohl das Bild als auch der Ton durch denselben Code erzeugt werden. Dementsprechend habe ich die ganze Zeit am falschen Ort nach einem Grund gesucht: Der Grund war der Code, der die Daten für den Bildschirminhalt generiert hat.
Damir schickte mir einen Screenshot, und es wurde klar, dass der Algorithmus Bytes mit null Inhalten der höchsten 4 Bits erzeugt, und zufällig wurden diese Bits an den Ton ausgegeben (d. H. Immer Nullen). Der Grund, warum sich der Algorithmus so verhielt, blieb jedoch vage. Dies ist die Stelle im Code (Assembler- Makro11 von PDP-11, Register r0-r5 umbenannt!):
; 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$: ... ...
Aus irgendeinem Grund wurde bei einem echten BC immer ein bedingter Sprung bei der 1-Dollar-Marke durchgeführt. Das heißt, der bcc-Befehl hat das Übertragsflag immer als zurückgesetzt wahrgenommen, obwohl der ASR-Verschiebungsbefehl dieses Flag entweder auf 0 oder 1 setzen könnte. Wie könnte dies sein, da gemäß der Prozessordokumentation weder BIC noch BIS noch MOVB sollte die Carry Flag beeinflussen ?!
Darüber hinaus ist es in allen Emulatoren (die gemäß der Dokumentation für den Prozessor geschrieben wurden!) So: Diese Anweisungen berühren nicht das C-Flag. Es wurde klar, dass der reale Prozessor 1801BM1A in diesem Fall gemäß der Dokumentation nicht funktioniert. Dies muss noch bestätigt werden.
Für den Anfang eine offensichtliche schnelle Lösung:
... 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 ...
Das Speichern von Flags auf dem Stapel unmittelbar nach der Schaltanweisung und das Wiederherstellen dieser Flaggen vor dem bedingten Sprung löste sofort das Problem, das zeigte, dass ich auf dem richtigen Weg war. Es bleibt, den "Kreis der Verdächtigen" einzugrenzen. Um die Hypothese zu testen, wurde zuerst ein solcher synthetischer Test geschrieben (die Register wurden hier nicht umbenannt; die Initialisierung wurde weggelassen, um den Code nicht zu überladen; emt 64 ist ein Programminterrupt zum Drucken einer Zeile):
... 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 ...
Und der Test ... hat nicht funktioniert! Programm auf dem Bildschirm gedruckt
Flag CF gesetzt
Flag CF klar
Was hat sich herausgestellt? Es stellte sich heraus, dass die anfängliche Annahme, dass das Codefragment zwischen Anfang und Ende nur das C-Flag verdirbt, falsch ist und geklärt werden muss. Was ist der Unterschied zwischen diesem Test und dem Quellcode? Und die Tatsache, dass andere Anweisungen zwischen dem Block "verdächtiger" Befehle und dem bedingten Sprung erschienen. Das Flag C wird nicht beeinflusst, aber der interne Status des Prozessors wird geändert. Daher war der folgende Test wie folgt:
... 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 ...
Und jetzt wurde dieser Test bereits auf einem echten BK-0011M gedruckt:
Flag CF klar
Flag CF klar
Auf dem Emulator wie zuvor
Flag CF gesetzt
Flag CF klar
Weiter ist eine Frage der Technologie. Durch schrittweise Vereinfachungen wurde ein solcher Minimaltest erhalten, bei dem ein Fehler reproduziert wird (ich zitiere die gesamte Quelle):
.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
Auf einem echten BK-0011M wird dieser Test angezeigt
Flag CF klar
Flag CF klar
Das heißt, der MOVB-Befehl, der sich direkt vor dem bedingten Verzweigungsbefehl befand, war schuld, und das Erscheinen des ersten Operanden ist nicht wichtig. Wenn beispielsweise NOP zwischen MOVB und BCC eingefügt wird, kehrt das Verhalten zum dokumentierten zurück und das Programm wird gedruckt
Flag CF gesetzt
Flag CF klar
Das ermöglichte es, eine verfeinerte Hypothese zu formulieren (ich zitiere mich aus einem Telegrammkanal):
... Bezüglich des Fehlers: Das Verhalten scheint sich geklärt zu haben. Wie ich mir vorstelle, verdirbt MOVB src, dst (übrigens scheinen die Operanden nicht wichtig zu sein) aufgrund einiger architektonischer Merkmale vorübergehend das C-Flag im Prozessor, aber nicht tödlich, da der Prozentsatz eine Kopie dieses Flags zu speichern scheint. Wenn sich zwischen dem MOVB und dem bedingten Zweig andere Befehle befinden (die C nicht beeinflussen), z. B. NOP, ist das Verhalten wie in der Dokumentation beschrieben.
Was ist als nächstes passiert? Außerdem halfen Kollegen des Senders, Vyacheslav (@ K1801BM1, den legendären Mann, der diesen Prozessor zuvor auf Transistorebene umgedreht hatte ) in die Diskussion einzubeziehen. Die Reaktion von Vyacheslav (Yuot), als er das Verhalten auf einem Stand mit einem echten 1801BM1A testete (Rechtschreibung und Zeichensetzung erhalten):
Stanislav Maslovski:
Für die Wiedergabe werden mindestens zwei Befehle benötigt
movb und bedingter Sprung in C.
Setzen Sie vorher Flag C auf einen bekannten Zustand
Yuot:
Das Flag mit immer zurückgesetzt wird erhalten
Stanislav Maslovski:
ja
jetzt nop einfügen
Yuot:
Jetzt niemals
Yuot:
Abwechselnd 0 1
Das ist eine Schande
Mit Hilfe von Vyacheslav wurden die Details herausgefunden, nämlich dass der Grund für den Fehler darin besteht, dass im Prozessor neben dem PSW ein weiteres 4-Bit-Register vorhanden ist, in dem normalerweise eine Kopie der Flags aus dem PSW gespeichert wird. Dieses Register ist mit der automatischen Firmware verbunden und bedingte Übergänge übernehmen die Flag-Werte daraus. Bei der Ausführung der Anweisungen MVB, SWAB, MFPS mit dem Empfängerregister wird aufgrund der Besonderheiten der Verarbeitung der Vorzeichenerweiterung und aufgrund eines Fehlers im Mikrocode eine Kopie des Flags C in diesem Register verworfen, und bedingte Übergänge, die dieses Flag verwenden, funktionieren nicht richtig. Wenn Sie jedoch die folgenden Anweisungen befolgen, wird der temporäre Registerwert aus dem PSW wiederhergestellt. Aus diesem Grund stellt das Einfügen von NOP das korrekte Verhalten wieder her.
Abschließend möchte ich mich auch bei den Abonnenten des Telegrammkanals BK0010 / 11M World für die Teilnahme an der Diskussion dieses Fehlers und für die Kommentare zum Text des Artikels bedanken. Das Titelfoto für den Artikel wurde freundlicherweise von Manwe_SandS zur Verfügung gestellt . Interessanterweise war Manwe kurz davor, denselben Fehler zu entdecken, fast zur gleichen Zeit, als Damir und ich uns bemühten, das Soundproblem zu lösen!
Jetzt liegt es an den Kleinen (nur ein Scherz) - bringen Sie alle Emulatoren mit dem tatsächlichen Verhalten des Prozessors in Einklang. Schließlich kann der Prozessor selbst leider nicht mehr repariert werden.
Damit werde ich enden. Ich hoffe es war interessant.