Vier Pseudo-VICs mit 32 Sprites
Sie wollen mit 32 Sprites und vier Bildschirmbereichen gleichzeitig arbeiten? Nichts leichter als das. Mit Provic 64 können simultan Grafik, Text oder veränderte Zeichensätze dargestellt werden.

Die Autoren (Jürgen, 21, Physikstudent, und Stefan, 18, Schüler) haben sich Mitte 1983 einen Commodore 64 angeschafft. Schon nach kurzer Zeit stellte sich der bei den C 64-Fans übliche Frust über die schlechte Dokumentation und die schwierige Informationsbeschaffung ein, besonders wenn es um die speziellen Grafikfähigkeiten dieses Computers geht. So sitzen wir oft stundenlang vor dem Bildschirm, der nur undefinierbare Zeichen zeigt, weil wir bei dem Versuch, die Geheimnisse des C 64 zu enträtseln, in irgendeinen unbekannten Darstellungsmodus geraten sind.
Dabei entdeckten wir, daß der C 64 nicht nur acht, sondern auch 16, 24, 32 oder noch mehr Sprites gleichzeitig zeigen kann. Zusätzlich ergibt sich die Möglichkeit, mehrere Bildschirmmodi zu mischen.
Nun haben wir uns entschlossen, den Kunstgriff, der dies ermöglicht, anderen C 64-Fans nicht vorzuenthalten. Also entwickelten wir ein Programm in Maschinensprache und dazu ein kleines Demonstrationsprogramm in Basic.
Zum Programm
Durch Aufruf der Initialisierungsroutine wird der Interruptmechanismus des C 64 verändert. Nicht mehr der Timer der CIA 1, sondern der VIC 6567 löst jetzt den Interrupt aus, und zwar synchron zum Takt des Bildschirmsignals. Außerdem werden vier sogenannte Pseudo-VICs eingerichtet. Alle POKEs, von Spritebewegung über Bildschirmfarbe bis zur Grafikkonfiguration, müssen ab jetzt in diese Pseudo-VICs erfolgen. Jeder dieser Pseudo-VICs ist für einen der vier Bildschirmbereiche zuständig:
Der Bildschirm wird in vier waagerechte Bereiche aufgeteilt, deren Grenzlinien fast beliebig nach oben oder unten verschoben werden können. Jeder einzelne Bereich kann acht Sprites darstellen und eine eigene Farb- und Grafikkonfiguration aufweisen. So können zum Beispiel Normalschrift, HiRes-Grafik, Multicolor-Grafik und eventuell ein selbstdefinierter Zeichensatz gleichzeitig auf dem Bildschirm gezeigt werden.
Provic 64 kann selbstverständlich wieder abgeschaltet werden (bei Kassetten- oder Diskettenoperationen nötig).
Für Maschinensprachefreaks nun eine kurze Funktionsbeschreibung der Interruptroutine:
Bei Aufruf der Einschaltroutine (SYS 52544) wird der IRQ-Vektor auf die Hauptroutine des Provic 64 gestellt und der bisherige Interrupt durch den Timer A der CIA 1 verboten, während der Raster-IRQ des VIC 6567 erlaubt wird.
Sobald der Bildschirmstrahl die eingestellte Rasterzeile erreicht, wird ein Interrupt ausgelöst und der Prozessor bearbeitet die Hauptroutine des Provic 64. In dieser wird zunächst anhand eines Zählers ($ CFFF) festgestellt, welcher Bildschirmbereich an der Reihe ist. Dann wird die Rasterzeile, die das Ende dieses Bildschirms kennzeichnet, eingestellt.
Anschließend werden, falls ein entsprechendes Flag gesetzt ist, die Sprite- und andere Bildschirmparameter in den VIC 6567 übertragen. Nach dem Weiterzählen des IR-Zählers ($ CFFF) wird entweder der Interrupt beendet, oder zur IRQ-Routine des Betriebssystems gesprungen (nach jedem vierten Interrupt). So werden in der Sekunde 200 Interrupts (vier pro Fersehbild) ausgelöst und 50 mal in der Sekunde (einmal pro Bild) die normale IRQ-Routine abgearbeitet. Dadurch zählt die interne Uhr TI in 50stel Sekunden und Tl$ wird unbrauchbar.
Beim Aufruf der Ausschaltroutine wird der Raster-IRQ des VIC 6567 unterbunden, der Interrupt des Timers A in CIA 1 erlaubt und der IRQ-Vektor auf die IRQ-Routine des Betriebssystems eingestellt.
Handhabung der Pseudo-VICs
Im Grunde ist jeder der vier Pseudo-VICs wie der echte VIC zu behandeln. Ausnahmen sind hier nur die Register 30 (Sprite-Sprite-Kollision) und 31 (Sprite-Hintergrund-Kollision), die sich auf den jeweils vorausgegangenen Bildschirmbereich beziehen. Die Register 19 und 20 (Lightpenkoordinaten), sowie 25 und 26 (IRQ-Flags und -maske) werden nicht behandelt, da diese Funktionen nur direkt über den VIC 6567 sinnvoll gehandhabt werden können. Außerdem hat jeder Pseudo-VIC noch zusätzliche Register für zwei Flags (REG 47 und REG 57), acht Sprite-Pointer (REG 48 bis REG 55), Videomatrix-Anfangsadresse Highbyte (REG 56) und die CIA 2, REG 0, Bits 0 und 1 (REG 58) (Adreßbits 14 und 15 des VIC 6567).
Die vier Basisadressen der PVICs sind:
PVIC 1 | 52992 ($ CF00) | = REG 0 |
PVIC 2 | 53056 ($ CF40) | = REG 0 |
PVIC 3 | 53120 ($ CF80) | = REG 0 |
PVIC 4 | 53184 ($ CFC0) | = REG 0 |
Da die Pseudo-VICs praktisch gleichberechtigt sind, hier die Registerbeschreibung eines Pseudo-VICs:
REG 0: | X-Koordinate des Sprite 0 |
REG 1: | Y-Koordinate des Sprite 0 Beachte: Die Y-Koordinaten sollten im Bereich des zugehörigen Bildschirmbereichs liegen, sonst ist der Sprite nicht zu sehen. Näheres siehe unten. |
REG 2 bis 15: | Wie REG 0 und 1, aber für Sprites 1 — 7 |
REG 16: | MSB (höchstes Bit) der X-Koordinaten |
REG 17: | Bits 0 bis 2: Y-Abstand der Zeichen vom oberen Bildrand in Rasterzeilen (Softscrolling!) |
REG 17: |
|
REG 18: | Nummer der Rasterzeile Bits 0 — 7; hier ist anzugeben, wann der nächste Interrupt ausgelöst werden soll, das heißt wo der Bildschirmbereich dieses PVICs zu Ende sein soll. Dabei sollte folgende Reihenfolge eingehalten werden: REG 18: PVIC 1 < PVIC 2 < PVIC 3 <PVIC 4 (Zyklische Vertauschungen möglich!) |
REG 19 und 20: | nicht verwendet (siehe oben) |
REG 21: | Sprite enable (einschalten) |
REG 22: |
|
REG 23: | Sprite vergrößern in Y-Richtung |
REG 24: |
|
REG 25 und 26: | nicht verwendet (siehe oben) |
REG 27: | Sprite-Priorität vor Hintergrund |
REG 28: | Flags für Multicolor-Sprites |
REG 29: | Sprite vergrößern in X-Richtung |
REG 30: | Sprite-Sprite-Kollision |
REG 31: | Sprite-Hintergrund-Kollision Achtung: Geben die Kollisionen des vorangegangenen Bildschirmbereichs an: Findet im Bereich von PVIC 3 eine Kollision statt, wird dies im PVIC 4 registriert. Kollisionen im Bereich von PVIC 4 werden im PVIC 1 registriert. Dieses Register muß gelöscht werden, um neue Kollisionen anzeigen zu können! |
REG 32: | Rahmenfarbe |
REG 33 bis 36: | Hintergrundfarben 0 bis 3 |
REG 37 und 38: | Multicolor-Sprite-Farben 0 und 1 |
REG 39 bis 46: | Farben für Sprites 0 bis 7 |
REG 47: | Flag für Spritebehandlung; nur wenn der Inhalt dieses Registers nicht Null ist, werden die Register, die etwas mit Sprites zu tun haben, vom PVIC in den VIC 6567 übertragen. Das sind REG 0 bis REG 16, REG 21, REG 23, REG 27 bis REG 31, REG 37 bis 46 sowie REG 48 bis 55. Ist der Inhalt Null, gelten für die Sprites die Werte des vorherigen PVICs, während die Kollisionen erst im nächsten PVIC, in dem REG 48 ungleich Null ist, angezeigt werden. |
REG 48 bis 55: | Sprite-Pointer für Sprites 0 bis 7; Die Pointer auf die Bitmuster der Sprites werden nicht mehr in die Speicherzellen 2040 bis 2047 geschrieben, sondern in diese Register des PVICs. |
REG 56: | In diesem Register muß das Highbyte der Video-RAM-Anfangsadresse plus 3 stehen; normalerweise also 4 + 3 = 7 (da der Bildschirm nach dem Einschalten des Computers bei 1024 beginnt, 1024 = $ 0400). Bei Verlegung des Video-RAMs ist also der Inhalt dieses Registers zu korrigieren. |
REG 57: | Flag für Bildschirmparameter-Behandlung; nur wenn der Inhalt dieses Registers nicht Null ist, werden die REG 17, 22, 24, sowie 32 bis 36 und REG 58 in den VIC 6567 übertragen. |
REG 58: | Bits 0 und 1: Adressbits 14 und 15 des VIC 6557; werden nach CIA 2 REG 0 Bits 0 und 1 übertragen. Mit diesen Bits kann Video-RAM, Charaktergenerator, Grafik-Bitmap in 16-KByte- Schritten verschoben werden. Da die Bits low- aktiv sind, sind sie beim Einschalten gesetzt (also REG 58 = 3). Bits 2 bis 7: unbenutzt, immer 0. |
Übergang eines Sprites zwischen zwei Bildschirmbereichen:
Soll ein Sprite zwischen zwei Bildschirmbereichen wechseln, muß in beiden Bereichen derselbe Sprite (also zum Beispiel beidesmal Sprite 4) die gleiche Position besitzen, und zwar so lange, wie der Sprite die Trennlinie zwischen den Bereichen überdeckt. Wird dies nicht beachtet, werden die entsprechenden Sprites zerschnitten und verschoben.
Aktivieren von Provic 64: Von Basic aus mit SYS 52544 und von Maschinensprache aus mit JSR $CD40.
Ausschalten von Provic 64: Von Basic aus mit SYS 52970 und von Maschinensprache aus mit JSR $CEEA.
Der Basic-Lader:
Der Lader erzeugt Provic 64 aus den DATA-Zeilen und falls kein Prüfsummenfehler vorliegt, wird Provic 64 sofort als Maschinenprogramm auf Floppy oder Datasette (Zeile 400 entsprechend ändern!) abgespeichert. Dieses Maschinenprogramm enthält auch gleich die Standardwerte der Pseudo-VICs.
Laden von Provic 64: Im Programm am besten mit der Zeile IF PEEK(52544)><120 THEN LOAD "PROVIC64",Gerätenummer, 1 die am Anfang des Basic-Programms stehen sollte.
Das Demonstrationsprogramm zeigt einige der Vorzüge von Provic 64. Es ist nur als Anregung gedacht, deshalb verzichten wir hier auf eine nähere Beschreibung.
Provic 64 ist nicht nur für Basic-Programmierer, sondern vor allem auch für Maschinensprache-Freaks gedacht, da erst durch schnelle Maschinenprogramme die Möglichkeiten von Provic 64 voll ausgeschöpft werden können.
(Jürgen und Stefan Haas/rg)
$CD40 | Einschaltroutine |
$CD58 | Interruptroutine |
$CEEA | Ausschaltroutine |
$CF00 | Pseudo-VIC 1 |
$CF40 | Pseudo-VIC 2 |
$CF80 | Pseudo-VIC 3 |
$CFCO | Pseudo-VIC 4 |
$CFFF | Interruptzähler |
- in Basic: SYS 52544
- in Maschinensprache: JSR $CD40
- in Basic: SYS 52970
- in Maschinensprache JSR $CEEA
- in der Zero-Page: 187 ($BB)
- 188 ($BC)
alle Spriteflags (REG 47) und Bildschirmparameterflags (REG 57) gelöscht: | + 2,5% |
für jedes gesetzte Spriteflag (REG 47): | zirka + 2,4% |
für jedes gesetzte Bildschirmflag (REG 57): | + 0,5% |
alle Sprite- und Bildschirmflags gesetzt: | zirka + 15,0% |
- Falls der Rechner abstürzt rettet Run-Stop/Restore!
- Die Zeitvariable Tl zählt bei aktiviertem Provic 64 in 50stel Sekunden (statt 60stel);
- TI$ wird somit unbrauchbar.
- Zeiger für Interruptaussprung von PVIC 3 bis PVIC 4: $CEE5
- Zeiger für Interruptaussprung von PVIC 1: $CEE8
10 rem interrupt-routine zur erzeugung 11 rem 12 rem eines maximal vierteiligen 13 rem 14 rem bildschirmes und 32 sprites 15 rem 16 rem auf einem commodore 64 computer 17 rem 18 rem 1984 by gebr. haas 19 rem 100 rem pruefsummen-kontrolle 101 rem 110 restore:ps=0 120 fora=0to511 130 read wert 140 ps=ps+wert 150 nexta 160 ifps<>60913thenprint"data-pruefsumme falsch !":end:* 199 rem 200 rem maschinencode uebertragen 201 rem 210 restore 220 fora=0to447 230 read wert 240 poke52544+a,wert 250 nexta 260 fora=0to63 265 read wert 270 forb=0to3 280 poke52992+b*64+a,wert 290 poke52992+b*64+18,95+50*b 295 nextb,a 299 rem 300 rem provic 64 abspeichern 301 rem 310 n$="provic 64" 320 fora=1tolen(n$) 330 poke49151+a,asc(mid$(n$,a,1)) 340 nexta 350 poke183,len(n$) 360 poke187,0:poke188,192 370 poke185,1 380 poke193,64:poke194,205 390 poke174,0:poke175,208 400 poke186,8: rem fuer floppy : 8 fuer datasette: 1 410 sys62957: rem save routine 420 end 999 rem 1000 rem provic 64 maschinencode 1001 rem 1002 data120,169,88,162,205,141,20,3,142,21,3,169,1,141,13,220,141,26,208 1003 data141,255,207,88,96,169,1,141,25,208,172,255,207,240,15,136,240,9,136 1004 data240,3,162,192,44,162,128,44,162,64,44,162,0,189,18,207,141,18,208 1005 data189,47,207,208,3,76,141,206,173,30,208,29,30,207,157,30,207,173,31 1006 data208,29,31,207,157,31,207,189,21,207,141,21,208,189,23,207,141,23 1007 data208,189,29,207,141,29,208,189,0,207,141,0,208,189,1,207,141,1,208 1008 data189,2,207,141,2,208,189,3,207,141,3,208,189,4,207,141,4,208,189,5 1009 data207,141,5,208,189,6,207,141,6,208,189,7,207,141,7,208,189,8,207,141 1010 data8,208,189,9,207,141,9,208,189,10,207,141,10,208,189,11,207,141,11 1011 data208,189,12,207,141,12,208,189,13,207,141,13,208,189,14,207,141,14 1012 data208,189,15,207,141,15,208,189,16,207,141,16,208,189,27,207,141,27 1013 data208,189,28,207,141,28,208,189,37,207,141,37,208,189,38,207,141,38 1014 data208,189,39,207,141,39,208,189,40,207,141,40,208,189,41,207,141,41 1015 data208,189,42,207,141,42,208,189,43,207,141,43,208,189,44,207,141,44 1016 data208,189,45,207,141,45,208,189,46,207,141,46,208,189,56,207,133,188 1017 data169,248,133,187,160,0,189,48,207,145,187,200,189,49,207,145,187,200 1018 data189,50,207,145,187,200,189,51,207,145,187,200,189,52,207,145,187 1019 data200,189,53,207,145,187,200,189,54,207,145,187,200,189,55,207,145 1020 data187,189,57,207,240,67,189,58,207,41,3,157,58,207,173,0,221,41,252 1021 data29,58,207,141,0,221,189,17,207,141,17,208,189,22,207,141,22,208,189 1022 data24,207,141,24,208,189,32,207,141,32,208,189,33,207,141,33,208,189 1023 data34,207,141,34,208,189,35,207,141,35,208,189,36,207,141,36,208,224 1024 data192,208,5,169,255,141,255,207,238,255,207,138,240,3,76,129,234,76 1025 data49,234,120,169,49,162,234,141,20,3,142,21,3,169,129,141,13,220,169 1026 data0,76,80,205,234,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,95,0,0,0,200 1027 data0,21,121,240,0,0,0,0,0,14,6,1,2,3,4,0,1,2,3,4,5,6,7,8,0,0,0,0,0,0 1028 data0,0,0,7,1,3,0,0,0,0,0
6 rem dieses kurze demo-programm soll 8 rem ein paar darstellungsformen 10 rem zeigen, wie sie mit provic-64 12 rem relativ einfach erreichbar sind. 14 rem 1984 by gebr. haas 19 rem 20 rem laden der provic-64 routine 21 rem 30 ifpeek(52544)=120then100 40 print"{down}{down} auf welchem datentraeger ist provic-64" 50 print"{down} verfuegbar ( floppy =8 / datasette =1 )" 60 input" ";a$:a=val(a$) 70 if a<>1 and a<>8 then40 80 load"provic 64",a,1 99 rem 100 rem pseudo-vic's initialisieren 101 rem 110 p1=52992:p2=53056:p3=53120:p4=53184:rem basisadressen der pseudo-vic's 120 pokep1+21,255:pokep1+24,22:pokep1+47,1:pokep1+27,255:pokep2+21,255 130 pokep2+17,59:pokep2+24,24:pokep2+32,7:pokep2+47,1:pokep2+27,255 140 pokep3+21,255:pokep3+32,9:pokep3+47,1:pokep3+27,255:pokep4+32,5 150 pokep4+21,255:pokep4+24,22:pokep4+47,1:pokep4+18,230:pokep4+27,255 199 rem 200 rem sprite-daten uebertragen 201 rem 210 restore 220 fora=0to126 230 read wert 240 poke832+a,wert 250 nexta 299 rem 300 rem bilschirm aufbauen 301 rem 310 print"{clr}{wht}{down}{rvon}{rght}{rght}{rght}{rght}{rght}{rght}{rght}P{$a0}R{$a0}O{$a0}V{$a0}I{$a0}C{$a0}{$a0}{$a0}6{$a0}4{$a0}{$a0}{$a0}D{$a0}E{$a0}M{$a0}O" 320 print"{down}{down} In diesem Bereich: GROSS/klein-Schrift{down}": 330 fora=0to7:print"{blu}rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr{wht}";:nexta 335 fora=0to14:poke1289+a,34:nexta 340 print" ^ dort oben: hires-grafik-modus ^" 350 print"{down} hier: gross-schrift/grafik" 360 print"{down} QWERTYUIO{SHIFT-@}{SHIFT-*}~LKJHFSAZXCVBNM{CBM-Q}{CBM-W}{CBM-E}{CBM-R}{CBM-T}{CBM-F}{CBM-G}{CBM-Z}{CBM-X}{CBM-C}{CBM-V}{CBM-B}" 370 print"{down}{down}{down}{down}{down} ^ Dort oben: Laufschrift ^{up}{up}{up}":printtab(6); 390 sys52544:rem provic-64 activieren 399 rem 400 rem hires-grafik zeichnen 401 rem 410 fora=10110to12360:pokea,0:nexta 420 fora=0to8*~step.08 430 x=3+a/.08:y=77-11*sin(a)-9*cos(a/.7) 440 av=8192+320*int(y/8)+(y and7)+8*int(x/8) 450 pokeav,peek(av) or 2^(7-(x and 7)) 460 nexta 470 la$="*** von HaasiSoft *** Fuer das 64'er Magazin " 480 la$=la$+"*** P{$a0}R{$a0}O{$a0}V{$a0}I{$a0}C{$a0}{$a0}{$a0}6 4 " 490 la$=la$+left$(la$,25):r=53266 499 rem 500 rem demonstratins-schleife 501 rem 510 rem sprites setzen 511 rem 520 fora=0to7 530 pokep1+2*a,30+24*a+7*rnd(1):pokep1+2*a+1,60+6*rnd(1) 540 pokep1+39+a,rnd(1)*16:pokep1+48+a,13.5+rnd(1) 550 pokep2+2*a,30+24*a+7*rnd(1):pokep2+2*a+1,110+6*rnd(1) 560 pokep2+39+a,rnd(1)*16:pokep2+48+a,13.5+rnd(1) 570 pokep3+2*a,30+24*a+7*rnd(1):pokep3+2*a+1,160+6*rnd(1) 580 pokep3+39+a,rnd(1)*16:pokep3+48+a,13.5+rnd(1) 590 pokep4+2*a,30+24*a+7*rnd(1):pokep4+2*a+1,207+6*rnd(1) 600 pokep4+39+a,rnd(1)*16:pokep4+48+a,13.5+rnd(1) 610 nexta 619 rem 620 rem laufschrift setzen 621 rem 625 forlp=1tolen(la$)-25 630 lz=lz-1:iflz>0thenpokep4+22,lz or 8:fora=0to9:nexta:goto630 640 printtab(6);:wait53265,128:wait53266,64:poke53206,15:printlf$:print"{up}{up}" 660 lz=7:lf$=mid$(la$,lp,25) 670 nextlp 680 geta$:ifa$=""then500 690 sys52970:rem provic-64 desaktivieren 999 rem 1000 rem sprite-daten 1001 rem 1002 data0,0,0,0,126,0,1,255,128,7,255,224,15,255,240,15,253,240,31,255,248 1003 data31,255,248,63,255,252,63,255,252,63,243,252,63,252,0,63,255,252,63 1004 data255,252,31,255,248,31,255,248,15,255,240,15,255,240,7,255,224,1,255 1005 data128,0,126,0,0,0,0,0,0,126,0,1,255,128,7,255,224,15,255,240,15,251 1006 data240,31,255,248,31,255,248,63,255,240,63,255,0,63,240,0,63,252,0,63 1007 data255,0,63,255,224,31,255,248,31,255,248,15,255,240,15,255,240,7,255 1008 data224,1,255,128,0,126,0