Raster-IRQ: Bad Lines

Für diesen Beitrag wurde das CBM prg Studio verwendet.
weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn
Erstmal ein herzliches Willkommen zum 100. Beitrag auf dieser Seite.
Erstmal ein herzliches Willkommen zum 100. Beitrag auf dieser Seite.

Zur Feier des Tages gibt es den bisher wohl anspruchvollsten Beitrag. Ich hoffe ihr könnt mit den folgenden Ausführungen etwas anfangen, ich kämpfe mich derweil noch weiter durch die Eigenheiten des VIC-II.

 

CBM prg StudioDie Bad Lines

Trotz des im letzten Beitrag ‚Raster-IRQ: Endlich stabil!!!‚ entwickelten stabilen Rasterzeilen-Interrupts, funktioniert (wie bereits häufiger erwähnt) leider nicht immer alles wie erwartet. Der Grund sind u. a. die sog. Bad Lines. Hier geht es jetzt also darum was Bad Lines sind, wann sie auftreten, welche Auswirkungen sie haben und wie man mit ihnen umgehen kann.

 

Wieder wird das standard PAL-System vorausgesetzt!

 

Was sind Bad Lines?
Um uns das Problem mit den ‚bösen Linien‚ etwas genauer vor Augen zu führen, benutzen wir ein kleines Beispielprogramm.

Das Programm sollte euch bekannt vorkommen. Es entspricht fast zu 100% dem im letzten Beitrag entwickelten stabilen Rasterzeileninterrupt. Die wenigen Änderungen sind schnell erklärt. Der Interrupt beginnt diesmal schon in Zeile 3 (s. RASTER), damit wir möglichst viele Linien zu sehen bekommen.

Wichtig ist folgende Zeile bei der Initialisierung:

Damit schalten wir den Bildschrim erstmal aus (s. ‚VIC-II: Die Register‚). Somit besteht unsere Anzeige so zu sagen nur aus einem durchgängigen Rahmen.

Am Schluß von DoubleIRQ: holen wir jetzt schwarz (statt weiß) in den Akku. Ab MyIRQ_Main: bereiten wir unsere Hauptschleife vor und ‚verschwenden‚ soviel Zeit, dass die erste Linie linksbündig beginnt. Wir ‚beginnen‚ also mit dem Setzen der Farbe am Schluß der vorherigen Zeile. In der Schleife @loop1: färben wir dann den Rahmen abwechselnd schwarz und hellrot ein. Der Rest sollte dann wieder bekannt sein.

Ohne Bildschirmausgabe sieht alles gut aus.
Ohne Bildschirmausgabe sieht alles gut aus. (Bild-1)

Die Anzeige sieht doch exakt so aus, wie wir es uns gedacht haben. Ein Problem ist nicht zu erkennen. Da wir noch zur Systemroutine nach $EA31 springen, zeichnen wir die Linien nicht ganz bis zum unteren Rand.

Also alles paletti, oder? Kommentiert nun das AND zwischen ;*** TEST TEST TEST *** aus und startet das Programm erneut.

Kaum wird die Ausgabe aktiviert geht es schief.
Kaum wird die Ausgabe aktiviert geht es schief. (Bild-2)

Und schon haben wir den Salat!

Wer möchte kann übrigens noch ein kleines BASIC-Programm starten (z. B. „HALLO„ in einer Endlosschleife ausgeben) um dann festzustellen, dass dieses keine Veränderung bei den Linien hervorruft. Es liegt also einzig am aktivierten Ausgabebereich.  

Was zeigen uns diese beiden Bilder?
Ohne Bildschirmausgabe (s. Bild-1) funktionierte ja alles, also muss das Problem mit der Ausgabe zusammenhängen. Auf Bild-2 erkennen wir, dass auch dort im oberen und unteren Rahmen alles glatt läuft. Nur im Ausgabebereich kommt das System aus dem Tritt. Es fällt ebenfalls auf, dass die Linien nun weiter nach unten reichen. Wir scheinen mit aktivierter Ausgabe also mehr Zeit zu benötigen.

