Montag, 28. April 2014

Gehversuche mit dem CPLD

Ich bin ja normalerweise ein eher ruhiger (manche sagen: phlegmatischer) Zeitgenosse. Aber heute Abend bin ich fast wahnsinnig geworden, mit diesem Scheiß von Xilinx. Mit Scheiß meine ich konkret: Die Verbindung von der ISE zum Programmierkabel. Man kann doch nicht den Linux-Standard-USB Treiber nehmen, nicht doch. Es muss ein proprietärer eigener Rotz sein, der mit nichts kompatibel ist (und der auch nicht funktioniert). Glücklicherweise gibt es noch andere Nerds, denen das auf die Nerven ging, und die einen Wrapper geschrieben haben, sodass die ISE direkt auf den Linux-USB Treiber zugreift.
Dennoch brauchte ich zwei Stunden um heraus zu finden, dass das Parallelport-Kabel nur dann funktionieren kann, wenn es an einem echten (sprich: PC-eingebauten) Parallelport angeschlossen ist. Steckkarten oder USB->Parallel Kabel werden von der ISE einfach ignoriert. Welch grandioser Schwachsinn, da ja keiner der heute ausgelieferten PCs noch eine parallele Schnittstelle hat.
Aber ich habe ja das USB Programmiergerät bekommen. Es dauerte eine weitere Stunde, bis ich diesen mit allen Treibern bestückt hatte und die ISE das Teil erkannte. Was ein Krampf.
Schlussendlich funktionierte aber auch das, und ich wagte mich daran, das Programmiergerät an die von mir zusammen gelötete CPLD-Karte anzustöpseln. Kurzes Innehalten: Kein Qualm, kein Geruch, alles leuchtet noch... Weiter im Text. Nun die ISE starten und den Chip suchen lassen - siehe da: Die ISE erkennt den Chip.
Mutig schrieb ich einen kleinen Zähler und hängte die Ausgänge an die acht Leuchtdioden. Bösartigerweise war im Pollin Handbuch zu den Pinnummern des CPLD ein Fehler, weshalb sich die ISE hartnäckig weigerte, den Pin 98 des CPLD an die LED #1 anzuschließen. Ein Blick in den Schaltplan (mit einer starken Lupe) zeigte den Fehler: Es ist Pin 97. Das also korrigiert, neu compiliert und den Chip programmiert. "Successfully". Hurra. Nur leider leuchteten nun alle acht LEDs.
Hmm, ja, klar doch: Bei 16 MHz Taktfrequenz sieht man da nicht viel, also wurde aus einem 8-Bit Zähler ein 16-Bit, dann ein 24-Bit und schließlich ein 27-Bit Zähler. Die höchsten acht Bits habe ich jeweils an die LEDs geschaltet.
Dies ist das Programm:

module Counter(
    input clock,
    output [7:0] led
    );

reg [26:0] zaehler;

always @(posedge clock) begin
  zaehler = zaehler + 1;
end

initial begin
  zaehler = 0;
end

assign led[7:0] = zaehler[26:19];

endmodule

Und so sieht es dann aus:

Genug für heute, sonst werde ich noch übermütig :-)

Mittwoch, 23. April 2014

Es werde Hardware

Heute bei diesem schönen Wetter mal keine tiefschürfenden philosophischen Gedanken, sondern solides Handwerk. Gestern bekam ich mit der Post nämlich ein kleines Päckchen aus Fernost, worin sich der langersehnte Xilinx USB Programmer befand:

Mit dabei ein USB Kabel und eine Menge Steck-Adapter, um sowohl FPGAs als auch CPLDs programmieren zu können. Jetzt brauchen wir "nur" noch einen CPLD. Und den haben wir ja, zumindest als Bausatz:
Zwei Stunden Bastelarbeit und ein gut eingeschenktes Glas (alkoholfreies) Weizenbier bei bestem Wetter auf der Terrasse und der Drops war gelutscht.
Soviel für heute.

Donnerstag, 17. April 2014

Es wird langsam konkret

Nachdem ich mich nun damit angefreundet habe, einen CPLD für die Ansteuerung der CF-Karte zu verwenden, konnte ich den Schaltplan damit erst einmal komplettieren. Ein erster Versuch eines Layouts scheiterte noch kläglich, auf nur zwei Lagen war da nichts zu machen.
Ich hatte aber zum einen noch einige 74er Bausteine auf dem Board, die nur zur Hälfte, bzw zu einem sechstel verwendet wurden. Da der CPLD aber noch eine Menge freier Leitungen hatte, konnte ich im Xilinx ISE Tool auch noch diese beiden ICs komplett in den CPLD abbilden. Auch der Frequenzteiler durch 4, der den Takt für die serielle Schnittstelle erzeugt, wurde durch den CPLD ersetzt. Damit sieht der Schaltplan um die CPU nun wie folgt aus:
Der Schalplan für den CPLD und die CF-Karte:


Die serielle Schnittstelle:

Ein erstes Layout sieht wie folgt aus:


Wie man erkennt, passt alles wunderbar auf 100 cm² Platinenfläche. Das ist natürlich nur ein erster Rohentwurf, hauptsächlich als Nachweis, dass das Ganze überhaupt noch zweiseitig zu layouten ist. Als nächstes kommen noch die vielen kleinen Details, wie z. B.

  • Einige Status-LEDs an die Stirnseite, 
  • Ein Netzteil, wenn ich das mal so nennen darf, das es erlaubt, das System entweder mit 8 - 12 Volt Gleich- oder Wechselspannung zu betreiben 
  • Reset-Taster nach vorne
  • Stützkondensatoren direkt an die Spannungsversorgung der ICs
  • Alles, an was ich hier noch nicht gedacht habe.
Und dann muss die Platine auch noch Realität werden. Aus einer Anzeige in der Amateurfunkzeitung CQ DL habe ich einen heißen Kandidaten: IMDES. Der derzeitige Preis für die oben abgebildete Platine liegt bei 16 Euronen, doppelseitig und durchkontaktiert wohlverstanden. Kein Mindestbestellwert, hauptsächlich kleine Stückzahlen. Für uns Bastler ideal.

In diesem Sinne

Frohe Ostern

Montag, 14. April 2014

CF-Karte und CPLD Teil II

Nachdem ich nun ein Wochenende in Ruhe drüber nachdenken konnte, wie ich denn dieses Riesen-CPLD vereinfachen kann, ist mir eine Idee gekommen. Den Adressbus brauche ich nicht wirklich durch das CPLD zu routen, da die Adressinformationen die ganze Zeit über an der CF-Karte anliegen können. Unter dieser Bedingung komme ich zu einem etwas einfacherem Verilog-Programm:

module CF_Card_Interface(
clk,
data_z8,
data_cf,
iorq,
wr,
rd,
cfrd,
cfwr,
cfsel,
z8wait,
cpld_selected);

input clk;
inout [7:0] data_z8;
inout [7:0] data_cf;
input iorq;
input wr;
input rd;
output cfrd;
reg cfrd = 1;
output cfwr;
reg cfwr = 1;
output cfsel;
reg cfsel = 1;
output z8wait;
reg z8wait = 1;
reg [5:0] counter;
reg [7:0] data_z8_reg;
reg [7:0] data_cf_reg;
input cpld_selected;

wire cpld_sel = (iorq == 0 && cpld_selected == 1);
wire z8_io_read = (rd == 0 && cpld_sel == 1) ? 1 : 0;
wire z8_io_write = (wr == 0 && cpld_sel == 1) ? 1 : 0;

assign data_z8 = (z8_io_read == 1) ? data_z8_reg : 8'bzzzzzzzz;
assign data_cf = (z8_io_write == 1) ? data_cf_reg : 8'bzzzzzzzz;

always @(negedge clk) begin
if (!z8_io_read && !z8_io_write) begin
counter = 0;
cfrd = 1;
cfwr = 1;
cfsel = 1;
z8wait = 1;
end else begin
case(counter)
0: begin
z8wait = 0;
if (wr == 0) begin
data_cf_reg = data_z8;
end
end
3: if (rd == 0) begin
cfrd = 0;
cfsel = 0;
end else begin
cfsel = 0;
cfwr = 0;
end
 13: if (rd == 0) begin
data_z8_reg = data_cf;
end
 14: begin
cfsel = 1;
cfrd = 1;
cfwr = 1;
end
 15: begin
z8wait = 1;
end
endcase
counter = counter + 1;
end
end
endmodule

