AMIGA-Magazin · Ausgabe 8/04 · Programmierung: »Exec« in AmigaOS 4

Aktuelles Heft 8/04

Kernstücke

Nachdem das neue SDK installiert ist, sollen die ersten Programme unter AmigaOS 4 entstehen. Damit die Basis stimmt, geht es in dieser Ausgabe um Grundlagen zum neuen Kern von AmigaOS.

von Michael Christoph

Eine gute Nachricht gleich vorab ­ die SysBase ist auch bei AmigaOS 4 weiterhin an der absoluten Speicheradresse 4 zu finden. Die struct ExecBase wurde um den Eintrag MainInterface erweitert. Dieser verweist auf die (main)-Sprungtabelle für die Exec-Funktionen:

SysBase = *(struct ExecBase **)4;
IExec = (struct ExecIFace*)((struct ExecBase*)SysBase)->MainInterface;

Diese Aufgabe steht aber bereits im Startup-Code des vom Linker erzeugten Programms. Man muss sich also bei der herkömmlichen Programmierung von Anwendungen keine Gedanken über diesen Teil des Codes machen. Ebenso verhält es sich mit der DosBase bzw. dem Interface IDOS. (Hinweis: Alle Buchstaben werden bei dieser Bezeichnung groß geschrieben.) Es stehen also auch alle Dos-Funktionen sofort nach dem Programmstart zur Verfügung.

Interfaces statt Sprungtabelle
Neue Datentypen in exec/types.h
Typedefinition Name Alter Name
typedef unsigned char uint8 UBYTE
typedef signed char int8 BYTE
typedef unsigned short uint16 UWORD
typedef signed short int16 WORD
typedef unsigned long uint32 ULONG
typedef signed long int32 LONG
typedef unsigned long long uint64 -
typedef signed long long int64 -
typedef float float32 FLOAT
typedef double float64 DOUBLE
     
Die alten Namen stehen aber weiterhin zur Verfügung und sind noch in den meisten Includes zu finden. Sie werden aber Schritt für Schritt ersetzt.
Die alten 68k-Shared-Libraries waren so aufgebaut, dass sie eine Sprungtabelle hatten. In dieser waren der Reihe nach die vorhandenen Funktionen aufgelistet. Zum Ausführen der Funktionen musste nur der Offset mit der Sprunganweisung und Adresse ausgeführt werden. Unter OS 4 bzw. auf Grund des PPC-Prozessors ist dies nicht mehr so (direkt) möglich. Ein weiteres Problem: Funktionen konnten nicht mehr verändert werden, speziell die Anzahl/Bedeutung der Übergabeargumente. Beides wurde durch das neue Interface-Konzept gelöst.

Das Interface ist praktisch nichts anderes als die frühere Sprungtabelle. Allerdings stehen nur noch die Adressen der einzelnen Funktionen darin, die auszuführen sind. Entscheidender ist aber, dass eine Library mehrere Interfaces bereitstellen kann. Das Standardinterface ist per Definition mit main zu bezeichnen und hat außerdem eine Versionsnummer. Diese ist bei allen Systembibliotheken zur Zeit 1.0. Soll nun z.B. die Aufrufliste einer Funktion verändert werden, so wird ein zusätzliches Interface (z.B. 2.0) bereitgestellt. Ältere Programme verlangen nach main 1.0, während neuere auf main 2.0 zugreifen. Es sind aber auch alternative Interfaces möglich. Davon Gebrauch machen bisher die exec- und expansion.library. So stellt exec neben dem main-Interface mit den bekannten Funktionen noch »MMU« und »debug« zur Verfügung. Für normale Anwender sind beide jedoch nicht von Interesse.

Die Namen der Interfaces sind per Definition als Libraryname+IFace festgelegt. Wie die Interfaces zu öffnen sind, ist in Listing 2 zu sehen. Die Unterschiede zu den alten Programmen wurden in Listing 2 mit roter Schrift hervorgehoben.
Im Artikel kommen durchgehend reine OS-4-Quellen mit Interfaces zum Einsatz. Teilweise sind die Programme auch noch unter älteren Betriebssystemversionen lauffähig. Dann kann durch Definieren von __USE_INLINE__ auf das Öffnen und Schließen der Interfaces verzichtet werden. Der Sourcecode muss dann zweimal übersetzt werden. Einmal als ppc-native Version für AmigaOS 4 und einmal als 68k-native Version für OS 3.x.

Los geht es!
Listings des Artikels
Listing 2 Öffnen eines Interfaces
Listing 3 Prüfung der OS-Version
Listing 4 Ermittlung der aktiven Hardware
Listing 5 Die Ermittlung des Prozessor im System
Listing 6 Den freien Speicher ermitteln
Listing 7 Debug-Ausgaben für Entwickler
Neben den bekannten Basisfunktionen wie Obtain, Release und Expunge wurde die vierte ­ bisher unbenutzte Funktion ­ als Clone-Funktion definiert. Sie ist dazu vorgesehen, dass mehrere Instanzen eines Interfaces im Speicher sein können. Beispiel: Dort werden programmspezifische Daten gehalten. Bisher wird davon allerdings noch kein Gebrauch gemacht.

Die nachfolgenden Programmbeispiele setzen voraus, dass sie unter dem neuen AmigaOS 4 gestartet werden. Ob das neue Betriebssystem läuft, lässt sich allerdings sehr einfach feststellen. Es genügt, die Version der exec.library abzufragen. SysBase->LibNode.lib _Version enthält die Versionsnummer. Ist diese 50, handelt es sich um die OS-4-PreRelease-Version. Die öffentliche Vollversion von AmigaOS 4 wird hier eine 51 als Wert haben. Zum Vergleich: AmigaOS 3.0 den Wert 39 und Amiga OS 3.1 liefert 40. Workbench 3.5 und 3.9 laufen auf 3.1-ROMs und können daher nur über die versions.library oder resource.library ermittlet werden. Listing 3 zeigt den Test auf die OS-Version.
Sie finden den Quelltext auf der Heft-CD (Amiga Magazin/AmigaOS-4-Beispiele).
Übersetzt wird das Beispiel mit:

gcc CheckForOS4.c -o CheckForOS4

Flags zur Speicher-Allokierung

MEMF_PRIVATE: nur vom allokierten Task zu verwenden (für die Zukunft mit Speicherschutz wichtig).
MEMF_SHARED: andere Tasks dürfen auf den Speicher zugreifen, Speicher kann ausgelagert werden (z.B. für Messages notwendig).
MEMF_EXECUTABLE: schreibgeschützter Speicherbereich für ausführbaren Code ­ verhindert selbstmodifizierende Programme. Alle PPC-Programme werden automatisch in diese Art von Speicher geladen.
MEMF_PUBLIC: nicht auslagerungsfähiger, interruptfähiger Speicher.
MEMF_CHIP, MEMF_FAST: Speicher für ältere Programm. Existiert praktisch nicht mehr, kann aber von den emulierten Programmen weiterhin angefordert werden.

Wurde alles fehlerfrei übersetzt, können Sie das erzeugte Programm »Check ForOS4« ausgeführen. Unter OS 2.x/3.x lässt es sich übrigens nicht ausführen, da das Programm im PPC-ELF-Format vorliegt, womit ein 68k Prozessor nichts anzufangen weiß. Soll es auch unter älteren Betriebssystem-Versionen verwendet werden (z.B. in Shell-Skripten), muss es als 68k-Programm gelinkt werden. Unter AmigaOS 4 wird es dann automatisch im Emulationsmodus ausgeführt.

Wer sich dafür interessiert, auf welcher Hardware-Plattform das Programm ausgeführt wird, hat unterschiedliche Möglichkeiten. Das "a1ide.device" ist eine Möglichkeit, den AmigaOne zu erkennen. Das vorhandensein von "AmigaOne.card" (als residentes Modul) ist im Moment eine weitere Möglichkeit. Kommt das SNAP-Gfx-Treibersystem zum Einsatz, wird es vermutlich keine AmigaOne.card mehr geben. Aber hier unterstützt die expansions.library von AmigaOS 4 den Programmierer. GetMachineInfo() nennt sich die hilfreiche Funktion. Anhand einer Tagliste lässt sich festlegen, was ermittelt werden soll. Nicht vergessen: Zuvor müssen Sie die expansion.library öffnen und das Interface abfragen. Listing 4 zeigt wie es richtig gemacht wird. Zusätzlich werden auch noch andere Umgebungen erkannt und benannt. Der Beispielcode in Listing 4 ist extra so gehalten, dass er auch problemlos unter OS 3.x übersetzt und ausgeführt werden kann.

Welche CPU haben wir ?
Diese Frage wurde früher noch durch Bitvergleich ExecBase->AttnFlags mit AFF_xxx herausgefunden. Dafür gibt es jetzt eine neue Funktion. Notwendig wurde dies auch durch die Vielzahl an PPC-Prozessorvarianten. Die Funktion lautet GetCPUInfoTags() und erwartet eine Tagliste mit GCIT_xxx Einträgen als Argument. Die möglichen Tags sind in der Includedatei exec/exectags.h zu finden. Das ist der erste Beispiel-Code, der die »korrekte(n)« Schreibweise/Funktionszugriffe verwendet. Da es auf eine ganz neue Funktion zurückgreift, ist es nicht unter älteren OS-Versionen compilierbar bzw. ausführbar. Der vollständige Soucecode steht in Listing 5.

Speicher und Funktionen
Das AmigaOS-4-System arbeitet mit zwei getrennten Speicherbereichen. Einem zur Ausführung OS-4-nativer Programme: Der kann später auch ausgelagert werden, wenn dies vom Programm erlaubt wird und der physikalische Speicher nicht ausreicht. Der andere Bereich steht allen 68k-emulierten Programmen zur Verfügung. Dieser Bereich ist speziell abgeschirmt, sodass »Amok laufende« Programme nur hier Schaden anrichten können. Auf PPC-Programme oder gar das Betriebssystem selber haben sie keinen Einfluss. Eine Unterscheidung zwischen Chip- und Fast-Ram erfolgt nicht mehr. Es stehen zwar beide weiterhin zwecks Kompatibilität zur Verfügung, physikalisch bedienen sich aber beide aus demselben Speicherpool. Beide Speicherarten werden aber getrennt geführt und niemals vermischt. So kann es durchaus passieren, dass ein emuliertes Programm fehlenden Speicher meldet, obwohl noch reichlich nativer Speicher zur Verfügung steht. Beim Reservieren von Speicher stehen verschiedene Flags zur Verfügung (s. Kasten »Flags zur Speicher-Allokierung«).

Zusätzlich kann für den Speicher das Flag MEMF_VIRTUAL gesetzt sein ­ das tritt auf, wenn der Speicherbereich gerade ausgelagert ist, d.h. nicht im physikalischen Speicher steht. Für die Anwendung ist das nicht relevant. Wenn Sie auf Daten aus dem ausgelagerten Speicher zugreifen, wird der Speicher wieder automatisch eingelagert und ggf. anderer Speicher dafür ausgelagert. Bei großzügig ausgestatteten AmigaOne-Systemen mit 256 MByte bzw. mehr und den speicher-sparsamen Amiga-Programmen sollte ständig genug freier Speicher zur Verfügung stehen. Speicherbereiche, die auf der Grafikkarte liegen, haben keine Bedeutung und werden lediglich intern von den Grafiktreibern verwendet. Chip-RAM hat also absolut nichts mit dem Speicher der Grafikkarte zu tun! Was die einzelnen Speicherflags liefern, zeigt Listing 6.

Aus der exec.library verschwunden sind die speziellen Funktionen, die direkt auf den 68k-Prozessor ausgelegt waren. Dazu gehören AllocTrap() und FreeTrap() zum Reservieren bzw. Freigeben eines Prozessor-Trap-Vektors. Auch GetCC() zum Ermitteln des Condition-Codes, SetSR() zum Setzen der Prozessor-Statusregister und SuperState() zum Umschalten in den Supervisor-Modus sind nicht mehr möglich. Für normale Anwendungsprogramme sind diese Funktionen ohne Bedeutung und bereiten daher auch keine Probleme beim Umstellen alter Sourcen.

Neues zum Debuggen
Speziell für Entwickler von Treibern und LowLevel-Teilen ist die Funktion VOID DebugPrintF(STRPTR,...) aus der exec.library interessant. Der Text wird über die serielle Schnittstelle ausgegeben und kann auf einem zweiten Rechner (kann auch ein Amiga sein) ausgelesen werden. Dazu sind beide Rechner mit einem Null-Modem-Kabel verbunden. Außerdem muss ein Terminal-Programm laufen, das die Ausgaben empfängt und anzeigt. »Term« ist eine Möglichkeit dafür. Für normale Anwendungs-Programmierer ist allerdings die altbekannte kprintf() Funktion besser geeignet. Diese Ausgaben lassen sich mittels dem öffentlichen Debug-Tool »Sashimi« abfangen und in einem Konsolenfenster anzeigen. Ein zweiter Rechner wird also nicht benötigt. Die praktische Anwendung zeigt Listing 7.

Beim nächsten Mal geht es dann um die runderneuerten dos.library. Nicht nur die langen Dateinamen bringen so manchen Dateiverwalter in Bedrängnis.

lb



Ergänzende Grafiken:
Die neue Interface-Schreibweise Beispielausgabe von CpuInfo Speicherverteilung der 512 MByte Ram

Ergänzende Texte:
Neue Funktionen in der exec.library
Basis-Interfacenamen und die zugehörige Includedatei


Hauptseite © 2004 All Rights Reserved. Alle Rechte vorbehalten Franzis' Verlag GmbH
Veröffentlichung und Vervielfältigung nur mit schriftlicher Genehmigung des Verlags

Kommentare, Fragen, Korrekturen und Kritik bitte an Webmaster AMIGA schicken.
Zuletzt aktualisiert am 24. Juli 2004, Michael Christoph.