Gamefix: Falcon030 wird ST(E)-kompatibel

Endlich hat man den begehrten Vogel auf seinem Tisch stehen, und die Freude über seine vielen Talente ist groß (er kann sogar sprechen, nur mit dem Fliegen hapert es ...) Zur kurzzeitigen Entspannung kramt man sein Lieblingsspiel hervor, startet es erwartungs voll, und ... zwei Bomben! Auch andere ältere Sachen lassen sich nicht mehr starten oder sind unspielbar schnell.

Jetzt ist guter Rat teuer, denn man will ja schließlich mit seinem Falcon nicht nur arbeiten. Der folgende Artikel beschreibt die Probleme und ihre möglichen Lösungen und bietet ein Listing, das es auf komfortable Weise ermöglicht. die ST(E)-Kompatibilität des Falcon030 wesentlich zu erhöhen.

Zu Beginn sei allerdings deutlich darauf hingewiesen, daß die Probleme, die manche Programme haben, in den allermeisten Fällen auf unsaubere Programmierung zurückzuführen sind, nicht etwa auf Designfehler des Falcon030. Es rächt sich jetzt wieder einmal, wie schon beim TT, wenn man sich als Programmierer auf irgendwelche Sachen verläßt, die nirgendwo dokumentiert sind und somit nicht immer zutreffen müssen. Die in diesem Artikel vorgestellten Methoden zur Verbesserung der Kompatibilität beruhen zwar größtenteils auch auf undokumentierten Eigenschaften des Falcon030 oder sind kein sauberer Programmierstil, allerdings ist dies unumgänglich, um den gewünschten Effekt zu erzielen. Anwenderprogramme und Spiele sollten weiterhin nur dokumentierte Eigenschaften ausnutzen.

Probleme und Lösungen

Wie bereits aus [1] bekannt, besitzt der Falcon030 ein undokumentiertes Register (0xFF8007), mit dem man viele Probleme auf einmal lösen kann. Durch die Möglichkeit, mit Bit 0 und Bit 2 die Taktfrequenz von 68030 und Blitter zwischen 8 (Bit gelöscht) und 16 MHz (Bit gesetzt) umzuschalten, lassen sich zu schnelle Spiele bremsen. Dabei sollte zunächst nur der Prozessor auf 8 MHz geschaltet werden, da der Blitter nur bestimmte Grafikoperationen beeinflußt und diese selten von Spielen benutzt werden. Das Bremsen des Blitters dürfte also nur sehr selten nötig sein. Das Halbieren des CPU-Taktes kann auch bei nicht mehr funktionierenden Kopierschutzabfragen helfen, die nicht-Timer-gesteuerte Zeitschleifen verwenden.

Bei dieser Gelegenheit der Aufruf an die (Spiele-) Programmierer, sich nicht auf die Geschwindigkeit eines Rechners zu verlassen. Inzwischen gibt es bereits die ersten Beschleuniger-Boards für den Falcon030, so daß auf 16 MHz ausgelegte Programme damit schon zu schnell sind. Man sollte meinen, daß Benutzer eines Rechners mit „Intel inside“ dieses Problem nicht mehr kennen, da es dort schon seit langem stark unterschiedliche Rechnergeschwindigkeiten gibt. Dennoch gibt es immer noch neue Spiele, die zwar erst ab 386/33 vernünftig schnell, auf einem 486DX2/66 aber schon nicht mehr spielbar sind. Diese Tatsache sollte doch Ansporn genug sein, es mit dem Falcon030 besser zu machen!

Zurück zum Thema: Es gibt viele Spiele, die den guten alten Digitalsound des Soundchips verwenden (nicht DMA-Sound wie beim STE). Leider versagt ein Großteil seinen Dienst auf dem Falcon030, sie stürzen mit einem Busfehler ab. Wieso? Beim ST (und auch beim STE) gibt es die (undokumentierten) Spiegelregister des Soundchips. Normalerweise stehen lediglich die Register 0xFF8800 und 0xFF8802 (giselect/giread und giwrite) für die Registerprogrammierung zur Verfügung, allerdings haben die Adressen 0xFF8804/6 usw. die gleiche Funktion, ein Beschreiben von 0xFF8804 bewirkt also das gleiche wie die Registerselektion durch Schreiben in giselect. Viele Programmierer machen sich das zunutze, wenn sie digitale Sounds spielen wollen, denn dabei kommt es besonders auf hohe Geschwindigkeit an, und ein movem-Befehl kann mit diesen Spiegelregistern viele Soundchip-Register „gleichzeitig“ beschreiben. Leider existieren diese Spiegeladressen von giselect und giwrite auf dem Falcon030 nicht mehr, es kommt also zum bereits erwähnten Busfehler (zwei Bomben).

Bild 1: Der Konfigurationsdialog von Gamefix

Dazu gibt es zwei Lösungsansätze: 1) Man klinkt sich in den Busfehler-Vektor ein und überprüft, ob es sich um eines der Spiegelregister handelte und „simuliert“ diese dann, oder 2) man aktiviert durch Löschen von Bit 5 in 0xFF8007 den ST(E)-kompatiblen Busmodus. Die erste Methode hat den Nachteil, daß man durch die Ausnahmebehandlung und das Simulieren viel Zeit verbraucht und die Digitalsounds u.U. sehr verfremdet oder langsam klingen. Außerdem kann es passieren, daß das gesamte Programm wegen des geänderten Timings nicht mehr richtig läuft. Die zweite Methode bewirkt zwar, daß kein Busfehler mehr auftritt, wenn eines der Spiegelregister angesprochen wird, allerdings passiert auch nichts weiter, d.h. der ursprüngliche Effekt der Spiegelregister wird dadurch nicht wiederhergestellt. Somit laufen die Digisounds zwar wieder in normaler Geschwindigkeit, klingen allerdings auch verfremdet und rauschen stark (man kann hier die Musik jedoch noch gut erkennen). Das Listing bietet Methode 1 nicht an, da sie sehr aufwendig und nicht besonders befriedigend ist.

