8-Bit-Breadboard-Computer auf Basis einer 6502-CPU - wie hoch kann ich die Taktfrequenz schrauben?

Bisherige Artikel dieser Serie - hier könnt ihr nochmal alle Grundlagen nachlesen, falls ihr jetzt erst einsteigt: Heutiges Projektziel soll sein, herauszufinden, wie hoch wir die Taktfrequenz einstellen können, die der Breadboard Computer mitmacht. Für die höheren Frequenzen werden wir Oszillatoren verwenden.

Aber rekapitulieren wir erst einmal den Stand der Dinge und der jetzigen Takt-Steuerungsmöglichkeiten auf dem Breadboard: In den neueren Projektteilen haben wir immer mit 40 KHz gearbeitet, was eine angenehme Geschwindigkeit ist. Das LCD baut sich schnell auf, man muss eigentlich auf nichts mehr warten und das System läuft stabil.

Aber wir haben auch noch nicht wirklich so richtig etwas berechnet, was längere Rechenzeit in Anspruch nehmen würde. Wollte wir Pi auf 100 Stellen ausrechnen, müssten wir sicher eine lange Zeit warten.

Darum will ich heute mal schauen, wie hoch ich die Frequenz drehen kann, bevor der Breadboard Computer aussteigt. Das ist sicherlich nicht bei allzuhohen Frequenzen der Fall, denn die Breadboards bestehen aus einzelnen dicht nebeneinander liegenden Metallklammern, die empfänglich sind für Einstrahlungen und die eine gewisse eigenen Kapazität und Widerstand haben.

Die 6502 CPU und der 6522 VIA von WDC können bis zu 14 MHz getaktet werden. Das ist schon mal sehr viel. Ist die Frage, ob die Logik-Chips zur Gerätansteuerung da noch mitkommen. Und natürlich der Computer selbst mit seines Breadboards und langen Leitungen.

Oszillatoren

Um noch höhere Taktfrequenzen könnten man sich einen sündhaft teuren Frequenzgenerator kaufen oder es machen wie ich. Ich habe mir in MegaHertz-Schritten einen Satz von Oszillatoren gekauft. Da kostet das Stück ca. 1 Euro, also habe ich mich mit Werten zu 1, 2, 4, 6, 8, 10, 14 und 16 MHz eingedeckt. 16 MHz wäre schon über den 14 MHz, die die CPU maximal kann, aber einen Versuch ist es eventuell wert.



Ein Oszillator ist ein schwingender Quartz samt der erforderlichen Schaltung, um daraus ein auf- und abschwellendes Signal zu machen. Das hat man alles zusammen in ein kompaktes Gehäuse, meist in einem rechteckigen Blechgehäuse eingebaut. Ein Oszillator hat drei aktive Anschlüsse: VCC, GND und Signal. Der vierte Anschluss dient rein der mechanischen Befestigung.

Mein 8 MHz-Oszillator liefert das folgende Signalbild:



Eine Wellenlänge dauert laut Oszilloskop 125 Nanosekunden, das sind eine Achtel Mikrosekunden, was 8 Millionen Schwingungen pro Sekunde entspricht. Stimmt exakt. Über die Wellenform lässt sich diskutieren. Ich würde das eine mit Sinuskurven emulierte Rechteckkurve nennen. Die ist allemal gut genug zur Taktung unserer CPU.

Nachdem ich das bisherige Takt mit 160 KHz über den Frequenzgenerator ausgereizt habe, platziere ich den ersten Oszillator mit 1 MHz und einen weiteren Schalter auf dem Breadboard, mit dem ich zwischen Frequenzgenerator und Oszillator umschalten kann. Langsam wird es kompliziert mit den ganzen Schaltern. Vielleicht sollte ich mir eine Gedächtnisstütze zeichnen...



1: Ein/Ausschalter Sniffer
2: Ein/Ausschalter Frequenzgenerator
3: Umschalter zwischen manueller Takt und NE555-Takt (7 Hz bis 2 KHz)
4: Umschalter zwischen NE555-Takt (7 Hz bis 2 KHz) und Frequenzgenerator-Takt (1 Hz bis 160 KHz)
5: Umschalter zwischen Frequenzgenerator-Takt (1 Hz bis 160 KHz) und festem Oszillator-Takt (1 Mhz bis 16 Mhz)
6: RGB-LED Anzeige manueller Takt (grün) oder NE555-Takt (blau)
7: Taster zum manuellen Takt (ein Druck entspricht einem Takt)
8: Poti zum einstellen des NE555-Taktes (ganz links:7 Hz; ganz rechts: 2 KHz)
9: blaue LED zur Anzeige des NE555-Taktes
10: weiße LED zur Anzeige des gewählten Ausgangstaktes

Software-Einstellungen

Damit das Timing stimmen kann, muss in der Software die Taktfrequenz eingegeben werden. Nach den dort festgelegten Paramteern richten sich dann die delay-Routinen, die zukünftigt benutzt werden müssen, damit das Timing bei der angegebenen Taktfrequenz passt.

Die Definition der Taktfrequenz erfolgt über folgende Zeilen am Anfang des Source-Codes:

; ?? KHz / 8 = ?? NopsPerMs ; wieviele NOPs braucht es, um eine Millisek. voll zu machen? TaktfrequenzKHz: ASCII 8000 Byte 0 ; wieviele NOPs braucht es, um eine Millisek. voll zu machen? NopsPerMs: equ 250 ; TaktfrequenzKHz / 8 (250 = 2 MHz) NopsPerMsMult: equ 4 ; TaktfrequenzMHz / 2 und NopsPerMs = #250 ; und bei höheren Taktraten: wieviele NOPs pro 10 Mikrosek. (CentiMilliSek.) (min. 1) NopsPerCMs: equ 10 ; NopsPerMs * NopsPerMsMult / 100 Die Angabe TaktfrequenzKHz ist rein kosmetischer Natur. Sie wird ggf. im LCD angezeigt. Wichtig für die richtigen Pausen und das richtige Timing ist der Wert NopsPerMs. Dieser bestimmt, wieviele NOPs-OpCodes es braucht, damit eine Millisekunde in der verwendeten delay-Routine vergeht. In der Routine läuft eine Schleife. delayMs: ; NopsPerMs setzen. Dann gilt: delay (ms) phx phy sta millisecs ldy #NopsPerMsMult ; Wie oft muss die Schleife durchlaufen werden ; (weil 250 NOPs nicht mehr reichen; alles > 2 MHz) delayMsMult: lda millisecs delayMs2: ldx #NopsPerMs ; NopsPerMs mal warten, 1 ms verstreichen lassen delayMs3: NOP ; Zeit verschwenden, 1 NOP = 2 Taktzyklen dex bne delayMs3 dec A bne delayMs2 lda #NopsPerMsMult ; keinen Mult verwendet beq delayMsDone dey ; Mult (min. 2) verwendet, dann runterzählen bne delayMsMult delayMsDone: ply plx rts Bei 255 ist bei NopsPerMs allerdings Schluss, denn das ist ein 1-Byte-Wert. Und da dieser Wert der Taktfrequenz in KHz durch 8 entsprechen muss, entspricht ein NopsPerMs-Wert von 250 gleich 8 x 250 KHz = 2000 KHz.

Über 2 MHz reicht der einfacher NopsPerMs-Wert nicht mehr aus und wir müssen die Schleife nochmals wiederholen. Dazu dient der NopsPerMsMult-Wert. Wenn NopsPerMs auf 250 steht und wir eine vielfache von 2 MHz haben, stellen wir hier einfach die Taktfrequenz in MHz durch 2 ein. Das wird auch für die höchstmöglichen Taktfrequenzen ausreichend sein.

