Beiträge von woop im Thema „Unterbrechungsroutinen C64“

    Ich hab zwar nie ein wirklich großes Projekt auf dem C64 gestemmt, aber trotzdem würde ich auch dort versuchen, alles entweder im Interrupt oder im Hauptprogramm laufen zu lassen. Ausnahmen wären eigentlich nur Dinge, die völlig autark von einem Hauptprogramm sind, also z.B. ein Hintergrundsmusikplayer oder ein einfacher Splitscreen mit einer Laufschrift oder sowas.

    Ansonsten hab ich damit zwar auch mal experimentiert weil ich dachte das sei gut fürs Karma, aber das lief dann nur darauf hinaus, dass das Hauptprogramm die meiste Zeit nur darauf gewartet hat, dass ein IRQ den Empfang irgendwelcher Daten quittiert die es ihm zur Verfügung stellt.

    ich habe langsam den verdacht, vernunftmensch will gar kein spiel programmieren, sondern eine atombombe bauen.
    die fragen sind nur so geschickt, damit das keiner merkt.

    Hoffentlich, wenn er sich weiterhin so anstellt werden wir und die 23 uns nachfolgenden Generationen die vernunftmännische Atombombe nicht mehr erleben... :bgdev

    A. Wie kann man ganz leicht herauskriegen, ob es PAL oder NTSC ist, das C64-System?
    B. Gibt es außer dem aus Programmiersicht weitere Unterschiede zwischen C64ern´(Defekte ´mal ausgenommen.)?
    C. Du meinst mit Interruptvektor einen Zeigerinteger, aber nicht eine Zusammenfassung mehrerer Sprungziele, oder?

    Zu A und B: Machst du das absichtlich? Ich werde auf weitere Fragen hierzu nicht eingehen und du machst dir nur den Einstieg unnötig schwer. Und ja, deinen Fragen nach zu urteilen steigst du gerade ein. Ich rate dir nochmal, hör auf dich in solchen irrelevante Dingen zu verzetteln und setzte dir mal ein paar Nahziele. Es wird dir nicht gelingen das perfekte, alles berücksichtigende System vorab zu entwerfen und es dann runterzuprogrammieren. Dir fehlt es wirklich noch an sehr elementarem Grundwissen. Schon alleine, dass du offenbar nicht in der Lage bist einen acme zu bedienen und mit irgendwelchen C-inline-ASM oder hilflos zusammengelinkten 40k-Binaries daherkommst spricht Bände. Daran solltest du erstmal arbeiten.

    Zu C: Äh, "Zeigerinteger" hast du dir jetzt ausgedacht, Vektor ist der richtige Begriff dafür. Im Interrupt liest die CPU $fffe und $ffff und springt an die Adresse die dort steht. Normalerweise ist an der Stelle das ROM eingeblendet und du musst dich da nicht drum kümmern, aber sobald du das ROM ausblendest musst du entweder Interrupts sperren oder dafür sorgen, dass im RAM an $fffe und $ffff eine Adresse steht, an der eine sinnvolle Interruptbehandlung stattfindet (und wenn es nur ein rti ist)
    Hier zu auch mal Bitte melde dich an, um diesen Link zu sehen. lesen, insbesondere den Absatz "Ablauf".

    Aber hey, vergiss auch mal das, lass den Kernel eingeblendet und sieh ihn als deinen Freund und Helfer an. Im Moment wirst du dich anders nur verzetteln.


    A. Während ich den Kernal ausschalte, dann muß ich für den CIA-Interrupt gewollte Startadresse ans Ende des Speichers legen? Funktioniert dann überhaupt noch ein VIC-Interrupt?
    B. Was passiert, wenn ich in einem CIA-Interrupt stecke, beispielsweise Musik und Sound wegen, und nun der VIC-Interrupt will. Wird dann ein Frame geschluckt und es ruckelt?
    C. Wäre es nicht vielleicht sogar vernünftig, das Teasing während des Spritesaufbaus komplett zu vernachlässigen und nur mit dem CIA-Interrupt zu arbeiten?

    Zu A: Ja, wenn der Kernal ausgeblendet ist und an $fffe RAM statt ROM liegt musst du dafür sorgen dass der Interruptvektor dort auf etwas sinnvolles zeigt (oder du sperrst alle IRQs per SEI, aber dann gib's bis zum erlösenden CLI auch keinen Rasterinterrupt mehr)

    Zu B: Es wird kein Frame geschluckt, aber es kann sein, dass dein Rasterinterrupt verzögert bei dir ankommt. Grundsätzlich würde ich mich nur um eine Art Interrupt kümmern und Musik und Sound im Rasterinterrupt anstatt an einem CIA-Timer auszuführen. CIA-Interrupts lassen sich auch einfach abschalten allerdings werden dann solange du nicht $ea31 weiter im Rasterinterrupt bedienst einige Kernal-Funktionen nicht mehr funktionieren. Gilt natürlich nicht, wenn du den Kernal sowieso abschaltest.

    Zu C: Du meinst vermutlich Bitte melde dich an, um diesen Link zu sehen.? Das würde ich bei Sprites nicht vernachlässigen, gerade bei schneller bewegten Sprites fällt das dann schnell auf. Also besser die Sprites im Rasterinterrupt bewegen und den CIA-Interrupt komplett ignorieren oder gleich abschalten.

    Aber ganz ehrlich, ich glaube du übernimmst dich gerade wieder. Ich würde empfehlen sich erstmal leichteren Fingerübungen zuzuwenden und z.B. die Sternendemo so umschreiben, so dass sie per Joystick gesteuert in alle vier Richtungen scrollt, vielleicht auch mal mit unterschiedlichen Geschwindigkeiten und Beschleunigung oder sowas. Ein nächster Schritt wäre dann mal einen frei erstellbaren Hintergrund statt dem Sternchenpattern zu scrollen, hierfür musst du dann umkopieren. Dann mal ein paar Sprites hinzufügen und versuchen die mit dem Hintergrund mitbewegen zu lassen. Und dann mal schauen wie es mit Kollisionsabfrage derselben untereinander und mit dem Hintergrund aussieht.

    Das sind alles Dinge die ich wärmstens empfehlen würde anzugehen bevor man überhaupt an sowas wie Interrupts ohne Kernel und Musik und Sound oder gar komplette Spieleengines denkt. Wenn du dagegen sowas in kleinen Schritten angehst prophezeie ich dir eine ziemlich steile Lernkurve und gerade so Dinge wie Scrolling und Spritehandling wirst du vermutlich noch 769576 mal schreiben, zum einen weil du immer dazulernst und es besser machen willst und zum anderen weil man auf einem C64 mit seinen arg begrenzten Ressourcen die Idee einer alleskönnenden Spieleengine mit arger Vorsicht genießen sollte. Die meisten Spiele sind ziemlich exakt auf ihre eigenen Bedürfnisse zurechtgeschrieben.

    Himmel, Vernunftmensch, du verzettelst dich aber auch wirklich mit Gewalt. Ignoriere doch jetzt erstmal NTSC und fang nicht an Probleme herbeizuhalluzinieren wo keine sind. Horden von Spielen laufen mit dem "NTSC-Speedup" und das sind nicht die Schlechtesten. Jetzt hat man dir ein paar Spielwiesen vor die Füße gelegt mit Schleifchen drum und anstatt da ein bisschen Rumzutoben sorgst du dich über irgendeinen belanglosen Mist.

    Mist, wer hat sich denn so eine Sache ausgedacht! :motz:

    Der CIA ist so eingestellt, daß er ca. 50 Mal pro Sekunde einen IRQ auslöst. Gibt es dabei feste Rasterzeiten oder funktioniert der völlig unabhängig vom Vic2?

    Edit: 60 und das auch nur ohne Umprogrammierung.

    Der CIA-Timer läuft unabhängig vom VIC2 aber wieso stört dich das?

    $fa wird als Auslöser für den Rasterinterrupt einprogrammiert.

    Was passiert, wenn der IRQ abgeschlossen ist, aber der Wert der Rasterzeile immer noch $fa ist?
    Wird dann der Interrupt direkt nochmal ausgelöst?

    $fa ist der Parameter für den Rasterinterrupt und steht für die Rasterzeile in der ein IRQ ausgelöst wird. Programmiert für Rasterinterrupts wird der VIC2 durch das Setzen von $d01a. Hier mal die Registerbelegung ansehen und mit dem Code vergleichen:

    Code
    --+-------+----+----+----+----+----+----+----+----+------------------------
    26| $d01a |  - |  - |  - |  - | ELP|EMMC|EMBC|ERST| Interrupt enabled
    --+-------+----+----+----+----+----+----+----+----+------------------------

    ERST steht hier für "enable raster irq", deswegen wird dieses Register auf %11110001 gesetzt.


    Man muss dem VIC2 die Bearbeitung des Interrupts bestätigen, damit er erst wieder im nächsten Frame einen IRQ auslöst, das geschieht durch das Schreiben von $d019 deswegen dieses scheinbar sinnlose sta $d019 im IRQ-Handler.

    Und weil die Sternchen so toll sind hier noch eine Version im Rasterinterrupt. Als kleine Besonderheit kann das Programm mit Run/Stop beendet werden, lässt aber den Scrolleffekt im Interrupt weiterlaufen. Startet man es dann erneut mit RUN wird die Interruptroutine wieder sauber abgeschaltet.

    wenn du es schaffst den ganzen screen in 8 zeilen umzukopieren bin ich echt beeindruckt =)

    Das wäre ich auch, aber wenn ich nur ein Pixel pro Frame scrolle muss ich nur alle 8 Frames den Screen umkopieren und es steht auch nicht geschrieben, dass es selbst dann auch immer gleich der ganze Screen sein muss :D

    alternativ einfach auf rasterline >= $f8 oder sowas warten, also in dem ersten schnipsel das BNE auf BCC ändern :)

    Nee, genau das funktioniert ja nicht. Hier mal aus der Sicht der CPU:

    Der Rasterstrahl sei mal eben an Position 42 als wir in unsere Schleife reinlaufen. Nun pollen wir also so lange die Rasterstrahlposition bis sie 250 erreicht oder überschreitet: 42, 42, 43, 44, 44, 45, ..., 249, 250 Yeah!

    Nun machen wir den Kram den wir pro Frame an Position 250 eben so tun wollen und weil das alles in liebevoll woop-optimierten handgestickten und polierten Code geschieht sind wir damit schon nach 8,23 Taktzyklen fertig und beginnen unsere Schleife von vorne.

    Leider leider hat es der Rasterstrahl in dieser Zeit gerade mal ans Ende von Position 250 geschafft und so durchlaufen wir unseren Code nocheinmal für das gleiche Frame; und beim nächsten Mal sind wir an 251 und machen es nochmal und nochmal, bis sich der VIC2 unserem Elend erbarmt und dem unseligen Treiben per V-Sync ein Ende setzt und unseren Rasterstrahl wieder auf 0 setzt.

    Deswegen brauchen wir hier diese Barriere, die vor dem Überschreiten einer bestimmten Rasterzeile zunächst auf das Unterschreiten einer Zeile davor wartet.

    Jetzt hat mich das Thema doch nicht losgelassen und ich habe wegen des Ruckeln das ganze nochmal überdacht und am echten C64 probiert.

    Mein Vorschlag auf die Rasterzeile zu warten ist so in der Tat ungenau und wackelig, weil ich zum einen die exakte Rasterzeile verpassen kann oder -- wenn ich zu schnell bin -- eine Rasterzeile mehrmals bearbeite, weil beim erneuten Auslesen zuwenig Zeit vergangen ist.

    Ich muss also in zwei Stufen warten, erstens solange bis der Rasterstrahl kleiner als die Wunschposition ist und zeitens solange bis der Rasterstrahl größer gleich meiner Wunschposition ist. So ist gewährleistet, dass ich nur einmal pro Bilddurchlauf in die Scrollroutine reinlaufe und ich zum anderen eine Toleranz habe, falls ich mal die exakte Zeile verpassen sollte.

    Und mit diesem überarbeiteten Code habe ich dann tatsächlich butterweiches 50fps-Scrolling:

    Läuft die untere Prg bei Dir vielleicht sogar reibungsfrei?

    Also ich hab jetzt mal das 180-Block-Sternchendemo (Rekord?) in vice geladen und es zeigt tatsächlich ein anderes Timingverhalten als mein acme-binary hier. Den Blick in den Disassmbler spare ich mir angesichts dieser Größe dann doch.

    Allerdings sehe ich auch da kein Tearing, nur das übliche Emulatorgeruckel. Hast du schonmal Uridium bei dir im Emulator laufen lassen? Gibts da Tearing? Ich würde vermuten, dass dein Emulator ein Tearingproblem hat. Damit eigenet er sich natürlich nicht zur RasterIRQ-Entwicklung :smile:

    Hai.

    Ich habe Deine Assemblerroutine in eine Assemblerdatei reinkopiert (bei heap am Ende fehlte noch ein Doppelpunkt), selbiges Problem. Die ersten vier Zeilen eilen dem Rest voraus.

    :motz:

    ((auf dem vice x64 unter ubuntu))

    Läuft die untere Prg bei Dir vielleicht sogar reibungsfrei?

    Kein Grund zu Motzen, den Doppelpunkt habe ich mal nachgetragen. Dein problem.prg ist 45k groß, was hast du denn da alles drin? Meine Routine oben passt zumindest in 1k...

    Vernunftmensch: ich hab echt noch niemanden gesehen der so konsequent jeden tip ignoriert und sich dann die denkbar schlechteste aller möglichkeiten aussucht.

    Vernunftmensch: Hör da mal auf Sauhund, dir helfen zu wollen ist eine echt nervenaufreibende Sache: man erzählt dir was und öffnet dir einen Weg und du fängst an irgendwelchen Unfug zu treiben auf den man im Leben nicht kommen würde und man fragt sich, ob man sich selbst wirklich so unverständlich ausdrückt oder ob Missverständnisse so eine Art persönliches Hobby von dir sind. :smile:

    Wah, bring mal deinen Assemblercode in lesbare Form und lass diese __asm__ makros weg...
    Also grundsätzlich solltest du deine Sternchen nur einmal zeichnen und dann in der Schleife nur noch $d016 beackern.
    Außerdem ist die letzte sichtbare Zeile bei PAL-Geräten 250, nicht 255.

    Hier das ganze mal kommentiert, und mit dämlicher Sternchenfüllroutine: