8bit-Computer: bo8h

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

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.

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.