Donnerstag, 24. Februar 2011

Interrupts

Interrupts sind ne feine Sache. Wenn ein Computer Peripheriegeräte wie Tastatur, Maus, UART u.Ä. verwendet, müsste er theoretisch zyklisch diese Geräte abfragen, ob sie neue Daten zur Verfügung haben. Wenn man also schnell auf einen Tastendruck reagieren will, müsste man entsprechend häufig die Tastatur abfragen, um die Reaktionszeit klein zu halten. Dieses ständige Abfragen nennt man Polling. Die Zeit, die für's Polling draufgeht, steht dann nicht mehr für das eigentlich laufende Programm zur Verfügung. Deswegen nimmt man (meistens) ein anderes Prinzip, nämlich Interrupts. Der Z80 hat einen Interrupt-Pin (eigentlich zwei, aber ich benutze nur einen). Der liegt im Normalfall auf High-Pegel. Wird nun eine Taste gedrückt, so wird von der Tastatur der High-Pegel auf low gezogen. Der Prozessor merkt dadurch, dass etwas passiert ist, um das er sich kümmern sollte. Dann kann er die Peripherie "auslesen", um festzustellen, was passiert ist. Er liest also die Tastatur nur dann aus, wenn wirklich eine Taste gedrückt wurde.
Der Z80 hat drei Interrupt-Modi. Modus 0 wurde aus Kompatibilitätsgründen zum Intel 8080 beibehalten. Löst das Gerät einen Interrupt aus, so bekommt es die Möglichkeit, eine Instruktion auf den Datenbus zu legen, die der Prozessor dann ausführt. Dies ist meistens der RST-Befehl, mit dem man ich glaube acht verschiedene (aber a priori festgelegte) Stellen in der Speicherseite 0 anspringen kann.
Im Modus 1 springt der Prozessor im Interruptfall pauschal zu 0x38. Und Modus 2 ist der flexibelste Modus: Der Programmierer legt im Speicher eine Tabelle mit Interruptvektoren an. In das Register I lädt er die Nummer der Speicherseite, in der sich die Tabelle befindet. Beim Interrupt legt nun das Gerät eine Nummer auf dem Datenbus, die dem Eintrag in der Tabelle entspricht. Der Z80 liest nun diesen Interruptvektor ein und springt an diese Adresse. Dort befindet sich dann die entsprechende Routine, die bspw. die Tastatur ausliest. Auf diese Weise lassen sich 128 verschiedene Interrupt-Routinen anspringen.
Soviel zur Theorie. Ich wollte ja eigentlich den Modus 2 benutzen, doch ich habe nen Layoutfehler drauf. Das wird so nicht klappen, weswegen ich erstmal mit Modus 1 Vorlieb nehme. Nur ein Interrupt ist besser als gar keiner :-) Das Problem ist folgendes: Der Interrupt wird ausgelöst. Der Prozessor weiß jedoch erstmal gar nicht, wer denn die Interruptleitung runtergezogen hat, er sieht nur, dass sie low ist. Deswegen löst er einen IORequest parallel zu einem M1 Zyklus aus. Dies signalisiert dem Interrupt-Gerät, nun die Nummer des Interruptvektors auf den Datenbus zu legen. Ich habe nicht bedacht, dass er ja gar keine Geräteadresse auf den Datenbus legt, weswegen kein entsprechendes Chipselect ausgelöst wird.
Ich hätte sogar alle nötigen Logikgatter auf der IOBoard-Platine noch frei um das zu fixen, jedoch wäre das mit einem SMD-Beinchenbiegen und rumpfuschen verbunden, das ist mir erstmal zu heikel. Hab kein Bock, mir wieder ein Pad abzureissen wie bei der Main-Platine. Interrupt-Modus 1 reicht mir erstmal :-)

Dienstag, 22. Februar 2011

Assembler-Spaß