Ein weiterer Grund für Abstürze mit zwei Bomben ist das geänderte Busverhalten des Falcon030 (das, wie erwähnt, durch Löschen von Bit 5 in 0xFF8007 umgeschaltet werden kann). Beim ST(E) passiert nichts, wenn Adressen angesprochen werden, die überhaupt nicht belegt sind (also weder durch RAM, ROM noch durch Hardware-Register), beim Falcon030 erhält man jedoch einen Busfehler (wie eigentlich zu erwarten). Wird das Busverhalten jedoch umgeschaltet, werden keine Busfehler mehr ausgelöst, so daß das betreffende Programm wieder funktionieren könnte.

Beim ST(E) ist der Bildschirm (ohne jegliche Grafikerweiterungen) immer 32000 Bytes groß, wobei das Betriebssystem großzügig gleich 32768 Bytes reserviert. Im Normalfall liegt der Bildschirmspeicher somit 32 KB unter dem Speicherende und hat noch 768 unbenutzte Bytes im Anschluß. Diese 768 Bytes verführen natürlich, dort kleine Routinen unterzubringen. Außerdem machen es sich viele Routinen, die den Bildschirm löschen, leicht und füllen einfach die kompletten 32KB mit Nullen. Beim Falcon030 liegt die Sache jedoch etwas anders: hier kann der Bildschirm, je nach Auflösung, bis über 700KB groß werden. ATARI hat dem TOS deswegen eine (undokumentierte) GEMDOS-Funktion spendiert, die am Speicherende eine als Parameter gegebene Anzahl von Bytes für den Bildschirmspeicher reserviert (die dann für Malloc nicht mehr zur Verfügung stehen). Allerdings ist das TOS bei den ST-kompatiblen Bildschirmmodi nicht mehr so verschwenderisch, es beansprucht nur noch 32256 Bytes für den Bildschirm. Somit stürzen Programme, die sich auf die 768 Bytes verlassen (von denen jetzt ja nur noch 256 übrig sind) ebenfalls mit einem Busfehler ab, da sie über das Ende des RAMs hinaus schreiben wollen. Lösen läßt sich dies durch Einstellen des ST(E)-Busmodus (siehe oben) oder durch Verschieben des Bildschirmspeichers an die altgewohnte Adresse. Das später beschriebene Listing bietet letzteres als Option an, da man durch die erste Methode nicht den altgewohnten Platz herstellt, sondern nur die Busfehler abfängt.

Von der Umorganisation der Bildschirmspeicherverwaltung ist auch die Systemvariable _memtop (0x436) betroffen, die angibt, wo der nutzbare ST-Speicher aufhört und beim ST(E) auf den Beginn des Bildschirmspeichers zeigt. Beim Falcon zeigt sie jedoch auf das Ende des RAMs, ist also gleich phystop (0x42E), da der Bildschirm in die Speicherverwaltung des GEMDOS integriert wurde. Programme, die sich auf den ST-Wert von _memtop verlassen, bekommen damit verständlicherweise Probleme. Es bereitet jedoch keine Schwierigkeiten, _memtop nachträglich zu korrigieren, da die Variable nur ein einziges Mal (bei der Initialisierung des GEMDOS) vom Betriebssystem ausgelesen wird.

Die PMMU

Bekanntlich besitzt der Falcon030 einen Motorola-68030-Prozessor, der mit einer PMMU (Paged Memory Managing Unit) zur Speicherverwaltung ausgestattet ist. Sie benötigt für korrektes Arbeiten einen Adreßumsetzungsbaum, den ATARI in den beim ST(E) nicht benutzten Speicherbereich ab 0x700 gelegt hat (ebenso beim TT). Leider wird dieser Bereich auch von manchen Programmen für eigene Zwecke mißbraucht, so daß es zum Absturz kommt, da dann die Adressen nicht mehr korrekt umgesetzt werden können. Leider läßt sich die PMMU des Falcon030 nicht so einfach abschalten, da sie u.a. zur korrekten Umsetzung der Hardware-Register benötigt wird (bekanntlich ist es egal, ob man 0xFF8007 oder 0xFFFF8007 anspricht). Als Lösung bleibt also nur, den kompletten PMMU-Baum in einen sicheren Speicherbereich zu verschieben. Das gelingt aber nur, wenn man weniger Speicher vortäuscht (dazu später mehr).

Der MC68030 besitzt neben der PMMU auch noch zwei jeweils 256 Byte große Caches, den Daten- und den Befehls-Cache. Leider gibt es immer noch Programme, die selbstmodifizierenden Code benutzen, darunter vor allem Spiele (und deren Kopierschutzabfragen) und Demos. Diese vertragen sich natürlich nicht mit einem Befehls-Cache, also muß er abgeschaltet werden. Dies kann man ganz legitim über das Cache-Control-Register (CACR) des Prozessors erreichen (das GENERAL-CPX von XCONTROL macht dies genauso). Der Daten-Cache ist seltener Grund für Probleme, aber es schadet auf jeden Fall nicht, ihn auszuschalten. Leider hat sich gezeigt, daß das TOS ab und zu den Cache wieder einschaltet, warum auch immer. Deshalb verwendet das Listing eine Methode, dies zu umgehen, wenn beide Caches ausgeschaltet werden sollen: Im PMMU-Baum wird der gesamte Speicher als nichtcachefähig gekennzeichnet, somit wird auch bei über das CACR eingeschaltetem Cache nichts mehr gemacht. Es ist übrigens erstaunlich, wieviel der Cache ausmacht: Ich habe testweise ein Primzahlenprogramm die Primzahlen von 1 bis 900000 berechnen lassen, mit Cache dauerte es etwa 3.5s, ohne Cache etwa 10s.

Sound

Wer ein Spiel oder Programm hat, das STE-DMA-Sound benutzt, wird sich vielleicht schon gewundert haben, warum der Sound nicht so richtig klingt, obwohl das Soundsubsystem des Falcon030 ja angeblich abwärtskompatibel ist. Dies liegt daran, daß das TOS (bis einschließlich 4.04) die Hardware nicht richtig initialisiert, denn für „alten“ DMA-Sound müssen bestimmte Einstellungen vorgenommen werden: Mittels devconnect muß die DMA-Ausgabe mit dem Digital-Analog-Wandler verknüpft werden, und zwar unter Benutzung des Vorteilerwertes 0, der in den STE-Modus schaltet. Des weiteren müssen der Hardware-Addierer und die DMA-Eingabe korrekt eingestellt und der tatsächliche Vorteilerwert für den DMA-Sound gesetzt werden. Diese Aufgaben erledigt übrigens auch das AUTO-Ordner-Programm FPATCH von ATARI, das nebenbei auch einen Fehler der Bconmap-Funktion behebt. Das Accessory STESOUND bietet die gleiche Möglichkeit zur ständigen Verfügung, wenn das Subsystem von einem Falcon-Programm nicht in den Vorgefundenen Zustand zurückversetzt wurde. Beide Programme sollten in gut sortierten Mailboxen oder auf vielen ftps zu finden sein.

