Magic Disk 64

home to index to text: MD9409-KURSE-IRQ-KURS_11.1.txt
                IRQ-KURS                
     "Die Hardware ausgetrickst..."     
                (Teil 11)               

Herzlich Willkommen zum elften Teil unseres IRQ-Kurses. Wie schon in den letzten Kursteilen, werden wir uns auch diesen Monat mit der Spriteprogrammierung der besonderen Art beschäftigen. Es soll um einige Tricks gehen, mit denen man den Bildschirm auch über alle Ränder hinaus mit Gafikdaten füllen kann. Diesen Effekt nennt man " ESCOS", der Drehund Angelpunkt für die Rastertricks in diesem Kursteil sein wird.
1) UNSER ZIEL In früheren Kursteilen hatten wir ja schon einmal besprochen, auf welche Art und Weise oberer und unterer, sowie linker und rechter Bildschirmrand abgeschaltet werden. Wir hatten weiterhin gelernt, daß in diesen Bereichen ausschließlich Sprites auftauchen können, die durch die abgeschalteten Ränder sichtbar sind, wo sie sonst von letzteren überdeckt werden. Wir hatten ebenso eine Möglichkeit kennengelernt, beide Ränder, die horizontalen und vertikalen, gleichzeitig abzuschalten, wobei wir auf sehr exaktes Timing achten mussten, da das Abschalten der linken und rechten Bildschirmbegrenzung eine hohe Genauigkeit erforderte. Desweiteren wird Ihnen aus dem letzten Kursteilen bestimmt noch die Sprite-Multiplexer- Routine in Kombination mit einem Moviescroller im Kopf sein, mit der wir 104 Sprites gleichzeitig auf den Bildschirm brachten. Wie Sie sich vielleicht erinnern, waren wir dabei an gewisse Grenzen gebunden. So war z. B. zwischen zwei Spritezeilen immer ein Abstand von ca.2 Rasterzeilen erforderlich, die wir benötigten, um die Spritepointer sowie die neuen Y-Positionen der Sprites zu setzen. Des- weiteren mussten wir ein komplizierte Timingroutine benutzen, die zwischen Charakterzeilen ( jede achte Rasterzeile, in der der VIC den Prozessor für eine Dauer von 42 Taktzyklen anhält) und normalen Rasterzeilen zu unterscheiden hatte. In dieser Folge unseres Kurses wollen wir nun all diese Komponenten miteinander verbinden und eine Möglichkeit kennenlernen, Timingprobleme durch Charakterzeilenberücksichtigung, zu umgehen. Das Endergebnis wird ein flächendeckend ( !) mit Sprites belegter Bildschirm sein, wobei weder Leerräume zwischen den Sprites, noch im gesamten Bildschirmrahmen zu sehen sein werden!
Wir werden also über eine Grafik verfügen, die, ähnlich einem Fernsehbild, die gesamte Bildröhrenfläche ausfüllt!
2) ERSTES PROBLEM: DAS TIMING Kommen wir gleich zum Kern dieses Kursteils, dem Timing-Problem, das sich uns entgegenstellt. Möchten wir nämlich alle Bildschirmränder abschalten und gleichzeitig auch noch die Sprites multiplexen, so können wir programmtechnisch in " Teufels Küche" gelangen. Wir müssten berücksichtigen, daß im sichtbaren Bildschirmfenster alle acht Rasterzeilen eine Chakaterzeile auftritt, gleichzeitig müsste in jeder Rasterzeile der linke und rechte Bildschirmrand abgeschaltet, sowie in jeder 21 . Rasterzeile die Sprites neu positioniert werden. Dabei stellen vor allem die Charakterzeilen ein großes Problem dar. Wir müssten unterscheiden zwischen Rasterstrahlpositionen im oberen und unteren Bildschirmrand und innerhalb des sichtbaren Bildschirmfensters, und zudem noch für letzteren Fall berücksichtigen, wann sich der VIC gerade in einer Chakaterzeile befindet und wann in einer normalen Rasterzeile. Dieses Problem stellte sich bei unseren Raster-Effekten nun schon häufiger in den Weg, wobei wir es meist durch einen einfachen Trick umgingen: in der Regel benutzten wir in solchen Fällen eine FLD-Routine, die die Charakterzeile im fraglichen Bildschirmbereich einfach nach unten " wegdrückte", so daß wir in jeder Rasterzeile 63 Taktzyklen zur Verfügung hatten und somit ein einheitliches Timing programmieren konnten.
Wir könnten diesen Effekt hier nun auch anwenden, jedoch gibt es speziell für diese Anwendung einen weiteren, viel einfacherern Trick, die Charakterzeilen zu umgehen: da wir ja den gesamten Bildschirm mit Sprites füllen möchten, können wir davon ausgehen, daß wir keinerlei Hintergrundgrafik, bzw. Textzeichen benötigen. Es gibt nun einen Trick, den wir noch nicht kennengelernt haben, mit dem wir die Charakterzeilen ganz abschalten können, so daß nur noch die Sprites dargestellt werden. Wie fast immer ist Register $ D011, ein Drehund Angelpunkt der VIC-Trickeffekt- Kiste, für diesen Trick verantwortlich. Mit Bit4 dieses Registers können wir nämlich den gesamten Bildschirm abschalten, was einer Deaktivierung des VICs gleichkommt. Er wird durch das Löschen dieses Bits veranlasst, auf dem gesamten Bildschirm nur noch die Rahmenfarbe darzustellen, und keine Charakterzeilen mehr zu lesen. Die Sprites bleiben jedoch weiterhin aktiv, obwohl sie jetzt unsichbar sind, da sie jetzt auf dem gesamten Bildschirm mit dem Rahmen überdeckt werden. Man könnte das Setzen und Löschen des 4 . Bits von Register $ D011 quasi mit dem Üffnen und Schließen eines Vorhangs vor einem Fenster vergleichen:
Eine Fliege ( oder unser Sprite), die sich auf der Fensterscheibe befindet, ist bei geschlossenem Vorhang nicht sichtbar. Ist letzterer jedoch geöffnet, so sieht man die Fliege, solange sie sich im sichtbaren Bereich des Fenster bewegt, und nicht unter den seitlich aufgerafften Vorhängen verschwindet.
Nun, selbst wenn die Sprites noch aktiv sind, so nutzen Sie uns herzlich wenig wenn sie unsichtbar sind. Deshalb gilt es mal wieder, den VIC auszutricksen, um das gewünschte Ergebnis zu erhalten.
Dies gestaltet sich in diesem Fall recht einfach: Zunächst einmal schalten wir an einer Rasterposition, an der der VIC normalerweise den oberen oder unteren Bildschirmrand zeichnet, den gesamten Bildschirm durch Löschen von Bit 4 aus Register $ D011, ab. Erreicht der Rasterstrahl nun Rasterzeile $30, an der eigentlich das sichtbare Bildschirmfenster beginnt, so prüft der VIC, ob der Bildschirm nun einoder ausgeschaltet ist.
In letzterem Fall deaktiviert er seine Zeichenaufbau-Schaltkreise bis zum nächsten Erreichen dieser Rasterposition, womit er keine einzige Charakterzeile mehr liest. Anstelle dessen zeigt er in den folgenden Rasterzeilen nur noch die Farbe des Bildschirmrahmens an. Wenn wir diesen jedoch mit Hilfe einer Border-Routine bei $ FA abschalten, so - oh Wun- der - zeigt uns der VIC den Bildschirmhintergrund, auf dem sich auch die Sprites herumtollen dürfen! Wie bei jedem Effekt, bei dem der VIC etwas tut, was er sonst nicht tun kann, erscheint hier dann wieder der Inhalt der letzten Adresse des VIC-Speichers ( normalerweise $3 FFF) in Schwarz auf Hintergrundfarbe.
Durch Schreiben des Wertes 0 in diese Speicherzelle können wir natürlich die Schwarzen Streifen auch abschalten und damit nur die Hintergrundfarbe anzeigen lassen.
Um diese Vorgehensweise nun besser zu erläutern haben wir natürlich wieder ein Programmbeispiel auf Lager, das ich Ihnen nun auflisten möchte. Sie finden es auf dieser MD auch als fertig ausführbares File mit dem Namen " SPRITES-ONLY", daß Sie wie immer mit ",8,1" laden und durch ein " SYS4096" starten müssen.
Kommen wir also zur Initialiserungsroutine des Beispiels, die bei Adresse$1000 beginnt:

INIT:                                   
    sei        ;IRQs sperren            
    lda #$7f   ;Alle CIA-IRQs abschalten
    sta $dc0d  ; (CIA1)                 
    sta $dd0d  ; (CIA2)                 
    bit $dc0d  ;CIA1-ICR löschen        
    bit $dd0d  ;CIA2-ICR löschen        

lda #$01 ; VIC-Hintergrundstriche sta $3 fff ; auf 1 setzen jsr sprinit; Sprites initialiseren jsr irqinit; IRQ initialiseren

    lda #$35   ;ROMs abschalte          
    sta $01                             
    cli        ;IRQs erlauben           
spc:lda #$7f   ;Auf SPACE-Taste         
    sta $dc00  ; warten...              
    lda $dc01                           
    cmp #$ef                            
    bne spc                             
    sei        ;IRQs sperren            
    lda #$37   ;ROM wieder einschalten  
    sta $01                             
    jmp $fce2  ;und RESET auslösen      

Alles in allem für uns keine besondere Initialisierung. Wichtig sind noch die Routinen " SPRINIT" und " IRQINIT" . In ersterer initialisieren wir lediglich die Sprite-Positionen, sowie die Sprite- Pointer und schalten alle acht Sprites ein. Letzere Routine ist für das Korrekte initialisieren unseres IRQs zurständig und sieht folgendermaßen aus:
IRQINIT:
lda #< bordirq ; IRQ-Vektor bei sta $ fffe ;$ FFFE/$ FFFF lda #> bordirq ; auf " BORDIRQ" verbiegen sta $ ffff lda #$1 b ; Wert für $ D011 mit gel.
sta $ d011 ; High-Bit f. Rasterpos.
lda #$ fa ; Ersten Raster-IRQ bei

  sta $d012     ; Zeile $FA auslösen    
  lda #$81      ;VIC-Raster-IRQs        
  sta $d01a     ; erlauben              
  dec $d019     ;VIC-ICR ggf. löschen   
  rts                                   