Nachdem ich diese Änderungen im Xilinx ISE eingegeben hatte und nach einem passenden CPLD fahnden ließ, lautete die Antwort tatsächlich XC9536, der kleinste aller CPLDs von Xilinx. Bei Reichelt für € 1,80 in einem VQFP-44 Gehäuse (quadratischer SMD) zu bekommen.
Leider hat die ISE bei dem automatischen Fitting die Zuordnung der Pins recht willkürlich vorgenommen, um die Funktionsbausteine gleichmäßig auszunutzen. Da wird nun noch eine Menge Handarbeit erforderlich sein, um die Pins so gut wie möglich zu sortieren, damit noch ein sinnvolles Platinenlayout möglich ist. Aber diese Hürde wäre dann auch schon mal genommen.
Dann wäre der übernächste Schritt in der Tat die Fertigung der Platine. Es geht voran.

Freitag, 11. April 2014

So einfach geht's mit CF-Karten nun auch wieder nicht

Das war nun auch zu schön um wahr zu sein. Die Demo-Schaltung mit einem Microcontroller und einer direkt dort angeschlossenen CF-Karte funktioniert leider nur deshalb, weil der Microcontroller die CF-Karte erstens mit Port-Bausteinen und zweitens auch noch langsam genug anspricht. Wenn man, wie in meinem Falle, die CF Karte direkt an den Adress- und Datenbus anschließen möchte, dann sollte man auch einen Blick in die Timing-Diagramme werfen. Und genau hier zeigen sich ein unschönes und zwei hässliche Probleme:
  1. Die CF-Karte erwartet die Adress-Informationen auf den Leitungen A0..A2 70ns vor dem eigentlichen Schreib- oder Leseimpuls (hier IORQ und RD oder WR). Der Z8S180 legt bei einem 33 MHz Takt die Adress-Informationen aber gerade einmal 5ns vor dem Zugriff auf den Bus.
  2. Die CF-Karte braucht relativ lange nach dem Abfall der Schreib- Lesesignale, bis es den Datenbus wieder freigibt (in den Tri-State geht). Immerhin bis zu 30ns, laut Datenblatt. In der Zeit ist der Z8 schon beinahe wieder am nächsten Befehl.
  3. Unschön, aber mit einigen -zig Wait-States zu regeln ist die relativ lange Wartezeit von bis zu 290ns auf die Daten aus der CF-Karte.
Ich habe spaßeshalber diesen Zugriffsmechanismus einmal für einen CPLD in Verilog geschrieben und durchsimuliert. Hier ist das Programm:


module CF_Card_Interface(
  clk,
  addr_in,
  addr_compare,
  addr_out,
  data_z8,
  data_cf,
  iorq,
  wr,
  rd,
  cfrd,
  cfwr,
  cfsel,
  z8wait);

input clk;
input [7:0] addr_in;
input [4:0] addr_compare;
output [2:0] addr_out;
reg [2:0] addr_out;
inout [7:0] data_z8;
inout [7:0] data_cf;
input iorq;
input wr;
input rd;
output cfrd;
reg cfrd;
output cfwr;
reg cfwr;
output cfsel;
reg cfsel;
output z8wait;
reg z8wait;
reg [5:0] counter;
reg [7:0] data_z8_reg;
reg [7:0] data_cf_reg;

wire cpld_sel = (iorq == 0 && addr_compare == addr_in[7:3]) ? 1 : 0;
wire z8_io_read = (rd == 0 && cpld_sel == 1) ? 1 : 0;
wire z8_io_write = (wr == 0 && cpld_sel == 1) ? 1 : 0;

assign data_z8 = (z8_io_read == 1) ? data_z8_reg : 8'bzzzzzzzz;
assign data_cf = (z8_io_write == 1) ? data_cf_reg : 8'bzzzzzzzz;

always @(negedge clk) begin
  if (!z8_io_read && !z8_io_write) begin
    counter = 0;
    cfrd = 1;
    cfwr = 1;
    cfsel = 1;
    z8wait = 1;
  end else begin
    case(counter) 
      0: begin
        addr_out <= addr_in[2:0];
        z8wait = 0;
        if (wr == 0) begin
          data_cf_reg = data_z8;
        end
      end
      3: if (rd == 0) begin
        cfrd = 0;
        cfsel = 0;
      end else begin
        cfsel = 0;
        cfwr = 0;
      end
      13: if (rd == 0) begin
        data_z8_reg = data_cf;
      end
      14: begin
        cfsel = 1;
        cfrd = 1;
        cfwr = 1;
      end
      15: begin
        z8wait = 1;
        end
      endcase
      counter = counter + 1;
    end
  end
endmodule

