IRQ-KURS "Die Hardware ausgetrickst..." (Teil 16)
Herzlich Willkommen zum 16 . Teil unseres
Kurses über die Rasterstrahlprogrammierung. In den letzten beiden Kursteilen
hatten wir uns mit zwei IRQ-Routinen
beschäftigt, die das hardwaremässige
Scrollen des Bildschirms jeweils in der
Horizontalen ( HSP-Routine) und Vertikalen ( VSP-Routine) ermöglichten. Der Clou
an diesen beiden Routinen war, daß des
GESAMTE Bildschirm vom VIC verschoben
wurde, und wir keinen einzigen Taktzyklus zum Kopieren von Bildschirmdaten
verschwenden mussten. In diesem Kursteil
wollen wir nun das " Sahnestückchen" der
Raster-IRQ- Programmierung besprechen:
die Kombinattion aus HSPund VSP-Routine, genannt " AGSP" . Diese Abkürzung
steht für " Any Given Screen Position" und bedeutet, daß der Bildschirm in jede Richtung verschoben werden kann, und das
natürlich HARDWAREMÄSSIG, also wie schon
bei HSP und VSP ohne auch nur einen Zyklus zum Kopieren von Bildschirmdaten zu
verschwenden!
Stellen Sie sich vor, was für Möglichkeiten sich hierdurch für Spiele ergeben: so kann man z. B. problemlos Spiele
programmieren, die sich über einer beliebig großen Oberfläche abspielen, die
in alle Richtungen flüssig gescrollt
werden kann, ohne dabei mehr als 30 Rasterzeilen pro Frame zu verbrauchen.25 Rasterzeilen lang ist der Prozessor eigentlich nur mit dem Abpassen der optimalen Rasterstrahlpostion für den HSP-Effekt beschäftigt, der, wie wir schon
im 14 . Kursteil sehen konnten, pro Charakterzeile, die der Bildschirm horizontal gescrollt werden soll, eine Rasterzeile für das Timing verbraucht.
Damit Sie sehen, was mit der AGSP-Routine alles möglich ist, haben wir
Ihnen natürlich wieder zwei Beispielpro- gramme vorbereitet. Sie heissen " AGSP1" und " AGSP2" und werden wie immer mit
",8,1" geladen und durch ein " SYS4096" gestartet. Desweiteren finden Sie auf
dieser MD eine Demo mit Namen " AGSP-Demo", in der am eindrucksvollsten die
Möglichkeiten der AGSP-Routine demonstriert werden. Sie sehen hier einige
Hiresgrafiken, die in Sinuswellenform
aufund abschwingen und gleichzeitig
von links nach rechts scrollen. Hierbei
werden jeweils neue Grafiken in die Grafik einkopiert, so daß der Eindruck entsteht, daß der Bildschirm weitaus größer
sei, als eigentlich sichtbar. Das Demo
laden Sie mit LOAD" AGSP-DEMO",8 und
starten es durch " RUN" .
1) DAS AGSP-PRINZIP Kommen wir nun also zum Arbeitsprinzip
von AGSP, das eigentlich recht schnell
erläutert ist: Zunächst einmal passen
wir die erste Rasterzeile des Bild- schirms ab, an der die erste Charakterzeile gelesen werden muß. Hier nun lassen wir eine VSP-Routine, so wie wir Sie
im letzten Kurteil schon kennenlernten, zunächst dem VIC vorgaugeln, daß er auf
den Beginn der Charakterzeile noch zu
warten hat, indem wir eine horizontale
Bildschirmverschiebung um 1 Pixel in
$ D011 angeben. Inmitten dieser Zeit soll
nun die VSP-Routine diese Verschiebung
wieder Aufheben, um so den VIC sofort
die Charakterdaten lesen zu lassen, und
ihn somit dazu zu zwingen, den Bildschirm nach rechts versetzt darzustellen. Die Anzahl Taktzyklen, die bis zum
Zurückschalten verzögert werden müssen, muß dabei der Anzahl Zeichen entsprechen, die der Bildschirm verschoben werden soll. Hieran anschließend lasen wir
eine HSP-Routine folgen, die den Beginn
der nächsten Charakterzeilen vor dem VIC
herdrückt, um so auch die zeilenweise
Verschiebung des Bildschirmanfangs zu
erreichen. Da diese Routine maximal 25
Rasterzeilen benötigt ( nämlich dann, wenn die Darstellung erst 25 Charakterzeilen später beginnen soll, müssen die
ersten 25 Rasterzeilen des sichtbaren
Bildschirms immer für das Timing der
AGSP-Routine verwendet werden, auch wenn
stellenweise weniger Rasterzeilen dazu
benötigt werden ( z. B. wenn nur eine Zeile Verschiebung erzeugt werden muß) . Für
diese Fälle müssen wir mit Hilfe einer
normalen FLD-Routine den Bildschirm um
die fehlende Anzahl Rasterzeilen nach
unten drücken, damit der Bildschirm auch
immer in ein und derselben Rasterzeile
beginnt. Diese FLD-Routine wird in unserem Programmbeispiel den VSPund HSP-Routinen vorgeschaltet. Sie sorgt also
gleichzeitig für immer gleiches Timing
und zudem für die richtige Positionierung in der Horzontalen. Aus diesem
Grund sind dann die ersten 25 Rasterzeilen des Bildschirms auch nicht zum Darstellen von Bildschirmdaten verwendbar.
In unserem Programmbeispielen haben wir hier jedoch Sprites untergebracht, in
denen die Scrollrichtung angezeigt wird.
In einem Spiel könnte sich hier z. B.
auch eine Score-Anzeige befinden.
2) DAS PROGRAMM Wollen wir uns nun die Funktionsweise
von AGSP anhand des Programmbeispiels
" AGSP1" anschauen. Die Routinen zur Joystickabfrage und Scrollgeschwindigkeitsverzögerung sollen hier nicht Thema unseres Kurses sein, sondern lediglich die
Routine, die uns den Bildschirm beliebig
im sichtbaren Fenster positioniert. Zur
angesprochenen Scrollgeschwindigkeitsverzögerung sei erwähnt, daß wir hier
beim Drücken und Loslassen des Joysticks
die Scrollrichtung verzögern, bzw. nachlaufen lassen, so daß der Scrolleffekt
zunächst träge anfängt und beschleunigt
und beim Loslassen erst abgebremst werden muß, bis er zum Stillstand kommt.
Die Initialisierungsroutine zu AGSP1 bei$1000 legt nun zunächst einen Border-IRQ
in Zeile $ FB fest, wobei, wie schon so
oft in unseren Beispielen, der Hard-IRQ- Vektor bei $ FFFE/$ FFFF benutzt wird.
Diese Border-Routine ( bei $1400) schaltet nun den oberen und unteren Bildschirmrand ab und initialisiert einen
Raster-IRQ für Rasterzeile $18, wobei
dann unsere eigentliche IRQ-Routine
" AGSP" angesprungen wird. Sie befindet
sich an Adresse $1200 und soll im nun
Folgenden ausführlich beschrieben werden. Die AGSP-Routine soll nun der Reihe
nach folgende Arbeiten verrichten:
* Verwaltung des Sprite-Scoreboards, das
aus zwei Spritereihen zu je acht Sprites
bestehen soll.
* Glätten des IRQs, um ein möglichst
exaktes Timing zu bewirken.
* FLD-Routine benutzen, um die fehlenden
Rasterzeilen, die von VSP ggf. nicht
benötigt werden, auszugleichen
* VSP-Routine charakterweisen zum hoch- und runterscrollen des Bildschirms einsetzen
* HSP-Routine zum charakterweisen linksund rechtsscrollen des Bildschirms einsetzen
* horizontales und vertikales Softscrolling zur exakten Bildschirmverschiebung
durchführen
a) DIE SPRITELEISTE Kommen wir nun also zum ersten Teil der
AGSP-Routine, die zunächst das Sprite-Scoreboard verwaltet. Wir verwenden hier
zwei Sätze zu je acht Sprites, deren
Spritedaten in den Adressen von $0 C00-$1000 zu finden sein sollen ( Sprite-Pointer $30-$3 f) . Um die Pointer zwischen beiden leichter umschalten zu können benutzen wir zwei Video-RAM- Adressen. Für die erste Zeile, die eh in
einem unsichtbaren Bildbereich liegt, wird das Video-RAM an Adresse $0000 verschoben, so daß wir die Spritepointer in
den Adressen $03 F8-$03 FF liegen haben.
Für die zweite Spritezeile wird das Video- RAM an die ( normale) Adresse $0400 gelegt, womit wir die Spritepointer an
den Adressen $07 F8-$07 FF vorfinden. Dadurch, daß durch den VSP-Effekt auch
diese Spritepointer als einzelne Zeichen
auf dem Bildschirm auftauchen können, müssen wir die Pointer in jedem Rasterdurchlauf ( Frame) wieder neu setzen, da
die Pointer auf dem Bildschirm ja durchaus auch Bildschirmzeichen enthalten
können. Doch kommen wir nun endlich zum
Source-Code der AGSP-Routine, der in
seinem ersten Teil zunächst einmal die
Spriteinitialisierungen vornimmt und
eigentlich einfach zu verstehen sein
sollte:
agsp: pha ;IRQ-Beginn -> also txa ; Prozessorregs. pha ; retten tya pha lda #$1e ;Y-Position aller sta $d001 ; Sprites auf Raster- sta $d003 ; zeile $1E (dez. 30) sta $d005 ; setzen sta $d007 sta $d009 sta $d00b sta $d00d sta $d00f lda #$01 ;Die Farbe aller sta $d027 ; Sprites auf 1, also sta $d028 ; 'weiß' setzen sta $d029 sta $d02a sta $d02b sta $d02c sta $d02d sta $d02e
lda #$ ff ; Alle Sprites einsta $ d015 ; schalten lda #$80 ; Hi-Bit d. X-Pos. von sta $ d010 ; Sprite 8 setzen lda #$00 ; Sprite-Multicolor sta $ d01 c ; ausschalten
clc ;C-Bit f.Add. löschen lda #$58 ;XPos Sprite 0 sta $d000 ; setzen adc #$18 ;$18 (dez.24) add. sta $d002 ; u. XPos Spr.1 setz. adc #$18 ;$18 (dez.24) add. sta $d004 ; u. XPos Spr.2 setz. adc #$18 ;usw. sta $d006 adc #$18 sta $d008 adc #$18 sta $d00a adc #$18 sta $d00c adc #$18 ;$18 (dez.24) add. sta $d00e ; u. XPos Spr7 setz.
Bis hierhin hätten wir nun die wichtigsten Spritedaten initialisiert. Dadurch, daß diese in jedem Frame neu gesetzt werden, können Sie im AGSP-Bereich problemlos auch noch acht weitere Sprites
sich bewegen lassen. Sie müssen deren
Spritedaten dann nur am Ende der AGSP-Routine wieder in die VIC-Register einkopieren. Nun folgt noch die Initialisierung der Spritepointer. Zunächst die
für die Sprites der ersten Spritezeile, deren Pointer ja im Video-RAM ab Adresse
$0000 untergebracht sind, und sich somit
in den Adressen von $03 f8-$03 ff befinden. Anschließend werden die Spritepointer für die zweite Spritereihe eingetragen, die sich im normalen Bildschirmspeicher bei $0400, in den Adressen
$07 f8-$07 ff befinden. Das abschließende
schreiben des Wertes 3 in Register $ DD00 stellt sicher, daß der 16 K-Adressbereich
des VICs auf den unteren Bereich, von
$0000 bis $3 FFF, gelegt ist:
ldx #$30 ;Spr.Pointer Spr0=$30 stx $03f8 ; bis Spr7=$37 in inx ; die Pointeradressen stx $03f9 ; $03F8-$03FF ein- inx ; tragen stx $03fa inx stx $03fb inx stx $03fc inx stx $03fd inx stx $03fe inx stx $03ff inx ;Spr.Pointer Spr0=$38 stx $07f8 ; bis Spr8=$3F in inx ; die Pointeradressen stx $07f9 ; $07F8-$07FF ein- inx ; tragen stx $07fa inx stx $07fb inx stx $07fc inx stx $07fd inx stx $07fe inx stx $07ff
lda #$03 ; VIC-Adressraum auf sta $ dd00 ;$0000-$3 FFF schalt.
b) DAS GLÄTTEN DES IRQS Der nun folgende Teil der AGSP-Routine
ist für das Glätten des IRQs verantwortlich. Ausserdem wird hier der Border-IRQ
wieder als nächste IRQ-Quelle festgelegt, womit diese Arbeit nun auch erledigt wäre:
dec $d019 ;IRQ-ICR freigeben lda #$1d ;Nächster Raster-IRQ sta $d012 ; bei Zeile $1D lda #<irq2 ;Adresse Glättungs- sta $fffe ; IRQ in $FFFE/$FFFF lda #>irq2 ; eintragen sta $ffff cli ;IRQs erlauben
ch: nop ; Insgesamt 23 NOPs, in
... ; denen der Glättungs- nop ; IRQ ausgelöst wird bne ch
Beachten Sie bitte, daß das Programm
hier nicht mehr normal fortgesetzt wird, sondern daß innerhalb der 23 NOPs auf
den Glättungs-IRQ bei " IRQ2" gewartet
wird. Selbiger folgt gleich diesem
Stückchen Source-Code, wobei ihm ein
RTS-Befehl vorangestellt ist, der mit
dem Label " Cycles" assoziiert wird. Dieser RTS-Befehl wird später im AGSP-IRQ
desöfteren zum Verzögern angesprungen.
Zusammen mit dem aufrufenden JSR-Befehl
werden so 12 Taktzyklen verbraucht ( je
Befehl 6 Zyklen) :
cycles:
rts ; Verzög.- Unterroutine
irq2:pla ;(IRQ-) Prozessorstatus pla ; und Rücksprungadresse pla ; vom Stapel werfen dec $d019 ;VIC-ICR freigeben lda #$f8 ;Nächster Raster-IRQ sta $d012 ;bei Zeile $F8 lda #<border;Adresse der Border-IRQ sta $fffe ; -Routine in Vektor lda #>border; bei $FFFE/$FFFF ein- sta $ffff ; tragen lda #$c8 ;40-Zeichen-Darst. sta $d016 ; einschalten lda #$06 ;Video-RAM nach $0000 sta $d018 ; verschieben (für Spr. Pointer 1.Spr.Zeile, sh. oberste 4 Bits!) nop ;verzögern
lda $ d012 ; Und den letzten Taktcmp #$1 d ; Zyklus korrigieren beq line ;( IRQ-Glättung)
line: lda #$00
. . .
c) DIE FLD-ROUTINE Nun folgt der wichtige Teil der AGSP-Routine. Zunächst einmal noch ein wenig
Verwaltungsarbeit. Wir setzen hier den
Bildschirmbereich, in dem das VSP-Timing
unergebracht ist auf schwarz und setzen
schon einmal die Y-Positionen der Sprites für die zweite Spritezeile des Scoreboards ( wie Sie aus unseren Kursteilen
über die Spriteprogrammierung wissen, so
wird die neue Y-Koordinate erst dann vom
VIC übernommen, wenn die ersten Sprites
fertig gezeichnet sind - somit können
wir die neuen Koordinaten irgendwann
setzen, wenn der VIC die alten Sprites
noch zeichnet - was hier der Fall ist) :
line lda #$00 ; Bildschirm und Rahsta $ d020 ; mein auf ' schwarz' sta $ d021 ; schalten
jsr cycles ;3*12=36 Zyklen jsr cycles ; verzögern jsr cycles bit $ea ;3 Zyklen verz. ldy #$1e+21;YPos=YPos+21 sty $d001 ; und für die Spr0- sty $d003 ; Spr7 setzen sty $d005 sty $d007 sty $d009 sty $d00b sty $d00d sty $d00f
Nach diesen mehr organisatorisch wichtigen Aufgaben folgt nun die FLD-Routine, die das Timing zur VSP-Routine ausgleichen soll:
fld: ldx #$27 ; Max. Anz. FLD-Durchl.
ldy #$01 ; Index d011/ d018- Tab.
fldlp: jsr cycles ;12 Zyklen verz.
lda field1,y;Wert für $d011 holen sta $d011 ; und setzen lda field2,y;Wert für $d018 holen sta $d018 ; und setzen nop ;6 Zyklen verz. nop nop iny ;Tab-Index+1 dex ;FLD-Durchläufe-1 cpx <fldcnt ;=erforderliche Anz. bne fldlp ; Durchl.?Nein->Weiter nop ;Sonst 14 Zyklen jsr cycles ; verzögern lda field2,y;und letzten Wert für iny ; $d018 setzen sta $d018
( Anm. d. Red. : Bitte wählen Sie nun den 2 . Teil des Kurses aus dem Textmenu)