Betrachten wir den Ausgabebereich mal genauer: Die letzte Linie von oben, bevor der Ausgabebereich beginnt, sieht noch sauber aus, aber direkt die nächste wird schon vermurkst. Hin und wieder werden die Linien (wenn auch versetzt) durchgängig sauber gezeichnet. Mit einigem Aufwand (spart euch die Mühe) würdet ihr feststellen, dass wir ab Zeile 51 alle acht Zeilen ein Timing-Problem haben. Genau dies sind die Bad Lines!

 

Der technische Hintergrund
Der Takt des C64 wird in eine erste und zweite Phase unterteilt. Während der ersten Phase darf der VIC-II auf den Adressbus zugreifen und kann seine Arbeit verrichten, der Bus ist dann für den Prozessor gesperrt. Die zweite gehört der CPU und der VIC dürfte dann nicht auf den Adressbus zugreifen. Nun reicht bei aktivierter Ausgabe die Zeit, die dem VIC-II zur Verfügung steht, aber nicht aus, um alle Aufgaben zu erledigen. Er benötigt den Adressbus länger, um die sog. Zeichenzeiger und Pixeldaten für die Ausgabe zu ‚lesen‚. Diese zusätzliche Zeit benötigt er immer zu Beginn einer Ausgabzeile (Textzeile, aber auch im Bitmap-Modus)! Daher kommt unser Muster direkt mit Beginn der ersten Textzeile aus dem Tritt. Uns stehen in einer Bad Line einfach viel weniger Taktzyklen zur Verfügung als normalerweise (ihr wisst, dass es normal 63TZ beim PAL-System sind).

 

Was nun?
Ist unser Streifenmuster also unmöglich hinzubekommen? Natürlich nicht! Was liegt nun näher, als das Programm so umzubauen, dass es die folgenden Bedingungen beachtet.

  • Rahmen oben
    • es stehen die vollen 63TZ zur Verfügung
       
  • Im Ausgabebereich für jeweils acht Zeilen
    • in der ersten Zeile (Bad Line!) etwas weniger Zeit verschwenden
    • die nächsten sieben Zeilen wieder volle 63 Taktzyklen abwarten
       
  • Rahmen unten
    • genau wie im oberen Rahmen sind 63TZ möglich

 

Schön gesagt, ‚in der ersten Zeile (Bad Line!) etwas weniger Zeit verschwenden‚!

 

Wieviel Zeit ist denn etwas weniger?
Um dass jetzt zu ermitteln, verwenden wir ein abgewandeltes Testprogramm. Dieses ist mit dem bisherigen größtenteils identisch, die wenigen Unterschiede sind gelb hervorgehoben.

Wir lassen unseren Raster-IRQ so auftreten, dass wir in der letzten normalen Zeile vor der ersten  Bad Line mit MyIRQ_Main: beginnen. Dort ändern wir einfach laufend die Rahmenfarbe (immer zwischen schwarz und weiß umschalten), bis die Rasterzeile zuende ist. Den restlichen Rahmen setzen wir auf grau. Wie ihr oben seht, verbrauchen wir sogar 65 Taktzyklen und landen somit schon in der Bad Line, was hier aber noch nicht von Interesse ist.

Das Programm sollte zu folgender Ausgabe führen (unbedingt Rahmen debuggen aktivieren!):

Unsere Testausgabe...
Unsere Testausgabe…

Dieses Bild wurde direkt aus WinVICE gespeichert, es ist KEIN Windows-Screenshot! Dass ist wichtig, damit die Pixel wirklich 1:1 erhalten bleiben. Denn gleich werden wir die einzelnen Pixel zählen. Um den nun kommenden Schritten besser zu folgen solltet ihr euer bevorzugtes Grafikprogramm (ich verwende z. B. Paint.NET) starten. Dann benötigt ihr die Bilder in ihrer original Größe. Klickt zur Sicherheit aufs Bild, kopiert es dann über das Kontextmenü und fügt es ins Grafikprogramm ein.

Wie ihr seht, beginnt unsere normale Zeile erst mit einem grauen Teilstück, danach wechseln sich schwarz und weiß immer ab.

Als nächstes habe ich links beim ersten Pixel begonnen und jeweils 8 Pixel abwechselnd rot und grün eingefärbt. (Dies hat übrigens keinerlei politischen Bezug! 😉 )

Hier seht ihr die 63 Taktzyklen!
Der rote und grüne Block ist je 8 Pixel breit.

Klickt bitte auf die Grafik, um sie als Vollbild anzuzeigen. Wie ihr seht, können wir die gesamte Bildschirmbreite exakt mit den 8 Pixel breiten rot / grün Blöcken füllen. Wie euch bekannt ist, stehen uns im PAL-System die bereits häufiger erwähnten 63 Taktzyklen zur Verfügung. Dann zählt oben mal nach, wieviele rot und grün Blöcke es insgesamt gibt….

… schon fertig? Ihr solltet 63 Stück gezählt haben!!

Hier habt ihr also die Taktzyklen mal direkt vor Augen 😉 . Euch ist bestimmt aufgefallen, dass die schwarzen und weißen Abschnitte exakt auf die Zyklengrenze fallen.

Untersuchen wir den Beginn der Grafik noch etwas genauer.

Anfang der normalen Rasterzeile.
Anfang der normalen Rasterzeile.

Ein roter bzw. grüner Block einspricht also immer einem Taktzyklus. Vergleichen wir den Beginn der Rasterzeile doch einfach mal mit den ersten Befehlen ab MyIRQ_Main:.

  1. Die ersten drei Taktzyklen werden noch vom stabilen Raster-IRQ verbraucht. Ihr erinnert euch: Nach 3TZ in der 3. Zeile?  
  2. Jetzt folgt der sty um den Rahmen auf schwarz zu setzen. Dieser Befehl benötigt 4 TZ. Wie ihr oben seht ändert sich die Rahmenfarbe direkt am Ende des Befehls.  
  3. Der iny benötigt 2 TZ. Auf die Rahmenfarbe hat das natürlich erstmal keine Auswirkung. Nur der Rasterstrahl läuft weiter.  
  4. Wieder ein 4 TZ langer sty, jetzt wird der Rahmen auf weiß gesetzt.  
  5. Ein dey braucht auch nur 2 TZ (s. Punkt 3)  
  6. Hier wiederholt sich alles ab Punkt 2.

Wir können also unsere Befehle direkt in der Grafik erkennen. So könnt ihr nun direkt abzählen, wo welcher Befehl stattfindet.

Schaut euch als nächstes folgendes Bild einmal an (am besten im Grafikprogramm vergrößern).

Ein TZ = ein Zeichen!
Ein TZ = ein Zeichen!

Ich habe die ersten rot / grün Blöcke im Ausgabebereich mal etwas ‚verlängert‚, um euch einen wichtigen Zusammenhang zu zeigen. Dass ein Taktzyklus 8 Pixel ‚dauert‚ haben wir ja schon gesehen. Hier erkennt ihr, dass die TZ synchron mit den einzelnen Zeichen auf dem Bildschirm ‚laufen‚! Außerdem erkennt man, dass der Ausgabebereich exakt an einer Zyklengrenze beginnt und endet.

Eine letzte Erkenntnis, die wir aus diesen Grafiken ziehen können. Am Schluß von ‚Raster-IRQ: PAL oder NTSC‚ habe ich euch eine Tabelle präsentiert, in der u. a. die Anzahl der sichtbaren Pixel verzeichnet ist. Diese könnt ihr nun um die Anzahl der max. Pixel ergänzen. Da eine Rasterzeile 63 TZ hat und pro TZ 8 Pixel ‚vergehen‚ kommen wir auf 8 * 63 = 504 Pixel je Zeile bei einem PAL-System.

 

Jetzt aber endlich zurück zu den Bad Lines. Wie wir festgestellt haben, tritt eine Bad Line nur dann auf, wenn der Ausgabebereich aktiv ist. Die in einer Bad Line verfügbaren Taktzyklen könnt ihr nun direkt abzählen oder berechnen. Es sind die für den Rahmen verfügbaren Zyklen. Da wir 40 Zeichen darstellen können (was wie eben gesehen auch 40 Taktzyklen in der Rasterzeile entspricht), kommen wir auf 63 – 40 = 23 TZ für eine Bad Line. Ein Abzählen in der Grafik, sollte zum selben Ergebnis führen. Wir haben 17TZ für den linken und 6TZ im rechten Rahmen zur Verfügung.

Dann lasst uns dass gleich mal überprüfen, übernehmt biite die gelb markierten Änderungen in unser kleines Testprogramm.

Wir verbringen durch das abschließende dey jetzt die vollen 63 Taktzyklen in der letzten normalen Zeile vor der Bad Line. In der Bad Line angekommen, setzen wir direkt die Rahmenfarbe und holen uns dann als nächste Farbe hellgrün ins Y-Register (einfach zur besseren Unterscheidung). Dann warten wir etwas, setzen den Rahmen auf hellgrün und verbringen den Rest der Bad Line mit warten, bis die von uns ermittelten 23 TZ vergangen sind. Zum Schluß wird wieder grau als Rahmenfarbe gesetzt.

Ein Blick auf die neue Bildschirmausgabe sollte euch stutzig werden lassen.

Da passt was nicht!
Da passt was nicht!

Wenn ihr das Bild vergrößert, seht ihr, dass das hellgrün vom Schluß der Bad Line sich zuweit in die nächste normale Zeile erstreckt, weil er zu spät beginnt. Eigentlich dürfte der hellgrüne Teil nur solang wie der weiße in der darüberliegenden Bad Line sein, da sty $d020 ja nur vier Zyklen benötigt und er müsste ganz links beginnen. Hier vergehen aber noch drei weitere Takte, bevor die Farbe geändert wird. Was geht denn da schon wieder schief?

Anscheinend stehen uns in der Bad Line doch keine 23 TZ zur Verfügung. Löschen wir den Befehl bit $01, sodass wir auf 20TZ für die Bad Line kommen, dann passt wieder alles.

Also haben wir nur 20 TZ???

Ganz so einfach ist es dann aber doch nicht!
Wieviele Taktzyklen tatsächlich vergehen hängt auch von unserem Programm ab. Bevor der VIC-II dem Prozessor den Bus in einer Bad Line entzieht, ‚fordert‚ er den Bus an. Dazu wird das BA-Signal des VIC-II drei Zyklen, bevor er den Bus benötigt auf Low gesetzt. BA ist mit der RDY-Leitung des 6510 verbunden. Geht RDY auf low, dann hält die CPU an. Allerdings prüft der Prozessor den RDY-Status nur bei Lesezugriffen, da ein Schreibvorgang nicht unterbrochen werden darf. Beim 6510 können max. drei Schreibzugriffe direkt hintereinander vorkommen, somit ist die Quelle dieser ominösen 😉 Zahl-3 nun auch geklärt. Wir haben also 20-23 TZ in einer Bad Line, da der Prozessor bei einem Lesezugriff innerhalb der eben erwähnten 3 Taktzyklen sofort stoppt. Aber weshalb geschieht dass hier überhaupt? Bevor der Ausgabebereich beginnt, haben wir doch nur nop-Befehle?? Also wird doch nichts gelesen und wir sollten 23 TZ haben. Der 6510 führt auch dann Lesezugriffe aus, wenn eigentlich keine notwendig sind. So führt ein nop, der ja 2 TZ benötigt dazu, dass das Read/Write-Signal für beide Taktzyklen auf Read gesetzt wird.

Ändert unser Testprogramm nochmal:

Den Befehl bit $01 haben wir oben bereits gelöscht, um auf 20 TZ zu kommen, nun ziehen wir das sty $D020 von ganz unten etwas weiter nach oben. Wenn wir jetzt dass Programm starten, dann sollte die hellgrüne Line doch einfach nur früher beginnen und wie eben wieder nach 4 TZ in der nächsten Zeile enden, oder?

Obwohl sich die Anzahl der Taktzyklen nicht ändert, verschiebt sich die Ausgabe.
Obwohl sich die Anzahl der Taktzyklen nicht ändert, verschiebt sich die Ausgabe!

Wir haben den sty $D020 eben so verschoben, dass sein abschließender Write-Zugiff in die 3 TZ fällt, in denen der VIC den Bus anfordert. Dadurch haben wir in diesem Fall 21 TZ statt 20 in der Bad Line. Verschiebt jetzt mal ein nop von unten vor das eben verschobenen sty $D020 und startet das Programm. Nun sind es wieder 20 TZ, aber das hellgrün beginnt erst nach dem Ausgabebereich! Ihr müsst also ganz genau darauf achten, welche Befehle in einer Bad Line kurz vor dem Ausgabebereich auftreten und wie ihr Read/Write-Status in dem Moment ist. Diese optische Herangehensweise ist natürlich nicht 100% korrekt! Sie erklärt nicht wirklich was, wann ‚abgeht‚. Aber ich möchte die genauen Zusammenhänge hier nicht weiter ausführen und euch auf den nächsten Beitrag vertrösten.

 

Zurück zum Steifenmuster!
Um jetzt das Streifenmuster sauber zu erstellen, müssen wir also nur auf die Bad Lines gesondert reagieren. Setzt die Anforderungen aus obiger Liste doch mal in ein Programm um.

Ich möchte euch empfehlen, das Problem zunächst selbst zu lösen, bevor ihr weiter lest. Ich würde die Aufgabe als nicht allzu schwer erachten. Es geht einzig ums haargenaue Verschwenden von Taktzyklen. Allerdings ist hier eure Einsatzbereitschaft gefragt, bis zur erfolgreichen Lösung kann es schon etwas dauern. Gleich folgen noch einige Tipps und Anregungen, wie man die Sache angehen kann. Um euch nicht in Versuchung zu führen, ist das Listing diesmal ‚geschützt‚.

[is-login]Hier meine Lösung, ich habe mich auf den Teil ab MyIRQ_Main: beschränkt.

Das sieht nun schlimmer aus, als es wirklich ist. Der Programmabschnitt bedarf eigentlich keiner weiteren Erklärung (alles steht in den Kommentaren), es geht hier, wie bereits erwähnt, einzig und allein um die genaue Verschwendung von Taktzyklen. [/is-login]

Wenn alles geklappt hat, sollte das Ergebnis (Rahmen debuggen ist aktiv) so aussehen:

So solltes es aussehen, wenn die Bad Lines beachtet werden.
So solltes es aussehen, wenn die Bad Lines beachtet werden.

 

Mein Ansatz
Es gibt eine Schleife, die sich solange um alle normalen Zeilen kümmert, bis eine Bad Line ansteht. Die folgende Bad Line wird dann speziell verarbeitet, da in dieser weniger Taktzyklen zur Verfügung stehen. Die nächste Zeile ist wieder normal und bereitet den Block der weiteren normalen Zeilen vor. Diese Block wird dann wieder mit der ersten Schleife abgearbeitet. Zum Schluß kümmert sich eine letzte Schleife um die Zeilen im unteren Rahmen, da kommen ja nur noch normale Zeilen.

 

Wer mal ein BASIC-Programm laufen läßt, wird feststellen, dass der C64 plötzlich sehr langsam geworden ist. Das liegt daran, dass wir fast die ganz Rechenleistung für unsere Linien verschwenden, fürs BASIC steht dann natürlich weniger Zeit zur Verfügung.

Ihr könnt die Linien auch bis ganz nach unten zeichnen, dann flackert aber alles, sobald ihr z. B. eine Taste drückt.

Unser Lohn ist die Erkenntnis, dass in einer Bad Line nur 20-23 Taktzyklen, statt der sonst üblichen 63 auf einem PAL-System möglich sind.

 

Die Probleme reißen nicht ab!
Nehmen wir jetzt mal an, ihr müsst den Bildschirm um einige Zeilen scrollen. Also ändern wir am Beginn des Programms die Zeile and #%01111111 ;für die Rasterzeile löschen so, dass wir auch das unterste BIT durch den AND-Befehl löschen ( and #%01111110). Dies bewirkt ein Verschieben des Ausgabebereichs (s. ‚VIC-II: Die Register‚).

Ein Start läßt uns dann schon wieder verzweifeln:

Kaum wird die Anzeige 'gescrollt', kommt es wieder zu Darstellungsfehlern.
Kaum wird die Anzeige ‚gescrollt‚, kommt es erneut zu Darstellungsfehlern.

 

Bad Lines & Scrolling
Das Auftreten von Bad Lines scheint also mit der aktuellen Scrollposition zusammen zu hängen.

Dies ist in der Tat so! Da der Ausgabebereich verschoben wurde, verschiebt sich auch die erste (und damit alle folgenden) Bad Lines. Wer den Zusammenhang genauer untersucht wird feststellen, dass eine Bad Line auftritt, wenn im Bereich der Ausgabe, die unteren 3-BITs von $D012 mit dem vertikalen Scrollwert (die unteren 3-BITs von $D011 s. ‚VIC-II: Die Register‚) übereinstimmt.

Wenn man diesen Zusammenhang genauer überdenkt, dann müssten sich Bad Lines durch eine Veränderung des vertikalen Scrollwertes vermeiden lassen. Das klappt tatsächlich, außerdem ist es dadurch möglich Bad Lines dann zu erzeugen wann man es möchte. So wird z. B. durch das Auslösen einer Bad Line in jeder Zeile der FLIinfoFlexible Line InterpretationIm 'Flexible Line Interpretation'-Modus können, im Gegensatz zum normalen Multicolor-Modus, sogar alle 16 Farben in jeder 4*8 Pixel großen 'Zelle' verwendet werden.-Grafikmodus erst möglich.

Wer die Auswirkung des Scrollens mal testen möchte, der braucht z. B. nur in der Zeile vor einer Bad Line $D011 um eins erhöhen, somit sind auch in der nächsten Zeile die unteren drei BITs von $D011 und $D012 verschieden. Es gibt also keine Bad Line. In der eigentlichen Bad Line dann nochmal $D011 um eins erhöhen und daran denken, jetzt 63TZ zu ‚warten‚. In der Zeile nach der Bad Line dann $D011 wieder auf seinen ursprünglichen Wert zurück setzen.

Es gibt keine Bad Lines mehr!
Es gibt keine Bad Lines mehr!

Die Ausgabe sieht zwar ‚merkwürdig‚ aus, aber es gibt jetzt wirklich keine Bad Lines mehr! Die Erklärung, weshalb der Ausgabebereich schwarz ist, wurde eigentlich schon oben gegeben. Der VIC benötigt die Bad Lines, um die Grafikausgabe (s. oben ‚Zeichenzeiger und Pixeldaten‚) vorzubereiten. Da wir ihm hier aber keine Bad Line zubilligen, kann er auch nichts ausgeben. Was man mit ohne 😉 Bad Lines anstellen kann, schauen wir uns nach dem nächsten Beitrag einmal an.

Hier noch das komplette Listing um die Bad Lines zu vermeiden. Dort seht ihr auch dass von mir weiter oben noch versteckte Vorgehen, um die Bad Lines gesondert zu behandeln. Wie immer gilt, dieses Programm dient der Erklärung, es ist in keinster Weise optimiert.

Eure Ausgabe könnte etwas anders aussehen. Auf einem Röhrenmonitor erhalten wir evtl. kein Streifenmuster im Rahmen. Dies liegt an der Technik der Röhrenmonitore.

Ausgabe auf dem SX64 (Röhrenmonitor).
Ausgabe auf dem SX64 (Röhrenmonitor).

Statt einem schwarzen Hintergrund kann auch ein anderes Muster (s. Foto vom SX64) erscheinen. Wie schon bei den Demo-Effekten ‚Oberen & unteren Rand öffnen‚ erklärt, nimmt der VIC-II das BYTE von $3FFF für die Ausgabe, falls ihm nichts Gültiges zur Verfügung steht. Schreibt doch einfach mal verschiedene Werte an diese Adresse und schaut, was dann passiert. Auch im Java Emulator weicht das Ergebnis ab, hier hat der Wert von $3FFF anscheinend überhaupt keine Auswirkung.


Da der Beitrag die Grenze des Erträglichen bereits überschritten hat, soll nun erstmal Schluß sein. Allerdings müssen wir im nächsten Beitrag noch einige Punkte klären, z. B. die Auswirkung von Sprites auf das Raster-Timing.
 


Schrott!!Naja...Geht so...Ganz gut...SUPER! (8 Bewertungen | Ø 4,88 von 5 | 97,50%)

Loading...


 

 

<<< zurück | weiter >>>

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

Ein Gedanke zu „Raster-IRQ: Bad Lines“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Protected by WP Anti Spam