Wo ich ja nun endlich ein funktionierendes System habe, kann ich mich mal etwas dem Z80-Assembler widmen. Das ist schon eine kleine Umstellung, wenn man sonst nur C programmiert und auch "in C" denkt. Die ersten Routinen, die ich programmiert habe, sind natürlich String über UART senden und String vom UART empfangen. Da mein Z80-Computer ein sehr freundlicher ist, wird man auch gleich angenehm begrüßt :-) Das sieht dann im Terminal so aus:

Ist er nicht nett? Ok- zugegeben nicht sehr spektakulär ;-) Aber es läuft auf meiner Hardware und ich habe jedes Byte selbst programmiert!

Und weil's so praktisch ist, hier ein Screenshot meines Programmers, mit dem ich den EEProm (und auch den RAM) lesen und schreiben kann:


Lädt man ein assembliertes Binary, so gibt der Programmer erstmal den Inhalt als Hex aus. Im Offset-Eingabefeld kann man das Startoffset eingeben, wo die Bytes hingeschrieben werden sollen. Mit "write" werden die Bytes an den dsPIC (über UART) auf der Mainplatine geschickt. Der schreibt dann die Bytes an die gewünschte Stelle in den EEProm (oder RAM).
Durch "release" entlässt der dsPIC den Z80 wieder aus dem Reset und der neue Code wird vom Z80 direkt ausgeführt.

Montag, 21. Februar 2011

Es funzt!!

Mann mann, das war frustrierend! Manchmal hat die Schaltung funktioniert, sprich der Z80 hat über den UART mit mir gesprochen. Dann habe ich kleine Änderungen an der Z80-Software gemacht, nämlich Code in Subroutinen gepackt, die mit dem call-Befehl aufgerufen werden. Dann hat es sporadisch funktioniert, aber nach einem Reset wieder nicht. Dann habe ich die alte, funktionierende Version aufgespielt, die dann aber plötzlich nicht mehr funktionierte. Sehr seltsam, genau wie bei meiner alten, selbstverdrahteten Platine! Also habe ich heute eine kleine Display-Platine gebastelt, um zu schauen, ob diese denn ansprechbar ist. Hier trat das gleiche Phänomen auf. Das Problem musste also auf der Main-Platine liegen.
Mir ist dann aufgefallen, das die Masse der Displayplatine unsauber war. Und siehe da: Eine kalte Lötstelle an einer Steckbuchse auf dem Mainboard. Doch das hat das Problem immer noch nicht beseitigt. Da nur Probleme bei Aufrufen von Subroutinen auftraten, bin ich dann endlich mal auf die Idee gekommen, den RAM-Baustein zu testen. Bei einem Lese-/Schreibtest hat sich dann rausgestellt, dass der manchmal Daten nicht richtig speichert. Das erklärt auch, warum der Z80 Probleme mit den Subroutinen hatte. Denn beim Subroutinen-call wird der PC (Program Counter) auf den Stack kopiert, der sich im RAM befindet. Und wenn der RAM den Wert nicht richtig speichert, wird beim return der PC nicht korrekt zurückgesetzt und der Z80 springt sonstwo hin.
Die UART-Platine funktioniert nun auch wie gewünscht.

Hier ein Foto der Display-Platine:

Donnerstag, 17. Februar 2011

Main-Platine bestückt und erste Tests

Ich habe gerade den dsPIC zum Laufen gebracht. Ich hatte ein paar Fehler in die µC-Firmware eingebaut, damit ich zwei Stunden lang Debuggen üben kann ;-) Nun lässt sich aber endlich per dsPIC der RAM und das EEPROM lesen und schreiben. Desweiteren kann er einen Takt mit Hilfe des integrierten Timers erzeugen, mit dem ich den Z80 betreiben kann, für Single-Step z.B. Das Testprogramm aus einem meiner ersten Posts habe ich dann in den EEPROM programmiert und den Z80 erfolgreich damit laufen lassen. Das scheint also zu klappen. Hoffentlich finde ich am WE Zeit, das IO-Board zu bestücken!

