Build your OS – Der Regnatix-Code – eRAM

Externer RAM

Der Hive hat drei verschiedene Speichermodelle:

  • cRAM – Jedes der 24 RISC-Subsysteme hat eine eigene universelle Rambank intern exklusiv nur für die COG verfügbar – der sogenannte COG-RAM. Dieser Speicher ist als 512 x 32 Bit Bank organisiert und als Datenregister oder Programmspeicher für den RISC-Mikrocode verwendbar. Der cRAM hat die höchste Zugriffsgeschwindigkeit im System von 50 ns für Long-Zugriffe und jede COG kann nur auf die eigene Rambank zugreifen.
  • hRAM – Jeder Propellerchip verfügt über einen für alle COG’s gemeinsam nutzbaren Hub-RAM mit einer Kapazität von 32 KByte pro Chip – insgesamt besitzt der Hive also über 96 KByte hRAM. Wie der Name schon andeutet, teilen sich alle COG’s eines Propellerchips  diesen RAM und so ist auch die Zugriffszeit nicht genau festgelegt. Ein Zugriff dauert zwischen 7 und 22 Taktzyklen, allerdings auch hier für einen kompletten Long-Zugriff. Diese Zeit ist davon abhängig, wie viele COG’s aktiv sind und auf den hRAM zugreifen.
  • eRAM – Regnatix verfügt über eine direkte Möglichkeit zwei externe Rambänke von je 512 x 8 Bit anzusteuern. Insgesamt stehen dem Hive also 1 MB RAM als zusätzlicher Speicher zur Verfügung. Die aktuell eingesetzten Speicher sind statische RAM’s und besitzen eine Zugriffszeit von 55 ns. Da wir im Hive einen 8Bit-Bus haben sind physisch natürlich auch nur Byte-Zugriffe möglich. Wie hoch die ganz konkrete Zugriffsgeschwindigkeit liegt, hängt extrem von der konkreten softwaretechnischen Realisierung ab.

Von Parallax ist kein Anschluss von externem RAM vorgesehen, was uns aber nicht davon abhalten soll es trotzdem zu tun. 🙂 RISC-Systeme folgen an diesem Punkt eh dem IKEA-Motto „Was nicht passt, wird passend gemacht!“, also werden wie so viele Dinge bei den Propellerchips, die externen RAM’s einfach per Software angebunden. Zu den sich daraus ergebenden Fragen zum Thema Geschwindigkeit, Programmcode im eRAM und Zugriff anderer Propeller kommen wir später noch. Jetzt wollen wir erst sehen wie das ganze prinzipiell funktioniert, bevor wir darüber nachdenken, was man noch alles schönes damit machen kann. Aber schauen wir uns als erstes an, wie die RAM’s schematisch an Regnatix angeschlossen sind:

Das RAM-Interface beutzt drei eigene Steuersignale. Das Signal /WR bestimmt die Schreibrichtung: Ist dieses Signal High, wird ein Byte gelesen, ist es Low wird ein Byte geschrieben. Wie schon bei der Kommunikation der Propellerchips müssen wir an diesem Punkt den Modus der Datenbusleitungen an Regnatix beachten, damit es zu keinem Buskonflikt kommt. Das Signal /RAM1 & 2 wählt mit einem Low selektiert entsprechende Rambank. Mit dem Signal AL steuern wir unser Adresslatch. Dieses Adressregister benötigen wir im Hive, da wir nicht genug I/O-Ports an Regnatix haben, um eine vollständige 19Bit-Adresse direkt auszugeben. Also speichern wir den höherwertigen Teil (HWT) A11-18 der Adresse in einem Latch. Dafür sind die Eingänge des Registers an die Adressports A0..7 angeschlossen. Legen wir dort den HWT an, so wird dieser mit einem Impuls am Signal AL im Latch gespeichert. Drauf folgend können wir an den Adressports von Regnatix den niederwertige Adressteil (NWT) anlegen und den Speicherbaustein selektieren um ein Byte zu lesen oder zu schreiben.

Link Wikipedia: „RAM – Random Access Memory“
Link Wikipedia: „Statische RAM’s“
Link Wikipedia: „Latch“

In unserem SpinOS wollen wir den externen Speicher natürlich auch mit einfachen SPIN-Routinen ansteuern. Schauen wir uns an wie das am Beispiel der ersten Speicherbank funktioniert, die zweite Bank wird analog eingebunden und unterscheidet sich nur in der Verwendung der Signale /RAM1 und /RAM2. Exemplarisch betrachten wir den Ablauf bei der Routine zum Lesen einer Speicherzelle. Ich denke die Prozedur für das Schreiben eines Bytes in den externen Speicher ergibt sich anhand der Darstellung von selbst.

PUB ram_read(adresse):wert                              'eram: liest ein byte vom eram
'rambank 1 000000 - 07FFFF
  outa[15..8] := adresse >> 11          'höherwertige adresse setzen
  outa[23] := 1                         'obere adresse in adresslatch übernehmen
  outa[23] := 0
  outa[18..8] := adresse                'niederwertige adresse setzen
  outa[reg_ram1] := 0                   'ram1 selektieren (wert wird geschrieben)
  wert := ina[7..0]                     'speicherzelle einlesen
  outa[reg_ram1] := 1                   'ram1 deselektieren