Soweit das Modul. Das Modul-Interface ist gleichzeitig die Pin-Beschreibung des CPLD. Ich möchte die Pins hier im einzelnen beschreiben.
Clk ist der Ausgang Phi des Z8S180 und somit ein 33 MHz Taktsignal.
Addr_In sind die Adressleitungen A0...A7 der CPU, Data_z8 ist der Datenbus der CPU.
Addr_Compare ist mit einem 5-stelligen DIP-Schalter verbunden, über den von außen der Adressbereich des Bausteins eingestellt werden kann.
IORQ, WR und RD sind die low-aktiven Schreib-/Lesesignale der CPU.
Z8WAIT ist das low-aktive WAIT Signal an die CPU.
Die restlichen Leitungen Addr_Out, Data_CF, CFWR, CFRD und CFSEL sind mit der CF-Karte verbunden.

Und so sieht das ganze dann auf dem Logic-Analyzer aus. Hier zuerst ein Schreibzugriff.


In dem Moment, in dem der Z8 Adresse und IORD anlegt, erkennt man, dass das interne Signal CPLD_SEL aktiv wird. Bei der nächsten fallenden Flanke des CLK-Signals (bei 120ns) werden sowohl Adress- und Datenleitungen für die CF-Karte beschickt, als auch ein WAIT-Signal an die Z8 gesendet.
3 CLK Zyklen später (also 90ns) werden sowohl CFSEL als auch CFWR aktiviert, also der Schreibvorgang in die CF-Karte gestartet. Laut Datenblatt der CF-Karte darf dies frühestens 70ns nach dem stabilen Anlegen der Adresse geschehen.
Gut 300ns später (die CF-Karte braucht 290ns für den Schreibvorgang), werden CFSEL und CFWR wieder deaktiviert. Damit sich nun der Datenbus der CF-Karte beruhigen kann, wird noch einmal ein CLK-Zyklus gewartet, bevor das WAIT-Signal zur Z8 wieder deaktiviert wird. Die Z8 läuft daraufhin wieder an und beendet den Schreibvorgang.

Hier dasselbe für den Lesezugriff:


Der Unterschied liegt hier am Ende des Lesezyklus. 300ns nachdem der CPLD der CF-Karte das Lesesignal gegeben hat, werden die Daten der CF-Karte auf den Datenbus des Prozessors gelegt. Bis dahin ist der Status auf dem Datenbus nicht definiert. Danach wird der Z8 wieder aus dem Wartezustand geholt und der Ablauf ist analog zum Schreibzugriff.

Leider ist mein Programm für die kleinen CPLDs schon zu kompliziert, sodass mit die Xilinx-ISE Workbench einen XC108-PC84 vorschlägt, einen Klotz, größer als die eigentliche CPU. Ich werde mal versuchen, ob ich dasselbe auch mit herkömmlichen TTL Bausteinen zusammen setzen kann. Wird zwar bestimmt genauso groß, wie der CPLD, dafür aber preiswerter und ohne großen Aufwand.

Mittwoch, 9. April 2014

Die SD-Karte. Das unbekannte Wesen.

