Navigation
« 

Anonymous




Register
Login
« 
« 

Amiga Future

« 

Community

« 

Knowledge

« 

Last Magazine

The Amiga Future 167 was released on the March 5th.

The Amiga Future 167 was released on the March 5th.
The Amiga Future 167 was released on the March 5th.

The Amiga Future 167 was released on the March 5th.
More informations

« 

Service

« 

Search




Advanced search

Unanswered topics
Active topics
« 

Social Media

Twitter Amigafuture Facebook Amigafuture RSS-Feed [german] Amigafuture RSS-Feed [english] Instagram YouTube Patreon WhatsApp
« 

Advertisement

Amazon

Patreon

« 

Partnerlinks

Programmierung des PowerPC mit WarpOS

Description: Amiga Aktuell Ausgabe 5/98

Categories: [DE] Workshops

Link to this article: Select all

[url=https://www.amigafuture.de/app.php/kb/viewarticle?a=1764&sid=b93200bb2dd63bbc7e13345c3a06c112]Artikeldatenbank - Programmierung des PowerPC mit WarpOS[/url]

Programmierung des PowerPC mit WarpOS (von Steffen Häuser)

»Seit dem Erscheinen der PowerUP-Karten erschienen auf dem Aminet bereits einige Programme, die den PPC unterstützen. Es gibt jedoch zahlreiche Autoren, die ihre Programme noch nicht mit PPC-Support versehen, obwohl dies durch die Verwendung von StormC und WarpOS eigentlich sehr einfach ist. Dieser Artikel beschreibt, wie man ein Programm mit PPC-Support versieht.

Dabei wäre es sogar durchaus denkbar, ein Programm jetzt für den 68k zu entwickeln - da weder PPC-Karte noch PPC-Compiler verfügbar -, jedoch mit Blick auf eine leichte PPC-Portierbarkeit, und dann später die wenigen noch nötigen Schritte, um eine PPC-Version zu generieren. Dieses Vorgehen dürfte vor allem für Spiele-Entwickler interessant sein. Im Zweifelsfall, falls ein Rechner gesucht wird, auf dem ein bereits fertiggestelltes PPC-Programm compiliert werden kann, ohne gleich eine PPC- Karte kaufen zu müssen, stehe ich auch gerne zum Recompilieren zur Verfügung (obwohl es sicher praktikabler wäre, einen eigenen Rechner hier zu haben). Das Programmtesting kann im Übrigen prinzipiell auch mit der 68k-Version erfolgen, da eigentlich keine größeren Änderungen erforderlich sind.

Prinzipiell erfolgt die Anpassung in folgenden Phasen (um die Entwicklung zu vereinfachen, ist empfohlen, dies schon während der Entwicklung der 68k- Version durchzuführen):

A) Umschreiben aller 68k-Assembler-Teile nach C oder C++ oder PPC-ASM
B) ANSI/StormC-Anpassung
C) PPC-Anpassung
D) Kontextswitch-Optimierung
E) Weitere Anpassung

Im Gegensatz zu einer PPC-Anpassung auf ppc.library hat man bei WarpOS nach Schritt A) eigentlich schon fast "gewonnen", die letztlichen PPC- Anpassungen sind (zumindest bei Sourcen ohne Assembler-Optimierung) minimal. Ich verzichte darauf, auf Teil A) einzugehen, wer unbedingt Assembler-Projekte auf PPC portieren möchte, sollte E-Mail-Kontakt mit mir aufnehmen, da es evtl. ein besser geeignetes Verfahren der Portierung als das hier beschriebene gibt (und zudem vor einer Riesenarbeit geprüft werden sollte, ob es sich überhaupt lohnt).

Ich empfehle, zumindest Schritt B) bereits während der Entwicklung der 68k- Version vorzunehmen, um später nicht mehr durch den ganzen Source durchgehen zu müssen.

B. StormC - ein strenger ANSI-Compiler

Der wildeste Part bei der Anpassung eines PPC-Programms ist nicht etwa die Anpassung von 68k auf PPC, sondern von SAS/C oder GNU C auf StormC.

