SuperCPU durchleuchtet - Folge 1
65816-Assembler?
Leider ist das angekuendigte "Developer's Kit" von CMD noch nicht
erhaeltlich, daher solltet ihr unbedingt den Kommentar zu den Listings lesen!
Die Post ist da !
Da ist sie nun, die sagenumwobene Turbokarte von CMD. Jeder, der sie
einmal gesehen hat, ist fasziniert von ihrer Schnelligkeit und
Kompatibilitaet. Doch wie entwickelt man eigene Programme fuer die
SuperCPU, wie nutzt man sie wirklich aus ? Unser Kurs weist Sie
Schritt fuer Schritt in die Geheimnisse dieser Erweiterung ein.
SuperCPU present?
Als allererstes ist es wichtig, die Karte zu erkennen. Denn nur wenn
sie im Expansionsport steckt, kann auch auf sie zurueckgegriffen
werden, ansonsten hat man einen normalen C64 vor sich und das Programm
muss sich entsprechend verhalten. Um die SuperCPU zu erkennen, gibt es
viele Moeglichkeiten, von denen wir hier zwei vorstellen. Als erstes
wuerde man sicher auf die Idee kommen, eine Warteschleife und einen
CIA-Timer laufenzulassen. Doch diese Methode fuehrt sofort zum
falschen Ergebnis, wenn der Benutzer die Turbokarte per Schalter auf 1
MHz geschaltet hat. Doch es gibt einen anderen Weg: In der SuperCPU
steckt naemlich eine Weiterentwicklung unseres 6502/6510, der
65816. Im 6502 gibt es einen kleinen, weitestgehend unbekannten Fehler
(keine Sorge, in der Regel rechnet der Prozessor vollkommen richtig!):
Im Dezimalmodus (mit SED einzuschalten) wird naemlich das Negativ-Flag
nicht richtig gesetzt. Holt man mit LDA #$99 im Dezimalmodus die Zahl
99 in den Akku, wird das N-Flag gesetzt. Zaehlt man nun zum
Akku-Inhalt eins dazu, bleibt das N-Flag unveraendert, waehrend der
65816 es korrekterweise loescht, da das Ergebnis Null ist (ein
positiver Wert).
Dies koennen wir uns zunutze machen, indem wir dieses Verhalten
ueberpruefen und somit wissen, ob ein 6510 oder ein 65816 gerade seine
Arbeit verrichtet. Wir schalten in den Dezimal-Modus, laden 99 in den
Akku und zaehlen eins dazu. Danach brauchen wir nur noch das
Negativ-Flag zu testen: Ist es gesetzt, liegt ein 6510 vor, ist es
geloescht, handelt es sich um einen 65816. Listing 1.1 zeigt diese
Routine.
Doch Vorsicht: Einige aeltere Turbokarten fuer den C64 besitzen
ebenfalls den 65816-Prozessor, haben aber sonst kaum die positiven
Eigenschaften einer SuperCPU. Ausserdem verhalten sich einige
C64-Emulatoren in dieser Hinsicht wie ein 65816, erreichen aber wohl
eher selten die Geschwindigkeit der CMD-Karte. Wie kann man nun
absolut sicher sein, dass man eine SuperCPU vor sich hat ? Nichts
einfacher als das: Sie blendet naemlich einige neue, hoch interessante
Register ab $D070 und $D0B0 ein. Eines davon, $D0BC, hilft uns
herauszufinden, ob eine SuperCPU vorliegt. Dazu muss man lediglich Bit
7 dieses Registers testen. Beim Betrieb der Turbokarte ist dies in der
Regel immer null, waehrend ein C64 ohne angeschlossene SuperCPU in der
Regel eine eins zurueckliefert. In Listing 1.2 sieht man, wie's gemacht
wird. Da man nicht immer 100%ig sicher sein kann, dass auch wirklich
jeder C64 (ohne eingesteckte CMD-Turbokarte) beim ueberpruefen des
Bits dieses (dann ja nicht vorhandenen) Registers eine eins
zurueckliefert, kann man beide Methoden zur Erkennung kombinieren, so
ist man auf jeden Fall auf der sicheren Seite.
Turbo oder Normal?
So, nun wissen wir, dass eine SuperCPU vorhanden ist. Befinden wir uns
aber im Turbo-Mode oder im normalen, langsamen Modus ? Wenn unser
Programm fuer den Turbo-Modus ausgelegt ist, sollte es auch nicht im
Standard-Mode ausgefuehrt werden. Jedes Mal eine Meldung wie "Bitte
auf Turbo schalten" einzublenden wuerde allerdings sehr
unprofessionell wirken. Viel besser waere es doch, diese Meldung nur
auszugeben, wenn die Karte wirklich mit 1 MHz laeuft. Auch hier hat
CMD eine Moeglichkeit eingebaut, dies auf einfache Art und Weise
abzutesten. Das Bit 6 im neuen Register $D0B8 ist high (eins), wenn
sich die Karte im langsamen Modus befindet, ansonsten steht dort eine
logische null. In Listing 1.3 sieht man, wie eine solche Abfrage mit
entsprechender Reaktion zu programmieren ist.
Speed-Switching
Sehr oft moechte man bestehende Programme an die SuperCPU anpassen,
z.B. solche, in denen es teilweise noetig ist, manchmal auf 1 MHz
herunterzuschalten. Da will man beispielsweise im Turbo-Mode
entpacken, die darauf folgende Routine soll aber (z.B. aus
Timing-Gruenden) im normalen Modus laufen. Die Turbokarte laesst sich
ja mit dem Schalter jederzeit absturzfrei umschalten - aber es geht
auch softwaremaessig! Hierzu gibt es zwei Register die im
$D07X-Bereich liegen. Dieser Speicherbereich enthaelt einige Register,
die nicht zum Abfragen, sondern zum aendern gedacht sind. Damit kein
Programm sie aus Versehen ueberschreibt, muessen sie in der Regel erst
aktiviert und nach dem Zugriff wieder deaktiviert werden. Alle
Register sind Write-Sensitive, dass heisst, es muss lediglich ein
Schreibzugriff darauf erfolgen, um die gewuenschte Option
einzustellen. Es reicht beispielsweise ein STA, der Inhalt des Akkus
spielt dabei keine Rolle. Die Speicherstelle zum Aktivieren der
restlichen $D07X-Register lautet $D07E. Ein STA $D07E bewirkt also,
dass die anderen Register "sichtbar" und somit beschreibbar
werden. Die Register ab $D0BX kann man aber jederzeit abfragen. Die
Entwickler haben bei diesem Konzept sogar die Moeglichkeit
beruecksichtigt, dass eine Memory-Fill-Routine die Register zufaellig
beschreiben koennte. Die Speicherstelle zum deaktivieren der Register
ist aber direkt dahinter - $D07F- , womit sie sofort wieder
ausgeblendet werden. Kommt die Fill-Routine aus der anderen Richtung,
macht dies auch nichts: das Register $D07F gibt es noch ein zweites
Mal bei $D07D.
Nicht so schnell !
Dieselbe Methode wurde bei der softwaremaessigen
Geschwindigkeitsumschaltung verwendet. Damit dies sehr schnell
geschehen kann, muessen die Register nicht extra aktiviert werden. Das
Register zum Schalten auf Turbo-Speed existiert aus den oben
geschilderten Gruenden als auch zweimal, bei $D07B und $D079. Genau
dazwischen (bei $D07A) ist dann das Register zum Schalten auf 1
MHz. Somit ist sichergestellt, dass auch bei zufaelligem
Schreibzugriff auf den Register-Bereich die Karte nicht versehentlich
heruntergeschaltet wird. Will man aber nun in seinem Programm mal mit
normaler Geschwindigkeit, mal mit Turbo arbeiten, bietet es sich an,
die SuperCPU per STA $D07A auf 1 MHz zu schalten. Sobald man die volle
Power haben will, genuegt ein STA $D07B und schon befindet man sich im
Turbo-Modus. Dieser bleibt so lange aktiv, bis wieder mit STA $D07A
auf normal geschaltet wird. Im Gegensatz zu anderen Turbokarten ist
diese Art der Umschaltung sehr sicher, da man davon ausgehen kann,
dass das Programm in der Regel nicht $D07A/$D07B beschreibt. Somit
bleibt die CMD-Karte immer in der vom Programmierer gewuenschten
Geschwindigkeit. Man beachte jedoch, dass die Umschaltung per Software
nicht den Speed-Umschalter an der SuperCPU ausser Kraft setzen kann.
Wie ist das moeglich?
Erinnern wir uns: Bevor die ersten Beschleunigerkarten fuer den C64
erschienen, wurde oft gesagt, eine solche Hardware werde es niemals
geben. Schliesslich konnte man ja selbst auf Commodores C128 im
C64-Modus nicht auf 2 MHz schalten, ohne dass dabei der VIC
ausgeschaltet werden musste. Dieses Problem existiert nach wie vor, und
hinzu kommt, dass der Grafik-Chip des C64 nicht auf RAM ausserhalb des
Computers direkt zugreifen kann. Das Problem wurde so geloest: Bei
jedem Schreib-Zugriff auf den Speicher der Turbokarte wird dieser auch
im Speicher des C64 ausgefuehrt (auf den der VIC ja problemlos
zugreifen kann). Dies kann aber nur im Takt von 1 MHz erfolgen. Dies
hoert sich schlimmer an als es ist, schliesslich muss nur fuer den Moment
des tatsaechlichen Schreibens heruntergeschaltet werden, was voll
automatisch passiert. So war es zumindest bei anderen Turbokarten,
tatsaechlich ist dies bei der SuperCPU noch eleganter geloest. Ohne dass
sich der Programmierer darum kuemmern muss, existiert ein
Cache-Byte. Bei einem STA landet das Byte im (schnellen statischen)
Speicher der SuperCPU, und im Cache-Byte. Danach wird sofort der
naechste Befehl abgearbeitet! Waehrenddessen wartet die SuperCPU-Logik
auf den internen 1 MHz-Takt des C64 und schreibt beim Taktsignal das
Cache-Byte an die Stelle wo es hingehoert. So kommt es zu keiner
Verzoegerung. Findet allerdings kurz danach ein weiterer Schreibzugriff
statt, und ist das Cache-Byte noch nicht geleert, muss der Prozessor
ein paar Waitstates einlegen. Von der ganzen Sache bekommt man als
Coder nichts mit, aber man muss es natuerlich wissen, um das Verhalten
der CMD-Karte zu durchschauen. Der Geschwindigkeitsverlust ist je nach
Programm unterschiedlich, jedoch wird in der Regel immer noch Faktor
10-15 erreicht. Leider ist die Doppel-Schreib-Prozedur ("Mirroring"
genannt) notwendig, da die SuperCPU ja nicht wissen kann, ob es sich
im Augenblick um Grafikdaten handelt, die der VIC spaeter lesen will
(z.B. aus Screenram, Bitmap oder Sprite-Area). Die CPU kann es nicht
wissen - aber als Programmierer weiss man es doch genau !
Noch schneller!
Es gibt naemlich die SuperCPU-Optimization-Modes. Damit kann man der
Karte mitteilen, welcher Speicherbereich gemirrored werden soll. Alle
Schreibzugriffe ausserhalb dieses Bereiches werden dann mit voller
Turbo-Geschwindigkeit ausgefuehrt ! Vor allem bei Neuentwicklungen
direkt fuer die SuperCPU kann man dadurch natuerlich jederzeit die
optimale Geschwindigkeit herausholen. Es gibt 4 Optimization-Modes,
die man mit einem STA auf das entsprechende Register aktiviert:
$4000-$8000 (VIC-Bank 1): $D075, $8000-$C000 (VIC-Bank 2): $D074,
$0400-$0800 (nur Standard Screen-Ram): $D076, keine Optimization
(gesamter Speicher wird gemirrort; default): $D077. Damit der
Schreibzugriff auf die entsprechende Speicherstelle auch seine Wirkung
tut, muss man mit einem STA $D07E die Register erst einschalten,
danach mit STA $D07F wieder aus (siehe oben). Fuer VIC-Bank 0 und 3
gibt es leider keine Optimization-Modes - laut CMD haette dies den
Platz in dem Logikchip gesprengt. Fuer SuperCPU-Projekte nimmt man
also am besten VIC-Bank 1 oder 2, oder, falls man keine Grafiken
braucht (z.B. bei Berechnungen) den Screenram-Optimization-Mode. Hat
man beispielsweise VIC-Bank 2 gemirrort, findet die oben beschriebene
Cache-Prozedur und die eventuell anfallenden Waitstates nur beim
Schreibzugriff auf diesen Speicherbereich ($8000-$C000) statt - alle
anderen Schreibzugriffe (die Lesezugriffe ja sowieso) werden mit
maximalem Speed abgearbeitet - Listing 1.4 zeigt anhand einer kleinen
Routine mit Rasterzeit-Anzeige die Unterschiede zwischen normaler
Geschwindigkeit, Turbo und Turbo mit Optimization Mode.
Irgendwann muss man natuerlich auf jeden Fall auf seinen
Grafik-Bereich zugreifen. Wenn man hier den minimalen
Geschwindigkeitsverlust beim Schreiben nicht in Kauf nehmen will oder
kann, sollte man durch geschicktes Coding das Cache-Byte in der
SuperCPU nutzen. Denn eine Verzoegerung tritt ja erst auf, wenn das
Cache-Byte noch nicht geschrieben wurde und ein neuer Schreibzugriff
erfolgt. Anstatt die SuperCPU nun warten zu lassen, kann man dies
selber tun und ein paar andere Befehle ausfuehren, die nicht auf den
Grafik-Bereich, sondern auf einen nicht gemirrorten Bereich
zugreifen. Dies geschieht bei vollem Speed. Waehrenddessen wird von
der Logik auf der Turbokarte in Ruhe das Cache-Byte zum C64
uebertragen. Dies dauert im unguenstigsten Fall etwa 16 (20 MHz!)
Taktzyklen, in denen man beispielsweise diverse Berechnungen oder
sonstiges ausfuehren lassen kann. Probieren Sie's einfach aus - die
eben geschilderte Methode wird nur dann moeglich, wenn man wirklich
extrem viel Rechenzeit braucht, in den allermeisten Faellen reicht die
Geschwindigkeit voll aus. Aber es ist immer ein gutes Gefuehl, zu
wissen, wie man noch mehr herausholen kann...
Im naechsten Kursteil werden wir den 65816-Prozessor genauer unter die
Lupe nehmen. Der ist naemlich nicht nur schnell und kompatibel,
sondern bietet darueber hinaus noch eine Menge neuer Opcodes, die
einem das Leben erleichtern und die Programme noch weiter
beschleunigen.
(w) Malte Mundt
©1999 Go64 Redax! & Count Zero/SCS*TRC for all HTML Stuff
[ Zum Index ][ Zum 2. Teil ]