Im folgenden noch einige Aspekte in Bezug auf den externen Speicher, welche keinen direkten Bezug zu unserem Tutorial haben, aber die durchaus interessant sind.

Maschinencode im eRAM

Da Parallax uns im Propeller kein Interface für externen Ram spendiert hat, ist es auf den ersten Blick auch nicht möglich, Maschinencode im eRAM auszuführen. Diese Erkenntnis ist aber nur auf den ersten Blick korrekt, denn auch im Propellerchip selbst kann Maschinencode nur im cRAM und nicht im hRAM ausgeführt werden! Das klingt erstmal verwirrend, aber es ist so und es ist konsequent. Zugriffe auf den hRAM sind dem entsprechend als CISC-Operationen eingestuft und müssen aus mehreren RISC-Befehlen zusammengesetzt werden. Und genau nach diesem Schema kann man auch Maschinencode im h- und eRAM abarbeiten. Für den hRAM exestiert dafür schon ein entsprechendes Modell – das „Lare Memory Model“ (LMM). Mit vier RISC-Befehlen kann dabei Maschinencode aus dem hRAM abgearbeitet werden, wobei man sich genau überlegen muß was man tut, denn dadurch wird dieser Code auch entsprechend langsamer ausgeführt. Ebenso wäre es natürlich auch möglich Maschinencode im externen Speicher auszuführen.

Link Propeller-Wiki: „Large Memory Model“

Geschwindigkeit

In unserem Tutorial-OS verwenden wir SPIN zur Ansteuerung der externen Speicherbausteine um ein möglichst einfaches und konsistentes System zu haben. Um die volle Leistungsfähigeit des Systems auszuschöpfen, ist es möglich die Routinen in PASM zu realisieren. Dafür wäre es wahrscheinlich sinnvoll, eine COG als Speichermanager zu reservieren. Im besonderen bei Blockoperationen, wo größere Speicherblöcke zwischen eRAM und hRAM ausgetauscht werden, kann sich der Zugriff so um den Faktor 60..100 beschleunigen. Dafür ein kleines Beispiel, bei welchem eine komplette Speicherbank von 512 KByte mit einem definierten Wert beschrieben wird:

  • SPIN: ca. 60 Sekunden
  • PASM: ca. 0,5 Sekunden

Parallelität der Bänke: In bestimmten Fällen kann es sinnvoll sein beide Speicherbänke parallel zu bearbeiten. Da wir die Adresse für die Bänke per Software dekodieren, können wir auch problemlos beide Bänke gleichzeitig selektieren, zum Beispiel bei einem Schreibvorgang.  So dauert das füllen mit Werten wie in unserem obigen Beispiel nicht ca. 1 Sekunde, wenn wir den gesamten Speicher von 1 MB beschreiben, sondern ebenfalls nur ca. 0,5 Sekunden, da beide Bänke gleichzeitig und parallel beschrieben werden können!

Schneller Zugriff auf NWT-Pages: Verwendet man nur den NWT der Adresse, also nicht unser Adresslatch, so kann man in jeder Speicherbank auf 256 „Pages“ mit je 2048 Byte Größe zugreifen. Da man beim Zugriff  innerhalb dieser Seiten keine Änderung am Adresslatch vornehmen muss, kann der Zugriff innerhlb dieser Seiten schneller ablaufen.

Zugriff durch andere Propeller

Im Konzept des Hive ist nur ein direkter Zugriff von Regnatix auf den eRAM vorgesehen. Das ist aber nur eine Softwarekonvention des bisherigen Systems. Es ist durchaus auch möglich, dass Bellatrix auf den eRAM zugreift, sofern man in Regnatix eine COG als Adresseinheit für Bellatrix vorsieht.  So könnte Bella mit einem umfunktionierten Signal (zum Beispiel BUSCLK) den Adresszähler inkrementieren oder mit einem zweiten Signal den Adresszähler neu setzen. Der Bus ist während dieser Zugriffe natürlich entsprechend blockiert. An diesem Punkt muss man mental Abstand vom bisherigen Konzept und der Aufteilung der Funktionen zwischen den drei Propellerchips nehmen, aber das ist durchaus eine Herausforderung für ganz verwegene Drohnen. 🙂

Denkbar wäre also ein Systemmodus, in welchem Bellatrix die Kontrolle übernimmt und Regnatix und Administra nur Hilfsaufgaben ausführen. In einem Game könnte man so zumindest für den TV-Modus eine Vollfarb-Rastergrafik realsieren, wobei die Grafik sich im eRAM befindet. Regnatix übernimmt in diesem Modell die Aufgabe eines Speicherkontrollers und die restlichen COG’s können Sprites oder die Grafik manipulieren und sich um solche Sachen wie Kollisionsabfragen kümmern. Dieser Systemmodus kann dynamisch sein und zur Laufzeit hergestellt werden, wenn die entsprechende Anwendung geladen wird und wieder deaktiviert werden, wenn das Spektakel vorbei ist. Klingt zwar erstmal kompliziert, aber wer mal in Richtung tilesbasierte Grafik experimentiert, wird diese Meinung vielleicht noch ändern. 😉