Dienstag, 29. November 2011

Grafisches Display am Z80

Zum Testen und als erste halbwegs sinnvolle Anwendung der neuen Platine habe ich ein grafisches LCD-Display mit 128x64 Auflösung angebunden:
Z80 mit Display
Das ist ein DEM 128064A SYH-LY mit einem 8-Bit-Interface. Das Interface besteht im Wesentlichen aus dem 8-Bit-Datenbus, einer Register Select Leitung (RS), zwei high-aktive ChipSelects (CS1,CS2), high-aktives Enable (E) und low-aktives Reset (RSTB).
Das Display ist aus zwei Segmenten mit 64x64 Pixeln aufgebaut, betrieben durch je einem Treiber-IC S6B0108. Deswegen gibt es auch die beiden Chip Selects CS1, CS2. Mit CS1 selektiert man den linken Teil des Displays, mit CS2 den rechten. Register Select bestimmt, ob das Datum auf dem Datenbus ein Befehl für einen Treiber-IC ist (RS=low), oder in den Speicher des Displays geschrieben werden soll (RS=high). Bei einer fallenden Flanke von E wird das Datum vom Datenbus vom selekierten IC gelatcht und dort entsprechend verwurstet.

Mittwoch, 16. November 2011

Neues Board

Yet another Z80-Board



Da ich mit dem Z80-Board unzufrieden war, habe ich nun ein neues designt. Hauptmotivation war die Grafikkarte, die an das System angebunden werden soll. Diese hätte nur über IO-Ports angesprochen werden können. Für Zugriffe auf den Grafikspeicher ist das sehr langsam. Nicht nur, weil IO-Zugriffe einen extra-Wait-State-Takt haben, sondern weil sich die Pixel nicht direkt adressieren lassen. Statt dessen hätte ich Register für die Pixeladresse und dem Pixelfarbwert bereitstellen müssen. Um einen beliebigen Pixel zu ändern, müsste also eine 16-bit Adresse (2 IO-Zugriffe) und ein Byte für die Pixeldaten (1 IO-Zugriff) geschrieben werden.
Im neuen Design befindet sich ein CPLD auf dem Board, der den 64kB-Adressraum in vier Viertel einteilt:

BankStartEnde
00 kB16 kB
116 kB32 kB
232 kB48 kB
348 kB64 kB

In jedes Viertel (Bank) können acht verschiedene RAM-Seiten eingeblendet werden. Zusätzlich lässt sich in jedes Viertel ein externer Bereich einblenden, wie z.B. der Grafikspeicher. Im ersten Viertel ist zuerst das EEProm eingeblendet, auf dem sich der Bootloader befindet.
Das Einblenden von Speicherbereichen wird mit Hilfe eines 16-Bit-Registers im CPLD realisiert, welches über IO-Port-Adresse 0 und 1 geschrieben werden kann.

Für jedes Viertel sind vier Bits im Register vorgesehen:

extbs2bs1bs0
3210

Das ganze mal vier für vier Viertel macht 16 Bits.

Ist das ext-Bit auf 1, wird bei Zugriff auf dieses Viertel der externe Speicher selektiert, egal wie die bs-Bits stehen. In Bank 0 wird bei bs=000 das EEProm selektiert, ansonsten der RAM-Baustein.
Möchte man nun in Bank 1 in eine andere Speicherseite einblenden, z.B. durch bs=001, schreibt man Folgendes:

ld a, 0001 0000 b
out (0), a       

Es wird 00010000 in den Akku geladen und über Port 0 in das CPLD-Register geschrieben.
Das untere Nibble ist null, denn in der Bank 0 soll der EEPRom eingeblendet bleiben. Das obere Nibble ist für Bank 1. Um den EEProm auszublenden und RAM einzublenden, schreibt man:

ld a, 0001 0001 b
out (0), a       

Das obere Nibble bleibt gleich, denn Bank 1 soll ja nicht umgeschaltet werden.
Bank 2 und 3 liegen im oberen Byte des 16-Bit-Registers und werden über Port 1 angesprochen:

out (1),a

Beim "Banking" muss man generell aufpassen, dass man nicht die Seite umschaltet, von der man gerade Code ausführt, denn das führt unweigerlich zum Absturz. Auch die Seite, in der der Stack liegt, sollte nicht umgeschaltet werden, es sei denn, man weiß genau, was man tut :-)

Das neue Z80-System kann auf diese Weise 4 * 8 * 16 kB = 512 kB RAM ansprechen (minus der EEProm-Seite). Mit den ext-Bits lässt sich noch weiterer Speicher von außen einblenden.

Die MMU kann man auch recht einfach mit TTL-Logikbausteinen aufbauen. Mein Ziel, alle Features auf eine Euro-Platine zu packen, hätte dies zunichte gemacht. Es wären nämlich doch einige Bausteine nötig gewesen, um die Logik zu implementieren. Der CPLD erschlägt diese Aufgabe alleine und kann sogar noch umprogrammiert werden, eine flexible Lösung also. Als mein erstes sinnvolles CPLD/Verilog-Projekt war dies schonmal eine gute Einführung für mein Grafikkartenvorhaben.

Hier nochmal wichtige Schnipsel aus dem Schaltplan der MMU:
Speicheranbindung
Die Leitungen MA16-MA18 legen die Werte von bs0-bs2 an den RAM an, abhängig von der Bank, die gerade angesprochen werden soll. Die Bank wiederrum wird durch A14, A15 bestimmt. A14=A15=0 entspricht Bank 0, A14=1, A15=0 entspricht Bank 1, usw.

CPLD XC9536

Die PullUps an den Ausgängen (MA16-MA18, /ROM_CS, /RAM_CS, /EXT_CS) sind nötig, weil der XC9536 es nicht auf 5V-High-Pegel schafft, sondern nur ~3,9V. Statt High-Pegel wird nun ein Ausgang hochohmig geschaltet und über den PullUp auf 5V gezogen.

Weiterhin habe ich den UART 16C550 entfernt. Der dsPIC auf dem Board programmiert jetzt nicht nur den EEPROM, sondern hängt am IO-Port als UART und Co-Prozessor für schnelle Multiplikationen und Divisionen.

Und da Blog-Lesen ohne Bilder nur halb so viel Spaß macht, noch ein paar Impressionen der letzten Debugsession:


 
Erster Einsatz meines neuen Logic Analyzers