ROM-Power am ST

Der ROM-Port führte bisher leider ein Schattendasein unter den Schnittstellen des ATARI-Computers. Doch an Anwendungsmöglichkeiten fehlt es ihm bestimmt nicht. Dies zeigen wohl auch die zwei bekanntesten Cartridges. Dabei handelt es sich zum einen um einen Macintosh-Emulator, der dem ST Kompatibilität zu diesem Rechner verschafft, und zum anderen um das in der Industrie bewährte Echtzeitbetriebssystem „RTOS-UH“. Auch der „Omikron-BASIC“-Compiler war zumindest zeitweise als Cartridge verfügbar.

Durch den Anschluß am ROM-Port entfällt die für Anwendungsprogramme lästige Ladezeit. Außerdem belegen sie keinen Platz im RAM, was 520ST-Besitzern, aber auch anderen zugute kommt. Heute kann jeder, der eine Möglichkeit hat, sich EPROMS selbst zu brennen, diese Vorteile des ROM-Ports nutzen. Cartridges, in denen Sie die selbst-gebrannten EPROMS nur noch einsetzen müssen, sind mittlerweile schon von vielen Drittanbietem zu günstigen Preisen zu haben.

Es gibt zwei Modultypen, und zwar Diagnose- und Programm-Module. Der erste Typ findet normalerweise nur bei Gerätetests des Reparaturservices Anwendung. Sie werden direkt nach einem Reset gestartet. Zu diesem Zeitpunkt hat der ST noch gar nichts initialisiert (noch nicht einmal die Speicherkonfiguration). Man ist somit gezwungen, dies selbst durchzuführen. Dadurch läßt sich jeder Teil des Systems prüfen und auf Funktionstüchtigkeit checken. Das Betriebssystem erkennt solche Module an der magischen Zahl $FA52235F in der Speicherzelle $FA0000 (1. Langwort des Speicherbereichs für das Modul).

Programm-Module sind Cartridges, die nach einer teilweisen oder vollständigen Initialisierung des Systems gestartet werden und die magische Zahl $ABCDEF42 besitzen. Beide Arten von Modulen sind nicht nur auf ein Programm beschränkt, sondern können auch mehrere beinhalten. Unterstützung durch das Betriebssystem Das Betriebssystem ist schon darauf vorbereitet, Cartridges am ROM-Port zu empfangen, und stellt dafür den Speicherbereich von $FA0000 bis $FBFFFF zur Verfügung. Die Schnittstelle läßt sich als eigenes Laufwerk verwalten und ist im Desktop als Laufwerk ,c:‘ anzumelden. Die Programme lassen sich daraus wie gewöhnlich starten.

Ein bißchen Hardware

Vorsicht für eigene Experimente! Am ROM-Port stehen die Leitungen für den Daten- und Adreßbus ungepuffert zur Verfügung! Es sind folgende Signale an der Schnittstelle anzutreffen:

+5V Betriebsspannung für das Modul
GND Masseleitung des Moduls
A1-A15 die unteren 15 Adreßleitungen des 68000ers
D0-D15 die 16 Datenleitungen der CPU
LDS (Low-Aktiv) Low an LDS zeigt an, daß das niederwertige Byte des Datenbusses gültig ist.
UDS (Low-Aktiv) Low an UDS zeigt an, daß das höherwertige Byte des Datenbusses gültig ist.

Sind LDS und UDS Low, handelt es sich um einen Wortzugriff.

ROM3 (Low-Aktiv) wird Low, wenn die oberen 64 KB des Speichers angesprochen werden ($FB0000-$FBFFFF).
ROM4 (Low_Aktiv) wird Low, wenn die unteren 64 KB des Speichers angesprochen werden ($FA0000-$FAFFFF).

Die Pin-Belegung ist in Bild 1 angegeben. Mit einem gewöhnlichen Aufbau des Cartridges lassen sich dem Rechner also 128 KB zusätzliches ROM verpassen. Doch einigen Tüftlern reichte dies nicht aus, sie entwickelten deshalb Platinen, mit denen mittels Bank-Switching-Technik mehr als 128 KB, z. B. 512 KB oder 1 MB, angesprochen werden können. Unter Bank-Switching versteht man eine Vorgehensweise, bei der ein großer Speicher angelegt wird, der Computer aber nur ein „Fenster“ davon zu sehen bekommt. Dazu kann man die ROMs beispielsweise in 64-KB-Blöcke aufteilen, eine Decodierschaltung sorgt dann dafür, daß der Rechner stets auf den jeweils gewünschten Block zugreift. Für Hardware-Freaks sei dabei auf Bild 2 verwiesen, in dem das Prinzip einer erweiterten EPROM-Bank dargestellt ist. Mit Hilfe des Latches und den Adreßleitungen A1, A2, A15 wird der jeweils angesprochene Speicherblock selektiert und mit einem Decoder der CS-Eingang des ausgewählten Blockes aktiviert (Low-Aktiv). Das Betriebssystem ist natürlich auf eine solche Konfiguration nicht vorbereitet, weshalb ein neuer Treiber für die EPROM-Bank geschrieben werden muß. Hierbei verweisen wir vor allem auf [2].

Etwas genauer werden wir jetzt auf die 128-KB-Karte eingehen, da diese für jeden Elektronik-Freak zu verwirklichen ist. Sehen Sie sich dazu bitte Bild 3 an. Für die Karte werden vier ,27256‘-EPROMs zu je 32 KB verwendet. Es läßt sich erkennen, daß sämtliche Daten- und Adreßleitungen mit den entsprechenden Anschlüssen an den EPROMs zu verbinden sind. Ebenso die Versorgungsspannung, die mit einem Kondensator noch zusätzlich etwas stabilisiert wird. IC1 und IC2 werden für die unteren und IC3 und IC4 für die oberen 64 KB benutzt. Aus diesem Grund ist die CS-Leitung von IC 1 und 2 mit ROM4 und die von IC3 und 4 mit ROM3 verbunden. Jetzt fehlen nur noch die LDS- und UDS-Anschlüsse. LDS legen wir an OE von IC1 und 3, UDS an OE von IC2 und 4, was bedeutet, daß in IC1 und 3 alle geraden und in IC2 und 4 alle ungeraden Adressen liegen. Bitte berücksichtigen Sie das beim Brennen der EPROMs. Damit ist die Cartridge anschlußfertig.

Noch ein Hinweis: Leider ist es nicht möglich, in eine Cartridge zu schreiben, da der GLUE-Chip für diesen Adreßbereich einen Bus-Error liefert.

Bild 1: Anschlußbelegung des ROM-Ports
Bild 2: Aufbau einer erweiterten EPROM-Karte

Ohne Software geht es nicht!

Damit im EPROM kein Chaos entsteht, existiert zu jedem Programm ein Vorspann, der Cartridge-Application-Header. Der Aufbau ist in Bild 4 ersichtlich. Die Inhalte der Komponenten des Vorspanns haben folgende Bedeutung:

CA_NEXT
Sollten sich mehrere Programme auf dem Modul befinden, ist hier ein Zeiger auf den nächsten Programmvorspann vorzufinden, im letzten Header der Wert 0.

CA_INIT
In diesem Long-Wert steht in den untersten 3 Bytes eine Adresse, die das Betriebssystem aufruft, um das entsprechende Programm zu initialisieren. Die verbleibenden obersten 8 Bits geben an, wann dies geschieht.

Bit 0: Aufruf von Adresse in CA_INIT nach der Initialisierung der Hardware; die Bildschirmauflösung ist festgestellt, Betriebssystemvariablen und Interrupt-Vektoren sind gesetzt, lediglich noch nicht freigegeben (Interrupt-Priority-Level: 7).

Bit 1: wie bei Bit 0, jedoch sind die Interrupts freigegeben (Interrupt-Priority-Level: 3); vorder GEMDOS-Initialisierung

Bit 2: wie bei Bit 0, jedoch ist die Bildschirmauflösung noch nicht festgestellt

Bit 3: Initialisierung direkt vor Disk- bzw. DMA-Boot-Routine

Die folgenden 3 Bits geben den Programmtyp an:

Bit 5: Accessory
Bit 6: TOS-Programm
Bit 7: TTP-Programm

CA_RUN
Adresse, die beim Programmstart, z.B. aus dem Desktop, angesprungen wird.

CA_TIME
Uhrzeit im GEMDOS-Format (HHHHHMMMMMMSSSSS)

CA_DATE
Datum im GEMDOS-Format (YYYYYYYMMMMDDDDD)

CA_SIZE
Länge des Programms

CA_NAME
Programmname als C-String (Abschluß durch $0-Byte) Format wie gewöhnlich: FILENAME.EXT

Wie man sieht, haben die Application-Header durch CA_NAME keine konstante Länge. Deshalb kann die Anfangsadresse eines Headers nicht berechnet werden, sondern der Programmierer muß sich durch die CA_NEXT-Zeiger hangeln. Wollen Sie Programme für eine Cartridge schreiben, müssen Sie darauf achten, daß sie später auch im Adreßbereich ab $FA0000 laufen. Wie das geschieht, sehen wir noch.

Zum Listing

Mit dem abgedruckten Listing haben Sie die Möglichkeit, Ihre für die EPROMs geschriebenen Programme auf Lauffähigkeit im ROM-Modul zu testen. Dazu muß man eigentlich nur die Routine des Betriebssystems simulieren, welche testet, ob sich eine Cartridge im ROM-Port befindet oder nicht. Im Startup-Code wird sie Routine mehrmals aufgerufen, so daß es kein Problem darstellte, diese zu disassemblieren (siehe Listing 1).

Sie überprüft zunächst das Vorhandensein der magischen Zahl $ABCDEF42 in der Speicherzelle $FA0000. Danach erfolgt ein Bit-Test, mit dem die Routine feststellt, ob das zum aktuellen Header gehörende Programm das gewünschte Init-Bit (Bits 24-31 in CA_INIT) gesetzt hat. Wenn nicht, wird, falls es überhaupt noch einen gibt, der nächste Programm-Header untersucht. Ist das entsprechende Bit jedoch gesetzt, kann man die Adresse des Init-Teils holen und anspringen.

Wie Sie vielleicht gemerkt haben, ist der einzige ROM-Modul-spezifische Befehl LEA $FA0000,A0. Das heißt, wenn wir die Programme des Moduls im RAM unterbringen, müssen wir nur $F A0000 durch unsere RAM-Adresse ersetzen, und schon arbeitet die Routine nach unseren Wünschen. Dies haben wir in Listing 2 verwirklicht.

Das Programm fragt zunächst nach dem Init-Bit, welches gesetzt sein soll. Es sind nur Eingaben von 0-3 sinnvoll, da sich lediglich die Bits 0-3 auf die Initialisierung beziehen, die Bits 4-7 geben ja den Programmtyp an. Nun folgt der Aufruf der schon oben besprochenen Routine. In ihr werden alle Header auf das entsprechende Bit hin durchsucht und gegebenenfalls das Init-Programm aufgerufen. Danach beginnt der Teil des Listings, den Sie später ins EPROM brennen. Wie wir anfangs erwähnten, muß er dann im Bereich $FA0000 laufen. Dies erreichen wir durch den Befehl ORG $FA0000, der dafür sorgt, daß der Modulteil bei dieser Adresse beginnt. Bevor Sie jedoch das EPROM brennen, müssen Sie noch alles löschen, was zum Programmteil oberhalb des ORG-Befehles gehört. Natürlich ist auch das Kommentarzeichen der ORG-Zeile zu entfernen.

Zum Schluß noch eine Anregung. Der ROM-Port eignet sich ja nicht nur für ROM-Module, sondern auch für viele andere Erweiterungen, z.B. A/D-Wandler usw., denn an ihm liegen viele Signale der CPU an. Aber Achtung! Die meisten sind ungepuffert.

Christian Roth/Matthias Brust

Literatur:

[1] ATARI Profibuch, Jankowski/Reschke/ Rabich, Sybex Verlag

[2] Scheibenkleister II - Massenspeicher am ST, Claus Brod/Anton Stepper, MAXON Computer

Bild 3: Aufbau einer 128-KB-Karte
OFFSET BEDEUTUNG
+$00 Zeiger auf nächsten Header
+$04 Zeiger auf PGM-Init-Routine
+$08 Zeiger auf PGM-Beginn
+$0C GEMDOS-Zeit
+$0E GEMDOS-Datum
+$10 Programmlänge
+$14 Programnnane

Bild 4: Struktur der Cartridge-Application-Header

ROM_TEST    LEA     $FA0000,A0          ;Hole 1.Langwort aus EPROM 
            CMP.L   #$ABCDEF42,(A0)+    ;Magic Zahl?
            BNE.S   QUIT                ;sonst Tschüß
TEST_INIT   BTST    D0,4(A0)            ;Init-Bit testen
            BEQ.S   NO_INIT             ;nicht gesetzt?
            MOVEM.L D0-A6,-(A7)         ;Register retten
            MOVE.L  4(A0), A0           ;Startadresse des
                                        ;PRG's holen 

            JSR     (A0)                ;und anspringen
            MOVEM.L (A7)+,D0-A6         ;Register holen
NO_INIT     TST.L   (A0)                ;noch ein PGM
                                        ;vorhanden?
            MOVE.L  (A0),A0             ;ja annehmen
            BNE.S   TEST_INIT           ;wenn wirklich ja
QUIT        RTS                         ;sonst Tschüß

; *************************** 
; * Cartridge-Test-Programm * 
; *    geschrieben von      *
; *   Christian Roth u.     *
; *    Matthias Brust       *
; *   Assembler: Profimat   *
; *  (c) 20.6.92 by MAXON   *
; ***************************

loop:       move.l  #ask,d0             ;Eingabestring
            jsr     print               ;printen
            move.w  #1,-(sp)            ;Auf Taste
            trap    #1                  ;warten
            addq.l  #2,sp
            cmp.w   #$1B,d0             ;bei ESC
            beq.s   tschau              ;Tschüss...
            sub.l   #'0',d0             ;ASCII->Zahl
            and.l   #7,d0               ;nur 3 Bits
            jsr     test                ;Programme testen
            bra     loop                ;wieder von vorn
tschau:     clr.w   -(sp)               ;Auf
            trap    #1                  ;Wiedersehen

print:      move.l  d0,-(sp)            ;Stringadresse
            move.w  #9,-(sp)            ;holen und
            trap    #1                  ;String
            addq.l  #6,sp               ;printen
            rts                         ;zurück

; Hier folgt das eigentliche Cartridge-
; Test-Programm, es entspricht weit-
; gehend dem TOS-Test-Programm

test:       lea     base,a0             ;magische Zahl
            cmp.l   #$ABCDEF42,(a0)+    ;vergleichen
            bne.s   back                ;Tschüss...
initbit:    btst    d0,4(a0)            ;Init-Bit gesetzt?
            beq.s   no_init             ;sonst => no_init
            movem.l d0-a6,-(sp)         ;Register retten 
            move.l  4(a0),a0            ;PGM-Adr. holen
            jsr     (a0)                ;PGM initialisieren
            movem.l (sp)+,d0-a6         ;Regs zurückholen 
no_init:    tst.l   (a0)                ;gibts noch ein PGM
            move.l  (a0),a0             ;Adr. eintragen
            bne     initbit             ;das Spiel wiederholen
back:       rts                         ;sonst Tschüss...

; Wenn das Programm getestet wurde und einwand-
; frei funktioniert, müssen Sie alles, was nicht 
; zum unteren Programmteil gehört löschen und bei 
; folgender Zeile das Kommentarzeichen ent-
; fernen, bevor Sie das PGM brennen.
;        org $FA0000

base:       dc.l    $ABCDEF42           ;magische Zahl
head_1:     dc.l    head_2              ;Zeiger auf 2. Header
            dc.l    init_1+$8000000     ;Zeiger auf Init + 
                                        ;Bit 27 setzen 
            dc.l    begin_1             ;Startadresse PGM
            dc.w    0 ;Zeit
            dc.w    0 ;Datum
            dc.l    end_1-begin_1       ;Länge des PGM
            dc.b    'ZUM_BSP1.PRG',0    ;Name des PGM
            align.l                     ;auf gerade
                                        ;Adresse bringen 
head_2:     dc.l    head_3              ;s.o
            dc.l    init_2+$4000000     ;Bit 26 setzen 
            dc.l    begin_2             ;...
            dc.w    0 
            dc.w    0
            dc.l    end_2-begin_2 
            dc.b    'ZUM_BSP2.PRG',0 
            align.l

head_3:     dc.l    0                   ;kein Header mehr
            dc.l    init_3+$8000000     ;Bit 27 setzen +
            dc.l    begin_3             ;gleiches Init-PGM
            dc.w    0                   ;wie bei PGM 1
            dc.w    0                   ;...
            dc.l    end_3-begin_3 
            dc.b    'ZUM_BSP3.PRG',0 
            align.l

init_1:     move.l  #init_txt,d0        ;Init-Text
            jsr     print               ;printen
            move.l  #head_1+20,d0       ;PGM-Name
            jsr     print               ;printen
            rts

init_2:     move.l  #init_txt,d0        ;...
            jsr     print
            move.l  #head_2+20,d0
            jsr     print
            rts

init_3:     move.l  #init_txt,d0
            jsr     print
            move.l  #head_3+20,d0
            jsr     print
            rts

begin_1:    rts                         ;Hier steht das richtige PGM 
end_1:

begin_2:    rts 
end_2:

begin_3:    rts 
end_3:

ask:        dc.b    13,10
            dc.b    'Welches Init-Bit soll gesetzt sein? (0-7, ESC=Exit) ',0 
init_txt:   dc.b 13,10,'Initialisiere Programm',0 
            end


Aus: ST-Computer 12 / 1992, Seite 115

Links

Copyright-Bestimmungen: siehe Über diese Seite