Alle Schaltpläne, derer ich im Netz der Netze habhaft werden konnte, verwenden zur Kommunikation mit einer SD-Karte ausschließlich das 1-Bit Protokoll, gleichwohl eine SD-Karte durchaus auch in einem 4-Bit Mode betrieben werden kann. Neuere Modelle sogar in einem 8-Bit Mode. Hier eine Seite, die sich ausgiebig mit dem 1-Bit Mode auseinander setzt. Und hier noch eine Seite eines Controllers von TI, der auch 4-Bit und 8-Bit Modi unterstützt.
Gerade für Atmel-Prozessoren bietet sich der 1-Bit serielle Modus aber an, da hier der Microcontroller direkt über das SPI-Interface mit der Karte kommunizieren kann. Natürlich gibt es auch Überlegungen, die Karte im 4-Bit Modus zu betreiben, um damit höhere Geschwindigkeiten zu erreichen, allerdings hat die Sache (wie so viele) einen Haken: Beim Schreiben in die Karte verlangt diese zum Sicherstellen der Richtigkeit der Daten eine Prüfsumme. Diese Prüfsumme ist eine CRC16 mit einem Initialwert von 0 und einem XOR-Wert von 0x1021. Offenbar bereitet den Prozessoren das Berechnen dieser CRC bei einer 4-Bit Übertragung noch erheblich mehr Probleme, als das bitweise Übertragen und CRC-Berechnen, sodass unterm Strich keine nennenswerte Geschwindigkeitssteigerung zu erzielen ist.
Wie berechnet man überhaupt eine CRC? Zunächst einmal ist eine CRC16 oder CRC32 oder wie auch immer nur eine Rechenvorschrift, wie das Multiplizieren oder das Dividieren. Es gibt nicht die CRC16 oder die CRC32. Für die Berechnung einer CRC braucht man zusätzlich einen Startwert (den Seed) und das Polynom.
Für die CRC8 für die SD-Karten Kommandos sind das beispielsweise Startwert 0 und Polynom x⁷ + x³ + 1, oder auch 10001001. Für die CRC16 für die Datenübertragung zur SD-Karte sind dies Startwert 0 und Polynom 0x1021. Die CRC32 für Netzwerk-Verbindungen hat zum Beispiel das Polynom 0x04C11DB7. Die eigentliche Berechnung der CRC geschieht bitweise wie folgt:
1. Das CRC Register wird mit dem Startwert initialisiert.
2. Jedes eintreffende Bit wird mit dem höchsten Bit des CRC-Registers verglichen.
3. Sind diese beiden Bits identisch, wird das CRC-Register um 1 nach links geschoben und an die rechte Stelle kommt eine 0.
4. Sind diese beiden Bits nicht identisch, wird zunächst das CRC-Register um 1 nach links geschoben und an die rechte Stelle kommt eine 0, und anschließend wird das CRC-Register mit dem Polynom verXORt.
5. Gehe zurück zu 2. solange Daten vorhanden sind. Andernfalls steht nun im CRC-Register die Prüfsumme.
Nun hat die SD-Karte ja zwei Kommunikationspfade, nämlich den 1-Bit breiten Kommandokanal, und den 1-, 4-, oder 4-Bit breiten Datenkanal. Über ersteren wird eine auf 7 Bit abgeschnittene CRC8 benutzt, aber dem Datenkanal die CRC16. Die hauptsächliche Kommunikation auf dem Kommandokanal besteht aus der Initialisierung und den Kommandos zum Senden oder Empfangen von Daten. Da es sich hier zum einen nur um wenige Bytes handelt (die Kommandos sind 6 Bytes lang, die Antworten meistens ebenso, bis auf eine 17 Byte lange Ausnahme), und zum anderen die meisten Kommandos nur während und zur Intialisierung der Karte ausgetauscht werden, kann diese Arbeit getrost dem Prozessor überlassen werden, zumal eine CRC8 noch bequem von einer 8-Bit CPU zu bewältigen ist.
Bei der Betrachtung des Datenkanals fällt aber auf, dass hier hauptsächlich Sektoren zu 512 Bytes übertragen werden, und das mehrmals nacheinander. Hier macht sich beim Schreiben die Rechenzeit für die CRC16 deutlich bemerkbar. Beim Lesen könnte diese Rechenzeit theoretisch entfallen, wenn man denn die von der SD-Karte empfangenen Daten nicht auf Richtigkeit prüfen will.
Eine Idee, mit der gerade liebäugele, ist (mal wieder) die Verwendung eines CPLD. Nicht nur als Portexpander für den Prozessor, damit der überhaupt mit der SD-Karte kommunizieren kann, sondern auch als on-the-fly CRC16 Rechner. Das ist nicht allzu schwierig, da sich CRC-Routinen gut in Hardware realisieren lassen.
Schwieriger hingegen ist die Einhaltung des genauen Protokolls für die SD-Karten. Allein die Initialisierungs-Sequenz hat schon manchen Programmierer an den Rand des Wahnsinns gebracht, da auch jede Karte (MMC, SD, SDHC) anders initialisiert werden will.
Gesetz dem Fall, man hat es mit einer SD-Karte zu tun, dann muss man erst mal Daten-, Kommandoleitung und das CardSelect-Signal auf 1 legen und mindestens 74x an der Clock-Leitung rütteln, bis die Karte "wach" ist. Sodann darf man die Karte mit dem CMD0 Kommando zurücksetzen. Mit dem CMD5 Kommando fragt man nun solange nach, bis die Karte meldet, dass sie bereit ist. Das kann bei älteren und größeren Modellen schon mal eine Sekunde dauern. Nun kann man mit den Kommandos CMD2 und CMD3 die Kartenspezifikationen ermitteln, also Hersteller, Geschwindigkeit, Busbreite, usw. Sind diese Informationen alle beisammen, ist die Initialisierung abgeschlossen und die weitere Kommunikation beschränkt sich auf den Datentransfer.
Die Kommandos, die der Mikroprozessor an die Karte sendet, sind während der Initialisierung also immer identisch. Insofern spricht einiges dafür, die Bytesequenz der Kommandos komplett, also inklusive der Prüfsumme, im Programmcode zu hinterlegen. Für die weiteren Kommandos geht das leider nicht. Zum Schreiben und Lesen von Daten gibt es jeweils zwei Befehle. Einer der beiden Befehle initiiert die Übertragung für einen Block, der andere eine ganze Reihe von Blöcken. Die Blockgröße liegt bei SDHC-Karten bei 512 Bytes, bei SD-Karten kann sie mit dem CMD16 festgelegt werden.
Wenn beispielsweise mit dem CMD17 ein einzelner Block angefordert wird, dann empfängt man 512 Byte Daten inkl. Prüfsumme, und meldet dann mit dem CMD12 das Ende der Übertragung. Soweit, so einfach. Werden mit dem CMD18 eine ganze Reihe Blöcke angefordert, so sendet die SD-Karte solange Daten, bis der Prozessor einer CMD12 sendet. Was hier nicht unter den Tisch fallen darf ist, dass auf jedes Kommando auch eine Reaktion, eine Antwort auf dem Kommandokanal gesendet wird. Das bedeutet, dass nach einem CMD17 oder CMD18 sowohl auf dem Kommandokanal, also auch auf dem Datenkanal empfangen werden muss.
Jetzt mal ganz ehrlich: Wer sich sowas ausgedacht hat, sollte sich am Tag des Jüngsten Gerichtes dafür verantworten müssen!
Mehr und mehr komme ich zu der Einsicht, dass die Verwendung einer SD-Karte eher was für Masochisten ist. Es gibt nämlich eine Alternative, ohne Bitschiebereien, ohne Kommandosequenzen, ohne Prüfsummen: CompactFlash Karten. Diese Karten sind genauso preiswert zu bekommen wie SD-Karten, aber wesentlich angenehmer anzuschließen. Ich werde mal in dieser Richtung forschen, aber ich denke, einfach als das hier geht es nun wirklich nicht mehr.