Leider ist der Falcon030 nicht in der Lage, mit Abspielfrequenzen kleiner als 8 KHz zu arbeiten, so daß Programme, die STE-DMA-Sound mit 6.25 KHz benutzen, stumm bleiben. Es gibt allerdings Programme mit DMA-Sound, die trotz dieser Einstellungen und einer Abspielfrequenz >= 12.5 KHz nicht wollen; sie geben meist nur einen kurzen Ton und sonst nichts von sich. Hier ist dann der Grund in dem verwendeten DMA-Timer zu suchen. Der STE erlaubt es, sowohl Timer A als auch den MFP-Interrupt 7 zum kontinuierlichen Abspielen von Frames zu benutzen. Beim Falcon030 kann durch einen XBIOS-Aufruf (setinterru.pt) individuell bestimmt werden, welcher Interrupt benutzt werden soll. Somit kann man „Problemkindem“ durch Einstellen des von ihnen erwarteten Interrupts auf die Sprünge helfen.

Ist der Falcon an einem Monochrommonitor angeschlossen (z.B. SM 124/44/46), wird automatisch die Auflösung „ST-hoch“ gewählt, etwas anderes kann nicht dargestellt werden. Nun gibt es aber Programme, die sich trotzdem so verhalten, als wären sie an einem Farbmonitor angeschlossen (u.a. auch der von ATARI mitgelieferte Bildschirmschoner Maccel, der das Bild nur einmal invertiert, anstatt dies in kurzen Abständen zu wiederholen). Dies liegt daran, daß die Systemvariable sshiftmd (0x44C) nicht wie zu erwarten mit 2 besetzt ist (Auflösung ST-hoch), sondern mit 3, als wäre ein Falcon-Videomodus aktiv. Dies ist erstaunlich, da das Register shiftmd (0xFF8260) korrekt gesetzt ist und der Fehler am RGB-Monitor bei ST-hoch nicht auftritt. Korrigiert man die Variable bei Betrieb am SM 124 auf 2 (den Monitortyp kann man ja mittels der XBIOS-Funktion mon_type erfragen), funktionieren viele Programme wieder so, wie sie sollen, so auch Maccel.

Speicher

Es gibt Spiele, die nur mit einer bestimmten RAM-Konfiguration Zusammenarbeiten (beispielsweise 1MB), bei mehr oder weniger Speicher jedoch den Dienst versagen. Durch Umändern der Systemvariablen phystop (0x42E) kann man erreichen, daß nach dem nächsten Warmstart weniger RAM vorhanden ist (natürlich nur für das Betriebssystem). Setzt man gleichzeitig noch die Systemvariable memcntrl (0x424) und das Hardware-Register memcon/(0xFF8001) auf die zu der Speichergröße gehöngen Werte, macht man die Verringerung der RAM-Größe für ST(E)-Programme perfekt, sie können nicht mehr feststellen, daß in Wirklichkeit mehr Speicher vorhanden ist. memconf hat auf dem Falcon030 übrigens keine Bedeutung mehr, es ist nur aus Kompatibilitätsgründen vorhanden und läßt sich, im Gegensatz zum ST(E), problemlos beschreiben. Der Falcon030 entnimmt seine Speichergröße aus einem undokumentierten Hardware-Register (das Listing stellt so die RAM-Größe fest). Durch das Vortäuschen von weniger RAM-Speicher läßt sich der freigewordene Teil bestens als absolut sicherer Bereich für den PMMU-Baum nutzen, der auf diese Weise nicht mehr zerstört werden kann. Das Listing nutzt diesen Bereich auch, um eine für die Anpassung der Bildschirmadresse nötige Routine abzulegen, auf die der GEMDOS-Trap verbogen wird.

Es gibt auch immer noch Programme, die nur von Diskette gestartet werden können (damit ist nicht der Start per Boot-Sektor gemeint). Ein Teil von ihnen kommt auch nicht mit einer angeschlossenen Festplatte zurecht. Um solche Programme zum Laufen zu bewegen, muß während der Boot-Phase des Rechners die Altemate-Taste gedrückt gehalten werden, bis das Desktop erscheint. Dadurch wird der Festplattentreiber nicht aufgerufen und somit diePlatte(n) nicht ins System eingebunden.

Weniger ein Problem der Kompatibilität als eines der Belastbarkeit der Ohren ist der interne Lautsprecher des Falcon. Er bietet, milde ausgedrückt, bescheidene Klangqualität und ist unglaublich laut. Man kann ihn zwar per Kontrollfeld abschalten, doch das wird erst im Desktop aktiv, bei bootenden Spielen erfüllt er stur seine Aufgabe, für die er eindeutig nicht geschaffen wurde. Zum Glück läßt er sich über ein undokumentiertes Verhalten des Port-A-Registers des Soundchips abschalten. Wird dort Bit 6 gesetzt, schweigt er, und man kann seine Ohren schonen [2]. Das Listing ermöglicht es, daß der Lautsprecher auch bei Spielen, die per Boot-Sektor geladen werden, nicht aktiv ist.

Mindestens genauso nervig ist die anfangs eingestellte Lautstärke, von der man beinahe einen Hörschaden bekommt. Zum Glück stellt ATARI mit der XBIOS-Funktion soundcmd auch eine Möglichkeit zur Verfügung, die Lautstärke abzudämpfen, so wie es auch das SOUND-CPX macht. Dabei stehen 16 Abstufungen zur Verfügung, die für linken und rechten Kanal getrennt eingestellt werden können. Das im folgenden beschriebene Listing ermöglicht es, auch die Lautstärke für bootende Spiele voreinzustellen (allerdings nur für beide Kanäle gleichzeitig), so daß einem ungestörtem Hörgenuß nur noch die Qualität der benutzten Musik im Wege steht.

Das Programm GAMEFIX

