Hello, Guest the thread was viewed1k times and contains 22 replies

last post from 1570 at the

​Was macht der BASIC-Interpreter, wenn man RUN eingibt?

  • Ich möchte aus GUI64 heraus auch Dateien starten können. Dafür möchte ich gerne das Programm in den Speicher bei $0801 laden und dann das machen, was BASIC macht, wenn RUN eingegeben wird. Die Routine ist ja schon da im BASIC-ROM - ich bräuchte also lediglich die Adresse im ROM, welche bei der Eingabe von RUN aufgerufen wird. Kennt sich da jemand aus?

  • strik Alles klar, vielen Dank.

    Beachte aber, dass es testet, ob danach noch eine Zeilennummer kommt. Daher sollte das Z-Flag beim Einsprung gelöscht sein

    Jo, hab nachgeschaut. Sonst springt er nach $A87D. Es ginge also sowas wie

    Code
    1. lda #1 ; lösche zero flag
    2. jmp $a871
  • Die kanonische Vorgehensweise in dem Fall ist, daß man zunächst den TXTPTR in der CHRGET-Routine auf den Start des BASIC-Programms zurücksetzt, CLR ausführt und dann in die Interpreterschleife direkt einspringt. Das machen die zwei Aufrufe:

    Code
    1. JSR $A659 ; CLR, TXTPTR zurücksetzen
    2. JMP $A7AE ; Eintritt in Interpreterschleife

    Voraussetzung für eine einwandfreie Funktion ist natürlich, daß die Link-Pointer im BASIC-Text richtig sind (das ist relevant wenn das Programm an eine andere Position geladen wurde als von wo es abgespeichert wurde) und selbstredend muß der Zeiger in 45/46 auf das erste Byte nach dem BASIC-Text zeigen.


    Wenn also z.B. das BASIC-Programm mit der KERNAL-LOAD-Routine geladen wurde, sieht das insgesamt so aus:

    Code
    1. [... Vorbereitung für KERNAL-LOAD ...]
    2. JSR $FFD5
    3. [... hier ggfs. Fehlerbehandlung ...]
    4. STX $2D ; Zeiger auf Start der Variablen
    5. STY $2E ; (a.k.a. "Ende des Programms") setzen
    6. JSR $A533 ; Programm re-linken
    7. JSR $A659 ; CLR, TXTPTR zurücksetzen
    8. JMP $A7AE ; Eintritt in Interpreterschleife
  • Je nachdem, was Du genau vorhast, auch dran denken, vorher alle üblichen Pointer richtig zu setzen. Z.B. erwartet der Loader von Action Replay-Freezes einen korrekt gesetzten Dateinamen aus dem letzten LOAD, weil er daraus den Dateinamen der nachzuladenden Datei ableitet; eine Menge anderer Programme machen das auch.

  • $A659 [wird] in striks Methode mit JMP angesprungen

    Um das zu verstehen, muß man wissen wie der Aufruf von $A659 den Stack behandelt. Er nimmt die obersten zwei Bytes runter (bei einem JSR $A659 ist das genau die Rücksprungadresse hinter den JSR-Befehl!), stellt den Stackpointer zurück und legt dann die Rücksprungadresse wieder drauf.


    Wenn (aber auch nur wenn!) $A871 aus dem Kontext des BASIC-Interpreters aufgerufen wird, dann steht auf dem Stack bei $A87A die Rücksprungadresse $A7EA (minus 1, von $A7E7 JSR $A7ED), JMP $A659 hebt diese zwei Bytes ab, setzt den Stack zurück und legt $A7EA minus 1 wieder drauf, springt dann zu $A7EA - und $A7EA führt den gewünschten JMP $A7AE aus, der an den Start der Interpreterschleife springt.


    Du hast aber keine Garantie, daß die obersten zwei Bytes auf dem Stack genau die Rücksprungadresse $A7EA - 1 darstellen, wenn Du sozusagen von außerhalb des BASIC-Interpreters den Befehl JMP $A871 ausführst. Und steht da eben was anderes, dann crasht's.


    Die Abfolge JSR $A659/JMP $A7AE in Beitrag #4 führt nun genau die Routinen im Interpreter aus, die RUN ohne Parameter auch ausführen würde, ist aber nicht darauf angewiesen, daß der Stack wie gerade beschrieben präpariert ist. Heißt also: Geht. Tut. Funktioniert. :)

  • der Loader von Action Replay-Freezes [erwartet] einen korrekt gesetzten Dateinamen aus dem letzten LOAD, weil er daraus den Dateinamen der nachzuladenden Datei ableitet; eine Menge anderer Programme machen das auch.

    Das ist interessant, klingt aber einigermaßen nach "mit heißer Nadel gestrickt" (also, was die Programme da machen).


    Der LOAD-Befehl im Direktmodus legt den Dateinamen als temporären String am oberen Ende des BASIC-Speichers ab. Lädt man ein überlanges Programm, das schon teilweise unter das BASIC-ROM "ragt", dann wird genau dieser Dateiname überschrieben. Ebenso wenig haben Programme, die derartig auf den Dateinamen angewiesen sind eine Garantie, daß der User den Dateinamen brav ausgeschrieben hat. Er könnte genauso gut den Dateinamen mit "*" abgekürzt haben, oder gar gleich "*" verwendet haben.


    Insgesamt heißt das, daß die fortgesetzte Existenz des Dateinamens (mit Längenangabe und Zeiger darauf, etc.) nach dem LOAD-Aufruf eben keine Bedingung mehr für aufgerufene Programme darstellen sollte. Programme, die das tun, sind eigentlich "kaputt bei Design".


    Interessanterweise sollte ein Programm-Browser/Lader die Situation sogar eher entschärfen. Damit der Ladevorgang an sich nicht mit dem geladenem Programm kollidiert, steht die LOAD+RUN-Routine (hoffentlich) irgendwo versteckt im Speicher (z.B. im Stack ab $0140), zusammen mit dem (unverkürzten!) Dateinamen, und macht da eben SETNAM+SETLFS+LOAD+RUN, womit auch der Dateiname im Nachgang eher noch verfügbar ist.

  • Lädt man ein überlanges Programm, das schon teilweise unter das BASIC-ROM "ragt", dann wird genau dieser Dateiname überschrieben.

    Der Action Replay-Freeze-Loader ist allerdings kein überlanges Programm.



    Er könnte genauso gut den Dateinamen mit "*" abgekürzt haben, oder gar gleich "*" verwendet haben.

    Wenn ich mich recht entsinne wird der Dateiname der Datei vom Loader konstruiert, indem am Anfang was ergänzt wird. Das funktioniert also immerhin mit * am Ende, wobei noch zu klären wäre ob der Code dabei auch mit : getrennte Präfixe im Namen korrekt behandelt.

  • Mag ja sein, aber hier geht's ja anscheinend um einen allgemeinen Launcher für "Endbenutzer", für die gibt's diese Option nicht bzw. wenn das Symptom lediglich ist, dass das jeweilige Programm nicht startet oder hängt, ist es erstmal gar nicht klar, dass der Launcher mit das Problem ist.

  • Die Abfolge JSR $A659/JMP $A7AE in Beitrag #4 führt nun genau die Routinen im Interpreter aus, die RUN ohne Parameter auch ausführen würde, ist aber nicht darauf angewiesen, daß der Stack wie gerade beschrieben präpariert ist. Heißt also: Geht. Tut. Funktioniert. :)

    Du hast recht, ich hatte mir RUN nicht genau genug angeschaut. Irgendwo im Hinterkopf hatte ich noch, dass es etwas anders macht, ich hatte es bloß nicht mehr im Kopf.


    Ich habe aber auch nicht behauptet, dass ein JSR die Lösung ist. 8) Ich habe nur behauptet, dass dort die Routine steht. :thumbsup:


    Dein Ansatz hat aber noch eine Schwäche: Es vergisst, das Programm-Modus Flag zu setzen, welches in $A871 als erstes gemacht wird. (LDA #0, JSR $FF90). Je nachdem, in welchem Modus man vorher war (wie also das Maschinenspracheprogramm aufgerufen wurde), kann das überflüssig sein oder nicht.


    Und je nachdem, was das Programm macht, kann es zumindest die Ausgabe zerhauen, wenn es falsch steht.

  • Und da GUI64 schlussendlich auf ein Modul soll, hat ein Action Replay sowieso keinen Platz mehr im Modulschacht.

    Es geht um das LADEN von Freezes, die mit dem AR erstellt wurden. Dafür muss das AR nicht eingesteckt sein.


    Und wie gesagt fallen auch etliche andere Programme ohne sauber gesetzten Dateinamen auf die Nase.


    Aber mach sonst ruhig die gleichen Fehler wie dutzende andere Launcher-Autoren vor Dir (z.B. FB64 bekomnt's auch nicht hin). ;)

  • 1570 Ich lerne ja gerne dazu. Was ist "ein Freeze"? Ich hätte gedacht, sowas ist eine Datei, in die das AR den Zustand des gesamten C64 gespeichert hat. Aber sowas wäre ja keine Programmdatei, die man nach dem Laden mit RUN starten kann. Oder bereitet das AR die Datei so auf, dass sie standalone nach einem RUN tatsächlich "gestartet" wird und das Spiel ab dem Zeitpunkt des Freezes beginnt?

  • [...] das Programm-Modus Flag [...]

    Das ist ein guter Hinweis, danke. In Beitrag #4 hatte ich das jetzt ausgelassen, es ist aber auf jeden Fall richtig, daß die Systemmeldungen ("FOUND ...", "SEARCHING FOR ...") im Programmmodus ausgeschaltet sein sollen.


    Übrigens, nur als kleiner Hinweis, das ist übrigens auch ein Bug in CONT. CONT vergißt nämlich, den Programmmodus (wieder) einzuschalten. :whistling:


    Ist der Code oben [...] jetzt in Ordnung?

    Ja, auf jeden Fall. Der Einwand von 1570 betrifft Programme, die eine Sache machen ("Abfrage des Dateinamens unter dem das Programm geladen wurde"), welche vom KERNAL so *nicht* vorgesehen ist, nur rein zufällig funktioniert aber prinzipbedingt eben nicht 100%ig zuverlässig funktionieren kann.


    Wenn Du den kritischen Teil deines Ladeprogramms so wie von mir in Beitrag #9 kurz angedeutet so schreibst, daß der Dateiname, die Länge desselben und der Zeiger darauf in $B7/$BB/$BC und idealerweise auch das zuletzt genutzte Device (in $BA) noch vorhanden sind wenn Du das Programm startest, dann paßt alles.