Dienstag, 8. April 2014

Aktualisierter Schaltplan des Z8S180

In meinem Debian liegt eine (für Software-Verhältnisse) steinalte Version von KiCAD herum, die ich erst einmal auf den neuesten Stand gebracht habe. Einige lästige Fehler sind tatsächlich nicht mehr vorhanden. Hier also die aktualisierte Version der Schaltpläne, von der Kern-Schaltung und der seriellen Schnittstelle inkl. Baudraten-Generator.



Was nun noch fehlt, ist die Verbindung zur SD-Karte. Und nach allem, was ich da gelesen habe, scheint die Schwierigkeit nicht am Anschluss selbst zu liegen, sondern an der komplizierten Berechnung der Prüfsummen. Da muss ich nochmal forschen...

Montag, 7. April 2014

Zurück zum Z8-Design

Ich habe heute noch einmal gründlich über die Verwendung von CPLDs bei diesem Projekt nachgedacht. Eigentlich brauche ich den CPLD hauptsächlich nur wegen der seriellen Schnittstelle. Dadurch, dass der Z8S180 seine Taktfrequenz nur durch einige wenige fest vorgegebene Teiler dividieren kann, kommen nur sehr wenige Taktfrequenzen in Frage, mit denen überhaupt der sinnvolle Betrieb einer seriellen Schnittstelle vorstellbar ist.
Der Z8S180 kann seine Taktfrequenz - in Abhängigkeit von der Programmierung - durch 10 oder durch 30 teilen. Anschließend kann man, ebenfalls programmierbar, den Takt durch 1, 2, 4, 8, 16, 32, oder 64 dividieren. Womit man dann auch schon beim 16-fachen der Baudrate wäre, welche zum Betrieb erforderlich ist.
Um Beispielsweise mit 38.400 Baud zu übertragen, müsste man eine Taktfrequenz von 6,144 MHz wählen, und einen Vorteiler durch 10. Womit man schon bei 614,4 kHz ist, dem 16-fachen der gewünschten Baudrate.
Diese krummen Taktfrequenzen beißen sich nicht nur mit den gewünschten 33 MHz (mal ganz davon ab, dass man so eine Taktfrequenz nicht nur ausrechnen, sondern den Quarz auch kaufen können muss), sondern erst bei etwa 24 MHz kommt man auf korrekte Baudraten.
Das war der Grund, weshalb ich einen externen UART nehmen wollte. Aber wie immer gilt auch hier: Wer lesen kann, ist deutlich im Vorteil. Der Z8S180 kann nämlich auch einen externen Takt verwenden. Nu guck.
Man nehme also einen 2,4576 MHz Takt (wie praktisch - den passenden Oszillator gibt es bei Reichelt für unter einem Euro), dividiere diesen durch 4 und erhält oben erwähnte 614,4 kHz. Diesen führe man dem Z8S180 zu, programmiere seine Register derart, dass er den externen Takt wählt, und braucht nun keinen CPLD mehr.
Eine weitere Änderung habe ich hinsichtlich des ATMega vorgenommen. Es ist nun kein ATMega64 mehr, sondern ein ATMega128. Nicht, dass ich sonderlich Wert darauf legte, dass ich nun doppelt so viel Flash-Speicher habe, sondern wichtig sind die 15 weiteren Port-Pins. Nun kann ich erstens auf den 74LS244 verzichten, den ich als Port-Expander brauchte und zum anderen habe ich den ATMega128 in einem TQFP-64 Gehäuse, also einem kleinen quadratischen SMD Bauteil. Es schrumpft weiter.
Nach vorne, auf die Stirnseite der Platine kommt dann der ISP-Anschluss für den ATMega, die serielle Schnittstelle des Z8S180, die SD-Karte mit dem CP/M+ Betriebssystem und einige LEDs für die Systemdiagnose.