Damit jetzt nicht jeder anfangen muß, ein Programm zu schreiben, das die oben beschriebenen Lösungen benutzt, wurde das Listing GAMEFIX erstellt. Es ist ein in GEM eingebundenes Programm, das alle genannten Möglichkeiten (bis auf die Korrektur des Soundchip-Zugriffs über den Busfehlervektor) benutzt. Dabei können folgende Dinge individuell eingestellt werden: Daten-Cache an/aus, Befehls-Cache an/aus, CPU mit 8/16 MHz, Blitter mit 8/16 MHz, ST(E)-Busmodus an/aus, interner Lautsprecher an/aus, Benutzung der alten Bildschirmadresse an/aus, zu benutzende(r) DMA-Interrupt(s), RAM-Größe 512K/1MB/2MB/4MB sowie Lautstärke 0-15. Bei der RAM-Größe sind dabei je nach Speicherausbau des benutzten Falcon und Lage des Programms im Speicher nur bestimmte Werte wählbar (wenn die niedrigen Größen nicht wählbar sind, sollte man AUTO-Ordner-Programme und Accessories inaktivieren). Automatisch korrigiert werden die Systemvariablen _memtop und sshiftmd (wenn nötig), außerdem wird das Soundsubsystem richtig für STE-DMA-Sound initialisiert.

Nach dem Start des Programms erscheint eine Dialogbox (Bild 1), in der die Einstellungen vorgenommen werden können.

Dabei werden, soweit möglich und sinnvoll, die bei Programmstart Vorgefundenen Einstellungen angezeigt. Der „live“-Button neben dem Lautstärke-Slider legt fest, ob die eingestellte Lautstärke zum Testen gleich aktiviert wird oder nicht. Mit dem „Abbruchs-Button wird GAMEFIX ohne Auswirkungen verlassen.

Hat man alles nach seinen Vorstellungen gewählt, wird man nach einem Druck auf „OK“ gefragt, ob man neubooten oder die Einstellungen nur übernehmen will. Beim Booten wird ein „Magic Pack“ [3] im Speicher angelegt, der nach dem Reset ausgeführt wird. Er nimmt dann die gewählten Einstellungen vor, gibt einen kurzen Text aus und wartet auf einen Tastendruck. Drückt man Escape, wird normal mit dem Boot-Vorgang fortgefahren, ansonsten wird der Boot-Sektor der eingelegten Diskette eingelesen und gegebenenfalls ausgeführt. Somit können also Spiele, die über einen Boot-Sektor gestartet werden, wieder zum Laufen gebracht werden. Dabei ist wichtig, daß die Spielediskette während des Resets noch nicht im Laufwerk liegt, sie darf erst nach der Aufforderung eingelegt werden! Hat man sich hingegen für das Übernehmen der Einstellungen ohne Booten entschlossen, wird das Programm daraufhin verlassen. Es können wie gewohnt Programme von Diskette/Festplatte gestartet werden, die dann hoffentlich korrekt funktionieren. Hierbei bleibt die gewählte RAM-Konfiguration unberücksichtigt, deswegen kann auch der PMMU-Baum nicht verschoben werden. GAMEFIX gibt daher einen entsprechenden Hinweis aus.

Der „Speichern“-Button bietet die Möglichkeit, kleine Programme zu erzeugen, die die aktuellen Einstellungen beinhalten und entweder wie „OK/ Booten“ oder wie „OK/Übernehmen“ wirken. Bei letzterer Möglichkeit kann man auch noch ein Programm bestimmen, das im Anschluß gestartet wird. Auf diese Weise ist es möglich, individuelle Ladeprogramme zu benutzen, anstatt jedesmal GAMEFIX laden zu müssen, um dann dort die jeweiligen Einstellungen vorzunehmen.

Wie sollte man vorgehen?

Leider gibt es nicht DIE GAMEFIX-Konfiguration, mit der alle Spiele klaglos laufen. Deshalb hier eine kurze Beschreibung, welche Einstellungen man bei welchem Problem ausprobieren sollte:

Programm stürzt mit zwei Bomben ab: Dies ist der am häufigsten auftretende Fehler, der aber leider auch sehr vielfältige Ursachen haben kann. Als erstes sollte man versuchen, die alte Bildschirmadresse zu aktivieren, damit ist in vielen Fällen schon geholfen. Benutzt das Programm hingegen digitale Sounds, die nicht per STE-DMA gespielt werden, kann das zusätzliche Aktivieren des ST(E)-Busmodus Abhilfe bringen. Eventuell kann auch das Simulieren einer kleineren RAM-Größe bei Busfehlern helfen (hierbei nicht vergessen, daß GAMEFIX dazu mit „OK/Booten“ beendet werden muß). Alle restlichen Ursachen für zwei Bomben können vielleicht durch den ST(E)-Busmodus beseitigt werden.

Programm stürzt sang- und klanglos ab: In den allermeisten Fällen liegt dies daran, daß das Programm nicht mit den Caches des 68030 zurechtkommt (selbstmodifizierender Code). Man sollte daher zunächst den Befehls-Cache inaktivieren und, wenn das noch nicht hilft, auch den Daten-Cache.

Die Originaldiskette wird nicht erkannt: Der Kopierschutz des Programms funktioniert nicht mehr richtig. Dies kann daran liegen, daß einfache Schleifen zum Timing benutzt werden, die auf dem Falcon zu schnell ablaufen. Daher sollte man den Prozessor auf 8 MHz schalten, damit das Timing wieder stimmt. Es kann sein, daß auch die Caches das Zeitverhalten stören, hier kann dann das zusätzliche Inaktivieren von Befehls- und Daten-Cache helfen. Letzteres ist ebenfalls angebracht, falls die Kopierschutzabfrage mit selbstmodifizierendem Code arbeitet (was häufig der Fall ist, um Crackern das Leben schwer zu machen).

Das Programm läuft viel zu schnell: Hier sollte man zunächst die CPU auf 8 MHz zurückschalten, wenn das nicht hilft, zusätzlich den Befehls-Cache inaktivieren. Sollte das Spiel dann immer noch zu schnell sein, auch den Blitter auf 8 MHz setzen. Als letzte Möglichkeit bleibt noch, den Daten-Cache abzuschalten. Dann müßte eigentlich wieder die ST-Geschwindigkeit erreicht sein.

