8-Bit-Breadboard-Computer auf Basis einer 6502-CPU - neue Adressierungsarchitektur für IO-Geräte mit 74HC688 und 74HC138

Bisherige Artikel dieser Serie - hier könnt ihr nochmal alle Grundlagen nachlesen, falls ihr jetzt erst einsteigt: Nachdem ich im letzten Teil die Adressierung mit den 7400 NAND-Gattern nicht so perfekt funktioniert hatte, wie sie sollte und uns die Gatterlaufzeiten in die Quere kamen, habe ich mir das zum Anlass genommen, mich ein wenig auf dem Chip-Markt umzuschauen und zu überlegen, wie man die Adressierung der IO-Geräte stabiler und vielleicht auch einfacher gestalten könnte. Denn die Logik mit Gattern abzubilden und diese dann - wie ich- vielleicht auch noch in nur NAND-Gatter umzurechnen, ist doch etwas mühsam.

Natürlich hatte ich noch den 6522 in der Schublade liegen, aber ich wollte das erstmal mit "ganz normalen" TTL-Chips hinkriegen.

Der 74HC688 Komparator

Ein Chip, in den ich mich auf den ersten Blick verliebt habe ist der 74HC688. Das ist ein Komparator, zu deutsch ein Vergleicher.

Er vergleicht die jeweils die Eingänge P mit den Eingängen Q und wenn sie alle übereinstimmen, dann gibt er an Pin 19 ein Low aus, ansonsten ein High. Er hat jeweils 8 Eingangspaare zum Vergleich. Wenn man nicht alle braucht, setzt man die überflüssigen Paare beide auf Low (oder High, ist egal), so dass diese dann auf jeden Fall übereinstimmen.

Außerdem hat er einen Pin G. Nur wenn der auf Low ist, kann das Ergebnis P=Q Low werden, ansonsten ist P=Q auch High, wenn P und Q gleich sind. Dies kann man zur zusaätzlichen Steuerung benutzen. Wir brauchen die allerdings nicht, und nageln G deshalb auf Low fest.

Da Gatterlaufzeiten ja nicht unwichtig sind, wie ich in der jüngsten Vergangenheit gelernt habe, habe ich mich für einen flotten Chip von ST mit 17 ns entschieden.

Mit 8 Vergleichspaare kann ich aus dem Vollen schöpfen und alles mit einbeziehen, was evtl. nötig ist. Das schöne ist ja, dass wir den Komparator so schön umkonfigurieren können, indem wir einen Eingang fest auf Low (Ground) oder High (5V-Schiene) setzen. Und falls sich herausstellt, dass wir ihn nicht brauchen, setzen wir P und Q auf Low und nehmen das Paar aus der Rechnung.

Ich habe mich für folgenden Vergleich bzw. Auswertung entschieden: Paar Signal P / Q Bemerkung 0. PHI2 H/L H Der Adressbus ist valide, wenn PHI2 High ist 1. R/W H/L L Der Datenbus ist valide, wenn R/W Low ist 2. A15 H/L L nur für den Bereich $7*** nicht $F*** (ROM) 3. A14 H/L H \ 4. A13 H/L H } Adressen ab $7000 bis $7FFF 5. A12 H/L H / 6. L L unbenutzt 7. L L unbenutzt G L G wird fest auf Low gesetzt Dabei liegt folgende Aussage aus dem Datenblatt zugrunde:
W65C02 Datenblatt, 3.9 Read/Write (RWB)
The Read/Write (RWB) output signal is used to control data transfer. When in the high state, the microprocessor is reading data from memory or I/O. When in the low state, the Data Bus contains valid data to be written from the microprocessor and stored at the addressed memory or I/O location. lda SEG+1 The RWB signal is set to the high impedance state when Bus Enable (BE) is low.
und der hier makierte Teil des Timing-Diagramms,



der bedeutet, dass während der Low-Phase des PHI2-Signals der Addressbus geändert wird.

Mit PHI2 auf High und R/W auf Low passe ich genau den richtigen Zeitpunkt ab, bei dem Adressbus und Datenbus valide, das heißt stabil sind und ich darin zuverlässige Werte vorfinde. Mit Einbindung der Adressleitungen A12 bis A15 stelle ich sicher, dass nur Adressen ab $7000 bis $7FFF den Vergleich bestehen und damit P=Q kurz auf Low fällt.

Ich hätte A15 auch aus der Gleichung herauslassen können und hätte dann 3 Paare frei, um damit A0, A1 und A2 zu vergleichen und so die Geräte wie bisher über $7000 (dann mit Ignorieren von A0...A2), $7001, $7002 und $7004 etc. anzusprechen. Dazu hätte es dann pro Gerät einen 74HC688 gebraucht.

Aber eleganter wird es, wenn wir noch einen Decoder/Multiplexer wie den 74HC138 einsetzen.

Der 74HC138 3 to 8 Line Decoder

Der 74HC138 nimmt die 3 Bits an den Eingängen A, B und C und zählt damit sozusagen den Ausgang ab, den er auf Low schalten soll. Das ist immer einer. Und es funktioniert wie mit dem binären Zählen. Bei ABC=000 ist der Ausgang Y0 auf Low und der Rest auf High, bei ABC=001 wird Y1 low, bei ABC=010 Y2 und so weiter. Wir können also einen von acht Ausgängen auf Low schalten, je nachdem, was an unseren Eingängen A, B und C anliegt.

Liegen wir dort doch einfach A0, A1 und A2 an, dann können wir von $7000 bis $7007 acht IO-Geräte ansprechen.

