Magic Disk 64

home to index to text: MD9408-KURSE-IRQ-KURS_10.2.txt
      Fortsetzung IRQ-Kurs, Teil 10     

Es folgt nun der Programmteil mit dem Label " CONTINUE", der von der obigen Routine angesprungen wird. Hier kümmern wir uns wieder um den Scrolloffset, dessen Wert ja noch negativ ist, da wir im ersten Teil der MOVESPR-Routine durch die Subtraktion einen Unterlauf des Zählers erzeugt hatten. Damit Sie hier nun auch Werte größer 1 einsetzen können, womit der Scroll schneller durchläuft, wird " SOFTROLL" nicht wieder mit $17 vorinitialisiert, sondern wir addieren auf das Ergebnis der Subtraktion den Offset, der zwischen zwei Rasterinterrupts liegt,$18(= dez.24), auf. Der resultierende Wert wird dann wieder in Softroll abgelegt. Auf diese Weise werden also auch Scrollwerte größer 1 berücksichtigt. War das Ergebnis der Subtraktion z. B.-2, so wird " SOFTROLL" auf 22 zurückgesetzt, womit der Öberlauf abgefangen wird, und der Scrolleffekt flüssig weiterläuft:
CONTINUE:

   clc         ;C-Bit f.Add. löschen    
   lda softroll;SOFTROLL laden          
   adc #$18    ;24 addieren             
   sta softroll;und wieder ablegen      
   lda #$20    ;Op-Code für "JSR"       
   sta mt      ;in MT eintragen         

Besonders trickreich ist die LDA-STA- Folge am Ende dieses Programmteils. Wir tragen hier den Wert $20, der dem Assembler- Opcode des " JSR"- Befehls entspricht, in das Label " MT" ein. Letzteres befindet sich innerhalb der MOVIEIRQ-Routine, und zwar vor dem Befehl " JSR MAKETEXT" . Die MAKETEXT-Routine baut eine Spritezeile auf, indem Sie die Zeichendaten dieser Zeile von dem Zeichensatz bei $0800 in die zu benutzenden Sprites einkopiert. Da dies nicht direkt zu unserem Kursthema gehört, möchte ich auch nicht weiter auf diese Routine eingehen. Wichtig zu wissen ist nur, daß die MOVESPR-Routine, nachdem sie erkannt hat, daß eine neue Spritezeile aufgebaut werden muß, die MOVIEIRQ-Routine derart modifiziert, daß im nächsten IRQ die MAKETEXT-Routine angesprungen wird. Innerhalb selbiger existiert dann eine weitere Befehlsfolge, die den Wert $2 C in das Label " MT" schreibt. Selbiger Wert ist der Opcode für den Assemlerbefehl " BIT" . In allen folgenden IRQs arbeitet der Prozessor an diesem Label also immer den Befehl " BIT MAKETEXT" ab, der eigentlich keine Funktion beinhaltet, sondern lediglich verhindern soll, daß die Maketext-Routine angesprungen wird. Erst, wenn MOVESPR erkannt hat, daß eine neue Spritezeile aufgebaut werden muß, ändert sie den Befehl wieder in " JSR MAKETEXT" um, so daß die Zeile im nächsten IRQ wieder automatisch neu berechnet wird. Dieser, zugegebenermaßen etwas umständliche, Weg des Routinenaufrufs wurde gewählt, da MAKETEXT recht lange ( insgesamt etwa einen Rasterdurchlauf) braucht, um die Spritezeile aufzubauen. Damit Sie in dieser Zeit die Raster-IRQs nicht blokkiert, muß sie auf diesem Weg benutzt werden. Während ihres Ablaufs erlaubt sie auch weitere IRQs, so daß Sie während der Darstellung des nächsten Rasterdurchlaufs, immer zwischen den Spritepositionierungen durch den IRQ, ablaufen kann.
Kommen wir nun zum letzten Teil der MO-VESPR- Routine, dem Label " ROLLON" . Selbiges wird ja ganz am Anfang der Routine angesprungen, wenn kein Unterlauf von " SOFTROLL" stattfand, und somit ohne jegliche Änderung weitergescrollt wird.
Sie setzt den Spritepointerindex " ISLI-NE" zurück auf den Wert in " SHOWLINE" und bereitet den ersten Raster-IRQ vor, der ja immer in der Rasterzeile " SOFT-ROLL" aufzutreten hat.
ROLLON:

   lda showline;ISLINE mit Inhalt von   
   sta isline  ; SHOWLINE init.         
   lda softroll;Scroll-Offset holen     
   sta $d012   ;und als nächsten IRQ-   
   lda $d011   ;Auslöser setzen, dabei  
   and #$7f    ;Hi-Bit löschen u.       
   ora #$08    ;gleichz. 24-Zeilen-     
   sta $d011   ;Darst. einschalten      
   rts                                  

