JMP from Subroutine (no RTS)

Es gibt 62 Antworten in diesem Thema, welches 8.106 mal aufgerufen wurde. Der letzte Beitrag (20. Juni 2022 um 16:34) ist von Sorbas2020.

  • Ok. Ich möchte nochmal BACK TO TOPIC.

    Ich hab in Bezug auf meine ursprüngliche Fragestellung hier jetzt ein konkretes Beispiel.

    Es befindet sich in meinem Post zum schnellen Spielchen für Zwischendurch.

    MONOCHROME.

    gamecode.asm Zeile 334.

    jmp Titlescreen.

    Dieser Codeteil stammt übrigens nicht von mir!

    Ich hab nur Anpassungen in Bezug auf Grafik und Sound gemacht.

  • Im gleiche Projekt gibt es übrigens noch eine andere Strukturelle Unschönheit.

    Main.asm Zeile 560:

    jmp StartGame

    Hier wird aus dem Interrupt gesprungen.

  • Ich glaube, das geht alles zu off topic:

    Ich meine solche Sachen, wo die Scherzkekse jedes mögliche Problem in einer eigenen(!) Exception-Klasse werfen. Wenn man dann nur diese Exceptions abfangen will, aber alle anderen (Standard-)Exceptions nichts, dann hast du eine hübsche Catch-Kette im Code. So gesehen bei einem C#-Projekt.

    Oder Pappnasen wie Oracle, die in deren API den Rückgabewert in eine Exception packen. Will ich auf einen bestimmten Code eingehen, muss ich den aus der Exception wieder ausgraben, und kann dann drauf reagieren. Dazwischen liegt eine schöne Exception-Behandlung, die immer schön Performance kostet (C++)

    Ich ziehe in fast allen Fällen einen normalen Rückgabewert vor. Exceptions in C++ gar nicht, und bei C# nur bei wirklich wirklich fatalen Dingen, und selbst da nur ungern.

    On Error Goto ist natürlich Klasse. Und kann sogar mehr als Exceptions, man kann in der Regel bei dem Ort des Fehlers weitermachen.

    C64Studio: Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen. --- C64Studio WIP: 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.

  • Es befindet sich in meinem Post zum schnellen Spielchen für Zwischendurch.

    Kannst Du einen Link posten? Die Forensuche nach "Schnelle Spielchen für Zwischendurch" ergibt nichts brauchbares und in Deinen "Letzten Aktivitäten" finde ich auch nichts...

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • Danke! Ja, in beiden Fällen verlässt sich Richard wohl darauf, dass der Stack ein Ringbuffer ist und lässt das Spiel einfach an einer neuen Stackposition beginnen. Beim Sprung aus dem IRQ setzt er auch einfach die Flags wieder wie gewünscht. Ist jetzt nicht sooo sauber meiner Meinung nach, aber Mei, wenn's funktioniert ^^.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • Claus: man kann sich natürlich alles schönreden. Hardwaretechnisch ist der 65xx-Stack zwar als Ringpuffer implementieren, aber wie Mac Bacon in Beitrag Bitte melde dich an, um diesen Link zu sehen. bereits angemerkt hat, greift die 1st-Level-ISR im KERNAL nach TSX auf $0104,X zu, um das B-Flag abzuprüfen: Bitte melde dich an, um diesen Link zu sehen..

    Hat Richard also nicht explizit einen eigenen Hardware-IRQ (also: neuer Vektor im RAM bei $FFFE) eingerichtet, der das richtig macht, dann ist das Herausspringen aus dem IRQ mit JMP ein glatter Bug im Programm!

  • Hat Richard also nicht explizit einen eigenen Hardware-IRQ (also: neuer Vektor im RAM bei $FFFE) eingerichtet, der das richtig macht, dann ist das Herausspringen aus dem IRQ mit JMP ein glatter Bug im Programm!

    Ja, aber den Vektor umbiegen macht doch praktisch jeder. Hab jetzt nicht geschaut, aber das würde mich jetzt schon überraschen, wenn das bei Richard nicht so wäre.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • Claus: das habe ich gerade gemacht und ja, Richard hat $FFFE umgebogen. In den Ersatz-Routinen (sind mehrere) fragt er das B-Flag nicht ab, insofern erübrigt sich meine Bemerkung vorher.

    Allerdings benutzt er eine Methode, um die Register zu sichern, die auch recht "interessant" ist (nicht geeignet für ROM und nicht wiedereintrittsfest). Ob's da wirklich auf die paar gesparten Taktzyklen ankommt?

    ...

    Ich bin jedenfalls auch der Auffassung, daß unbedachtes Stack-Handling in der hier diskutierten Weise zumindest schlechter Stil ist, und man sich das eigentlich nur erlauben kann, wenn das (eigene) Programm das einzige ist, was auf dem Rechner läuft.

  • Ein Risiko sehe ich schon bei der Sache, das ist wenn man doch mal den Kernal einblendet, um z.B. Highscores zu speichern. Das kann dann natürlich zu spaßigen, gelegentlich auftretenden Abstürzen führen, wenn in den BRK-Handler gesprungen wird. Also ich würde es nicht so machen ^^.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • Claus: man kann sich natürlich alles schönreden. Hardwaretechnisch ist der 65xx-Stack zwar als Ringpuffer implementieren, aber wie Mac Bacon in Beitrag Bitte melde dich an, um diesen Link zu sehen. bereits angemerkt hat, greift die 1st-Level-ISR im KERNAL nach TSX auf $0104,X zu, um das B-Flag abzuprüfen: $FF48 - AAY64.

    Wieso Ringpuffer? Ein Stack ist nach LIFO oranisiert. Ein Ringpuffer funktioniert nach FIFO-Prinzip. Ich nehme an der Ringpuffer-Hinweis spielt auf den Überlauf in der Page 1, der in der Page 1 bleibt an. Das macht einen Stack aber als Datenstruktur nicht zum Ringpuffer.

    Erwartete Werte auf dem Stack mit $0104,X zu adressieren ist ja noch durchaus legitim. Gefährlich wird's, wenn man ein Element vom Stack nimmt (etwa den Stackpointer schon für den Ausstieg optimierend vorbereitet), aber auf dieses noch mit $100,X zugreift. Wenn da ein IRQ oder in einem IRQ auch ein NMI daher kommt, wird dann das Element mitunter zerstört ...

  • Man hätte natürlich auch schreiben können, dass der Stack auf einer Hardware-Implementierung basiert, die der Funktionalität eines Ringbuffers in manchen Aspekten ähnelt. Manchmal stehen sich Korrektheit und Verständlichkeit aber auch gegenseitig im Weg :D.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • Man hätte natürlich auch schreiben können, dass der Stack auf einer Hardware-Implementierung basiert, die der Funktionalität eines Ringbuffers in manchen Aspekten ähnelt. Manchmal stehen sich Korrektheit und Verständlichkeit aber auch gegenseitig im Weg :D.

    Nein, eigentlich nicht. Ein Stack ist kein Ringpuffer. Ein Stack bzw. Stapel lässt sich nicht im Entferntesten durch einen Ringpuffer (schon gar nicht der "besseren Erklärung" wegen) abbilden oder erklären.

    Welche Ähnlichkeit ist da gemeint? Dass beides Datenstrukturen sind und eine Hinzufügungs- und Entfernungsaktion haben? Das haben quasi alle Datenstrukturen zum Aufbewahren von Werten gemein. Das heißt noch lange nicht, dass damit ein Stack durch einen Ringbuffer erklärt werden kann.

    Ob es hardware-mäßig implementiert ist, spielt ja für das Prinzip keinerlei Rolle.

    Nur kurz rekapituliert: Um einen Ringpuffer zu implementieren braucht man zwei Zeiger (für die Einfügestelle und für die Entnahmestelle, FiFO-Prinzip, First In - First Out), wobei für einen Stack nur ein Zeiger notwendig ist, weil die Einfügestelle gleich der Entnahmestelle ist (LIFO-Prinzip: Last In - First Out).

  • Nur kurz rekapituliert: Um einen Ringpuffer zu implementieren braucht man zwei Zeiger (für die Einfügestelle und für die Entnahmestelle, FiFO-Prinzip, First In - First Out), wobei für einen Stack nur ein Zeiger notwendig ist, weil die Einfügestelle gleich der Entnahmestelle ist (LIFO-Prinzip: Last In - First Out).

    Bei dem ganzen Thema wird schlicht eins vergessen: was manche als Ringpuffer sehen oder bezeichnen, ist schlicht ein Überlauf des Stacks. Der Stack des Cevi ist - wie Du richtig sagst - einfach ein LIFO.

    Früher waren 64k unglaublich viel, heute reicht es nicht mal mehr für "Hello, world!".

  • Man hätte natürlich auch schreiben können, dass der Stack auf einer Hardware-Implementierung basiert, die der Funktionalität eines Ringbuffers in manchen Aspekten ähnelt. Manchmal stehen sich Korrektheit und Verständlichkeit aber auch gegenseitig im Weg :D.

    Nein, eigentlich nicht. Ein Stack ist kein Ringpuffer. Ein Stack bzw. Stapel lässt sich nicht im Entferntesten durch einen Ringpuffer (schon gar nicht der "besseren Erklärung" wegen) abbilden oder erklären.

    Welche Ähnlichkeit ist da gemeint? Dass beides Datenstrukturen sind und eine Hinzufügungs- und Entfernungsaktion haben? Das haben quasi alle Datenstrukturen zum Aufbewahren von Werten gemein. Das heißt noch lange nicht, dass damit ein Stack durch einen Ringbuffer erklärt werden kann.

    Ob es hardware-mäßig implementiert ist, spielt ja für das Prinzip keinerlei Rolle.

    Nur kurz rekapituliert: Um einen Ringpuffer zu implementieren braucht man zwei Zeiger (für die Einfügestelle und für die Entnahmestelle, FiFO-Prinzip, First In - First Out), wobei für einen Stack nur ein Zeiger notwendig ist, weil die Einfügestelle gleich der Entnahmestelle ist (LIFO-Prinzip: Last In - First Out).

    Boah, komm mal klar.

    Es ist doch relativ offensichtlich, woher das mit dem Ringpuffer kam.

    Einfach daher, dass der Stackpointer eben von 0 nach $ff rumwrappt, wenn man zuviel pusht (analog umgekehrt).

    Dass der Stack dennoch LIFO-mäßig funktioniert (und eben nur einen Reintu-/Raushol-Zeiger hat), ist denke allen bewusst.

  • Boah, komm mal klar.

    Es ist doch relativ offensichtlich, woher das mit dem Ringpuffer kam.

    Einfach daher, dass der Stackpointer eben von 0 nach $ff rumwrappt, wenn man zuviel pusht (analog umgekehrt).

    Dass der Stack dennoch LIFO-mäßig funktioniert (und eben nur einen Reintu-/Raushol-Zeiger hat), ist denke allen bewusst.

    Die Vermutung zur Herkunft hab ich ja bereits in Bitte melde dich an, um diesen Link zu sehen. erwähnt. Das rechtfertigt m. E. trotzdem die Verwendung des Begriffs "Ringpuffer" an sich nicht wirklich. Ein Page-Wrap-around hat mit einem Ringpuffer in erster Linie nichts zu tun, lediglich das die "Ringkonstruktion" auch mit einem Wrap-around implementiert ist. Aber das war schon. D.h. bloß weil 2 Datenstrukturen eine gemeinsame Technik nutzen oder Eigenschaft haben (Wrap-around), sind diese deswegen nicht gleich bzw. würde ich das eine in Bezug auf das andere nicht als ähnlich titulieren.

    Dass das "allen" bewusst ist, mag ja sein. Dann ist es um so erstaunlicher, dass hier diese missverständlicher Bezug hergestellt wird und dieser so vehement verteidigt wird.

    Da ist halt einfach der falsche Begriff, die falsche Assoziation gefallen, bloß weil ein Ringpuffer auch einen Wrap-around hat, ist es dennoch unpassend, bei einem Stack von einem Ringpuffer zu reden (was nur ein Implementierungsdetail des Ringpuffer ist, aber diese Datenstruktur an sich nicht charakterisiert). Auf das hab ich lediglich hingewiesen.
    Tut mir leid, das ich es wage zu erwähnen, dass es schlicht falsch ist. Es sollte nicht als persönlicher Angriff rüberkommen und nicht als solcher aufgefasst werden.
    Wie auch immer, ich bin es jedenfalls nicht, der damit klar kommen muss. ;)

  • …also vehement bin ich sicher nicht :whistling:. Mir ist es Wurscht, Du hast ja schon erfasst und mehrfach erklärt, was ich meinte. Können wir aus meiner Sicht einfach so belassen :bia.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • JeeK: O.K., O.K., die Bezeichnung des Stacks als "Ringpuffer" habe ich jetzt wirklich nicht glücklich von Claus übernommen.

    Worauf ich hinauswollte: die CPU macht einen Wraparound des Stackpointers, wenn ein Byte bei $0100 (d.h. hier vorher: Stackpointer = $00!) ge-pusht wurde, der Stackpointer enthält dann den Wert $FF womit der nächste Push bei $01FF erfolgt. Insbesondere löst diese Begebenheit keine Prozessor-Exception aus. Im BASIC-Interpreter wird der Stackpointer aber bei "kritischen" Situationen durchaus abgefragt, ob er bereits zu tief hängt, und dann gibt's einen ?OUT OF MEMORY ERROR - der aber nichts damit zu tun hat, daß im BASIC RAM jetzt der Speicher voll wäre.

    Die originale KERNAL 1st-Level-ISR macht trotzdem Murks an der Stelle. Wenn der Stackpointer nach dem Stacken von PC, SR, A, X und Y bei $FC..$FF steht, greift LDA $0104,X nicht auf $0100..$0103 sondern auf $0200..$0203 zu und ermittelt den Zustand des B-Flags nicht richtig. Korrekt wäre es etwa in der Art:

    Code
    PHA
    TXA
    TSX
    PHA
    INX
    INX
    LDA $0100,X
    AND #$10
    BNE Break
    [...]

    ... wobei man dann noch überlegen sollte, ganz am Anfang noch ein CLD zu spendieren. Y wurde hier noch nicht gestackt, das kann man noch nachholen und evtl. zwei IRQ-Exits (eins mit gestacktem Y und eins mit ungestacktem Y) anbieten, etc. pp.

  • Die originale KERNAL 1st-Level-ISR macht trotzdem Murks an der Stelle. Wenn der Stackpointer nach dem Stacken von PC, SR, A, X und Y bei $FC..$FF steht, greift LDA $0104,X nicht auf $0100..$0103 sondern auf $0200..$0203 zu und ermittelt den Zustand des B-Flags nicht richtig.

    Ja, diese $0104-Sache ist seltsam.

    Der BASIC-Interpreter setzt den Stackpointer aber beim Kaltstart auf $FB und beim Warmstart über CLR auf $FA, soweit ich das sehe.

    Insofern dürfte das kein Problem sein, es sei denn, der Stack läuft über, und dann ist eh schon alles kaputt. :)

  • Ja, diese $0104-Sache ist seltsam.

    Warum? Sowas habe ich auch schon verwendet, wenn ich weiss dass ein bestimmer Offset benötigt wird, statt erst X zu laden, oder zu ändern. So kann man sich ein wenig Code sparen.