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:- 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
- 3-fach 7-Segment-Anzeige als dezimale Ausgabe, Teil 2: 20 Nanosekunden, die nicht sein sollten
- 3-fach 7-Segment-Anzeige als dezimale Ausgabe, Teil 3: Assembler-Programme
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
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)und der hier makierte Teil des Timing-Diagramms,
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.

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
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
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...