Hier sieht man das bestückte Mainboard von unten:
Blöderweise hatte ich das NAND (der kleine Käfer oben in der Mitte) falsch rum draufgelötet. Also musste ich ihn wieder runterlöten. Dabei habe ich ein Pad abgerissen. Hier sieht man die Korrektur in Nahaufnahme und etwas Fädeldraht, mit dem ich das betroffene Beinchen verbunden habe:
Der Fädeldraht passt praktischer Weise genau durch die durchkontaktierte Via.

So sieht die Oberseite der Platine ohne DIL-ICs aus:
Der rote PicKit3 ist ein Gerät, um (ds-)PICs zu Programmieren und zu Debuggen. Sehr zu empfehlen, vor allem, weil es preislich dem Hobbybastler entgegen kommt.

Und so sieht der Aufbau derzeit aus:

Dienstag, 15. Februar 2011

Platinen sind angekommen!

Endlich sind sie da, die beiden Platinen! Ich habe begonnen, die ersten Komponenten zu bestücken. So sieht sie aus:

Ganz hinten sitzt der Max232 für die serielle Schnittstelle RS232, der größte IC ist der dsPIC30F4012, und die beiden kleinen rechten IC's sind Schieberegister, in die der dsPIC Adressbits reinschiebt, um den Speicher zu adressieren. Morgen geht's weiter!!

Sonntag, 6. Februar 2011

CPLD-Programmer

Heute habe ich es endlich getan: Der JTAG-Programmer für Xilinx CPLDs ist bestückt! Die Platine dazu und zu einem Testboard für den XC9536 habe ich hier schon seit einem halben Jahr rumliegen. Mir fehlte nur bisher die Muse dazu, das endlich mal aufzubauen und zu testen.
Links im Bild ist der JTAG-Programmer. Und ja, das ist ein 25poliger Sub-D-Stecker für die parallele Schnittstelle :-) Die beiden ICs sind Bustreiber 74HC125. Die rechte Platine ist das Testboard für den XC9536. Die fertigen Layouts findet man schnell im Netz, einfach nach "xc9536 jtag programmer" suchen.
Die Software zur Programmierung so eines CPLDs ist von der Xilinx-Seite frei herunterladbar. Sie nennt sich ISE Webpack und hat mal eben flotte 3 GB. Sie ist nicht ganz so einfach zu bedienen, aber ich habe es geschafft, ein Test-Programm auf den CPLD zu brennen. Da ich mich irgendwann eh mal mit FPGAs beschäftigen möchte, ist das hier schon eine ganz gute Einarbeitung. Mit dem Webpack lassen sich nämlich auch die Xilinx-FPGAs programmieren.

Während die Z80-Platinen in der Fertigung sind, werde ich mir dann erstmal CPLD-Programmierung mit VHDL/Verilog zu gemüte führen. Irgendwann möchte ich nämlich eine kleine "Grafikkarte" für den Z80 basteln. Und dafür könnte sich so ein CPLD ganz gut eignen glaube ich.

Samstag, 5. Februar 2011

Layout fertig

Es ist geschafft, das Layout steht. Ich habe nicht alles auf ein Board gepackt, sondern das auf zwei verteilt. Das Main-Board mit CPU, Speicher und dsPIC, sowie das IO-Board mit dem 74HC138 für das ChipSelect und dem 16c550.
Jetzt checke ich nochmal alles durch und werde dann nächste Woche die Boards in die Fertigung geben. Na hoffentlich ist kein Fehler drauf, sonst wäre das ein teurer Spaß...

So sieht das Main-Board jetzt aus:
Z80 Main-Board
Wie man sieht, ein zweilagiges Board mit SMD und DIL-Mischbestückung. Bei den 74er Bausteinen bin ich auf SMD gewechselt, um die Boardfläche klein zu halten. Den Z80 und den Speicher gibt's leider nicht als SMD, jedenfalls nicht bei Reichelt.