8bit-Computer: bo8h
von: Josef Gnadl (bome)
Übersicht
Habe einen 8bit-Rechner entwickelt und als Prototyp-Gerät realisiert auf folgenden FPGA-Boards:
- Spartan-3A Starter Kit von Xilinx
- Spartan-3E Starter Board und
- Nexys2 Board von Digilent
- DE1 Board / Cyclone2 Starter Board von Terasic/Altera
- Altera DE0 Board
Die Realisierung auf dem Spartan-3A Starter Kit funktioniert auch auf dem Spartan-3AN Starter Kit.
Die CPU ist eine Eigenentwicklung. Merkmale des Gesamtsystems sind der aus mehreren 64KByte-Seiten bestehende Adressraum, das Steckplatz-Konzept, die an die Hardware angepasste Programmiersprache bola und taktgenau berechenbare Programmlaufzeiten. Der Zeichensatz beinhaltet einen hexadezimalen Ziffernsatz, welcher für die Ziffern A..F spezielle Zeichen verwendet.
Das Prototyp-Gerät besitzt Bildschirm und Tastatur, nutzt RS232 zum Daten-Austausch mit PC und hat eine SD-Karte mit selbstgestricktem Dateisystem.
- Informationen und Downloads gibt es auf www.bomerenzprojekt.de.
- Im Forum Codesammlung gibt es dazu den Beitrag 8bit-Computing mit FPGA.
- Im embedded-projects-Journal 14 gibt es den Artikel Ein 8bit-Rechner auf dem Spartan-3A-Starterkit.
Die CPU steht unter der hier im Wiki geltenden Creative-Commons-Lizenz zur Verfügung: 8bit-CPU: bo8.
Das Prototyp-Gerät hat 4 freie virtuelle Steckplätze mit je 64KByte, wobei je 32KByte für Software vorgesehen sind. Damit haben Software-Entwickler die Möglichkeit, Steckkarten-Software in Eigen-Regie anzubieten. Zur Software-Entwicklung auf PC gibt es einen in C geschriebenen Cross-Assembler.
Es gibt eine Schnittstelle zum Anschluss von Zusatz-Hardware. Sie hat einen 9bit-breiten Ausgangsport und einen 8bit-breiten Eingangsport und zwei Handshake-Leitungen für asynchronen Betrieb. Damit sollte zB. der Anschluss eines uC möglich sein. 8 der 9 Ausgänge sind Tristate und können mit den 8 Eingängen zusammengelegt werden.
Die CPU
Der Punkt in den Mnemonics steht für einen auf der Grundlinie liegenden Bindestrich.
Der Akku A und das Erweiterungsregister B sind 8-bit. Das Doppelregister AB wird abkürzend mit K bezeichnet Das Vorzeichenbit A7 wird abkürzend mit U bezeichnet. Der Programmzähler P und die Adressregister X,Y,Z sind 16-bit. Das Register Q erhält bei Sprüngen die Rückkehradresse P+1. R ist Schleifen-Startadresse, S ist Schleifenzähler. Einziges Flag ist der Carry V. Bei bedingten Sprüngen kann ausserdem abgefragt werden, ob U/A/K Null sind. Alle Speicherzugriffe sind 8bit-Zugriffe. GTMX lädt nach A den Inhalt der Speicherzelle, auf welche X zeigt. STMX speichert A in der Speicherzelle, auf welche X zeigt. IXE inkrementiert X und tauscht A und B. DXE dekrementiert X und tauscht A und B. Damit lassen sich 2-byte-Speicherzugriffe aufbauen nach dem Muster GTMX/IXE/GTMX und STMX/DXE/STMX. Es gibt hierfür die Assembler-Makros GTMXI und STMXD. GTMXI lädt eine Adresse von Position X ST.Y überträgt die Adresse nach Y GTMXI lädt eine Adresse von Position X AD.X addiert X ST.Y überträgt die zu X relative Adresse nach Y J.. Sprung zu der Adresse, welche in K steht GTA 59 lädt den Wert 0059 nach K AD. 35 addiert 35 zu A J.. Sprung nach 3559 Das lässt sich kürzer schreiben mit Assembler-Makro /GTA 3559 J GTR 59 lädt den Wert P+0059+3 nach K AD. 35 addiert 35 zu A J.. relativer Sprung nach P+3559+3 Das lässt sich kürzer schreiben mit Assembler-Makro /GTR 3559 J GT.Q lädt Rückkehradresse nach K J Rücksprung aus Unterprogramm Wenn ein Unterprogramm selber J.. ausführen will für andere Zwecke als für den Rücksprung, muss es vorher die Rückkehr- adresse sichern. Dazu kann es die Rückkehradresse aus Q laden, anfangs steht sie aber auch in K und das Laden kann entfallen. Ausser dem Sprungbefehl J.. gibt es die bedingten Sprünge mit 8bit-Sprungdistanz: O.cc nn (Vorwärtssprung falls cc) und B.cc nn (Rückwärtssprung falls cc). Für schnelle Schleifen gibt es die Repeat-Befehle R.cc. Repeat-Befehle gibt es kombiniert mit Schleifenzähler- Dekrementieren und Adresse-Inkrementieren/Dekrementieren. Die Schleifenstartadresse R wird gesetzt am Schleifenanfang mittels S.RP oder mittels O.RP nn. Bei letzterem wird gleichzeitig ein Vorwärtssprung ausgeführt. Damit sind Schleifen mit Hineinsprung (while-Schleifen) realisierbar. Bei J.. wird die Zieladresse auch nach R übertragen. Das garantiert, dass R stets eine Adresse im Nahbereich des Programmzählers enthält. Eine Anwendung hiervon ergibt sich beim Sprung in eine Tabelle, welche aus O.WY nn - Befehlen (Vorwärtssprung always) besteht, wobei die O.WY nn alle zur selben Adresse springen. Die dortige Routine kann durch Auswertung von R die Nummer des O.WY - Befehls ermitteln. Adressierung mehrerer 64K-Seiten: ================================= Zu jeder auf dem Adressbus ausgegebenen Adresse wird auf den Steuerleitungen angezeigt, von welchem der Adressregister P,X,Y,Z sie kommt. Dadurch kann eine externe Logik jedem der Adressregister eine eigene 64K-Speicherseite zuordnen. Die CPU kann spezielle Steuersignale ausgeben, welche die externe Logik zur Memory-Page-Umschaltung für eines der Adressregister veranlassen sollen. Der Befehl H.. ist der einzige und universell einsetzbare IO-Befehl. Es wird K auf dem Adressbus ausgegeben, und der Datenbus wird nach A eingelesen. Wenn auf H.. ein J.. folgt, dann wirkt H.. stattdessen als Präfix und bewirkt, dass J.. mit einer Memory-Page-Umschaltung kombiniert wird. So kann die CPU von einer 64K-Seite in eine andere springen, ohne dass es einen gemeinsamen Speicherbereich geben muss. Bei den Adressregistern X,Y,Z gibt es spezielle Befehle SW.X, SW.Y, SW.Z für die Memory-Page-Umschaltung.
Die Gesamt-Hardware
Es gibt vier Memory-Pages mit je 64KByte: Page 0: Aktiver Steckplatz Page 1: ROM (32K), Text-RAM (16K), Video-RAM (16K) Page 2: Haupt-RAM Page 3: Zusatz-RAM Der aktive Steckplatz in Page 0 wird durch ein 3bit-Register SLT ausgewählt. Es gibt die 2bit-Register MP,MX,MY,MZ. Diese Register legen fest, in welche der vier Memory-Pages das betreffende Adress- register P,X,Y,Z zeigt. Ausserdem gibt es die Schattenregister NP,NX,NY,NZ. Das CPU-Signal zur Memory-Page-Umschaltung für ein bestimmtes Adressregister # bewirkt den Austausch von M# und N#, wobei # hier für P,X,Y,Z steht. Beim Sprung mit Memory-Page- Umschaltung H.. J.. werden also MP und NP getauscht. Die Schattenregister NP,NX,NY,NZ können über IO-Befehle H.. mit einem Wert 0 bis 3 geladen werden.