Hallo Besucher, der Thread wurde 1,8k mal aufgerufen und enthält 12 Antworten

letzter Beitrag von Jan1980 am

Rasterzeileninterrupts aufteilen...

  • Hallo.


    Ich habe hier einen Code geschrieben mit 4 Rasterzeileninterrupts. Ziel des ganzen ist es, mit einem Interrupt die Musik aus zu lösen (kommt später), mit dem nächsten eine feststehende Überschirft dar zu stellen, mit dem dritten eine Grafik in die Mitte des Bildschirms dar zu stelle. Und der vierte soll unten eine Laufschrift vorbeiscrollen lassen. Wie ich letzten Ende die Laufschrift mache und die Musik einfüge, weiß ich. Aber ich kriege es nicht hin, dass die Überschrift stehen bleibt, wenn sich die Scrollschrift unten bewegt. Dabei dachte ich,ich hätte mit den Rasterinterupts quasi 4 Bildschirme auf einem. Was mache ich falsch ??


    Vielen Dank !!


    Gruß Jan


  • Aber ich kriege es nicht hin, dass die Überschrift stehen bleibt, wenn sich die Scrollschrift unten bewegt. Dabei dachte ich,ich hätte mit den Rasterinterupts quasi 4 Bildschirme auf einem. Was mache ich falsch ??

    Im vierten Handler wird das Scrollregister verändert, um die Laufschrift laufen zu lassen. Aber unter der Laufschrift wird es nicht auf den Defaultwert zurückgesetzt, also wird im nächsten Frame der ganze Screen mit der neuen X-Position dargestellt.

    Du könntest gleich im ersten Handler das Scrollregister mit dem Defaultwert beschreiben, das würde das Problem lösen.


    ...und noch eine andere Sache: Die CMP-Vergleiche mit der gewünschten Rasterzeile könnten fehlschlagen, schließlich hat man - je nachdem, ob badline oder nicht - nur 23 oder 63 Zyklen Zeit zwischen dem Auslösen des Interrupts und dem Vergleich der Werte. Statt "gleich" wäre also "größer oder gleich" sinnvoll.

  • Ich würde da nicht nur eine IRQ-Routine mit Verzweigewurst machen, sondern 4 getrennte IRQ-Routinen machen, die jeweils am Ende den IRQ-Vektor auf die nächste Routine setzen. Wenn das CIA-Timing nicht unbedingt gebraucht wird, würde ich den CIA-IRQ deaktivieren. Damit spart man sich auch die Abfrage zur Feststellung, was den IRQ ausgelöst hat. Sofern die KERNAL-IRQ-Routinen benötigt werden, würde ich in einer der IRQ-Routinen einfach am Ende nach $ea31 springen.


    Für's Debugging empfiehlt es sich, am Anfang und Ende jeder IRQ-Routine die Rahmenfarbe zu ändern, damit man sieht, wie sich die CPU-Zeit verteilt und kann direkt erkennen, wo es eng wird.


    Das dürfte alles so gängige Praxis sein.

  • Hallo nochmal. Ich wollte jetzt keinen neuen Thread aufmachen. Ich bin jetzt hier wieder an meinem Rasterinterrupt. Der Titel steht, aber der Lauftext ist viel zu schnell. Ich kriege den Lauftext nicht langsamer, ohne dass das Timing "spinnt". Ich habe es mit einem Zähler in einem Register probiert, der ist zu schnell. Dann habe ich 2 Zählerschleifen verschachtelt, das geht gar nicht. Außerdem habe ich einen Counter in der Zeropage Adresse $02 programmiert.

    Entweder bleibt der Scroller schnell oder aber durch eine Verzögerungsschleife dreht das ganze Dingen durch. Was kann ich hier tun, dass der Text schön "smooth" da vorbei scrollt ? Vielen Dank !


  • Spring stattdessen zu einem RTS. Das wird einen großen Unterschied machen.

    Außerdem: Für einen wirklich smoothen Scroller solltest Du besser den CIA-Interrupt abschalten, wie LogicDeLux bereits vorschlug. Sein Tip mit den vier getrennten IRQ-Routinen ist ebenfalls sehr nützlich. Beim Raster-IRQ muß man nämlich stets bedenken, daß man nicht viel Zeit hat, um die VIC-Registerwerte neu zu setzen. Jeder Vergleich auf eine Rasterzeile kostet wertvolle Zeit, und ist man zu langsam, kommt es schnell zu Glitches in der Darstellung.

  • Das der Scroller zu schnell ist, liegt an dieser Abfrage.


    cmp #7

    bne main_scroller


    Die zählt einfach bis sieben hoch, anstatt die Routine zu verlassen. Durch den kurzen Blick in den Sourcecode ist mir noch was aufgefallen, beim abfragen und setzen der Rasterzeilen hast du überall das # Zeichen vergessen.

  • Vielen Dank für die Antworten !


    Also ich beschäftige mich jetzt seit knapp einem Jahr mit Assembler. Hatte quasi bei null angefangen. Nachdem ich mehrere Bücher gelesen habe, bin ich jetzt regelmäßig am probieren und machen. Assembler ist wie Klavier spielen, man kann es nur richtig lernen, wenn man es macht. Natürlich lerne ich viel aus Codes von anderen. Ich tippe die Codes dann ab und kommentiere sie und wenn ich etwas nicht verstehe, dann recherchiere ich, um den Code zu verstehen. Dann ändere ich die Codes ab und schaue was passiert. Anschließend mache ich dann mit dem erlernten meine eigenen Codes.


    Bzgl. dem #. Das # setze ich oben schon bei den Variablen. zB startzeile3=#150 . Ist vielleicht ungewöhnlich, aber funktioniert.

    Das cmp #7 ist für den Scroller. Die Zeichen verschieben sich 8 Pixel ( also von 0 bis 7 ) und dann wird der Bildschirminhalt umkopiert. Das kann ich also nicht abändern. Oder habe ich da etwas falsch verstanden ?


    Ok, die CIA Interrupts werde ich mal abschalten. Grundsätzlich hatte ich mich CIA Interrupts noch gar nicht beschäftigt, aber abschalten kann ich sie. :-)


    Das hab ich oben vergessen zu schreiben. Ich hatte den Rasterinterrupt um eine weitere Zeilen abfrage erweitert und in diesen dann eine Verzögerungsschleife geschrieben. Das hat auch nicht funktioniert. Das Timing war nichts mehr. Der Text lief zwar langsamer, aber der Bildschirm hat geflackert. Meine "Wald-und Wiesen-Verzögerungsschleife" sieht so aus:






    Außerdem hatte ich einen Counter in der Zeropage erstellt zum probieren:


    Code
    1. counter lda #0
    2. sta $02
    3. loop clc
    4. adc #$1
    5. ; sta $0500 ; Zur Kontrolle auf Bildschirm
    6. cmp #$ff
    7. bne loop
    8. sec
    9. rts


    Das hat alles nicht funktioniert. Ich glaube, ich muß mir zum einen angewöhnen, Taktzyklen im Interrupt zu zählen und ich habe noch ein kleines Verständnisproblem.

    Eine Zeile hat ca 60 Taktzyklen Platz. Habe ich dann 60 Taktzyklen Zeit für mein Unterprogramm. Oder habe ich Zeit, bis zur nächsten Zeile bzw. bis zum erneuten Erreichen der Zeile ?


    Dann noch eine Frage. Die Lage der Rasterzeilenabfrage hat ja letzten Endes mit dem Bildaufbau nichts zu tun, oder ? Also ich kann zB eine Rasterzeile bei #150 abfragen, obwohl in echt ein Bitmap dargestellt wird, also koala Bild ?!



    Vielen Dank !


    Gruß Jan

  • Du hast glaube ich nicht ganz verstanden, was die Verzögerung bewirken soll. Du sollst nicht dein Programm verlangsamen und damit uneffektiv machen, sondern der Rasterint muss 50/60 mal/Sekunde durch laufen. Verlangsamst Du also alles, flackert es weil der Bildschirmaufbau nicht nach kommt.


    Was du aber machen solltest, ist z.B. einen Zähler auf 50 zählen zu lassen 1x pro Raster IRQ. Wenn Du 50 erreichst, dann lässt Du dein Scrolling um eine Position weiter laufen. So scrollst du um einen Pixel pro Sekunde (was viel zu langsam sein wird, aber einfach nur mal als Beispiel)


    Pseudo:


    Lade Wert aus Variable

    erhöre um 1

    vergleich mit gewünschtem Wert (BEQ wert passt)

    wert kleiner, dann nicht weiter in der Scroll Routine (RTS)

    wert passt: Wert auf 0

    Scrollen


    Was Du dann z.B. machen kannst bei bestimmten Zeichen im Text ($ff, $fe, $fd) in der Scrollroutine reagieren und somit auch verschiedene Geschwindigkeiten einstellen, indem du deinen Variablen andere Werte zuweist. Wenn du sehr große Fonts nutzt, dann
    kann es ja z.B. auch sein, das Du mehr als 1 Pixel/Sekunde scrollen willst.

  • Eine Zeile hat ca 60 Taktzyklen Platz. Habe ich dann 60 Taktzyklen Zeit für mein Unterprogramm. Oder habe ich Zeit, bis zur nächsten Zeile bzw. bis zum erneuten Erreichen der Zeile ?

    In Badlines hat die CPU deutlich weniger Taktzyklen zur Verfügung als in anderen Zeilen. Taktzyklen muß man in den allermeisten Fällen sicher nicht abzählen, aber man sollte die Routinen schon so gestalten, daß die so schnell wie möglich, die gewünschten VIC-Register setzen. Was danach noch in der Routine passiert, kann sich Zeit lassen, sollte aber schon zum Ende kommen, bevor der nächste Interrupt fällig ist, weil sich sonst die Routinen in die Quere kommen.

    Alles über das Timing findet sich hier: http://www.cebix.net/VIC-Artikel.txt

    Dann noch eine Frage. Die Lage der Rasterzeilenabfrage hat ja letzten Endes mit dem Bildaufbau nichts zu tun, oder ?

    Ein Rasterzeileninterrupt ist dazu da, daß man keine Rasterzeilenabfrage machen muß.

    Um ein Gefühl für das Timing zu bekommen, erwähne ich gerne nochmal meine Empfehlung, am Anfang und Ende jeder Interruptroutine jeweils unterschiedliche Rahmenfarben zu setzen, um eine visuelle Repräsentation zu bekommen. Das kann man später, wenn das Timing erstmal sitzt, natürlich wieder rausnehmen.

  • Bzgl. dem #. Das # setze ich oben schon bei den Variablen. zB startzeile3=#150 . Ist vielleicht ungewöhnlich, aber funktioniert.

    Das ist nicht nur vielleicht ungewöhnlich, sondern extrem ungewöhnlich und nicht zu empfehlen. Beim ersten Lesen war ich auch irritiert, weil nahezu jeder 6502-Programmierer davon ausgeht, daß ein '#' beim Befehl selbst eine Konstante kennzeichnet, da dies die etablierte Syntax ist. Das Verschieben des '#' in eine Deklaration ist eine überflüssige potientielle Fehlerquelle mit der Eigenschaft, andere 6502-Programmierer zu verwirren bzw. den Quellcode unleserlich zu machen.

    Oder habe ich da etwas falsch verstanden ?

    Wahrscheinlich hast Du noch nicht verinnerlicht, daß der Interrupt bereits die Verzögerungsschleife ist. Eine weitere Verzögerung ist daher unnötig und kann so nicht funktionieren. Halte Dir mal vor Augen, was pro Frame gemacht werden muß:

    - dekrementiere die Scrollposition

    - Ist die Scrollposition wieder bei 7 angekommen, dann und nur dann kopiere die Zeichen um.

    Anders gesagt: Wenn die Scrollposition nicht 7 ist, hat der Interrupt für diesen Frame bereits seine Arbeit erledigt und kann beendet werden. Danach entsteht automatisch eine Verzögerung um eine 50tel-Sekunde, bis der Interrupt erneut ausgelöst wird. Diese Zeitspanne zwischen den beiden Interrupts ist somit Deine Wartezeit. Alles, was Du tun mußt, ist also, den Rat von Acorn und mir zu befolgen und die Interruptroutine beenden, wenn der Wert von Scrollposition nicht 7 ist.


    Was den Aufbau des Programms anbelangt, hier ein genereller Tip:

    Die Struktur ist etwas unordentlich und schlecht zu durchschauen. Normalerweise würde man das Programm so konzipieren:


    Eine Zeile hat ca 60 Taktzyklen Platz. Habe ich dann 60 Taktzyklen Zeit für mein Unterprogramm. Oder habe ich Zeit, bis zur nächsten Zeile bzw. bis zum erneuten Erreichen der Zeile ?

    Siehe hier:

    Die CMP-Vergleiche mit der gewünschten Rasterzeile könnten fehlschlagen, schließlich hat man - je nachdem, ob badline oder nicht - nur 23 oder 63 Zyklen Zeit zwischen dem Auslösen des Interrupts und dem Vergleich der Werte. Statt "gleich" wäre also "größer oder gleich" sinnvoll.

    Man hat bei einem Rasterinterrupt grundsätzlich zu wenig Zeit. Daher will man die Interruptroutine so kurz und schnell wie möglich halten. Die Interruptverarbeitung des Kernals ist in dieser Hinsicht sehr langsam und wird für solche Sachen wie Demos auch nicht verwendet. Auch die allermeisten Spiele dürften den Kernal-Interrupt umgehen. Der einzige Sinn der Kernalroutine liegt darin, die Tastatur abzufragen. (Das Weiterzählen von TI$ ist in der Regel unnötig.) Die Tastaturabfrage kann man aber auch in der eigenen Interruptroutine vornehmen, indem man mittels "JSR $ff9f" das Tastatur-Unterprogramm des Kernals selber aufruft.

    Was Du jedoch am Ende wirklich willst, ist das, was LogicDeLux bereits beschrieben hat: Du schreibst vier getrennte Interruptroutinen. Am Ende einer jeden Routine setzt Du den Interruptvektor um auf die nächste Routine. Dadurch sparst Du die wiederholte Abfrage der Rasterzeile und kannst zudem die Interruptroutine individueller gestalten. Wichtig: Am besten schaltest Du dafür das Rom komplett ab (LDA #$35 : STA $01) und verwendest den direkten Interruptvektor bei $fffe/$ffff und nicht $314/$315. Achte dann nur darauf, daß Du zu Beginn der Interruptroutine die Register selber rettest. Viel Erfolg!

  • Im großen und ganzen läuft dein Programm, habe nur ein paar Änderungen vorgenommen.