StormC ist ein strenger ANSI-Compiler, daher sind Standard-C-Funktionen, die im ANSI-Standard nicht verfügbar sind, nicht zulässig. Einige der Funktionen können über die offiziell noch nicht releaste UnixLib emuliert werden.

Die Liste der nicht erlaubten SAS/C-Funktionen wäre (keine dieser Funktionen ist im ANSI-Standard enthalten...):

astcsma isascii iscsym iscsymf toascii scdir stcpm
stcpma stcsma stccpy stpcpy stcis stcisn stclen
stpbrk stpchr stpchrn strcmpi strnset
strset stcarg stpsym stptok stpblk strbpl strdup
strins strmid stcd_i stcd_l ecvt fcvt gcvt
stch_i stch_l stci_d stci_h stci_o stcl_d stcl_h
stcl_o stco_i stco_l stcu_d stcul_d toascii stpdate
stptime __datecvt __timecvt utpack utunpk cot iabs
max min pow2 __emit getreg putreg geta
isatty ovlyMgr dqsort fqsort lqsort sqsort strsrt
tqsort drand48 erand48 jrand8 lcong48 lrand48 mrand8
nrand48 seed48 srand48 __autoopenfail chkabort Chk_Abort
_CXBRK __exit onexit _XCEXIT forkl forkv onbreak
wait waitm bldmem rstmem sizmem chkml getmem
getml halloc lsbrk sbrk _MemCleanup rbrk rlsmem
rlsml memccpy movmem repmem setmem swmem except
__matherr poserr datecmp timer __tzset getch fgetchar
fputchar _dread _dwrite read write clrerr close
_dclose fcloseall creat _dcreat _dcreatx fdopen fileno
fmode iomode open _dopen flushall mkstemp mktemp
setnbf _dseek lseek tell access chkufb chmod
fstat getfa getft stat stcgfe stcgfn stcgfp
strmfe strmfn strmfp strsfn unlink argopt chgclk
dos_packet getclk getasn getdfs putenv rawcon stackavail
stacksize stackused chdir closedir dfind dnext findpath
getcd getcwd getfnl getpath mkdir opendir readdir
rmdir seekdir rewinddir telldir readlocale scr_beep scr_bs
scr_cdelete scr_cinsert scr_clear scr_cr scr_curs scr_cursrt scr_cursup
scr_eol scl_home scr_ldelete scr_lf scr_linsert scr_tab _CXFERR
_CXOVF _EPILOG _PROLOG

Die Liste sieht lang aus, aber man muß bedenken, daß die meisten aufgelisteten Funktionen "extrem exotische Funktionen" sind, die vermutlich vielen Programmierern gar nicht bekannt sind. Im ANSI-Standard sind sie jedenfalls nicht enthalten.

Nach den Ersetzungen (die wichtigsten Ersetzungen laufen auf das Ersetzen von open/close/read/write hinaus...) gibt es noch einen anderen Aspekt von ANSI zu bedenken:

Schreibweisen wie:

char *string=malloc(300);

die bei SAS/C nur eine WARNING produzieren, produzieren bei strengen ANSI- C-Compilern einen Fehler. Derartiger Code sollte so aussehen:

char *string=(char *)malloc(300);

ANSI C verlangt eine STRENGE TYPISIERUNG. Dies gilt übrigens auch für Zeiger auf Funktionen. Ein guter "Trick", um einen nicht ANSI-konformen Source rasch zu konvertieren, ist:

Einfach mal durchcompilieren und dabei auf die Warnings/Fehler achten.
Alles, was nach Zeiger aussieht, und nicht streng typisiert ist, auf void * casten. Alles, was nicht nach Zeiger aussieht, und falsch typisiert ist, je nach Anwendung auf int, long oder double casten. Zeiger auf Funktionen auf void * casten, z.B.:
void *funktion=(void *)meine_funktion;

Programmierer, die keinen StormC besitzen, können das "Test-Compilieren" auch mit SAS/C im "STRICT_ANSI"-Modus machen, der meines Wissens ziemlich ähnlich wie StormC reagiert.

Zudem sollte man noch jedes Auftreten von K&R-Syntax durch die normale C- Syntax ersetzen, z.B.

void main(argv,argc)
int argv;
char **argc;

durch

void main(int argv,char **argc);

ersetzen, da der PPC-Compiler keine K&R-Syntax mag.

Falls ein Source - wie etwa der Doom-Source - relativ häufig Funktionen aus der Unix-Welt verwendet, so hat es sich als hilfreich erwiesen, eine auf StormC umgeschriebene Version der AmiTCP/IP-Includes zu verwenden, so daß Datentypen wie z.B. dev_t zur Verfügung stehen. Ein Source, der von Anfang an auf ANSI-Kompatibilität getrimmt ist, sollte solche Typen jedoch nicht nötig haben. Wer dies dennoch nötig hat, soll einfach mal bei mir mit Bitte um Hilfestellung anfragen (Kontaktadresse siehe unten).

Ein letzter Aspekt der Compiler-Unterschiede wären spezifische Unterschiede zwischen SAS/C und StormC. Ich habe mich hierbei auf die Beschreibung "normaler" Sources beschränkt, wer gerne PPC-Shared Libraries machen möchte, soll mich kontaktieren, und ich werde auch hier beschreiben, was die Unterschiede zwischen SAS/C und StormC sind.

Einige Schlüsselworte von SAS/C entfallen einfach, indem man sie auf "leer" definiert:

#define __stdargs
#define __regargs
#define __asm

__far sollte durch das Schlüsselwort FAR ersetzt werden, __inline durch inline, in diesen Dingen orientiert sich StormC ebenfalls mehr an ANSI. __chip, __fast und __interrupt funktionieren nicht so wie bei SAS/GNU, hier muß man den Weg über die entsprechenden OS-Funktionen gehen.

Registerparameter funktionieren (bis auf das Weglassen des Schlüsselwortes __asm) genau wie beim SAS/C, jedoch sollte man für eine PPC-Version darauf verzichten, da der PPC ja z.B. kein Register d0 hat (das ist ein 68k- Register). Man kann natürlich

register int a;

schreiben, das funktioniert. Der PPC sucht dann selbst nach einem geeigneten Register, bzw. der Compiler tut das.

C. PPC-Anpassung

So, den wildesten Part haben wir nun, es folgen eigentlich nur noch Kleinigkeiten.

Da die eigentliche PPC-Anpassung ja noch gar nicht erfolgte (bis auf die Kleinigkeit mit den Registern...), folgt, daß man mit WarpOS die 68k- und die PPC-Version sehr leicht parallel entwickeln kann.

Der erste wesentliche Unterschied betrifft die OS-Includes. Ein

#include

oder

#include
#include

schreibt sich unter PPC als:

#include

Die Pragmas entfallen komplett, und man sollte auch keine Protos includen.

Für die Parallelentwicklung sieht das Ganze so aus:

#include
#ifndef __PPC__
#include
#endif

Der Define __PPC__ ist immer entsprechend der Compiler-Optionen gesetzt.

Ein weiterer Unterschied fällt bei der Verwendung von Subtasks an. In dieser einfachen Variante der PPC-Portierung verwenden wir ja keine Mixed Binaries (über die Mixed Binary schreibe ich vielleicht später noch einen anderen Artikel), daher sind alle Tasks unseres Programms PPC-Native. Sollte man nun einen PPC-Native-Subtask starten, so muß dieser natürlich mit CreateTaskPPC() der powerpc.library gestartet werden, nicht etwa mit CreateTask(), weil das 68k-AmigaOS natürlich keine PPC-Tasks starten kann. Der Aufruf entspricht jedoch bei praktisch allen "Exec-ähnlichen" Funktionen der powerpc.library 1:1 dem Vorgehen unter dem 68k-AmigaOS. Eine Alternative wäre natürlich die Verwendung eines Mixed Binary, aber das sollte man vermeiden, da es die Performance senkt.