Beim Festlegen des Wertes " SOFTROLL" als nächste IRQ-Rasterzeile, muß die Routine auch das High-Bit, dieser Rasterposition, in $ D011 löschen. Gleichzeitig schaltet sie die 25- Zeilen-Darstellung durch Setzen des 3 . Bits dieses Registers wieder ein. Dies ist eigentlich eine Aufgabe, die für das Beispielprogramm " MOVIE.1" irrelevant ist. Wohl aber für " MOVIE.2", in dem wir den Movie- Scroller über einen Bildschirm mit abgeschaltetem oberen und unteren Rand laufen lassen. Wie Sie wissen, muß dazu in Rasterzeile $ FA die Darstellung von 25 auf 24 Zeichen-Zeilen heruntergeschaltet werden, und danach, vor nochmaligem Erreichen von $ FA, wieder auf 25 Zeilen zurück, was hiermit durchgeführt wird. Da MOVESPR immer im 13 . Interrupt aufgerufen wird, und dieser immer nur innerhalb der Rasterzeilen $10 C-$126 auftreten kann, befinden wir uns tatsächlich schon unterhalb der Rasterzeile $ FA, womit die Änderung zum korrekten Zeitpunkt durchgeführt wird.
3) GLEICHZEITIGES ÜFFNEN DES BILDSCHIRMS Wie schon angesprochen, öffnet das Programmbeispiel " MOVIE.2" zusätzlich noch den oberen und unteren Bildschirmrand, damit die Sprites in voller Bildhöhe über den Bildschirm laufen. Vom Prinzip her ist dies ein recht einfaches Unterfangen, das wir auch schon ausgiebig in diesem Kurs besprochen und angewandt haben. Durch unsere Scrollroutine stellt sich uns jedoch ein kleines Problem in den Weg: da unsere Raster-IRQs durch den Scrolleffekt immer in verschiedenen Rasterzeilen aufzutreten haben, und wir nicht immer genau sagen können, ob nun der 11 . oder 12 . Rasterinterrupt gerade ausgelöst wurde, bevor der Rasterstrahl die Position $ FA erreicht hat, wird es schwierig die Scroll-Routine so abzutimen, daß sie genau an dieser Position die Bildschirmdarstellung ändert. Würde man versuchen durch Verzögerungsschleifen die richtige Position abzutimen, so wäre das mit einem erheblichen Programmieraufwand verbunden. Deshalb greifen wir zu einem kleinen Trick: Die INIT-Routine von " MOVIE.2" wurde um eine kleine Änderung erweitert. Zunächst lassen wir hier den Prozessor, durch ständiges Auslesen und Vergleichen der aktuellen Rasterposition, auf Rasterzeile $ FA warten. Ist diese erreicht, so initialiseren wir Timer A von CIA-2 mit dem Wert $4 CC7 und starten ihn. Da der Ra- sterstrahl immer exakt so viele Taktzyklen braucht, um einmal über den ganzen Bildschirm zu laufen, erzeugt diese CIA immer genau in Rasterzeile $ FA, in der sie gestartet wurde, einen NMI. Weil dieser Vorrang vor dem IRQ hat, wird er selbst dann ausgelöst, wenn gerade ein Raster-IRQ auftritt oder in Bearbeitung ist. Die NMI-Routine nimmt nun die erforderliche Änderung von $ D011 vor, um den Rand abzuschalten ( Bit 3 löschen) und kehrt anschließend sofort wieder zurück, ggf. sogar in einen vom NMI unterbrochenen Raster-IRQ, der dann ganz normal zu Ende bearbeitet wird. Das Zurücksetzen von $ D011 auf die alte 25- Zeilen-Darstellung, wird dann wieder von der MOVESPR-Routine durchgeführt, wie wir oben ja schon gesehen hatten.
Um die NMIs zu erzeugen springt die INIT-Routine von " MOVIE.2" auf eine Unterrountine zum Initialiseren des Timer- NMIs. Wie das funktioniert hatten wir schon ganz zu Anfang des Interrupt-Kurses bespochen. Hier die Routine, um Ihnen den Vorgang wieder ins Gedächtnis zu rufen. Wie auch schon für den IRQ springen wir diesmal nicht über den Soft-NMI- Vektor bei $0318/$0319, sondern über den Hardvektor bei $ FFFA/$ FFFB in den NMI ein:
NMIINIT:

   lda #<nmi ;Startadresse NMI-Routine  
   sta $fffa ; in die Hardvektoren bei  
   lda #>nmi ;$FFFA/$FFFB eintragen     
   sta $fffb                            
   lda #$c7  ;Timer A mit dem Zählwert  
   sta $dd04 ; $4CC7 initialiseren      
   lda #$4c                             
   sta $dd05                            
   lda #$fa  ;Rasterz. $FA in Akku      
