Build your OS – Der Regnatix-Code – Seite 2

3. Slave-Funktionen

Nun sehen wir die ersten Lebenszeichen von Regnatix über den Bildschirm huschen. Der nächste folgerichtige Schritt wäre nun, die Keyboard Funktionen von Bellatrix über den Bus verfügbar zu machen. Aber vor der konkreten Realisierung dieses Schrittes sollten wir uns einige grundlegende Gedanken zum übergeordneten Dialog zwischen den Propellern machen.

Da alle Macht von Regnatix ausgeht, ist der erste Gedanke wie die Funktionen abgerufen werden können recht einfach: Jeder Busdialog beginnt mit der Übersendung einer entsprechenden Funktionsnummer zum Slave. Darauf folgt eine funktionsabhängige Abfolge von Sende- und Empfangszyklen. Genau nach diesem Muster funktioniert das BIOS in Administra im TriOS.

Bei Bellatrix aber habe ich für den Texttreiber einen anderen, asymetrischen Ablauf realisiert, da ein großer Anteil der Daten zwischen Bellatrix und Regnatix Zeichenausgaben sein werden. Also werden alle Daten <> 0 als Ausgabezeichen interpretiert und auf dem Bildschirm ausgegeben. Empfängt Bellatrix aber eine $0, so folgt darauf eine entsprechende Funktionsnummer. Für unser nächstes Experiment wollen wir zwei Funktionen in Bellatrix integrieren: Status und Tastaturcode abfragen.

Unser erstes Experiment dazu soll eine einfache Textkonsole sein. Die Routine in Regnatix sendet dazu alle per Tastatur eingegebenen Zeichen, welche er bei Bellatrix abfragt, einfach wieder zurück, um sie auf dem Textbildschirm auszugeben.

[002-reg-textkonsole.spin] – Regnatix-Code
[002-bel-bios.spin] – Bellatrix-Code

REGNATIX-CODE

PUB main                                                                        'Hauptroutine

  bus_init
  print(@msg1)
  repeat
    repeat until keystat > 0                            'taste gedrückt?
    printchar(key)                                      'echo der taste auf bildschirm

BELLATRIX-CODE

PUB main | zeichen,n                                                            'Hauptroutine

  init_subsysteme                                       'bus/vga/keyboard/maus initialisieren
  repeat
    zeichen := bus_getchar                              '1. zeichen empfangen
    if zeichen > 0
      print_char(zeichen)
    else
      zeichen := bus_getchar                            '2. zeichen kommando empfange
      case zeichen
        1: bus_putchar(key.gotkey)                      '1: Tastaturstatus senden
        2: bus_putchar(key.key)                         '2: Tastaturzeichen senden

4. Kommandointerpreter

Im vorigen Abschnitt haben wir im Regnatix-Code schon einige elementare Routinen gefunden. In unserem Fall sind es eigentlich nur die verschiedenen Funktionen für Textausgaben (print, printchar) und Zeicheneingabe (keystat, keycode). Da wir diese universellen Routinen in vielen Programmen brauchen werden, ist es sinnvoll, diese als Bibliothek in ein gesondertes Objekt auszulagern. Im TriOS heißt dieses Objekt „IOS“ (Input-Output-System), um Verwechslungen zu vermeiden, wollen wir unser Objekt „SIOS“ (Spin-IOS) nennen.

[003-reg-cli.spin] – Regnatix-Code
[003-bel-bios.spin] – Bellatrix-Code

Im Quelltext [003] ist das SIOS schon eingebunden. Auch das Bella-Bios ist an einigen wenigen Stellen verändert. So werden jetzt auch diverse Steuercodes eingebunden. Im SIOS findet man zu den meisten Funktionen die entsprechenden Routinen. Schauen wir uns an was wir bis jetzt in unserer Bibliothek verfügbar haben:

PUB start: wflag | n                                    'system: initialisiert system
PUB key:wert                                            'key: holt tastaturcode
PUB keyspec:wert                                        'key: statustasten zum letzten tastencode
PUB keystat:status                                      'key: übergibt tastaturstatus
PUB keywait:n                                           'key: wartet bis taste gedrückt wird
PUB print(stringptr)                                    'screen: bildschirmausgabe einer zeichenkette (0-terminiert)
PUB printdec(value) | i                                 'screen: dezimalen zahlenwert auf bildschirm ausgeben
PUB printhex(value, digits)                             'screen: hexadezimalen zahlenwert auf bildschirm ausgeben
PUB printchar(c)                                        'screen: einzelnes zeichen auf bildschirm ausgeben
PUB printctrl(c)                                        'screen: steuerzeichen ($100 bis $1FF) auf bildschirm ausgeben
PUB printnl                                             'screen: $0D - CR ausgeben
PUB printcls                                            'screen: screen löschen
PUB curhome                                             'screen: cursorposition auf erste position setzen
PUB printtab                                            'screen: zur nächsten tabulatorposition
PUB curchar(char)                                       'screen: setzt cursorzeichen
PUB curpos1                                             'screen: setzt cursor auf spalte 1 in zeile
PUB setcolor(color)                                     'screen: farbe setzen
PUB curon                                               'screen: schaltet cursor an
PUB curoff                                              'screen: schaltet cursor aus
PUB sline(n)                                            'screen: startzeile scrollbereich setzen
PUB screeninit(stradr,n)                                'screen: löschen, kopfzeile ausgeben und setzen
PUB bus_init                                            'bus: initialisiert bussystem
PUB bus_putchar2(c)                                     'BUS: Byte an Prop1 (Bellatrix) senden
PUB bus_getchar2:wert                                   'BUS: Byte vom Prop1 (Bellatrix) empfangen

Kern des Interpreters ist die Variable tib für eine Kommandozeile. In dieser Variable wird die Zeichenkette gespeichert, schrittweise zerlegt und interpretiert. Das Programm enthält keine großen Geheimnisse und es sollte schnell klar werden wie man den Interpreter durch weitere Kommandos erweitern kann.

Um die Funktionsweise zu verdeutlichen, habe ich noch zwei experimentelle Kommandos eingefügt – para und paranum. An diesen beiden Kommandos kann man gut die Funktion der Parameterübergabe sehen um selbst eigene Kommandos zu realisieren.

Dieser Kommandozeileninterpreter war lange Zeit die Basis meiner Versuche und Tests mit dem ersten Prototypen. Mit den entsprechenden Kommandos wird daraus ein Speichermonitor, ein Bustest, ein Speichertest usw.

Testroutinen zur Parameterübergabe

PUB fPara | stradr, i                                   'cmd: para - test parameterübergabe

  i := 0
  repeat
    stradr := os_nextpara                               'nächsten parameter aus tib in puffer kopieren
    if stradr > 0
      sios.print(string("Parameter "))
      sios.printdec(i++)
      sios.print(string(" : "))
      sios.print(stradr)
      sios.printnl
  until stradr == 0                                     'wiederhole bis kein parameter mehr vorhanden

PUB fParaNum | stradr, i, n, m                          'cmd: paranum - test zahlenparameter

  i := 0
  m := 0
  repeat
    stradr := os_nextpara                               'nächsten parameter aus tib in puffer kopieren
    if stradr > 0
      sios.print(string("Parameter "))
      sios.printdec(i++)
      sios.print(string(" : "))
      n := num.FromStr(stradr,num#dec)
      sios.printdec(n)
      sios.printnl
      m := m + n
  until stradr == 0                                     'wiederhole bis kein parameter mehr vorhanden
  sios.print(string("Summe : "))
  sios.printdec(m)
  sios.printnl

Seite 1 – Seite 2 – Seite 3 – Fortsetzung