Donnerstag, 3. April 2014

Was es alles so gegeben hat

Da spielt man also ein wenig mit der CPLD und FPGA Programmierung herum und sucht dabei das halbe Internet nach Beispielen und Dokumentation ab, da fällt mir plötzlich eine CPU auf, die bei mir weit mehr, als nur ein "Äh, wie jetzt?" hervorgerufen hat.
Die MC-14500 von Motorola. Eine 1-Bit CPU. Kein interner Programmzähler. Hier gibts sogar noch ein Handbuch zu dem Teilchen.
Ich habe dann tatsächlich auch eine deutsche Seite zu dem Thema gefunden, wo man um dieses 16-Pin-IC herum einen ganzen Computer gebaut hat.
Momentan hänge ich gerade in Verilog bei einem Beispiel fest, mal schauen, ob ich ein Forum finde, wo ich Hilfe bekommen kann.

Mittwoch, 2. April 2014

Niklaus Wirth kanns noch immer

Immer dann, wenn man meint, alles gesehen zu haben, wird man total überrascht. Wie ich zum Beispiel gerade eben vom "Projekt Oberon", ein Projekt von Niklaus Wirth (Erfinder von Pascal, Modula-2, Modula3 und Oberon) und Jürg Gutknecht.
Da stellen also zwei gestandene Schweizer Urgesteine der Computertechnik ein Projekt vor, welches nichts geringeres als einen Computer mitsamt Betriebssystem beschreibt. Und als Sahnetüpfelchen erklären sie auch noch, dass es jedem einzelnen möglich sein sollte, nicht nur das Betriebssystem, sondern auch den ganzen Rechner als Ganzes zu verstehen. Und überhaupt soll sich das System durchaus auch für den produktiven Einsatz eignen.
Nicht nur, dass der komplette Rechner komplett in einem FPGA verschwinden soll, nein, sämtliche Dokumentationen zu Rechner und Betriebssystem haben sie auch noch veröffentlicht, damit jeder davon lernen kann.
Na, dann mal los.

Nachdenkliches Gegrübel