WAIT:                                   
   cmp $d012 ;m. akt. Raster vgl.       
   bne wait  ;ungl. also weiter         
   lda #$11  ;Gleich, also Timer A      
   sta $dd0e ; starten                  
   lda #$81  ;Timer-A-NMIs in ICR       
   sta $dd0d ; erlauben                 
   rts                                  

Das war eigentlich schon alles. Von nun an löst Timer A von CIA-B alle $4 CC7 Taktzyklen einen NMI aus. Da der Rasterstrahl immer genau diese Anzahl Zyklen benötigt, um ein ganzes Mal über den Bildschirm zu laufen, tritt der NMI also immer in Rasterzeile $ FA ein, auf die wir vor Starten des Timers gewartet haben. Die NMI-Routine selbst ist recht kurz und sieht folgendermaßen aus:

NMI:  pha       ;Akku retten            
      lda $d011 ;$D011 holen            
HILO: ora #$00  ;7.Bit Rasterpos. setzen
      and #$F7  ;3.Bit löschen          
      sta $d011 ;$D011 zurückschreiben  
      bit $dd0d ;NMIs wieder erlauben   
      pla       ;Akku zurückholen       
      rti       ; und Ende              

Da die NMI-Routine lediglich den Akku benutzt, brauchen wir auch ausschlißelich nur diesen auf dem Stapel zu retten. Danach wird der Inhalt von $ D011 gelesen. Der nun folgende ORA-Befehl hat die Aufgabe eine ggf. gesetztes High-Bit der Rasterstrahlposition des nächsten Raster-IRQs zu setzen, damit wir durch unsere Manipulation von $ D011 nicht versehentlich die, schon gesetzte, nächste Raster-IRQ- Position verändern. Hierzu wurde die MOVIEIRQ-Routine von " MOVIE.2" derart abgeändert, daß Sie die High-Position für den nächsten Raster-IRQ nicht nur in $ D011 schreibt, sondern auch im Label " HILO+1" ablegt, so daß das Argument des ORA-Befehls zwischen $00 und $80 variiert und immer den richtigen ODER-Wert enthält. Anschließend folgt nun ein AND-Befehl zum Löschen des 3 . Bits, womit wir mit dem Ablegen des Wertes die 24- Zeilen-Darstellung einschalten. Durch den BIT-Befehl führen wir einen Lesezugriff auf das ICR- Register von CIA-2 aus, womit wir selbiges Löschen, und dadurch das Auftreten und Melden des nächsten NMIs ermöglichen. Hiernach wird dann nur noch der gerettete Akkuinhalt zurückgeholt, bevor wir den NMI mittels " RTI" beenden. Da die MOVESPR-Routine nun automatisch zu einer späteren Position Bit 3 in $ D011 wieder setzt, funktioniert der NMI-Border- Trick also auch wieder im folgenden Rasterdurchlauf! Mit Hilfe des hier benutzen NMI-Tricks können Sie quasi zwei Raster-Intterrupts gleichzeitig ablaufen lassen, was auch für andere Rasterroutinen sehr hilfreich sein kann.

                                 (ih/ub)

Valid HTML 4.0 Transitional Valid CSS!