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 ]