Je mehr ich über CPLDs und FPGAs nachdenke, desto mehr bin ich davon überzeugt, dass hierin tatsächlich die Zukunft des Selbstbaus liegt. Zum einen deshalb, weil es oberhalb einer bestimmten MHz-Grenze einfach nicht mehr möglich ist, daheim im stillen Kämmerchen einen Rechner zusammen zu stecken. Beispielsweise einfach aufgrund der simplen Tatsache, dass man CPUs oberhalb 20 MHz, aber unterhalb der Gigahertz-Grenze gar nicht mehr bekommt. Ausnahmen bestätigen die Regel. Dasselbe gilt für den Speicher: Während man unterhalb von einem MB noch alles nachgeschmissen bekommt, existiert darüber nur noch ein schwarzes Loch, das erst bei den Speicherriegeln für PCs endet. Zum anderen bekommt man das Timing gar nicht mehr in den Griff. Einerseits weil die dazwischenliegenden Logikschaltkreise im Nanosekundenbereich arbeiten müssen, andererseits weil das Layout der Platine einen immer höheren Einfluss auf die Laufzeiten bekommt. Baut man jedoch einen Rechner komplett in einem FPGA, so scheinen diese Probleme alle zu verschwinden. Tatsächlich hat man dann einen 250 MHz Oszillator, ein FPGA, einen Flash-Speicher für das FPGA Programm, einige Schnittstellen (z. B. PS/2 Tastatur, Videoausgang, Audioausgang, Netzwerk-Anschluss) und einen Programmieradapter auf der Platine. Mehr nicht. Des gesamte Rechner befindet sich dann innerhalb des FPGA. Und das nicht einmal virtuell oder simuliert, sondern real per Software verdrahtet.
Aber noch einmal zurück zum Timing: Im Falle meiner Z8S180 CPU heißt das, dass ich hier einen Prozessor habe, der mit 33 MHz vor sich hin werkelt und der - ohne die Waitstates - seiner Peripherie Antwortzeiten unterhalb von 45ns abverlangt. Das klingt noch handelbar, aber das täuscht. Exemplarisch sei hier der gute alte 8255 Port-Expander aufgeführt. 24 I/O Leitungen mit denen der Prozessor mit der Außenwelt kommunizieren kann. Ein Blick in das Datenblatt des 8255 offenbart das Problem in seiner vollen Hässlichkeit: Der 8255 braucht einen Schreib-/Leseimpuls von einer Mindestlänge von 300ns. Er ist rechnerisch also um den Faktor 7 zu langsam für diese CPU. Dasselbe gilt für die serielle Schnittstelle.
Moment: Wieso brauche ich eine externe serielle Schnittstelle, wenn die CPU doch zwei eingebaute UARTs hat? Auch das ist wieder so eine kleine Hässlichkeit, die sich daraus ergibt, dass ich die CPU unbedingt mit ihren vollen 33 MHz laufen lassen will. Zum Verständnis: Die Taktfrequenz für den UART muss um den Faktor 16 größer sein, als die eigentliche Baudrate. Für 38.400 Bit/s wären das also 614400 Hz. CPU-intern gibt es einen programmierbaren Frequenzteiler, der den Prozessortakt Phi (hier also 33 MHz) zunächst vorteilt (durch 2, 4, 8, 16, ... 256) und dann durch einen einstellbaren Wert von 1 bis 255 dividiert. Damit also überhaupt rechnerisch eine Taktfrequenz von 614400 Hz (20 Hz mehr oder weniger spielen da keine Rolle) erreicht werden kann, muss die CPU mit einer Frequenz von 24 MHz laufen. Oder 36 MHz, was nicht funktioniert.
Meine Idee ist daher, sowohl den Portexpander, als auch die serielle Schnittstelle in einen CPLD zu programmieren. CPLDs gibt es im Laufzeitbereich von 20ns bis hinunter zu 5ns. Der XC9572 ist auch tatsächlich für wenige Euro z. B. bei Reichelt zu bekommen. Interessanterweise gibt es ihn dort als auflötbares kleines Quadrat mit 44 oder 100 Pins zu fast identischem Preis von derzeit €2,15 oder € 2,60. Will man den Chip jedoch als sockelbaren 44 Pin PLCC haben (so einen Sockel kann man noch gut selbst fädeln und löten), dann kostet er gleich € 7,10.
Da auch die Speicherbausteine, die ich verwenden muss, lediglich als SMD-Bausteine zu bekommen sind, werde ich wohl nicht umhin kommen, mir auch noch einen SMD-Arbeitsplatz zuzulegen. Glücklicherweise hat Pollin justamente eine SMD-Heißluft Lötstation im Katalog. Außerdem einen SMD-Bausatz für SMD-Einsteiger, usw.
Was ein Aufwand. Ich glaube, meinen nächsten Rechner baue ich komplett in einen FPGA. Vielleicht sogar den SC/MP II, inclusive Speicher, EPROM und Ansteuerung für Tastatur, 8x7-Segment Displays und Kassetteninterface. Ach ja, ich weiß jetzt gar nicht mehr, wer das fragte, aber ja: Den SC/MP II gibt es immer noch zu kaufen. Und ja, er heißt wirklich INS-8060.