Wie Sie sehen, aktivieren wir hier einen Raster-IRQ für Rasterzeile $ FA, der bei Auftreten die Routine " BORDIRQ" anspringt, wo sich eine ganz gewöhnliche Routine zum Abschalten des oberen und unteren Bildschirmrandes befindet. Hier das Listing dieser Routine:
BORDIRQ:

  pha       ;Prozessorregs. retten      
  txa                                   
  pha                                   
  tya                                   
  pha                                   
  lda $d011 ;24-Zeilen-Darstellung      
  and #$77  ; einschalten               
  sta $d011                             
  lda #$28  ;nächster IRQ bei Zeile $28 
  sta $d012                             
  dec $d019 ;VIC-ICR löschen            
  lda #<soff;Routine für nächsten IRQ   
  sta $fffe ; "SOFF" in IRQ-Vektor      
  lda #>soff; eintragen                 
  sta $ffff                             
  pla       ;Prozessorregs. wieder vom  
  tay       ; Stapel holen und IRQ      
  pla       ; beenden                   
  tax                                   
  pla                                   
  rti                                   

Wir schalten hier also an der üblichen Position auf 24- Zeilen-Darstellung herunter, damit der VIC vergisst, den oberen und unteren Bildschirmrand zu zeichnen. Gleichzeitig wird ein neuer IRQ initialisiert, der bei Erreichen von Rasterzeile $28( acht Rasterzeilen vor Beginn des sichtbaren Bildschirmfens- ters) die Routine " SOFF" anspringen soll. Diese Routine übernimmt nun die Aufgabe, die Darstellung der Charakterzeilen zu verhindern:

soff:                                   
  pha       ;Prozessorregs. retten      
  txa                                   
  pha                                   
  tya                                   
  pha                                   

