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:- Digitale Logik und Logikgatter einfach erklärt
- Verwendung des 555-Timer als Taktgeber / Clock
- Das Clock-Modul: Taktgeber für unseren Breadboard-Computer
- Speichertypen und Zugriff auf Speicher
- Erste Schritte mit der CPU
- Eine echte WDC W65C02-CPU
- Das Speicher-Modul: Anbindung von RAM und ROM
- Erstes Programm in Maschinensprache: RAM-Test
- Das Sniffer-Modul: Ein Arduino/STM32 zeigt an, was auf dem Bus los ist.
- Erstes Ausgabegerät: Adressierung und Ausgabe auf 8 LEDs
- Programmiersprache-Evolution: von Maschinensprache zu Assembler
- 3-fach 7-Segment-Anzeige als dezimale Ausgabe, Teil 1: Taktungsprobleme
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:- "Du musst einen 4k7-Pullup einbauen" - Das kommt mir doch ein wenig komisch vor. Das Signal am CK-Eingang kommt doch aus einem 7400 NAND-Chip. Damit ist das doch immer auf einem definierten High oder Low. Ein Pullup-Widerstand hilft gegen floating pins - aber die gibt es hier nicht. Aber natürlich habe ich es trotzdem probiert und es habt Null gebracht. Keinerlei Veränderung. War ja zu erwarten.
- "Du brauchst mehr Kondensatoren parallel zu deiner Stromversorgung - du brauchst unbedingt einen Elko, nicht nur diese Kerkos, die du da hast" - Hmmm, ich habe fünf 100nF Kerkos dort verteilt, wo ein wenig ehr Strom gezogen werden könnte, also bei den ICs. Das sollte eigentlich reichen. Aber ein zusätzlicher Elko kann auch nicht schaden. Also einen fetten 100 µF dazu installiert und es tut sich wieder nichts. Nur wenn ich oben auf den Elko fasse, ist die Spanung welliger. Naja, einen Versuch war es wert und evtl. ist das sinnvoll, wenn mein Breadboard-Computer noch mehr Strom verbraucht. Aber momentan ist er bei 200 mA. Und so wie jetzt ist, ist es ausreichend. Das war also auch nichts.
- "Du musst unbedingt Phase2 des 6502 mit in die Schaltung bringen, wenn Phase2 low ist, dann ist die Adressleitung in einem instabilen, nicht verlässlichem Status" - Das hört sich plausibel an. Das wäre auch eine mögliche Erklärung dafür, das nur A1 (und nicht A0 oder A2) querschießt. Evtl. steht da kurzfristig was in der Adressleitung, wo A1 High ist. Das sollte ich weiterverfolgen.
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)Allerdings gibt es da noch das Timing Diagramm:
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.
(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:
- Bisherige Konfiguration: A12...A14 (gelb) kommt 20 ns nach A1 (blau) an.
Abb. Oszi 7 - blaue Kurve: A1, gelbe Kurve neuer Takt A12...A14 = Delta 20 ns
- 2facher Gatterdurchlauf mit TI-Chip: A12...A14 (gelb) kommt 10 ns nach A1 (blau) an.
Abb. Oszi 8 - blaue Kurve: A1 zweifach invertiert durch TI 74HCT00, gelbe Kurve neuer Takt A12...A14 = Delta 10 ns
- 2facher Gatterdurchlauf mit chin. Chip: A12...A14 (gelb) kommt 12 ns vor A1 (blau) an.
Abb. Oszi 9 - blaue Kurve: A1 zweifach invertiert durch chin. "74HC00", gelbe Kurve neuer Takt A12...A14 = Delta -12 ns
- Es reichen auch nur 2 Gatterdurchgänge (= 10 ns Verzögerung von A1) mit einem TI-Chip, damit die Anzeige stabil ist.
- Bei dem chinesischen Chip ergibt sich bei 2 Gatterdurchgängen sogar 32 ns Verzögerung, so dass A1 jetzt sogar 12 ns hinter A12...A14 ist. Die chin. Chips sind echt lahm, 4 Durchgänge würden 64 ms dauern, wofür der TI nur 20 ms braucht. Der chin. ist also 3-mal so langsam wie der TI. Auch damit ist die Anzeige stabil.
- Die chin. Chips sind erstklassige "Bremsen", falls mal Gatterlaufzeiten kompensiert werden müssen. Das behalte ich mal im Hinterkopf.
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: