Die Flaggschiffe der ATARI-Reihe TT und Falcon030 beherbergen beide den leistungsstarken Motorola-Prozessor MC68030, der von haus aus mit 2*256 Bytes internem Cache ausgestattet ist. Ein Cachespeicher dient zum Zwischenlagern von häufig benutzten Daten, der andere zur schnellen Verfügbarkeit von Prozessor-Instruktionen, wie z.B. kleine Schleifen, die komplett in die 256 Bytes passen. Die Caches sind in 16 Zeilen ä 4 Langwörter aufgeteilt, die zeilenweise verwaltet und im sogenannten Burst-Modus auch zeilenweise gefüllt werden, d.h es werden 4 aufeinanderfolgende Langwörter mit einem Schlag übertragen. Im Sing-le-Entry-Modus hingegen werden die Langwörter einzeln bearbeitet, was natürlich entsprechend langsamer aber in manchen Fällen wesentlich vorteilhafter ist, weil unter umständen die gewünschten Daten im Speicher verteilt sind. Der Burst-Modus würde hier die Cache-Effizienz drastisch verkleinern. Nun ist es möglich für jeden der beiden Caches einige Einstellungen vorzunehmen, die man nur im Supervisor-Modus der CPU durchführen kann. Zu diesem Zweck existiert ein neues 32 Bit Register im Prozessor mit Namen CACR, das wie folgt aufgebaut ist:
CACR:
BitNr: 31....14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Bedeutung: 00....00 WA DB CD CE FD ED 0 0 0 IB CI CE FI EI
WA=Write Allocate
Bei gelöschtem Bit werden die Daten, die der Prozessor schreibt nicht im Cache neu angelegt (dupliziert), sondern gehen direkt nach draußen. Bei gesetztem Bit werden die zu schreibenden Daten zusätlich im Datencache abgelegt. Der lesende Zugriff mit eventuellem Neueintragen wird hingegen nicht beeinflußt.
DB=Data Burst Enable
Ein gesetztes Bit sorgt dafür, daß der Datencache im Burst-Modus gefüllt wird.
CD=Clear Data Cache
Ein setzen dieses Bits bewirkt das löschen des Datencaches.
CE=Clear Entry
Im Gegensatz zu CD bewirkt das setzen dieses Bits nur das löschen eines einzelnen Eintrags im Datencache. Die Auswahl dieses Eintrags erfolgt über das 32 Bit Cache-Adreß-Register CAAR in dem die Bits 2-7 den entsprechenden Eintrag adressieren.
FD=Freeze Data Cache
Ein gesetztes Bit signalisiert, daß beim Lesen oder Schreiben der Cacheinhalt nicht aktualisiert werden soll, wenn der gewünschte Eintrag nicht vorhanden ist. Eine Ausnahme stellt die Aktualisierung eines vorhanden Eintrags beim Schreiben dar, damit es für einen physikalischen Speicherplatz nicht 2 Einträge gibt. Ansonsten wird die beschleunigende Funktion des Caches nicht beeinträchtigt.
ED=Enable Data Cache
Wenn dieses Bit gelöscht ist, ist der Datencache absolut inaktiv. Bei erneutem Einschalten, ist der alte Zustand vor dem Abschalten immer noch gültig, es wurde also nichts gelöscht. Diese Bit kann man zu Debug-Zwecken oder Emulationen verwenden, da hier jeder Zugriff nach außen geht.
Für die Instruction Cache-Flags sind die Bedeutungen analog:
IB=Instruction Burst Enable
CI=Clear Instruction Cache
CE=Clear Entry
FI=Freeze Instruction Cache
Da es im Instruction Cache kein Schreibzugriff geben kann, fällt hier kein WA-Register an und im Eingefrorenen Zustand werden dementsprechend auch keine Einträge aktualisiert sondern nur ausgelesen.
EI=Enable Instruction Cache
Um also beide Caches anzuschalten und im Burst-Modus zu betreiben reichen ein paar einfache Assemblerbefehle, die im Supervisor-Modus ausgeführt werden müssen:
moved #$1111,d0
movec d0,CACR
Oder das Löschen der beiden Caches:
movec CACR,d0 ;behalte alten Status
or.l #$808,d0 ;und ändere 2 Bits ab
movec d0,CACR
Natalie Lübcke
Es kommt oft vor, daß man 16 Bit-Integer-Multiplikationen und -Divisionen verschachteln muß. Die Zwischenergebnisse sind in der Regel größer als 16 Bit (int, short) und so ist jedesmal eine Konvertierung nach 32 Bit (long) notwendig. Als Beispiel diene die Slider-Positionierung in einer Fensterverwaltung:
Sliderposition = (int)Position*1000 / (int)Maximum;
Für viele C-Compiler ist dies unmöglich, da es bereits bei der ersten Multiplikation sehr schnell zum Überlauf kommt. Es müßte dann heißen:
Sliderposition = (int)((long)Position*1000L/(long)Maximum )
Für den M68000er Prozessor ist dies jedoch kein Problem: Das Produkt einer Multiplikation und der Divident einer Division dürfen 32 Bit breit sein, solange beide Faktoren, Divisor und Quotient in 16 Bit passen. Ab dem MC68020 gibt es diese Befehle auch für 32 Bit, mit der Möglichkeit auf 64 Bit zu erweitern. Eine Lösung wäre die Benutzung von Inline-Routinen. Für Lattice C würde dies folgendermaßen aussehen:
long imul(short,short);
#pragma inline d0=imul(d0,d1) {"C1C1";} // muls.w d1,d0
short idiv(long,short);
#pragma inline d0=idiv(d0,d1) {"81C1";} // divs.w d1,d0
short imuldiv(short,short,short) ;
#pragma inline d0=imuldiv(d0,d1,d2) {"C1C1";"81C2";} // muls.w d1,d0 divs.w d2,d0
Aus dem bereits benutzten Beispiel wird dann:
Sliderposition = idiv( imul( Position , 1000 ) , Maximum );
bzw.
Sliderposition = imuldiv( Position , 1000 , Maximum );
Der erzeugte Maschinencode ist nicht nur kürzer und somit auch schneller, sondern der Quellcode auch übersichtlicher.
Volker Hemsen
Das Löschen von Bit 5 des Registers 0xFFFF8007 bewirkt, daß der Falcon030 ST(E)-kompatibler wird. Allerdings entspricht dies nicht, wie im obigen Quicktip beschrieben, dem Einstellen des Kompatibilitätsmodus vom Desktop aus, ohne die Auflösung zu ändern. Der vom Desktop aus erreichbare Kompatibilitätsmodus betrifft nur den Grafikmodus, während ein gelöschtes Bit 5 des Registers 0xFFFF8007 einen ST(E)-kompatiblen Busmodus bewirkt. Beim ST(E) waren Zugriffe auf Speicherbereiche, in denen "nichts" (kein RAM, kein ROM und keine Hardwareregister) war, möglich (das TOS nutzte dies, um das verfügbare RAM zu ermitteln). Beim Falcon030 werden solche Zugriffe allerdings, wie zu erwarten, mit einem Busfehler bestraft. Ist der Falcon jedoch durch Bit 5 von 0xFFFFA007 ST(E)-kompatibel geschaltet, verhält sich der Rechner hier wie ein ST(E). Dadurch können viele Spiele, die sich (aus welchem Grund auch immer) auf dieses Busverhalten verlassen haben und daher mit 2 Bomben abgestürzt sind, auch auf dem Falcon weiterbenutzt werden. Es steht zu hoffen, daß ATARI dieses Register noch dokumentiert und/oder einen passenden XBIOS-Aufruf implementiert, damit auch auf zukünftigen Falcon-Modellen alte Spielesoftware benutzt werden kann.
Thomas Binder
Bekanntlich verwaltet GFA-BASIC Dateien unter eigenen Kennummern (Handles) manchmal kann es aber ganz nützlich sein, die dazugehörigen GEMDOS-Handles zu ermitteln. Mit dem nachfolgendem Listing ist dies möglich.
Es funktioniert mit den GFA-BASIC-Versionen:
Compiler: | Interpreter: |
---|---|
3.03 D | 3.07D |
3.50 E | 3.50 D |
3.6 TT D | 3.6 TT |
Christoph Conrad
' (c)1993 by MAXON-Computer
' Autor: Christoph Conrad
' Ermitteln der Adresse des GFA-internen
' GEMDOS-Handle-Arrays bei OPEN
' Sei adr% die Adresse des Handle-Arrays.
' Dann steht bei einem
' OPEN mode$,»iS,name$
' das GEMDOS-Handle als Byte an Adresse (adr%+i&)
' get_channel_adr am besten gleich am Programmanfang
' auf jeden Fall BEVOR
' irgendein File eroeffnet wird.
'
channel_adr%=@get_channel_adr
'
' Zur Demonstration mal ein paar Sachen oeffnen
OPEN "i",#1,"COM:"
OPEN "i",#2,"AUX:"
OPEN "i",#3,"PRN:"
OPEN "i",#88,"INIT.O" ! Irgendein File im aktuellen Verzeichnis einsetzen
'
PRINT "Gemdos-Filehandle COM: ";HEX$(@get_handle(1))
PRINT "Gemdos-Filehandle AUX: ";HEX$(@get_handle(2)) ! wie COM:
PRINT "Gemdos-Filehandle PRN: ";HEX$(@get_handle(3))
PRINT "Gemdos-Filehandle DIM.GFA: ";HEX$(@get_handle(88))
'
FUNCTION get_handle(channel&)
' channel&: wie bei OPEN mode$,#channel&,name$
' negative GEMDOS-Handles werden positiv zurueckgeliefert!!!
$F%
IF channel_adr%<>0
RETURN BYTE{channel_adr%+channel&}
ELSE
RETURN 0
ENDIF
ENDFUNC
'
FUNCTION get_channel_adr
$F%
LOCAL geta6%,pgeta6%,i&,a6%,adr%,offs|
' Register A6 holen
LET geta6%=&H200E4E75 ! move.l a6,d0 // rts
pgeta6%=V:geta6%
a6%=C:pgeta6%()
FOR i&=0 TO 79
' Bei COM: kein GEMDOS-Fopen!
OPEN "i",#i&,"COM:"
NEXT i&
' 4 KByte ab a6% nach 80 aufeinanderfolgenden &HFB absuchen...
FOR adr%=a6% TO a6%+&H1000
IF BYTE{adr%}=&HFB
FOR offs|=1 TO 79
EXIT IF BYTE{adr%+offs|}<>&HFB
NEXT offs|
IF offs|=80
' Erfolg!
CLOSE
RETURN adr%
ENDIF
ENDIF
NEXT adr%
' Nichts gefunden...
CLOSE
RETURN 0
ENDFUNC