Hallo Besucher, der Thread wurde 2,6k mal aufgerufen und enthält 11 Antworten

letzter Beitrag von Mike am

Frage zu einem Programm von C64-Wiki (Speicherbereich sichern)

  • Hallo!


    In der C64 Wiki habe ich dieses Programm gefunden, um einen benutzerdefinierten Speicherbereich per SAVE aus BASIC zu sichern:


    Ich brüte nun schon einige Zeit darüber und habe, denke ich, auch verstanden wie es funktioniert. Aber eine Sache irritiert mich doch sehr:
    Und zwar wird dort geschrieben, dass der Bereich von 49152 bis 53247 gesichert wird.
    Wenn ich aber die per LA und LE bzw. LE und HE übergebenen Adressen ausrechne, dann komme ich auf 40960 für den Anfang und 53248 für das Ende.
    ???

  • Wenn ich aber die per LA und LE bzw. LE und HE übergebenen Adressen ausrechne, dann komme ich auf 40960 für den Anfang

    Hmm, das scheint mir ein Fehler auf dieser Seite zu sein ... in Hex wäre es leichter zu lesen, Speicherbeginn ist $A000, also das BASIC ROM selbst, das ergibt wenig Sinn ... im Einzeiler darüber ist es übrigens korrekt, Highbyte 192 ergibt $C000 ...


    und 53248 für das Ende.

    Das allerdings ist schon ganz richtig so ($D000), die Endadresse ist die des ersten Bytes, das nicht mehr zum Programm gehört.

  • Ich habe jetzt noch ein anders Problem mit meinem Programm.
    Es soll dazu dienen, alle Tracks der Diskette nacheinander einzulesen und jeweils in eine Datei auf Datasette zu speicher.


    Bisher sieht es so aus:

    Die Diskettenstruktur mit Tracks, Zones, Sectors usw. wird also über ein paar Loops nachgeahmt und dann ein Track in den RAM gepoket. Dieser Speicherbereich soll dann mit dem Code vom Wiki auf Datasette gespeichert werden. Auf Diskette funktionert es, bei der Datasette habe ich aber das Problem, dass gar nicht auf den Druck der "Recordtaste" an der Datasette gewartet wird, sondern das Programm einfach weiter läuft. Auch wenn ich vorher schon Record drücke, läuft die Datasette beim Speichervorgang nicht an.


    Liegt das an der programmierten Benutzung des Direktmodus, weil er halt einfach den Tastaturbuffer durcharbeitet? Kann ich das irgendwie umgehen?
    Gruß und Danke :)

  • Das könnte der Punkt sein, an dem man BASIC vielleicht besser hinter sich lässt. Für solche Tools (im Gegensatz zu Demos oder Spielen) muss es ja nicht gleich Assembler sein, C beispielsweise bietet sich auch an ;) Nur so ein Gedanke ... denn dieser Tastaturpuffer-Missbrauch ist ja nicht gerade eine besonders robuste Art zu programmieren ;)

  • Ernsthaft so ein Mist steht im Wiki drin? Geht's denn noch schlimmer?


    Einen Speicherblock speichert man mit zwei Zeilen Code wie folgt weg:

    Code
    1. SYS57812(N$),<device>:POKE193,<start_lo>:POKE194,<start_hi>
    2. POKE780,193:POKE781,<end_lo>:POKE782,<end_hi>:SYS65496

    In N$ steht der Dateiname, <start> ist inklusive, <end> ist exklusive, und man muß nur beide Werte vorher in Low- und Highbyte zerlegen.


    Was da im Wiki verbrochen wird, dazu fehlen mir echt die Worte. Wer denkt sich so einen Sch**ß aus???

  • Hallo!


    Danke für deinen Vorschlag, ich bin froh, wenn ich erst einmal beim BASIC bleiben kann, den im Moment geht's mir mehr darum dieses kleine Tool auch wirklich zu benutzen, weil die Datasette in Verbindung mit einem alten Tapedeck mein einziger Weg ist, Daten von meinem Linux-Notebook zum Brotkasten zu transportieren. Zu Assembler wechseln muss ich später vielleicht dennoch, weil ich wohl, um eine Diskettenseite auf eine 45 Minutensite einer Kassette zu bekommen Turbotape benötigen werden. Aber erst möchte ich dieses Tool wenigstens mal zum Laufen bekommen.


    Die von dir gepostete Lösung habe ich so ähnlich schon gesehen, aber leider ohne Erklärung; deshalb habe ich die aus der Wiki genommen.
    Könntest du mir die bitte etwas erläutern?


    Ich nehme an SYS57821 springt zur Kernal-Routine zum abspeichern? Gibt es da einen Unterschied, wenn man an dieser Stelle anstatt "SYS57821,$N,device" ein "SAVE,$N,device" schreiben würde? Ich frage, weil beide ja syntaktisch gleich zu.


    Die Pokes machen ja offensichtlich das Gleiche, wie die Pokes bei Verwendung des Save Befehls, aber sie werden an andere Adressen geschrieben (43-46 beim BASIC-SAVE). Liegt das einfach nur daran, dass die Kernal-Routine andere Adressen konsultiert, bevor sie abspeichert? Hat es einen besonderen Grund, dass sie andere Adresse verwenden muss? Irgendwie erscheint es ja verschwenderisch diese Daten doppelt im Speicher liegen zu haben..



    Was macht SYS65496 genau? Ich denke es dient natürlich dazu, das Programm fortzusetzen. Aber wie genau funktioniert der Mechanismus dahinter? Habe zu SYS65496 nämlich ausser der Verwendung für diesen SAVE-Trick keine Detailinfos gefunden. Entspricht es vielleicht genau dem BASIC "CONT"?



    Danke nochmal :)


    PS: Ja, das Captcha in er 64-Wiki ist ein Krampf, vor Allem dank der "Strafauszeit". Und bis man realisiert hat, wie es geschrieben werden muss dauert schon ein paar Versuche..

  • Ich nehme an SYS57821 springt zur Kernal-Routine zum abspeichern? Gibt es da einen Unterschied, wenn man an dieser Stelle anstatt "SYS57821,$N,device" ein "SAVE,$N,device" schreiben würde?

    Die Basic-Befehle LOAD, SAVE und VERIFY tun grob gesagt drei Dinge:


    1. sie lesen ihre Parameter aus dem Basictext (also Dateiname, Geräteadresse und optional "Fake-Sekundäradresse") und übergeben sie an den Kernal. Da dieser Teil für alle drei Befehle komplett identisch ist, wird eine einzige Subroutine von allen drei Befehlen verwendet - und die beginnt bei 57812.


    2. sie setzen den Startzeiger auf den Basic-Start, und bei SAVE auch noch den Endzeiger auf das Basic-Ende.


    3. sie springen ihr jeweiliges Kernal-Pendant an, was dann die eigentliche Arbeit macht (Basic-SAVE springt z.B. zu 65496, das ist Kernal-SAVE).


    Mikes Zweizeiler führt die Schritte 1 und 3 direkt per SYS aus und ersetzt Schritt 2 durch ein paar eigene POKEs, damit eben nicht das BASIC-Programm, sondern ein beliebiger anderer Speicherblock gespeichert wird.

  • Danke! :)
    Wie genau läuft das denn ab, dass der BASIC Interpreter nach dem SYS korrekt weiterläuft?
    Da müssen ja vermutlich diverse Register etc. zuvor gesichert werden und nach Beendigung der Kernalroutine wieder recovered werden. Macht das alles der SYS-Befehl selbst?
    Was wäre denn deine Buchempfehlung, um mal eine Übersicht über die Kernalroutinen zu bekommen?

  • Da müssen ja vermutlich diverse Register etc. zuvor gesichert werden und nach Beendigung der Kernalroutine wieder recovered werden. Macht das alles der SYS-Befehl selbst?

    BASIC weiß, dass SYS Register "clobbered", da ist alles vorher woanders gesichert. Lustigerweise macht SYS aber quasi das Gegenteil -- die Registerinhalte des Maschinenprogrammms werden nach Rücksprung gesichert und zu Beginn eines weiteren SYS wiederhergestellt, man kann also mehrfach Routinen eines Maschinenprogramms aufrufen und diese Routinen können sich auf unveränderte Register verlassen.

    Das "Gefummel" ab Zeile 4 simuliert hier einfach ein indirektes JSR (was der 6502 nicht bietet), interessant sind die Zeilen 8 bis 12 und 17 bis 21.

  • Das "Gefummel" ab Zeile 4 simuliert hier einfach ein indirektes JSR (was der 6502 nicht bietet), [...]

    Hindert einen keiner daran, mit einem JSR ein JMP() anzuspringen. ;)


    Das wäre auch im BASIC-Interpreter gegangen und der Code wäre sogar ein paar Bytes kürzer.


    Aber noch zu der Frage:

    Wie genau läuft das denn ab, dass der BASIC Interpreter nach dem SYS korrekt weiterläuft?

    SYS57812 springt genau an der Stelle in den BASIC-Interpreter rein, wo LOAD/SAVE/VERIFY die Parameter abholen. Das ist eine ganz normale Unterroutine, die mit RTS endet.


    BASIC verwaltet einen Zeiger in den Text des BASIC-Programms. Nachdem das Token von LOAD, SAVE oder VERIFY gescannt und die passende Routine im Interpreter zur Ausführung gebracht wurde, steht der Textpointer genau richtig, um die Parameter einzulesen. Die landen dann in diversen Zeropage-Adressen die zur Dateiein- und -ausgabe gehören und sind dort weitgehend sicher bis halt irgendwas anderes in der Richtung gemacht wird.


    Bei SYS57812 steht der Zeiger nun hinter der 2 - die Routine kann da also direkt die Parameter einlesen. Da genau *zwischen* LOAD/SAVE/VERIFY und deren Parametern *kein* Komma steht, steht hier jetzt auch keins. Sieht zwar ungewöhnlich aus, funktioniert aber. Die Parameter sind dann gestellt für KERNAL-SAVE. Der Textzeiger steht jetzt hinter dem gesamten SYS-Befehl mit all den Extra-Parametern, also entweder auf einem Doppelpunkt oder am Zeilenende. Jetzt hat man noch "alle Zeit der Welt" um die Anfangs- und Endadresse des zu speichernden Bereichs per POKE anzugeben und dann mit SYS65496 die Routine im ROM aufzurufen, die einen beliebigen Speicherblock abspeichert.


    Alles klar?