HaDesWWW logo
Startseite

Downloads
Geschichte(n)
 
Hardware
FPGA-Board
Prozessor
  Instruktionssatz
Peripherie
  XBus-Referenz
PS/2-Board
Soundboard
USB-MMC-Board
 
PC-Software
HaCom
HoAsm, HLink
Emulator
Connectivity
 
Embedded Software
HAL
Dateimanager
Tetris
PacMan
3D-Engine
Pong
PacMan 3D
 
Kontakt

HaDes XP - Die HAL

Die HAL (HaDes Library) ist alles in einem: Betriebssystem, Hardwareabstraktionslayer, Standardbibliothek und Game Engine. Um es unter einen Hut zu bringen: alles, was uns allgemein genug erschien, um es in mehreren Programmen wiederverwenden zu können. Dementsprechend ist sie sehr umfangreich und enthält deutlich  mehr Code als das größte Anwendungsprogramm (Tetris). Natürlich findet sich in keinem fertig gelinkten Programm jede HAL-Funktion, meist werden eher kleine Teile benötigt. 

Die HAL ist auch recht gut im Quellcode dokumentiert, und mit Doxygen haben wir daraus eine schöne API-Referenz erstellt. Deswegen werden wir auf dieser Seite nur einen kurzen Überblick über den Funktionsumfang geben, die wichtigsten Konzepte erklären und ein kleines Tutorial zum Einsatz der HAL präsentieren. 

Funktionsumfang

Die HAL umfasst Funktionen aus vielen Anwendungsbereichen. Um diese sinnvoll zu gruppieren, sind sie in der API-Referenz zu „Modulen“ zusammengefasst. Diese sind üblicherweise auch in einer einzigen HL-Datei implementiert und die Funktionsnamen einer Gruppe beginnen meist mit demselben Präfix. Folgende Tabelle führt diese Informationen zusammen:


Funktionsgruppe Präfix Dateiname
3D-Grafik und Vektorarithmetik hg_ hal3d.hl
3D-Objektdateien laden und anzeigen h3o_ hal3o.hl
7-Segment-Anzeige Funktionen keiner halasm.hl
Algorithmen (Suchen und Sortieren) keiner halalgo.hl
Animationen bzw. Bilder laden und anzeigen (für HA Animationen) anim_ halanim.hl
Datei- und Dateisystemfunktionen f halfile.hl
Dateiübertragungsfunktionen hft_ halft.hl
Fehlerbehandlungsfunktionen und -konstanten ERR_ halbasic.hl
Geräteansteuerungsfunktionen (für I/O Geräte) dev_ haldev.hl
Grafik-Zeichenfunktionen (Linien, Polygone, Text) pix_ halpix.hl
Hardware-Direktansteuerungs-Funktionen und -Konstanten keiner halbasic.hl
Hauptspeicher-Verwaltungs-Funktionen (malloc etc.) m halmem.hl
Highscore-Funktionen (Anzeige, Aktualisierung, Speichern) hsc_ halhighscore.hl
Interruptbehandlungs- und Systemstartfunktionen keiner halintern.hl
hbasic.hoa
Mathematische Funktionen (Trigonometrie, Wurzeln, Zufall etc.) keiner halmath.hl
Mausfunktionen (Cursorsteuerung in Text- und Grafikmodus) mouse_ halmouse.hl
Menüfunktionen (Anzeigen und Bedienung durch Tasten oder Maus) menu_ halmenu.hl
Musik-Abspielfunktionen (für HM Musikdateien) music_ halmusic.hl
Message Loop Funktionen msg_ halmsg.hl
Netzwerkfunktionen (Paketversand und -empfang) net_ halnet.hl
PS/2-Bus-Überwachungsfunktionen keiner halps2.hl
Soundausgabefunktionen (für HSF Sound-Samples) sound_ halsound.hl
Stringfunktionen (Konvertierung von/zu Zahlen, Vergleich, ...) format_
conv_
str
cstr
halstring.hl
Tastatureingabe key_ halkeyboard.hl
Textmodus-Anzeigefunktionen (Textausgabe, Farben) gfx_ halgfx.hl
Zeitmessungsfunktionen (Echtzeituhr) time_ haltime.hl
Timerfunktionen (Timer setzen; Zeitmessung) timer_
watch_
haltimer.hl

Wichtige Konzepte

„Betriebssystem“-Funktionalität

Eine grundlegende Aufgabe der HAL ist die „Betriebssystem“-Funktionalität. Hier steht das „Betriebssystem“ bewusst in Anführungszeichen, denn die typischen Forderungen, die an moderne Betriebssysteme gestellt werden, wie Multitasking, Rechteverwaltung, Multiuser, etc. werden alle keineswegs von der HAL erfüllt. Die HAL stellt noch nicht einmal eine Benutzerschnittstelle zur Systemverwaltung bereit, schließlich ist sie nur eine Programmbibliothek. 

Von diesen philosophischen Diskussionen einmal abgesehen: Eine der Hauptaufgaben der HAL, und jedes Betriebssystems, ist die Bereitstellung einer bequemen und standardisierten Zugriffsmöglichkeit auf die Hardware. Dieser Zugriff wird für fast jedes an der HaDes anschließbare Gerät durch einen Satz von HL-Funktionen (siehe Tabelle oben) bereitgestellt. Da die HaDes Hardware und der XBus an sich schon recht benutzerfreundlich sind, ist dafür zumindest auf der Ausgabe-Seite oft nicht viel Aufwand nötig, als Beispiel betrachte man die Implementierung von pix_cls() zum Füllen des Grafikbildschirms mit einer Farbe. 

