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.)