Mal wieder Raster-Interrupt

Es gibt 25 Antworten in diesem Thema, welches 2.577 mal aufgerufen wurde. Der letzte Beitrag (4. Mai 2024 um 19:55) ist von goloMAK.

  • Sodele, jetzt hab' ich wieder Zeit und inzwischen dein Programm auch verstanden.

    Zuerst einmal zu den Badlines: Das sind immer die obersten Zeilen eines 8er-Blocks. Der VIC muss ja wissen, welche Zeichen in dieser Textzeile dargestellt werden sollen, und die normalen Zugriffszeiten reichen dafür nicht aus, weshalb er den Prozessor kurzerhand abschaltet und sich die Zeichen aus dem Speicher holt, wenn eigentlich der Prozessor dran wäre.

    Was dich (und wohl auch ogd oben) vermutlich hierbei verwirrt hat, sind die Sprites: Die werden nämlich eine Zeile weiter unten dargestellt. Ein Sprite mit Y-Position 226 beginnt also erst in Rasterzeile 227.

    Jetzt zum Timing deines Programms. Ich hab' das mal schematisch dargestellt:

    Bitte melde dich an, um diesen Anhang zu sehen.

    Am Anfang von Rasterzeile 126 wird ein IRQ ausgelöst (möglicherweise auch schon einen Taktzyklus vorher, bei den IRQs bin ich mir immer nicht so ganz sicher...) Es dauert aber noch mindestens einen Taktzyklus, bis der Prozessor das bemerkt, also in Taktzyklus 1 in Zeile 126. Dann wird erst noch der aktuell bearbeitete Befehl abgearbeitet. Im Diagramm bin ich davon ausgegangen, dass da gerade in Taktzyklus 1 ein Befehl geendet hat. Das muss aber nicht so sein, im blödsten Fall muss man (ich glaube) noch 8 Taktzyklen warten. Das Maximum erreicht man aber nur mit illegalen Opcodes. Soweit ich weiß kann man in der Praxis davon ausgehen, dass es maximal 6 sind.

    Dann wird ein spezieller Prozessorbefehl ausgeführt, der den IRQ startet (im wesentlichen ist das der BRK-Befehl). Der dauert 7 Taktzyklen und der Prozessor macht dann mit der IRQ-Routine weiter. Wo man die findet, steht in $FFFE und $FFFF. Normalerweise ist das $FF48. Dort werden erst mal die Register auf den Stack gerettet (PHA TXA PHA TYA PHA) und dann geprüft, ob das ein BRK-Befehl war oder ein IRQ (TSX LDA $0104,X AND #$10 BEQ $FF58). Am Ende folgt dann noch ein indirekter Spung an die Stelle, die in $0314 und $0315 steht.

    Erst dann beginnt deine `RasterIRQ`-Routine. In der Grafik habe ich noch markiert, wo die relevanten Speicherzugriffe stattfinden (BG=Hintergrund, MC=Multicolor, CH=Zeichensatz). Wie man sehen kann, wird die Hintergrundfarbe im rechten Rahmen von Zeile 126 geändert und Multicolor im linken Rahmen von Zeile 127.

    Der Wechsel des Zeichensatz erfolgt an einer ganz kritischen Position (Taktzyklus 14). Das ist nämlich der Bereich, wo der Prozessor abgeschaltet wird (Badline). Ich bin mir da nicht ganz sicher, aber ich glaube, das ist gerade schon ein Taktzyklus zu spät und der tatsächliche Schreibzugriff erfolgt erst in Taktzyklus 54 im rechten Rahmen von Zeile 127.


    Wie schon geschrieben, das ist der Idealfall, wenn die IRQ-Bearbeitung frühestmöglich beginnt. Das ganze Diagramm kann aber um einige Taktzyklen nach rechts verschoben sein, dann bist du mit dem letzten Schreibzugriff definitiv in der Badline drin.

  • Klingt, als ob ein FLD möglich wäre.

    Der Effekt ist so einfach wie beschrieben : :Scrollposition ändern, damit die Badline- Bedingung SPÄTER eintrifft. Da findet sich sicher Code für, und ein Testprogramm ist ganz schnell gemacht. Nicht vergessen, irgendwann wieder die Original Scrollposition zu setzen.

  • Ich hab' etliche Ideen, was man machen könnte, weiß aber nicht genau, was am Ende gut funktioniert.

    1. INC $D019 ist nicht zeitkritisch, das kannst du auch noch später ausführen. Das spart dir dann immerhin 6 Taktzyklen.
    2. LDA $D012, CMP #226, BCC L_ELSE kannst du dir auch sparen, wenn du stattdessen den IRQ-Vektor ($314/$315) hin- und herbiegst, also zwischen zwei IRQ-Routinen wechselst. Die eine ist nur für Zeile 226 zuständig, die andere für alle anderen.
    3. "Deinen Tipp mit x, y und a habe ich aber nicht ganz verstanden." Die Idee ist, die drei Schreibzugriffe (im Diagramm oben BG, MC und CH) so nahe wie möglich beieinander zu haben. Wenn du die beiden ersten Tipps umgesetzt hast, ist in der Zeile vermutlich noch genug Zeit, um die drei Register zu laden, bevor du den rechten Rand erreichst. Das Timing sähe dann so aus:


      Bitte melde dich an, um diesen Anhang zu sehen.

      Selbst wenn jetzt das Timing um 6 Taktzyklen nach rechts verschoben sein sollte, ist auch der letzte Speicherzugriff noch rechtzeitig.

    4. "Zusätzlich habe ich noch den Wert, der in $d016 geschrieben werden soll, im Handler für Zeile 0 in die Zeropage bei $06 geschrieben," Wenn du den Wert für $d016 (und $d018) vorher schon kennst (und ich glaube, das ist hier der Fall), kannst du auf die Konstruktion mit dem ORA verzichten und stattdessen einfach ldx #$nn, lda #$nn schreiben. Das spart nochmal viele Taktzyklen ein. Inklusive Schreiben sind es dann nur noch 18 Taktzyklen, drunter geht nicht, wenn du nicht zufällig eine der Zahlen für ein anderes Register wiederverwenden kannst.

    Die meisten Probleme habe ich natürlich, wenn der Mauszeiger (auch zwei Sprites) sich auf der Zeile befindet und/oder das Startmenu offen ist und ich einen Eintrag highlighte. Aber selbst mit dem Mauszeiger weit weg und geschlossenem Startmenu gab es Probleme.

    Mit den Sprites ist alles nochmal etwas komplizierter. Es reicht nämlich nicht die Anzahl der Sprites (0, 2 oder 4 bei dir, wenn ich dich richtig verstanden habe), sondern man muss auch noch wissen, welche das sind. Es macht einen Unterschied, ob du die Sprites 0-3 oder die Sprites 4-7 verwendest, weil die Prozessorabschaltungen für jedes Sprite zu einem anderen Zeitpunkt stattfinden.

  • Mann, berni, du bist echt ne große Hilfe. Vielen Dank! Das Schema ist super. So versteht man gut, was abgeht. Mir scheint, durch Abschalten des Kernals könnte man nochmal ca. 15 Zyklen sparen. Aber ich hab's jetzt so gemacht, wie du vorgeschlagen hast: ne eigene Routine für die 226. Die sieht jetzt so aus:

    Das Ändern der Hintergrundfarbe ist eh unkritisch, da in 227 sowieso nur ein weißer Streifen erscheinen soll. Daher hab ich das ans Ende gesetzt. Es flickert noch manchmal ganz rechts, wenn ich einen Eintrag im Startmenu highlighte. Da ist er nicht schnell genug mit dem Zeichensatz und flackert, weil ich die 6 Zeichen aus dem anderen Zeichensatz wieder gelöscht habe.

    Ich verstehe aber noch nicht ganz, was das tax bringen soll. Warum nicht gleich sta $d016? Geht doch schneller. EDIT: Ich glaube, ich verstehe. So hat man mehr Kontrolle darüber, wann die echten Änderungen kommen. Die stx/sta's sollten genau zwischen den Zeitpunkten kommen, wo der Rasterstrahl das Innere von 226 verlässt und in das Innere von 227 eintritt. Wenn ich es richtig verstehe, wird das Badline-Verhalten so umgangen, weil ich schneller bin und das Fetchen erst nach den stx/sta's passiert.

    Ich mach's jetzt noch mit festen Werten für $d016 und $d018. Dann sollte es klappen. Melde mich wieder mit nem Edit.

    Edit: Puh, jetzt klappt es. Auch mit allen möglichen Sprites. Das ganze ist unheimlich zeitkritisch. Da kommt es auf jeden Zykel an. So sieht der Anfang er Routine jetzt aus:

    Wenn ich ne Zeropage-Adresse statt "byte" verwende, bin ich zu früh. Dann flackert er am Ende von 226 bereits.

    Ich habe hierbei eine Menge gelernt und danke dir nochmal dafür!

    Bitte melde dich an, um diesen Link zu sehen. (Bitte melde dich an, um diesen Link zu sehen.)Bitte melde dich an, um diesen Link zu sehen.Bitte melde dich an, um diesen Link zu sehen.

    4 Mal editiert, zuletzt von WebFritzi (4. Mai 2024 um 19:33)

  • Die stx/sta's sollten genau zwischen den Zeitpunkten kommen, wo der Rasterstrahl das Innere von 226 verlässt und in das Innere von 227 eintritt. Wenn ich es richtig verstehe, wird das Badline-Verhalten so umgangen,

    Ja, so in etwa. Im Grunde genommen ist das mit der Badline sogar irrelevant. Das Problem hättest du in jeder anderen Zeile auch, da du ja vor dem Inneren, wie du es nennst, schon umschalten willst. Da ist noch gar nichts mit Badline, nur die Sprites stören da.

    Das Ganze ist tatsächlich noch einen kleinen Tick komplizierter, aber wenn es so tut, brauchst du das evtl. gar nicht zu beachten. Ich hatte es nur oben irgendwo schonmal erwähnt: Die einzelnen Register des VIC haben unterschiedliche Verzögerung. Beispielsweise (glaube ich grad zumindest) kannst du den Hintergrund schon drei Zyklen bevor der Rasterstrahl das Innere von 226 verlässt umschalten, weil die Wirkung halt erst später einsetzt. Ich hatte mal ein Demo gesehen, da wurde das ausgenutzt. Das hat dann so gewirkt, als würde in zwei direkt aufeinanderfolgenden Taktzyklen was geändert, was natürlich gar nicht möglich ist.

    Wenn ich ne Zeropage-Adresse statt "byte" verwende, bin ich zu früh.

    Deswegen hätte ich auch das ldy vor das sta vorgezogen. Dann hast du nochmal zwei Taktzyklen mehr Spielraum. Ansonsten sieht das aber schon super aus.


  • Mit den Sprites ist alles nochmal etwas komplizierter. Es reicht nämlich nicht die Anzahl der Sprites (0, 2 oder 4 bei dir, wenn ich dich richtig verstanden habe), sondern man muss auch noch wissen, welche das sind. Es macht einen Unterschied, ob du die Sprites 0-3 oder die Sprites 4-7 verwendest, weil die Prozessorabschaltungen für jedes Sprite zu einem anderen Zeitpunkt stattfinden.

    Ach du liebes Lieschen! 8|

    Bitte melde dich an, um diesen Link zu sehen. - Ratespiel • Bitte melde dich an, um diesen Link zu sehen. - BASIC-Erweiterung • Bitte melde dich an, um diesen Link zu sehen. - Sprite-Editor • Bitte melde dich an, um diesen Link zu sehen. - Zeichensatz-Editor Bitte melde dich an, um diesen Link zu sehen. - 2048 Blöcke