Auf der Eingaben-Seite (hauptsächlich Maus und Tastatur) ist dagegen einiges mehr zu erledigen. Üblicherweise melden sich alle Eingabegeräte mit einem der XBus-Interrupts bei der HaDes-CPU, wenn neue Benutzeraktionen vorliegen. (Polling der Eingabegeräte durch die CPU wäre ineffizient.) Dieser Interrupt muss also in einer Interruptroutine verarbeitet werden und unterbricht dabei das laufende Programm an einer beliebigen Stelle. Dieses Verhalten kann, wenn man nicht große Vorsicht walten lässt, leicht zu Konsistenzproblemen auf den Datenstrukturen des Programms führen. Daher ist es weder möglich noch wünschenswert, Interrupthandler im Anwendungsprogramm zu implementieren. Diese Aufgabe wird stattdessen von der HAL übernommen, die die Interrupts entgegennimmt, die Daten ausliest und interpretiert und dann dem Anwendungsprogramm als Messages zustellt.

Messages und Handler

Die HAL setzt alle Interrupts, die von Peripheriekomponenten ausgelöst werden (z.B. bei Maus- und Tastaturaktionen, aber auch beim Timer) in Messages um, die zunächst in einem globalen Array gespeichert werden und dann von der Applikation (außerhalb des Interrupthandlers) ohne strenge Zeitbedingungen verarbeitet werden können. Dies geschieht üblicherweise in einer von der HAL bereitgestellten Message Loop (Funktion do_msgs()). Diese verteilt die Ereignisse je nach Typ an weitere vom Anwender bereitgestellte Ereignis-Behandlungsfunktionen, die jeweils bei der HAL registriert werden müssen. 

Das folgende einfache Beispiel zeigt, wie dieses System angewandt wird. Es handelt sich um ein komplettes HAL-Programm, das auf Tastendrücke reagiert und Bildschirmausgaben durchführt. 

import hal;

// Hier fängt das Programm an.
function main() returns() vars()
{
load_keytable(); // deutsche Tastaturtabelle laden
gfx_cls(); // Bildschirm löschen

// Tasten-Eventhandler registrieren. Die Adresse

// der Behandlungsfunktion wird übergeben und
// die Abfrage der Tastaturinterrupts wird gestartet.
set_char_input_callback(addressof on_char);
// Event Loop starten
do_msgs(TRUE /* run forever */);
}

// Diese Funktion wird bei jedem eingegebenen Zeichen aufgerufen.

// Als Parameter 'char' erhält sie das eingebene Zeichen. Die
// anderen Parameter und der Rückgabewert sind vorerst unwichtig.
function on_char(char, UNUSED, context) returns(status) vars()
{
status = TRUE; // Stets "Alles OK!" sagen
if(char == 'H') // Wurde ein großes H eingegeben?
gfx_printstr("Hello, world!\n"); // => Rückmeldung
// Alle anderen Tasten ignorieren.
}

Die HAL unterstützt geschachtelte Ereignisverarbeitung durch einen Ereignisbehandlungs-Stack. Damit kann innerhalb eines Ereignisbehandlers (oder einer daraus aufgerufenen Funktion) ein Local Message Loop gestartet werden, indem dieselben Ereignisse (z.B. Tastendruck) anders behandelt werden. Diese lokalen Message Loops sind sehr nützlich, um Dialogboxen oder auch schon ein simples "Warte auf Tastendruck" zu realisieren. 

In den lokalen Ereignis-Behandlungsfunktionen muss dann auf den Rückgabewert status geachtet werden: TRUE=Ereignis wurde abschließend behandelt; FALSE = übergeordnete Behandlungsfunktion soll erneut aufgerufen werden; MH_QUIT=Ereignis wurde abschließend behandelt UND der lokale Message Loop soll beendet werden (do_msgs(TRUE) kehrt dann zum Aufrufer zurück). 

// Die Funktion wartet auf Druck der Leertaste.
function spacekey() returns() vars()
{
// Local Message Loop (also hier Registrierung zusätzlicher Tastenhandler)
// ermöglichen durch Einfügen eines leeren Kontextes auf dem Stack.
msg_push_context(0 /* keine Kontextdaten werden benötigt */);
// Lokalen Tastaturhandler installieren
set_key_down_callback(addressof sk_on_key);
// Message Loop laufen lassen, bis er beendet wird (mit MH_QUIT)
do_msgs(TRUE);
// Local Message Loop wieder vom Stack entfernen. Ab sofort wird
// wieder der übergeordnete Tastenhandler aufgerufen.
msg_pop_context();
}

// Der lokale Tastenhandler
function sk_on_key(key, UNUSED, UNUSED_TOO) returns(status) vars()
{
if (key == VK_SPACE) // Falls Leertaste gedrückt...
status = MH_QUIT; // beende den lokalen Message Loop.
else // Ansonsten...
status = TRUE; // tue nichts und warte einfach weiter auf Events.
}

HAL Tutorial

Beschreibt Erstellung einer kleinen HAL-Applikation. 

Schritt 1: Hello World

Schritt 2: Ereignisbehandlung

Schritt 3: Grafikausgabe

 
rrobek.de Hauptseite
 
Valid HTML 4.01!