Da GAMEFIX relativ umfangreich ist, befindet sich der Großteil des dokumentierten Quellcodes auf der Monatsdiskette. Listing 1 zeigt den Assembler-Teil, der die Methoden zur Erhöhung der Kompatibilität enthält. Die Listings 2 und 3 enthalten den Quellcode der Miniprogramme, die aus GAMEFIX heraus abgespeichert werden können (sie benötigen beide Listing 1, sind aber ohnehin so nicht lauffähig). Dabei zeigt Listing 2 insbesondere, wie man einen, Magic Pack“ installiert, der dann beim nächsten Reset aktiv wird. Auf der Monatsdiskette befindet sich außerdem eine Library für Pure C 1.0, die die Falcon-XBIOS-Funktionen von Video- und Sound-Hardware (ohne DSP-Routinen) bereitstellt.

Mit GAMEFIX sollte es möglich sein, eine ganze Reihe von „störrischen“ Programmen wieder zum Laufen zu bringen. Allerdings sollte dies nicht zum Anlaß genommen werden, bei der Neuprogrammierung nicht sauber zu arbeiten, so daß Probleme mit zukünftigen Rechnern schon jetzt so gut wie ausgeschlossen sind.

Literatur:

[1] Natalie Lübcke. Falcon030 CPU- und Blitter-Takt, Quicktip in ST-Computer 8/93

[2] Natalie Lübcke, Das Schweigen des Falcon, Quicktip in ST-Computer 5/93

[3] Jankowski/Rabich/Reschke, ATARI Profibuch ST-STE-TT, SYBEX-Verlag Düsseldorf 1991 (Teil I, Kapitel 1, Abschnitt 11: Systeminitialisierung; allerdings werden sie hier nicht „Magic Packs“ genannt, außerdem ist es falsch, daß durch die Initialisierung des GEMDOS der gesamte Speicher oberhalb von 0x800 gelöscht wird)


;****************************************************
;* Modulname        : ASSEM.S                       *
;* (c)1993 by MAXON-Computer                        *
;* Autor            : Thomas Binder                 *
;* Zweck            : Enthält den Assemblerteil     *
;*                    von GAMEFIX, insbesondere     *
;*                    die Routinen mpack und set,   *
;*                    die die im Artikel beschrie-  *
;*                    benen Manipulationen zeigen   *
;* Compiler         : Pure Assembler 03.02.1992     *
;* Erstellt am      : 12.08.1993                    *
;* Letzte Änderung  : 03.09.1993                    *
*****************************************************

    export _gemdos,mpack,reset,ramsize 
    export settings,get_settings,gdrout,set 
    export ramsizes,new_pmmu_tree,mtype 
    export rootpointer,checksum,get_ram 
    export mtype

    ; Benötigte Systeravariablen und Hardware-
    ; Register
    equ     trap_1,$84
    equ     memvalid,$420
    equ     memcntrl,$424
    equ     resvalid,$426
    equ     phystop,$42e
    equ     _memtop,$436
    equ     _bootdev,$446
    equ     sshiftmd,$44c
    equ     _v_bas_ad,$44e 
    equ     _dskbufp, $4c6
    equ     _sysbase,$4f2 
    equ     _longframe,$59e 
    equ     memconf,$ffff8001

    ; Indizes für das Settings-Feld
    equ     datacache,0
    equ     instcache,2
    equ     blit8mhz,4
    equ     cpu8mhz,6
    equ     busmode,8
    equ     timera,10
    equ     mfpi7,12
    equ     speaker,14
    equ     scrbase,16
    equ     volume, 18
    equ     ramconfig,20

    text

    ; Resetroutine für das Booten 
    ; Setzt die gewünschte Ramgröße und führt 
    ; einen Reset aus 
MODULE reset
    lea     settings,a0
    ; Zur Ramgröße gehörigen Wert nach
    ; memcntrl und memconf schreiben
    move.w  ramconfig(a0),d0
    lea     ramcntrls,a0
    move.b  (a0,d0.w),memcntrl.w
    move.b  (a0,d0.w),memconf.w
    lea     ramsizes,a0
    move.l  (a0,d0.w*4),phystop.w
    ; eventuelle andere Resetroutinen ausklinken
    clr.l   resvalid.w
    ; und ab zum Reset
    move.l  _sysbase.w,a0
    jmp     (a0)

    ; Werte für memcntrl und memconf für 512K,
    ; 1MB, 2MB und 4MB 
ramcntrls:
    dc.b    4,5,8,10 
    ; Die dazugehörigen Ramgroßen 
ramsizes:
    dc.l    $80000,$100000,$200000,$400000
ENDMOD

    ; Liest, soweit möglich, die alten Ein-
    ; Stellungen aus 
MODULE get_settings
    lea     settings,a3
    ; Testen, ob CPU mit 8MHz läuft
    ; Nicht dokumentiert!
    btst    #0,$ffff8007.w
    bne.s   gs1
    move.w  #1,cpu8mhz(a3)
gs1:
    ; BLiTTER mit 8MHz?
    ; Nicht dokumentiert! 
    btst    #2,$ffff8007.w 
    bne.s   gs2
    move.w  #1,blit8mhz(a3)
gs2:
    ; ST(E)-Busmodus aktiv?
    ; Nicht dokumentiert! 
    btst    #5,$ffff8007.w 
    bne.s   gs3 
    move.w  #1,busmode(a3)
gs3:
    movec   cacr,d0 
    ; Befehlscache aktiv? 
    btst    #0,d0 
    beq.s   gs4
    move.w  #1,instcache(a3)
gs4:
    ; Datencache aktiv? 
    btst    #8,d0 
    beq.s   gs5
    move.w  #1,datacache(a3)
gs5:
    ; Interner Lautsprecher an?
    ; Nicht dokumentiert! 
    move.w  #14,-(sp) 
    move.l  #$1c0000,-(sp) 
    trap    #14 
    addq.l  #6,sp
    btst    #6,d0 
    bne.s   gs6
    move.w  #1,speaker(a3)
gs6:
    ; Timer A für DMA-Sound? 
    ; Nicht dokumentiert! 
    btst    #2,$ffff8900.w 
    beq.s   gs7 
    move.w  #1,timera(a3)
gs7:
    ; MFP-Interrupt 7 für DMA-Sound?
    ; Nicht dokumentiert! 
    btst    #0,$ffff8900.w 
    beq.s   gs8 
    move.w  #1,mfpi7(a3)
gs8:
    ; Welchen Monitor haben wir denn?
    move.w  #89,-(sp)
    trap    #14
    addq.l  #2,sp
    move.w  d0,mtype
    jmp     get_ram(pc)
ENDMOD

MODULE get_ram
    ; Ramgröße des Falcon bestimmen
    ; Nicht dokumentiert!
    move.w  $ffff8006.w,d0
    lsr.w   #8,d0
    lsr.b   #1,d0
    move.b  d0,d1
    andi.b  #1,d1
    lsr.b   #2,d0
    andi.b  #6,d0
    or.b    d0,d1
    move.l  #$80000,d0
    asl.l   d1,d0
    cmpi.b  #5,d1
    bne.s   no16mb
    ; Wenn es 16MB sind, "klaut" uns das TOS 
    ; durch seine Lage 2 Megabyte :-( 
    move.l  #$e00000,d0 
no16mb: 
    rts 
ENDMOD

    data

    ; Diese Routine wird im Speicher als 
    ; "Magic-Pack" plaziert und nach dem Reset 
    ; vor den AUTO-Ordner-Programmen ausgeführt 
    ; Hier werden dann die Einstellungen vorge-
    ; nommen und auf Wunsch ein Diskettenboot-
    ; sektor ausgeführt 
mpack:
    movem.l d0-d3/a0-a4,-(sp)
    ; Den neuen PMMU-Baum installieren 
    lea     rootpointer(pc),a0 
    pmove (a0),crp
    ; Sicherheitshalber den ATC löschen 
    pflusha
    ; Dafür sorgen, daß die Prüfsumme des 
    ; "Magic Pack" zerstört wird 
    lea     checksum(pc),a0
    clr.l   (a0)
    ; Nächster Reset wird ein Kaltstart (aus 
    ; Sicherheitsgründen) 
    clr.l   memvalid.w
    ; Eventuell die GEMDOS-Routine einklinken,
    ; die dafür sorgt, daß die Bildschirmadresse
    ; die gleiche wie beim ST(E) ist
    lea     settings(pc),a4
    tst.w   scrbase(a4)
    beq.s   mp1
    movec   vbr,a0
    move.l  gdrout(pc),a3
    move.l  trap_1(a0),-4(a3)
    move.l  a3,trap_1(a0)
mp1:
    ; Die restlichen Einstellungen vornehmen 
    bsr.w   set
    ; Je nach Monitortyp den richtigen Bildschirm-
    ; modus einstellen (ST-hoch bei Monochrommoni-
    ; tor, sonst ST-niedrig)
    move.w  mtype(pc), d3
    lea     modecodes (pc), a3
    move.w  (a3,d3.w*2),-(sp)
    move.w  #3,-(sp)
    clr.l   -(sp)
    clr.l   -(sp)
    move.w  #5,-(sp)
    trap    #14 
    lea     14(sp),sp
    move.w  (a3,d3.w*2),-(sp) 
    move.w  #88,-(sp) 
    trap    #14 
    addq.l  #4,sp
    ; Die Nachricht von GAMEFIX ausgeben und
    ; auf Tastendruck warten
    pea     msg(pc)
    move.w  #9,-(sp)
    trap    #1
    addq.l  #6,sp
    move.w  #8,-(sp)
    trap    #1
    addq.l  #2,sp
    ; Wurde ESC gedrückt? Wenn ja, dann gleich 
    ; aufhören 
    cmp.b   #27,d0 
    beq.s   to_gem
    ; Ansonsten Diskettenbootsektor einiesen und 
    ; ausführen, wenn er die richtige Prüfsumme 
    ; hat
    move.l  _dskbufp,a3 
    pea     1.w
    clr.w   -(sp) 
    pea     1.w
    clr.l   -(sp) 
    pea     (a3) 
    move.w  #8,-(sp) 
    trap    #14
    lea     20(sp),sp
    move.w  #255,d0 
    moveq   #0,d1
mp2:
    add.w   (a3)+,d1 
    dbra    d0,mp2 
    cmpi.w  #$1234,d1 
    bne.s   to_gem
    ; Bootdrive auf A: ändern und Bootsektor 
    ; ausführen 
    clr.w   _bootdev 
    jsr     -512(a3)
to_gem:
    movem.l (sp)+,d0-d3/a0-a4 
    rts

checksum:
    dc.w    0

    ; Hier werden die Einstellungen vorgenommen, 
    ; die auch ohne Booten möglich sind
set:
    tst.w   mtype(pc) 
    bne.s   nomono
    ; Am Monochrommonitor die Systemvariable 
    ; sshiftmd korrigieren 
    move.b  #$2,sshiftmd.w
nomono:
    lea     settings(pc),a4
    ; Caches (de)aktivieren 
    move.l  #$0808,d0
    or.w    datacache(a4),d0
    or.w    instcache(a4),d0 
    movec   d0,cacr
    ; CPU- und BLiTTER-Takt und Busmodus 
    ; setzen
    ; Nicht dokumentiert!
    move.b  #$40,d0
    or.w    cpu8mhz(a4),d0
    or.w    blit8mhz(a4),d0
    or.w    busmode(a4),d0
    move.b  d0,$ffff8007.w
    ; Lautsprecher ein- bzw. ausschalten
    ; Nicht dokumentiert!
    move.w  #14,-(sp)
    move.l  #$1c0000,-(sp)
    trap    #14
    addq.l  #6,sp
    bclr    #6,d0
    or.w    speaker(a4),d0
    move.w  #$8e,-(sp)
    move.w  d0,-(sp)
    move.w  #$1c,-(sp)
    trap    #14
    addq.l  #6,sp
    ; Wird alte Screenadresse gewünscht, vom 
    ; Betriebssystem die dazu nötige Anzahl von 
    ; Bytes anforden (undokumentierter GEMDOS-
    ; Call) und die zurückerhaltene Adresse mit 
    ; Setscreen einstellen 
    tst.w   scrbase(a4)
    beq.s   s1
    pea     $7f00.w
    move.w  #$15,-(sp) 
    trap    #1
    addq.l  #6,sp 
    move.w  #-1,-(sp) 
    move.l  d0,-(sp) 
    move.l  d0,-(sp) 
    move.w  #5,-(sp) 
    trap    #14
    lea     12(sp),sp
s1:
    ; Das Soundsubsystem korrekt für STE-DMA-
    ; Sound initialisieren
    move.w  #1,—(sp)
    clr.l   -(sp)
    pea     8.w
    move.w  #$8b,-(sp)
    trap    #14
    lea     12(sp),sp
    move.w  #3,-{sp)
    move.l  #$820006,-(sp)
    trap    #14
    addq.l  #6,sp
    move.w  #3,-(sp)
    move.l  #$820005,-(sp)
    trap    #14
    addq.l  #6,sp
    move.w  #3,-(sp)
    move.l  #$820004,-(sp)
    trap    #14
    addq.l  #6,sp
    ; Die gewünschte Lautstärke einstellen
    move.w  volume(a4),-(sp)
    move.l  #$820000,-(sp)
    trap    #14
    addq.l  #6,sp
    move.w  volume(a4),-(sp)
    move.l  #$820001,-(sp)
    trap    #14
    addq.l  #6,sp
    ; Gewünschte (n) DMA-Interrupt (s)
    ; einstellen
    move.w  timera(a4),-(sp)
    move.l  #$870000,-(sp)
    trap    #14
    addq.l  #6,sp
    move.w  mfpi7(a4),-(sp)
    move.l  #$870001,-(sp)
    trap    #14
    addq.l  #6,sp
    ; _memtop auf ST(E)-üblichen Wert korrigieren
    move.l  _v_bas_ad.w,_memtop.w
    rts

mtype:
    dc.w    0
modecodes:
    ; Die Codes für den Bildschirmmodus für 
    ; alle Monitortypen (Mono, RGB, VGA, TV)
    ; Den 2. und 4. Wert in %10000010 ändern,
    ; wenn 60Hz bzw. NTSC-Modus am RGB/TV 
    ; gewünscht ist
    dc.w    %110001000,%10100010,%110010010 
    dc.w    %10100010 
    dc.w    $abdc
    ; Hier stehen später die gewünschten 
    ; Einstellungen
settings:
    dc.w    0,0,0,0,0,0,0,0,0,0,0
    ; Die Nachricht
msg:
    dc.b    27,"EGAMEFIX V1.00",13,10
    dc.b    13,10,"Einstellungen vorgenommen,"
    dc.b    "  zum  Booten"
    dc.b    13,10,"jetzt die Disk einlegen und"
    dc.b    " eine Taste"
    dc.b    13,10,"drücken (ESC zum direkten“ 
    dc.b    "  Weitermachen"
    dc.b    13,10,"ohne Booten)!"
    dc.b    7,0

    even

    ; Adresse der GEMDOS-Routine für alte 
    ; Bildschrimadresse
gdrout:
    dc.l    0
    ; Der neue PMMU-Rootpointer : 
rootpointer:
    dc.l    $80000002,$700 
    dc.w    $abcd

    ; Die GEMDOS-Routine, die für die alte 
    ; Bildschirmadresse sorgt 
_gemdos:
    dc.b    "XBRAGfix"
old_gemdos:
    dc.l    0
new_gemdos:
    move.l  usp,a0 
    btst    #5,(sp)
    beq.s   goon

    ; Wäre eigentlich nicht nötig, aber man 
    ; sollte es eigentlich immer so machen 
    lea     6(sp),a0
    tst.w   _longframe.w 
    beq.s   goon
    addg.l  #2,a0 
goon:
    ; Wird die undokumentierte GEMDOS-Routine 
    ; mit der Screengröße für ST-kompatible 
    ; Modi aufgerufen, einfach $200 addieren,
    ; um 512 Bytes mehr zu erhalten und somit 
    ; die resultierende Adresse nach unten 
    ; zu drücken 
    cmpi.w  #$15,(a0)
    bne.s   no_scrmem
    cmp.l   #$7d00,2 (a0) 
    bne.s   no_scrmem
    addi.l  #$200,2(a0) 
no_scrmem:
    move.l  old_gemdos(pc),-(sp) 
    rts
    dc.w    $abcd

    ; Der PMMU-Baum, eine leicht geänderte Kopie 
    ; aus dem ROM: Alle mit $ffff beginnenden 
    ; Werte werden später als Offsets zur Baum-
    ; adresse genommen, aus $ffff0042 wird also 
    ; Baumadresse + $40, die 2 ist ein PMMU-Flag 
    ; für 4-Byte-große Tabelleneinträge 
    ; Wer also will, kann den Baum auf diese Weise 
    ; abändern ;-)
    ; Sollen beide Caches deaktiviert werden, wird 
    ; jeder Nicht-Offset-Wert mit $40 geodert, um 
    ; ein Cache-Inhibit zu erzielen 
new_pmmu_tree:

dc.l $ffff0042,$10000001,$20000001,$30000001 
dc.l $40000001,$50000001,$60000001,$70000001 
dc.l $80000041,$90000041,$a0000041,$b0000041 
dc.l $c0000041,$d0000041,$e0000041,$ffff0082
dc.l $ffff00c2,$01000001,$02000001,$03000001 
dc.l $04000001,$05000001,$06000001,$07000001 
dc.l $08000001,$09000001,$0a000001,$0b000001 
dc.l $0c000001,$0d000001,$0e000001,$0f000001
dc.l $f0000041,$f1000041,$f2000041,$f3000041
dc.l $f4000041,$f5000041,$f6000041,$f7000041
dc.l $f8000041,$f9000041,$fa000041,$fb000041
dc.l $fc000041,$fd000041,$fe000041,$ffff00c2
dc.l $00000001,$00100001,$00200001,$00300001 
dc.l $00400001,$00500001,$00600001,$00700001 
dc.l $00800001,$00900001,$00a00001,$00b00001 
dc.l $00c00001,$00d00001,$00e00001,$00f00041

/************************************************/
/* Modulname      : MINI1.C                     */
/* (c)1993 by MAXON-Computer                    */
/* Autor          : Thomas Binder               */
/* Zweck:         : Miniprogramm, das aus       */
/*                  GAMEFIX heraus gespeichert  */
/*                  werden kann und wie "OK/    */
/*                  Booten" wirkt, also einen   */
/*                  "Magic Pack" im Speicher    */
/*                  anlegt und dann einen       */
/*                  Reset auslöst.              */
/* Compiler       : Pure C 1.0                  */
/* Erstellt am    : 28.08.1993                  */
/* Letzte Änderung: 03.09.1993                  */
/************************************************/