Außerdem gibt es noch den Wert NopsPerCMs. CMs steht für Centi-Millisekunden, also für 10 Mikrosekunden. Dieser Wert ist für eine weitere delay-Scheife nützlich, die in 10 µs Intervallen funktioniert. Das Minimum ist damit dann nicht mehr eine Millisekunde, sondern 10 Mikrosekunden. Das ist sinnvoll für die Pausen zwischen den LCD-Befehlen, die ja 20 µs sein müssen. Hier immer 1 ms nehmen zu müssen, wäre Zeitverschwendung und damit Geschwindigkeitseinbuße. Sinnvoll wird der Einsatz der delayCMs erst bei höheren Taktfrequenzen, bei dem der NopsPerMsMult-Wert über dem Minimum von 1 liegt, also bei Frequenzen über 2 MHz. delayCMs: ; NopsPerCMs setzen. Dann gilt: delayMicroseconds*10 (CMs) ; CMs steht für CentiMilliSek = Hunderstel Millisek. phx delayCMs2: ldx #NopsPerCMs ; NopsPerCMs mal warten, 1 ms verstreichen lassen delayCMs3: NOP ; Zeit verschwenden, 1 NOP = 2 Taktzyklen dex bne delayCMs3 dec A bne delayCMs2 plx rts

Herantasten an die Maximalfrequenz

Jedesmal, wenn ich also einen neuen Oszillator auf das Board stecke, muss ich den Assembler-Source anpassen, ihn neu übersetzen lassen und neu aufs EPROM brennen.

Bei der Maximalfrequenz des Frequenzgenerators von 160 KHz funktioniert alles wunderbar. Danach setze ich den ersten Oszillator mit einem Megahertz ein und auch damit funktioniert der Breadboard Computer nach Anpassung des Source-Codes zur Zufriedenheit.

Weiter geht es mit dem 2 MHz , dem 4 Mhz und dem 8 Mhz Oszillator. Auch das macht der Breadboard Computer alles klaglos mit. Was ich schon erstaunlich finde bei der Qualität der Breadboards und der langen und vielen Kabel. Wir haben hier ja keine professionelle Platine mit auf Kürze optimierte Leiterbahnen vor uns liegen. Dennoch befinden wir uns mit der Taktfrequenz schon über der eines Commodore Amiga mit ca. 7.1 MHz.

Bei 10 MHz steigt der Computer allerdings aus. Auf dem LCD wird nichts mehr ausgegeben und auch die Initialisierung der 7-Segment-Anzeigen schlägt wohl fehl, denn manchmal bleiben nach einem Reset Reste darauf stehen, obwohl die Initialisierungssequenz diese eigentlich löschen sollte.

Kein Wunder, dass mein Test mit dem 14 MHz Oszillator auch fehl schlägt. Das wäre die Frequenz, die der 6502 und der 6522 maximal vertragen würden laut Spezifikation.

Aber ich glaube, mit den 8 MHz kann ich sehr zufrieden sein. So viel hätte ich eigentlich nicht erwartet. Hat sich die Mühe beim Drahtbiegen und Kabel verlegen also doch gelohnt. Ich glaube, mit freien Verdrahtung mit Jumper-Kabeln könnte ich nicht eine so hohe Frequenz erreichen. Wahrscheinlich wäre ich vor lauter Kabelgewirr auch nie so weit gekommen, so viele Dinge auf/im dem Breadboard Computer unterzubringen, sondern wäre vorher an der Fehlersuche verzweifelt, weil ich irgendwann mal aus Versehen an einem Kabel hängengeblieben und das aus dem Breadboard gerupft hätte.

Was noch nicht ganz perfekt funktioniert, ist das KeyPad, das prellt ab und zu mal. Aber ich glaube, dass kann ich softwaretechnisch lösen.

Und dann wäre da natürlich immer noch das Problem mit dem CoProzessor, der nicht so will, wie ich das will. Irgendwas hakt in dem Arduino ATmega328P und das lässt sich nicht so einfach finden. Da muss ich wohl noch ganze Testreihen durchführen, bis das Teil stabil läuft. Aber zum einmal Zufallszahl, Temperatur, Luftfeuchtigkeit, Datum oder Zeit abzurufen, dafür taugt es ja jetzt schon. Man sollte es halt nur nicht in einer Dauerschleife tun. Trotzdem bleibe ich an dem Problem natürlich dran.

Video

Die Tests mit den unterschiedlichen Frequenzen habe ich natürlich wieder in einem Video dokumentiert. Viel Spaß beim Schauen.