Den 74HC138 versteht man am besten, wenn man sich seine Wahrheitstabelle anschaut: --Enable-- --Select-- ------------Outputs----------- G2B G2A G1 C B A Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 X X L X X X H H H H H H H H X H X X X X H H H H H H H H H X X X X X H H H H H H H H L L H L L L L H H H H H H H L L H L L H H L H H H H H H L L H L H L H H L H H H H H L L H L H H H H H L H H H H L L H H L L H H H H L H H H L L H H L H H H H H H L H H L L H H H L H H H H H H L H L L H H H H H H H H H H H L
Nur wenn G1 auf High, G2A auf Low und G2B auf Low gesetzt sind, greift die Schaltung und ein Output wird auf Low geschaltet. Ansonsten bleiben alle Outputs auf High (also aus). Mit G1 können wir nicht viel anfangen und setzen ihn hart auf High. Dann picken wir uns den G2A Eingang zur Steuerung aus und pinnen G2B auf Low fest.

An G2A schließen wir jetzt unseren Ausgang von 74HC688 Komparator an - der ist ja immer Low, wenn die Adresse $7*** ist. Dazu kommen jetzt noch A0...A2 und Hallelulja, wir können unsere IO-Geräte unter $7000 bis $7007 triggern. Pin Signal A A0 B A1 C A2 G2A Ausgang von HC688 G2B fest Low G1 fest High Es gibt (oder sollte ich eher sagen: gab?) sogar einen 4-to-16-line-Decoder, den 74HC154, in den man 4 Adressleitungen einspeisen kann und damit dann gleich bis zu 16 Geräte ansprechen kann. Leider ist der 154er schwer als DIP-Variante, die wir ja für unser Breadboard brauchen, zu beschaffen.

Was wir dann nur noch tun müssen, ist Y0 ($7000) an unsere LED-Ausgabe und Y1 ($7001) an die erste 7-Segment-Anzeige, Y2 ($7002) and die 2. Anzeige und Y3 ($7003) and die 4. Anzeige anschließen. Praktischerweise liefert der 74HC138 gleich das passende Low-Signal, so dass wir auf einen Inverter verzichten können.

Die 74HC374 reagieren wie zuvor. Sie bekommen die meiste Zeit ein High und nur in dem kurzen Zeitfenster, in der unsere Bedingung erfüllt sind, ein Low und geben dann die zuvor gespeicherten Zustände aus.

Die LED-Ausgabe reagiert jetzt allerdings nicht mehr auf alle Adressen nach dem Muster 7***, sondern nur noch auf $7000. Ich könnte sie direkt an den 688er anschließen, dann wäre dem wieder so, aber ich habe mir gedacht, dass es auch Vorteile haben kann, dass diese nicht immer mitläuft, wenn man z. B. etwas auf LED-Ausgabe und 7-Segment gleichzeitig ausgeben will, was nichts miteinander zu tun hat.

Und dann wäre da natürlich noch die 3. Anzeige, die jetzt die Adresse $7003 und nicht mehr $7004 hat.



Auf dem Breadboard sieht es aufgeräumter auf. Wir sparen und das durch-die-Gatter-Gehüpfe und brauchen außerdem weniger ICs.

Erweitertes Assembler-Programm

Ich habe das Assembler-Programm auf Bank 4 angepasst und um weitere Buchstaben erweitert: ; 3-fach Sieben-Segment-Anzeige Testprogramm ; 000 ... ZZZ zählen ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-07-09 CHIP W65C02S ; (default) ORG $8000 ; Programmstartadresse (von der CPU aus gesehen) ; --- Konstanten: IO-Adressen --- LED: equ $7000 ; 8-LED-Ausgabe, hört aber auf alles von $7000 bis $7fff SEGL: equ $7001 ; linke 7-Segment-Anzeige SEGM: equ $7002 ; mittlere 7-Segment-Anzeige SEGR: equ $7003 ; rechte 7-Segment-Anzeige init: lda #0 sta LED ; LED-Ausgabe löschen start: ldx #0 ; for x = 0 ... for(x=0;x<16;x++) {... ; mit der ersten Ziffer (0) anfangen next: lda SEG, x ; Ziffer aus SEG+x laden sta SEGL ; und in allen 3 Anzeigen anzeigen sta SEGM sta SEGR inx ; nächste Ziffer / Buchstabe cpx #36 ; ... to 36 bne next bra start ; und nochmal das Ganze ; 2 ; __ ; 4 | | 1 ; -- 8 ; 10 |__| 40 .=80 ; ; 20 SEG: BYTE $88, $BE, $C4, $94, $B2, $91, $81, $BC, $80, $90 ; 0 bis 9 = Ziffern 0 bis 9 BYTE $A0, $83, $C9, $86, $C1, $E1, $89, $A2, $BE, $9E ; 11 bis 20 = Buchst. A bis J BYTE $A1, $CB, $A5, $A8, $88, $E0, $B0, $E9, $91, $BC ; 21 bis 30 = Buchst. K bis T BYTE $8A, $DA, $D2, $D5, $92, $C4 ; 31 bis 36 = Buchst. U bis Z

Test und Video

Jetzt müssen wir das Ganze nur neu auf unserem Breadboard-Computer verkabeln und natürlich testen. Davon habe ich natürlich wieder ein Video gemacht. Ich bin gespannt, ob die Theorie in der Praxis auch funktioniert...



Das nächste mal wollen wir "Hello World" auf dem 7-Segment-Display ausgeben (das ist ja schließlich so etwas wie eine Pflichtübung) und vielleicht einen Zähler programmieren. Dann geht es also wieder mehr um die Software-Entwicklung in Assembler.