8-Bit-Breadboard-Computer auf Basis einer 6502-CPU - Zurück in die Zukunft - Zwanzig Nanosekunden, die nicht sein sollten

Bisherige Artikel dieser Serie - hier könnt ihr nochmal alle Grundlagen nachlesen, falls ihr jetzt erst einsteigt: Im letzten Teil, als ich meinen Breadboard-Computer um eine 3-fach 7-Segment-Anzeige erweitern wollte, stolperte ich darüber, dass sich die mittlere Anzeige änderte, obwohl sie keinen Takt bekam.


Abb. Oszi 1 - blaue Kurve: Q-Ausgang des 374er für A1, gelbe Kurve: Taktung durch A12...A14

Oszilloskop Anfänger-Fehler

Dass die (A12...A14 AND A1) - Leitung, also der CK-Takt für 0x7001 dabei immer high bleibt, habe ich natürlich vorher auch überprüft:


Abb. Oszi 2 - blaue Kurve: Q-Ausgang des 374er für A1, gelbe Kurve: Taktung durch A12...A14

Und dabei natürlich einen Oszilloskop-Anfänger-Fehler gemacht: Wenn ich das Oszi so einstelle, dass es nur 2500 mal pro Sekunde scannt, also die Werte am Eingang misst, dann habe ich bei beispielsweise einem kurzzeitigen Spannungsabfall von 20 Nanosekunden eine Chance von nur (1/20'000 ms) / (1/4 ms) = 0,0002 = 0,02 %, dieses superkurze Signal auch zu erwischen.

Aber ein Low-Peek von nur 20 ns reicht schon, um den 74HC374 zu schalten. Es lag also sehr wohl ein Takt an, auch wenn ich ihn übersehen habe.

Wenn ich aber 500 Mio. Messungen pro Sekunden (500 MS/s) durchführe, dann entgeht mir der kurze Abfall auf low nicht mehr:


Abb. Oszi 3 - blaue Kurve: Q-Ausgangssignal des 374er für A1, gelbe Kurve: Ausgangssignal NAND für A12...A14

Und dieser dauert etwas über 20 ns, genug um den schnellen 74HC374 zu takten und damit die Ausgabe zu verändern. Das steckt also hinter dem geheimnisvollen Phänomen - ich musste nur ganz genau hinschauen.

Vorschläge aus der Community

Nur: wie kommt dieser 20 ns dauernde Einbruch nun zustande? Und was kann ich dagegen tun? Ich habe mir mal ein wenig in den einschlägigen Foren umgehört und bekam ein paar Vorschläge:

Vorschlag: CPU-Clock (PHI2) mit einbeziehen

Wenn die Adressleitungen während der Low-Phase des PHI2-Clock-Signals undefiniert sind, dann finde ich doch sicher auch einen Hinweis im Datenblatt. Dort finde ich allerdings keinen Warnhinweis. Eher das Gegenteil:
1 INTRODUCTION

The W65C02S is a fully static core and the PHI2 clock can be stopped when it is in the high (logic 1) or low (logic 0) state.
3.8 Phase 2 In (PHI2), Phase 2 Out (PHI2O) and Phase 1 Out (PHI1O)
Phase 2 In (PHI2) is the system clock input to the microprocessor internal clock. During the low power Standby Mode, PHI2 can be held in either high or low state to preserve the contents of internal registers since the microprocessor is a fully static design. The Phase 2 Out (PHI2O) signal is generated from PHI2. Phase 1 Out (PHI1O) is the inverted PHI2 signal. An external oscillator is recommended for driving PHI2 and used for the main system clock. All production test timing is based on PHI2. PHI2O and PHI1O were used in older systems for system timing and internal oscillators when an external crystal was used.
Allerdings gibt es da noch das Timing Diagramm:


(Quelle: WDC W65C02 Datenblatt)

Das ist nicht ganz so einfach zu lesen, aber ich interpretiere das so, dass A0-A15, also die Adressleitungen nur in der Low-Phase von PHI2 ausgebaut werden (irgendwann müssen sie ja) und dass man in der High-Phase von PHI2 auf jeden Fall auf der sicheren Seite ist, dass sich da nichts mehr ändert.

Auf der anderen Seite wird der Datenbus am Ende des High-Zyklus (genau zum Zeitpunkt der fallenden Flanke) von PHI2 geändert. Wir müssen also möglichst schnell nach Steigen der Flanke von PHI2 auf die Daten zugreifen, da sie sich dann bald ändern. Bei 1 MHz Taktfrequenz wären das 0.5 µs, also 500 ns. Da liegen wir mit unserer Verzögerung durch die NAND-Gatter mit ~20 ns noch gut im Rahmen. Selbst bei 10 Mhz Takt (Fenster sinkt auf 50 ns) ginge noch alles gut und bei Maximaltakt von 14 Mhz (Fenster 35.7 ns) wird es langsam knapp.

Also habe ich den Vorschlag einmal umgesetzt und den PHI2-Takt der CPU mit einbezogen. Ich gebe zu, ich habe mich verleiten lassen, dass gleich auszuprobieren, weil es nicht viel Aufwand war, das umzusetzen. Und es nicht komplett durchgedacht. Und das Ergebnis sieht folgendermaßen aus:


Abb. Oszi 4 - blaue Kurve: alter Takt A12...A14, gelbe Kurve neuer Takt A12...A14+PHI2

Eigentlich hätte mir das klar sein sollen: Das PHI2-Clock-Signal zerstückelt mir natürlich mein Signal, dass ich brauche (blau) schon für die LED-Ausgabe (A12 AND A13 AND A14 AND PHI2) und das Ergebnis ist komplett unbrauchbar für meine Zwecke. Die LED-Ausgabe flackert wie wild bei jedem OpCode. Da kann ich mir auch gleich den Datenbus neben der CPU anschauen. Das nächste mal vielleicht doch mehr selbst denken und weniger auf andere hören.

Das Oszillogramm zeigt mir aber auch eines: wenn die Flanke meines bisherigen CK-Signals (blau) auf high geht, geht zeitgleich die PHI2-Clock auf High. Das heißt: im ersten PHI2-Clock-Zyklus bin ich im sicher PHI2-High-Bereich und das gilt auch für den letzten PHI2-Clock-Zyklus kurz vor Ende der Kurve. Und dieser ist ja wichtig, weil dieser letzte Data-Wert ja erhalten bleibt, weil die blaue Kurve dann auf low geht und den D-LAtch-Inhalt sperrt und erhält.

Zurück zum Anfang der Diagnose

Also zurück auf Anfang bei der Diagnose. Die Vorschläge aus der Community haben keine Lösungsannäherung gebracht. Aber das macht nichts. Habe ich mich doch trotzdem näher mit einigen Dingen beschäftigt und was dazu gerlernt, was später vielleicht noch einmal wichtig werden könnte.

Gatterlaufzeiten

Ich habe noch einmal die Laufzeiten durch die NAND-Gatter gemessen, und zwar einmal für den Wechsel auf High und einmal für den Wechsel auf Low:




Abb. Oszi 5, 6 - blaue Kurve: A12 ungefiltert, gelbe Kurve: Ausgangssignal NAND für A12...A14


und komme bei beiden mal auf knapp unter 20 ns für die Verarbeitungszeit durch vier NAND-Gatter, die ich hier einmal eingezeichnet habe (rechts eingehend, oben abgehend):


blau: A12 ungefiltert, gelb: Ausgangssignal von NAND für A12...A14

Der Fachbegriff dafür ist Gatterlaufzeit (englisch propagation delay). Für mich heißt das: Wir müssen PHI2 mit ins Boot nehmen, dürfen es mit dem Kaskadieren von NAND-Gattern aber nicht übertreiben, auch wenn ich den schneller HC-Chip-Typ und nicht den langsamen LS-Chip-Typ verwende. So rund 5 ns muss man also pro Gatterdurchlauf durch den selben 74HC00 rechnen.

Dieses ist übrigens auch im Datenblatt unter "propagation delay" verzeichnet. Da die Gatterlaufzeit abhängig von der Versorgungsspannung ist, ist dies eine Kurve:


Gatterlaufzeit nach Spannung, Quelle: TI SN74HC00N Datenblatt

Für unsere 5V ist dies der niedrigste Punkt bei etwas über 5 ns. Meine Messung mit 5 ns kommt also gut hin.

Schauen wir jetzt noch einmal die Adresslogik im Hinblick auf die Gtterlaufzeiten an:



Wenn wir jetzt A1 mit A12...A14 verknüpfen, dann verknüpfen wir ein 0 ns junges Signal (A1) mit einem 20 ns alten (A12...A14). Die beiden Werte müssen also nicht zwangsläufig beide dem Hier und Jetzt entsprechen, der eine ist 20 ns aus der Vergangenheit respektive der Zukunft (und noch nicht da). Das könnte Ursache für das komische Verhalten der Anzeigen sein.

Auf der anderen Seite scheinen die 10 ns zwischen A12 und A13...A14 noch keine Probleme zu machen. 10 ns Delay scheinen also noch okay zu sein, 20 ns sind es scheinbar nicht.

Andere Kompensationsmaßnahmen

Lösungsansatz: Kondensatoren

Mein nächster Ansatz zur Lösung des Problems hatte den Gedanken, die Spannungseinbruch von 20 ns einfach zu überbrücken, indem ich die Spannung für diese 20 ns einfach per Kondensator aufrecht erhalte. Der kurzer 20 ns Einbruch zu Low ist ja die Ursache, dass der 374er taktet, obwohl er das nicht soll.

Ein Kondensator lädt sich ja auf und gibt dann den Strom dann wieder ab, wenn er kein neues Futter bekommt (sprich in der 20 ns-Lücke). Die Kapazität einer Kondensators legt fest, wie lange er sich auflädt und entlädt.

Da ich hier keine Berechnungsformel parat hatte, habe ich es einfach ausprobiert. Den CPU-Takt auf ca. 200 Hz eingestellt, so dass sich die Änderungen der 7-Segment-Anzeige gut beobachten ließen und das Oszilloskop angeschlossen.

Also die CK-Leitung mit 10 nF angefangen und siehe da: der Drop auf dem Oszi war weg, das Signal blieb auf High. Gegentest - nein, das ist zuviel; die Anzeige aktualisiert sich nicht jedesmal, wenn sie angesprochen wird. Das Hochhalten war also zu lange und überschrieb Takte, die ausgeführt werden sollten.

Bei 22 pF war dann der richtige Wert gefunden: Wenn die Anzeige nicht angesprochen war änderte sich nichts an ihr und wenn sie gemeint war, machte sie jede Änderung mit. Freudig, die Lösung wohl gefunden zu haben, zog ich die Messleitung vom Oszilloskop wieder heraus. Aber was war das? Die Anzeige lief wieder von alleine los. Das Oszi hatte wohl auch noch ein wenig Kapazität mitgebracht. Nun musste es ein 30 pF Kerko sein, damit die Anzeige in bein Zuständen stabil ist.

Das war mir irgendwie eine zu wackelige Angelegenheit. Aber ich hatte noch eine andere Idee.

Lösungsansatz: eigentlich unnötige Gatterdurchläufe

Ich könnte ja ganz einfach A1 vorher durch 4 Gatter schicken und somit um 20 ns verlangsamen. Dann würden beide Signale wieder vom selben Zeitpunkt stammen und wären konsistent.

Zweimal negieren ist wieder der Ausgangswert. Viermal negieren auch. Für die Verzögerung bräuchte ich allerdings pro Gerät einen zusätzlich 74HC00, denn der hat ja genau 4 Gatter.

Die Unterschiede in den Laufzeiten habe ich natürlich wieder mit dem Oszilloskop gemessen: Es stellt sich heraus: Damit wäre dieses vertrackte Problem mit den 7-Segment-Anzeigen endlich gelöst. Das hat mich ganz schön aufgehalten, aber ich habe auch viel dazu gelernt.

Ich habe die ganzen Lösungsexperimente noch einmal in einem Video festgehalten, in dem es natürlich auch wieder ein paar zusätzliche Infos gibt:



Beim nächsten mal kümmern wir uns dann um die Software, um die 7-Segment-Anzeigen richtig ansteuern zu können.