#include <tos.h>
#include <portab.h>
#include <falcon.h>
#include "gamefix.h"

/* Prototypen */
LONG reset(void);
LONG get_ram(vo±d);

/* Globale Variablen */ 
extern WORD mtype;
WORD magic_pack [1280];

void main(void)
{
    WORD    i, j, 
            sum, 
            first, 
            checkpos, 
            pos;
    LONG    help;
    ULONG   ram;

    /* Ramgröße des F030 bestimmen */ 
    ram = (ULONG) Supexec (get_ram);
    /* Monitortyp auslesen */ 
    mtype = mon_type () ;
    /* Startadresse der GEMDOS-Routine für */
    /* die alte Bildschirmadresse und des */
    /* PMMU-Baums bestimmen */
    if (ramsizes [settings [_RAMCONFIG] ] == ram)
    {
        gdrout = (WORD *)0x600L; 
        rootpointer [1] = 0x700L; 
        if (!Super((void *)1L))
            Super(0L);
    }
    else
    {
        gdrout = (WORD *)(ram - 256LU); 
        rootpointer[1] = ram - 512LU;
    }
    /* PMMU-Baum kopieren */
    for (i = 0; i < 64; i++)
    {
        if ((new_pmmu_tree[i] / 65536LU) == 0xffffLU)
        {
            /* Bei entsprechend gekennzeich- */ 
            /* netem Eintrag den richtigen */
            /* Offset berechnen */ 
            new_pmmu_tree[i] = rootpointer[1] + (new_pmmu_tree[i] & 65535LU);
        }
        else
        {
            /* Sollen Daten- und Befehlscache */ 
            /* ausgeschaltet werden, im PMMU- */ 
            /* Baum Cache-Inhibit-Flag setzen */ 
            if (!settings[_DATACACHE] && !settings[_INSTCACHE])
            {
                new_pmmu_tree[i] |= 64LU;
            }
        }
        ((LONG *)rootpointer[1])[i] = new_pmmu_tree[i];
    }
    /* GEMDOS-Routine kopieren (egal, ob sie */
    /* gebraucht wird, oder nicht */ 
    for (i = 0; _gemdos[i] != (WORD)0xabcd; i++) 
        gdrout[i] = _gemdos[i]; 
    gdrout += 6L; 
    help = (LONG)magic_pack;
    /* Beginn des Magic Pack bestimmen (muß */
    /* auf 512-Byte-Grenze fallen). Die Magic */ 
    /* Packs sind übrigens offiziell nicht */
    /* dokumentiert, sie sollten also nur sehr */ 
    /* selten benutzt werden */ 
    if (help % 512L)
        help += 512L - (help % 512L); 
    first = pos = (WORD) ((help -(LONG)magic_pack) / 2L);
    /* Erster Long-Wert im Magic Pack muß */
    /* 0x12123456 sein */ 
    magic_pack[pos++] = 0x1212; 
    magic_pack[pos++] = 0x3456;
    /* Im zweiten Long-Wert muß die */
    /* Anfangsadresse des Packs stehen */ 
    magic_pack[pos++] = (WORD) (help >> 16); 
    magic_pack[pos++] = (WORD) (help & 65535L);
    /* Assembler-Routine kopieren */
    for (i = 0; mpack[i] != (WORD)0xabcd; i++) 
        magic_pack[pos + i] = mpack[i];
    /* 16-Bit-Prüfsumme über den Magic Pack */ 
    /* bilden */
    for (j = sum = 0; j < 256; sum += magic_pack[first + j++]);
    /* Checksumme so andern, daß die */
    /* Prüfsumme 0x5678 ergibt (sonst wird */ 
    /* der Magic Pack nicht ausgeführt) */ 
    checkpos = (pos « 1) + (WORD) ((LONG)&checksum - (LONG) mpack) ; 
    magic_pack[checkpos >> 1] += (0x5678 - sum); 
    /* Reset auslösen */
    Supexec(reset);
)

/***********************************************/
/* Modulname      : MINI2.C                    */
/* (c)1993 by MAXON-Computer                   */
/* Autor          : Thomas Binder              */
/* Zweck          : Miniprogramm, das aus      */
/*                  GAMEFIX heraus gespeichert */
/*                  werden kann und wie "OK/   */
/*                  Booten" wirkt, also einen  */
/*                  "Magic Pack" im Speicher   */
/*                  anlegt und dann einen      */
/*                  Reset auslöst.             */
/* Compiler       : Pure C 1.0                 */
/* Erstellt am    : 28.08.1993                 */
/* Letzte Änderung: 03.09.1993                 */
/***********************************************/

#include <tos.h>
#include <aes.h>
#include <portab.h>
#include <falcon.h>
#include «string.h>
#include "gamefix.h"

/* Prototypen */
LONG set(void);

/* Globale Variablen */ 
extern WORD mtype;
char loadprogram[129J = "\x0\x0\xab\xce"; 
char commandline[] = "";

LONG main(void)
{
    char    stdpath[129],
            *backslash;

    /* Programm beenden, wenn die alte Bild- */ 
    /* schirmadresse aktiviert werden soll, */
    /* aber kein ST-Kompatibilit&smodus aktiv */
    /* ist */
    if (settings[_SCRBASE])
        if (!(Vsetmode(-1) & STMODES)) 
            return(0L);
    /* Welcher Monitor ist dran? */ 
    mtype = mon_type();
    /* Einstellroutine aufrufen */
    Supexec(set);
    /* Soll ein Programm nachgeladen werden? */ 
    if (loadprogram[0])
    {
        /* Wenn ja, dessen Pfad zum aktuellen */
        /* machen */
        if (loadprogram[1] == ':')
        {
            Dsetdrv((WORD)loadprogram[0] - 65); 
            strcpy(stdpath, &loadprogram[2]);
        }
        else
            strcpy (stdpath, loadprogram); 
        if ((backslash = strrchr (stdpath, '\\')) != 0L)
        {
            backslash[1] = 0;
        }
        Dsetpath(stdpath);
        /* Programm laden & ausführen */ 
        return(Pexec(0, loadprogram, commandline,0L));
    }
    return(0L);
}

Thomas Binder
Aus: ST-Computer 11 / 1993, Seite 95

Links

Copyright-Bestimmungen: siehe Über diese Seite