Ein weiterer Unterschied betrifft noch die Tag-List-Schreibweisen mancher OS-Funktionen. So beherrscht der PPC-Compiler zwar OpenScreenTagList, aber nicht OpenScreenTags. Man muß den Source also entsprechend anpassen.

Ein weiterer Unterschied betrifft die Funktion BeginIO der alib_protos.h. Diese Funktion ist unter PPC nur über ein (im Beispiel für das audio.device)

#include
#include

void BeginIOAudioPPC(struct IORequest *arg1)
{
extern struct Library *AudioBase;
ULONG regs[16];
regs[9] = (ULONG) arg1;
__CallLibrary(AudioBase,-30,regs);
}

verfügbar. Wie man sieht, muß man unter PPC grundsätzlich die LibBase des Devices auslesen. Ein Beispielaufruf könnte wie folgt aussehen (Code- Beispiel aus ZhaDoomPPC...):

AudioBase = (struct Library *)audio_io->ioa_Request.io_Device;
c = &channel_info[cnum];
c->audio_io->ioa_Request.io_Command = CMD_WRITE;
c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
c->audio_io->ioa_Data = &chip_cache_info[cache_chip_data
(id)].chip_data[8];
c->audio_io->ioa_Length = lengths[id] - 8;
c->audio_io->ioa_Period = period_table[pitch];
c->audio_io->ioa_Volume = vol ioa_Cycles = 1;
#ifdef PPC
BeginIOAudioPPC((struct IORequest *)c->audio_io);
#else
BeginIO ((struct IORequest *)c->audio_io);
#endif

Einige Leser fragen sich vielleicht inzwischen, wo der berühmte Kontextswitch bleibt. Ganz einfach: Er bleibt. StormC verfügt nämlich über das Feature des "vollautomatischen Kontextswitches", was bedeutet, der User muß sich um nichts mehr kümmern, da dies bereits der Compiler für ihn erledigt. Es müssen lediglich Stub-Dateien oder Defines für die per Kontextswitch aufzurufenden Funktionen vorliegen. Diese sind für alle AmigaOS-Funktionen sowie für die 68k-Funktionen der rtgmaster.library (die jedoch auch PPC-Native-Funktionen besitzt) bereits in die ppcamiga.lib integriert. Für Funktionen, die nicht integriert sind, generiert man die Stubs mittels

genppcstub mylib_protos.h mylib.fd VERBOSE

wobei die Proto- und die FD-Datei vorliegen müssen. Das Ergebnis wird dann einfach ins Projekt integriert (es handelt sich um einen C-Source). Im Falle eines "Mixed Binary" geht übrigens der Wechsel zwischen 68k und PPC wieder automatisch, ohne daß etwas Zusätzliches gemacht werden muß.

Unter WarpOS braucht ein Kontextswitch etwa 0.5 Millisekunden (hängt aber auch von der verwendeten PPC-Karte ab, 0.5 Millisekunden braucht es bei einer 200-MHz-Karte). Es sollte vermieden werde, "viele Kontextswitches pro Sekunde" zu erzeugen.

Beispiele, was zu vermeiden ist:

Byteweises Einladen von Files mit fgetc (statt dessen mit fread in einen Fast-RAM-Buffer einladen, und dann nachbearbeiten)
Pixelweises Darstellen auf dem Bildschirm (statt dessen in einen Fast- RAM-Buffer zeichnen und den dann mit einem Befehl zeichnen)
In häufig pro Sekunde aufgerufenen Schleifen viele OS-Calls

Die Grafik kann auch mittels der PPC-Version der rtgmaster.library komplett PPC-Native abgearbeitet werden.

Ein Beispiel der Effekte von Kontextswitches:

ZhaDoomPPC auf einem 150-MHz-Rechner ohne Sound: 36 fps
ZhaDoomPPC auf einem 150-MHz-Rechner mit Sound : 32 fps

Der Sound bewirkt bei ZhaDoomPPC derzeit 9 Kontextswitches. Eine Lösung des Problems wäre die Auslagerung der kompletten Sound-Funktion in einen 68k- Part, den man dann über einen manuellen Aufruf des Kontextswitchers (siehe Dokumentation der powerpc.library) oder über ein Mixed Binary aufruft. Damit würde der Mehraufwand auf einen Kontextswitch reduziert. Im Falle von ZhaDoomPPC war das leider nicht so einfach machbar, da die Kontextswitches in verschiedenen Funktionen lagen, und so genau habe ich mir das noch nicht angeschaut.

Es sind zudem noch Optimierungen durch Ausnutzung der BAT-Register des PPC möglich, hier möchte ich jedoch einfach auf die Dokumentation von WarpOS verweisen.

Es ist natürlich möglich, Teile des Codes in PPC-Assembler zu übersetzen, aber im Normalfall ist das eigentlich gar nicht nötig. Der PPC ist eigentlich schnell genug, um (fast) alles in C oder C++ zu machen (rtgmaster PPC hat trotzdem einige Assembler-Parts, da dies bei einem Grafiktreiber Sinn macht).

In einigen Newsgruppen wurde diskutiert, Programmteile parallel auf dem 68k und dem PPC laufen zu lassen. Dies würde man mittels des Message-Systems von WarpOS implementieren (Stichwort AllocXMsg in der powerpc.library- Dokumentation), man sollte es jedoch aus zwei Gründen vermeiden:

1) Ein solches Programm würde bei (zukünftigen) PPC-only Maschinen nicht in idealster Weise profitieren, da Teile immer noch als 68k-Code abgearbeitet würden. Und ich denke, auf lange Sicht werden solche Maschinen kommen.

2) Die Hardware ist schlichtweg nicht für den Multiprozessor-Betrieb geeignet, ganz gleich, wie man die Software anstellt. Ich werde hierauf nicht näher eingehen, ist in den Newsgruppen genug zu Tode diskutiert worden.

Solange die Tasks nicht miteinander kommunizieren, dürfte es unproblematisch sein, aber dann machen sie auch vermutlich nicht viel Sinn. Dies ist ein prinzipielles Problem der Hardware.

Aus oben genannten Gründen kann ich nur empfehlen, "synchron" zu bleiben. Wobei zukünftige Kompatibilität bei optimaler Geschwindigkeit da wohl beinahe das Wichtigere ist.

Kontaktadresse bei Rückfragen:
Steffen Häuser
Limburgstr. 127
73265 Dettingen/Teck
Tel. 07021-51787
email: MagicSN@Birdland.es.bawue.de
Informationen zur Person: Informatik-Student. Haupt-Aktivitäten im Amiga-Bereich:

rtgmaster.library
ZhaDoomPPC (Ein PPC-Doom-Port unter WarpOS)
WarpView (Ein Image-Viewer für PPC unter WarpOS und 68k)
WarpAMP (ein Port des AMP-MPEG-3-Players für WarpOS)
Crystal3D (ein Port einer Spiele-artigen 3D-Engine)
Seit kurzem Coder bei der Demo-Gruppe "Giants"
ehemals Autor der "Amiga Texturemapping FAQ"
"Berater" in Grafikkarten/PPC-Fragen bei einigen Amiga-Spiele-Firmen
ppctut.guide (Einführung in PPC-Assembler-Programmierung)«


Korrekturen zum PowerPC-Workshop in Ausgabe 5/98 (von Steffen Häuser)

»Es gibt zwei kleine Korrekturen zu meinem PPC-Kurs:

1. Das mit den Tag-Geschichten... unter einem StormC mit halbwegs aktueller Version geht das auch mit dem PPC-Compiler. Das Umschreiben war nur auf einer sehr alten Beta-Version noetig, wie ich nun weiss.

2. Hin und wieder Probleme machte auch folgendes:

char bla[]={"..."};

Man kann das aber umschreiben in:

char *bla="...";

oder andere aehnliche Varianten...

Steffen«