lda $ d011 ; Bild ausschalten ( durch and #$6 F ; ausmaskieren von Bit4) sta $ d011

  lda #$32  ;nächster IRQ bei Raster-   
  sta $d012 ; zeile $32                 
  dec $d019 ;VIC-ICR löschen            
  lda #<son ;Nächster IRQ soll auf      
  sta $fffe ; Routine "SON" springen    
  lda #>son                             
  sta $ffff                             
  pla       ;Prozessorregs. wieder vom  
  tay       ; Stapel holen und IRQ      
  pla       ; beenden                   
  tax                                   
  pla                                   
  rti                                   

Wie Sie sehen eine recht einfache Aufgabe: durch eine AND-Verknüpfung des $ D011- Inhalts mit dem Wert $6 F wird einfach das 4 . Bit dieses Registers gelöscht. Gleichzeitig löschen wir dabei Bit 7, das ja das High-Bit der Rasterstrahlposition angibt, womit wir also auch dieses Bit für den folgenden Raster- IRQ bei Zeile $32 vorbereitet hättem. Die Routine, die hier abgearbeitet werden soll, heisst " SON" und ist für das Wiedereinschalten des Bildschirms verantwortlich. Da sich Rasterzeile $32 im sichtbaren Fenster befindet wäre somit der VIC überlistet und soweit gebracht, daß er keine Charakterzeilen mehr liest, geschweige denn darstellt.
Gleichzeitig schaltet diese Routine wieder auf die 25- Zeilen-Darstellung zurück ( Bit 3 von $ D011 muß gesetzt werden), damit das Abschalten des Borders auch im nächsten Rasterstrahldurchlauf funktioniert:

SON:                                    
  pha          ;Prozessorregs. retten   
  txa                                   
  pha                                   
  tya                                   
  pha                                   

lda $ d011 ; Bild und 25- Zeilenora #$18 ; Darstellung einschalten sta $ d011

  lda #$fa     ;nächster IRQ wieder bei 
  sta $d012    ; Zeile $FA              
  dec $d019    ;VIC-ICR löschen         
  lda #<bordirq;Wieder "BORDIRQ" in     
  sta $fffe    ; IRQ-Vektor eintragen   
  lda #>bordirq                         
  sta $ffff                             
  pla       ;Prozessorregs. wieder vom  
  tay       ; Stapel holen und IRQ      
  pla       ; beenden                   
  tax                                   
  pla                                   
  rti                                   

Nachdem Register $ D011 auf den gewünschten Wert zurückgesetzt wurde, wird der IRQ wieder für die Routine " BORDIRQ" bei Rasterzeile $ FA vorbereitet, womit sich der Kreis schließt und unser Programmbeispiel komplett ist.
3)" ESCOS"- EINEN SCHRITT WEITER Nachdem wir nun unser Timing-Problem gelöst, und die störenden Charakter-Zeilen aus dem Weg geräumt haben, möchten wir wieder zu unserer eigentlichen Aufgabenstellung zurückkehren: dem bild- schirmfüllenden Darstellen von Sprites.
Hierzu müssen wir, nachdem oberer und unterer Bildschirmrand, sowie die Charakterzeilen abgeschaltet wurden, zusätzlich auch noch die Bildschirmränder links und rechts deaktivieren. Das Funktionsprinzip einer solchen Sideborderroutine sollte Ihnen noch aus einem der ersten Kursteile im Kopf sein: durch rechtzeitiges Umstellen von 40- auf 38- Spaltendarstellung und zurück tricksen wir den VIC nach dem selben Prinzip aus, wie wir es bei den horizontalen Bildschirmrändern tun. Dadurch aber, daß sich der Rasterstrahl horizontal recht schnell bewegt, kommt es dabei auf ein höchst exaktes Timing an. Einen Taktzyklus zu früh oder zu spät funktioniert die Routine schon nicht mehr. Wenn man das Ganze nun zusätzlich noch mit dem Üffnen des oberen und unteren Randes, sowie dem Abschalten der Charakter-Zeilen und einem Sprite-Multiplexer kombinieren muß, so könnte man meinen, daß dies eine recht programmieraufwendige Sache werden kann. Doch keine Panik, die Umsetzung ist einfacher als Sie glauben.
Am Besten sehen Sie sich erst einmal das Demoprogramm " ESCOS1" an. Es wird wie üblich geladen und mit SYS4096 gestartet, und zeigt dann einen vollends mit Sprites gefüllten Bildschirm - und zwar über alle Ränder hinaus! Um so etwas nun sebst zu programmieren, werden wir zunächst auf die organisatirischen Probleme und deren Lösung eingehen:
Als Erstes müssen Sie davon ausgehen, daß wir keine IRQ-Routine im eigentlichen Sinne programmieren werden. Aufgrund des exakten Timings, das zum Abschalten des linken und rechten Randes notwendig ist, muß der Prozessor nahezu während des gesamten Rasterdurchlaufs damit beschäftigt sein, die richtige Rasterposition abzuwarten, um zwischen der 38- und 40- Zeilen-Darstellung hinund herzuschalten. Dadurch wird ledi- glich ein einziger IRQ pro Rasterdurchlauf aufgerufen, nämlich direkt zu Anfang desselben, in Rasterzeile 0 . Dieser IRQ muß nun, auf die uns schon bekannte Art und Weise," geglättet" werden, so daß kein einziger Taktzyklus Unterschied zum vorherigen Rasterdurchlauf besteht.
Ab dann ( durch das Glätten, das 2 Rasterzeilen dauert also ab Zeile 2) beginnt der Prozessor damit in jeder einzelnen Rasterzeile den Rand abzuschalten. Dies geschieht dadurch, daß wir nach jedem Umschalten der Spaltendarstellung genau am Öbergangspunkt zwischen sichtbarem Bildschirmfenster und - rahmen, exakt 63 Taktzyklen verzögern, bevor dieser Vorgang wiederholt wird. So zumindest sähe es aus, wenn wir keine Sprites darzustellen hätten. Da wir dies jedoch tun, müssen wir weiterhin berücksichtigen, daß der VIC zum Darstellen der Sprites den Prozessor ebenso anhalten muß, wie beim Lesen der Charakterzeilen, um sich die Spritedaten aus dem Speicher zu holen. Hierbei braucht er 3 Taktzyklen für das erste Sprite, und dann jeweils 2 Zyklen für alle weiteren, eingeschalteten Sprites. Da wir alle 8 Sprites benutzen, müssen wir also noch den Betrag 3+7*2=17 von den 63 Zyklen abziehen und erhalten somit exakt 46 Taktzyklen, die der Prozessor pro Rasterzeile " verbrauchen" muß.
( Anm. d. Red. : Bitte wählen Sie jetzt den zweiten Zeil des IRQ-Kurses aus dem Textmenu.)

Valid HTML 4.0 Transitional Valid CSS!