Posts by Mike

    Das fällt für mich allerdings in die Kategorie 'selbstgemachtes Problem'. Auf den frühen PET-Rechnern stehen in der KERNAL-Sprungtabelle nicht mal SETNAM, SETLFS, OPEN, CLOSE etc. zur Verfügung, die Routinen sind alle noch im BASIC-Interpreter! Die abstrahierte Fassung kam erst mit dem KERNAL im VC-20.


    Genaueres findest Du auf der Seite von Michael Steil, pagetable.com, hier: https://www.pagetable.com/?p=926



    P.S. zu deinem weiteren Beitrag: ja, mit POKE781,X:SYS65478 kann man die Eingabe auf eine Datei umlenken (und mit SYS65484 wieder zurückstellen) aber da gibt es bessere Anwendungsfälle für, als LOAD mit GET nachzubauen.

    Ok, und in der Routine muss ich jetzt erstmal zum entsprechenden SYS-Aufruf kommen. Wie komme ich denn da dran?

    Wenn im BASIC-Text SYS49152,A steht und ausgeführt wird, dann steht der interne Textzeiger des BASIC-Interpreters (TXTPTR, in der Routine CHRGET ab $0073 - ja, im RAM!) genau auf dem Komma.


    Der BASIC-Interpreter hat die 49152 ausgewertet, hinter der "2" ein Zeichen gefunden, das nicht mehr zu einer Zahl gehören kann und führt jetzt erstmal deine Maschinenroutine ab 49152 aus.


    Wenn die jetzt nichts besonderes macht und dann mit RTS zurückkehrt, überprüft der Interpreter das Zeichen 'unter' TXTPTR nochmal und findet das Komma. In der Folge gibt's dann einen ?SYNTAX ERROR.


    Deine Routine ab 49152 muß also jetzt den Parameter selbst einlesen. Zuerst soll überprüft werden, ob hinter der SYS-Adresse ein Komma steht. Das macht die Routine CHKCOM bei $AEFD. Wenn im BASIC-Text ein Komma steht, wird TXTPTR eins weiter geschoben und JSR $AEFD kehrt einfach zurück. Steht da kein Komma, gibt's wiederum einen Syntax Error.


    TXTPTR steht jetzt auf dem ersten Zeichen, von dem wir erwarten, daß es einen numerischen Ausdruck darstellen könnte: es könnte einfach eine Ziffernfolge sein, eine einfache Variable oder ein komplizierterer numerischer Ausdruck. Funktioniert alles. Wenn es sich um einen 8-Bit-Wert handelt, kann die Routine GETBYT bei $B79E den Wert direkt mit JSR $B79E in das X-Register einlesen und von dort kannst Du den Wert im Rest deiner Maschinencode-Routine weiterverarbeiten.


    Praktischerweise gibt es für die Kombination CHKCOM+GETBYT eine Routine im BASIC-Interpreter, die beides im einen macht, bei $B7F1. Sie wird von POKE und WAIT benutzt.


    Also, mal als Beispiel:

    Code
    1. $C000 JSR $B7F1
    2. $C003 STA $D020
    3. $C006 STA $D021
    4. $C009 RTS

    ... und mit SYS49152,X setzt Du nun Rahmen- und Hintegrundfarbe gleichzeitig auf den Wert X. Wie gesagt, für X ist eine einfache Zahl, eine numerische Variable oder ein komplizierter numerischer Ausdruck erlaubt.


    Wenn diese Routine dann zurückkehrt, steht der Textzeiger auf dem Zeichen hinter dem numerischen Ausdruck, bei einem syntaktisch einwandfreien Programm also entweder auf einem Doppelpunkt oder auf einem Zeilenende (wodurch der Interpreter vor Ausführung des nächsten Befehls erstmal an den Anfang der nächsten Zeile geht).


    ...


    Der SYS57812 im anderen Thread springt nun genau in die Routine im BASIC-Interpreter ein, die die Parameter für LOAD und SAVE auswertet. Die prüft zwischen LOAD/SAVE und dem Dateinamen nicht etwa auf ein Komma ab, und darum kommt hier der Dateiname unmittelbar hinter der SYS-Adresse zu stehen.


    ...


    In weiteren sind genauere Kenntnisse der Abläufe im BASIC-Interpreter und KERNAL schon dringend empfehlenswert. "64 intern" (mit allen bekannten Errata) + AAY64 sind deine Freunde. :)


    Viele Grüße,


    Michael

    Wobei ich zugeben muss, dass ich wohl einfach bisher nur zu faul war, mir die Daten für diese kleine SYS und POKE-Orgie für fünf verschiedene Rechnersysteme herauszusuchen. ;)

    Auf den 264-Rechnern bist Du mit:


    DN=PEEK(174):SYS43115"name",DN,1:POKE2034,0:SYS65493


    dabei.


    Der C128 hat ja BLOAD, insofern ...

    Den hier hab' ich noch:

    Davon abgesehen, sind manche POKEs unerlässlich, oder wie setzt du etwa die Hintergrundfarbe ohne POKE?

    z.B. mit PRINT"{CLR,RVS ON}){RVS OFF}A{RVS ON}M{RVS OFF}!{RVS ON,SHIFT-P,RVS OFF,SHIFT-SPACE}":SYS1024 auf weiß. ;)


    Alternativ, ein drei Byte großes PRG-File mit den Bytes 33, 208, 1 drin und geladen mit ",8,1".


    Wo bleibt der Retro-Gedanke? Was haben wir denn nur damals gemacht, als es noch kein Internet gab, man alle möglichen und unmöglichen Dinge in Büchern und Zeitschriften nachlesen konnte und sich dann GANZ ALLEIN für eine Methode entscheiden musste? :huh:

    Irgendwann kommt man vielleicht dann noch auf den Trichter, daß nicht alles, was damals™ in den Büchern und Zeitschriften stand, und auch heute dort und in Wikipedia und Co. steht, der Weisheit letzter Schluß ist. Insofern gehen wir beide hier ...

    Wenn einer nach Möglichkeiten fragt, heißt das nicht, dass er selbst gar nicht mehr denken will.

    ... völlig ohne Probleme konform.


    Also gut: lassen wir der IF ... LOAD - Methode ihre historische Relevanz. Hnnnggg ... :D


    atomcode: :bia

    atomcode: Eine derart ausführliche Ansage verdient eine ebenso ausführliche Entgegnung:

    Und deswegen geht das nicht? Der Code ist aus einem uralten funktionierenden Programm von mir, ein Iso-3D-Editor.

    Meine Code-Zeilen oben habe ich schon öfter verwendet, als ich noch irgendwie abzählen könnte.


    Es sollte klar sein, dass man das nicht aus einer Schleife oder Sub-Routine heraus aufruft - allein schon, weil man diese dann unordentlich verlässt. Das würde man dann schon merken, dass dies nicht geht.

    Es sollte nicht nur 'klar' sein, es geht überhaupt nicht, aus dem von mir genannten Grund (Stapel wird zurückgesetzt). Damit geht z.B. der Unterprogrammaufruf, den ich in Beitrag #56 verwende, einfach mal überhaupt nicht.


    Es ist aber ansonsten eine bewährte Alternative, ...

    Es ist technisch gesehen eine absolut miserable Methode. Die Notwendigkeit, den Seiteneffekt des ungewollten Programm-Neustarts mit irgendwelchen Programm-Konstrukten in den Griff bekommen zu müssen, macht sie nicht besser.


    ... um vor allem am Anfang des Programms etwas nachzuladen ...

    Für was anderes ist sie auch nicht zu gebrauchen.


    (so wie bei diesem Tetris-Spiel erforderlich),

    WebFritzi könnte hier alles in einen One-Filer packen (eigentlich haben wir hier ein XY-Problem). Das aber nur so nebenbei.


    zumal es auf reinem BASIC basiert und nicht auf POKEs und SYSs.

    Der Rest des Programms kommt auch ohne POKE und SYS aus? Echt?


    Wurde schon in vielen Programmen gesehen und auch in der 64'er behandelt.

    Das macht die IF ... LOAD Methode trotzdem nicht besser.


    Mir ist es egal, was WebFritzi letztendlich verwendet, aber alle gängigen oder möglichen Methoden sollten hier vorgestellt werden dürfen, denke ich. Man kann ja die Vor- und Nachteile auch aufzählen. Die Entscheidung liegt letztendlich bei ihm.

    Es heißt ja immer, das Bessere ist der Feind des Guten. Nur - die IF ... LOAD Methode ist noch nicht mal das: gut.

    Eine andere Möglichkeit zum Nachladen ist die Verwendung eines Zählers. Man kann damit auch mitten im Programm noch was nachladen, [...]

    Nein, das geht eben nicht. Auch mit deiner ON .. GOTO Variante des kaputten "IFA=0THENA=1:LOAD"blubb",8,1" wird beim ungewollten Neustart des Programms der Stapel zurückgesetzt, alle aktiven FOR-Schleifen und GOSUBs sind damit 'für die Fisch'!



    Wenn man mit meiner Methode mehrere Dateien nachladen will, bitte:

    Code
    1. ...
    2. 10 N$="FILE 1":GOSUB xx
    3. 15 N$="FILE 2":GOSUB xx
    4. 20 N$="FILE 3":GOSUB xx
    5. ...
    6. xx SYS57812(N$),8,1:POKE780,0:SYS65493:RETURN

    ... oder etwas ausführlicher mit vorheriger Ermittlung der Geräteadresse.

    RAM-Bereich speichern:

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

    <start> ist inklusiv, <end> ist exklusiv, N$ enthält den Dateinamen. Das hier sollte man i.A. immer zum Speichern von RAM-Bereichen hernehmen. Für Floppy-Betrieb macht es keinen Unterschied zur folgenden Methode, aber nur die gerade genannte Methode erlaubt es bei Tape-Betrieb, die Datei an eine andere Adresse zu laden.



    RAM-Bereich speichern (und Ladeadresse bei Tape erzwingen):

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

    Bei Disk ist das Ergebnis das gleiche wie zuvor. Für Tape erzwingt diese Methode aber das Laden des Speicherblocks an die ursprüngliche Adresse, egal welche Sekundäradresse man angibt!



    RAM-Bereich laden ('relatives' oder 'relozierendes' Laden):

    Code
    1. SYS57812(N$),<device>:POKE780,0:POKE781,<start_lo>:POKE782,<start_hi>:SYS65493

    ... oder SYS57812(N$),<device>,0 - lädt die Datei an Adresse <start>. Wenn bei Tape beim Speichern ",1" als Sekundäradresse angegeben wurde, gilt allerdings immer die Angabe auf Band!



    RAM-Bereich laden ('absolutes' Laden):

    Code
    1. SYS57812(N$),<device>,1:POKE780,0:SYS65493

    Lädt die Datei dahin, von wo sie abgespeichert wurde.


    Bei beiden genannten LOAD-Varianten wird das BASIC-Programm hinter SYS65493 normal fortgesetzt, es erfolgt kein ungewollter Neustart des Programms.


    ...


    Zur Erklärung:


    SYS57812 ruft die Routine im BASIC-Interpreter auf, die Dateinamen und Geräteadresse parst. Das 'fehlende' Komma zwischen SYS und Dateiname ist schon so richtig; die Klammern stehen da, damit die Variable dennoch nicht an der SYS-Adresse 'klebt' ... (also, aus ästhetischen Gründen ^^) und es keinen ?SYNTAX ERROR gibt, falls E...$ als Variable für den Dateinamen verwendet wird (Pop-Quiz: warum kommt dann ein Fehler?)


    SYS65493 und SYS65496 rufen KERNAL LOAD und KERNAL SAVE sauber über die Sprungtabelle am Ende des KERNALs auf. Ein vorhandener Schnell-Lader freut sich. :)


    Das dämliche Konstrukt mit IFA=0THENA=1:LOAD"blubb",8,1 bitte nicht mehr verwenden. Danke.


    Beim Speichern auf Disk vorher mit OPEN15,<device>,15,"S0:name":CLOSE15 eine alte Datei gleichen Namens löschen und bitte nicht Save-mit-Replace verwenden. Der User wird's danken.


    Mit DN=PEEK(186) bekommt man die Geräteadresse heraus, die zuletzt verwendet wurde. PEEK(186) nicht direkt im SYS57812 Aufruf verwenden, da SYS57812 die Adresse 186 auf 1 setzt (Default Tape), bevor das Parsing zu dem PEEK(186) kommt!



    Quelle: Denial - ROM calls and other tricks, für den VC-20.

    Dabei müsste ich wissen, wo der Stub aufhört.

    Am Ende des BASIC-Programms stehen drei Nullen: eine für das Zeilenende der letzten Zeile, zwei weitere für den 'leeren' Link-Pointer.


    Ab $0810 kannst Du also jetzt deine Daten zwischen Stub und Nutzlast ablegen. :)


    ...


    Bei sowas gibt's übrigens den Trick, den Speicher mit einem Monitor vorher mit einem bekannten nicht-0-Wert zu füllen (also, nach einem NEW von $0803 bis $9FFF). Ich nehm meistens $2A dafür. Dann erkennt man recht gut, was noch zum BASIC-Programm gehört.


    Im Anhang ist bei Interesse die Diskette.

    Ich hab's mir mal angeschaut. Nice!


    Bei dem Konstrukt in den Zeilen 220 und 280 mußt Du etwas aufpassen. Am Ende des Tages errechnet das Programm einen Wert für TN, der von TI nie erreicht werden kann, und dann hängt das Programm. Das geht besser so:

    Code
    1. 220 TN=TI
    2. 230 GETA$
    3. [...]
    4. 280 IFABS(TI-TN)<SPTHEN230

    Das GOTO ist hier überflüssig und kann weggelassen werden.

    Ich hab's jetzt nochmal ausprobiert mit einem Minimalbeispiel, das einfach "HALLO" ausgibt. Hat geklappt.

    O.K. - so als Referenz hab' ich eine geringfügig erweiterte Fassung mal angehängt, quasi als Versuchskaninchen. :)


    Also: nach LOAD und RUN ist das 'alte' Programm wieder da. Einfach ein bischen editieren, und dann mit vorangestelltem POKE44,8 unter neuem Namen abspeichern und schon läuft die Show.

    Files

    • hallo.prg

      (10.26 kB, downloaded 1 times, last: )

    Was da passiert, verstehe ich allerdings nicht. Das Programm in 2020 wird ja nie ausgeführt. Vor allem nach dem POKE im Direct Mode wird ja mit NEW der BASIC-Speicher gelöscht. Die 2020-Zeile müsste jetzt komplett verschwunden sein. Dennoch steht sie als einzige nach dem Abspeichern im Programm. :?: Wie ist das möglich?

    Die Zeile 2020 (der "BASIC-Stub") ist ja auch nicht für die sofortige Ausführung gedacht, sondern für später, wenn der One-Filer (das "Gesamt-Programm") geladen wird. Du "baust" mit dessen Eingabe den Teil des Gesamtprogramms der nachher als erstes im Speicher steht.


    Mit "POKE44,48:POKE12288,0:NEW" bereitest Du den Speicherplatz für das Hauptprogramm vor. Der BASIC-Stub 'unten' bei $0801 wird durch das NEW gar nicht angefaßt bzw. gelöscht, er steht immer noch im Speicher. In dem Byte *vor* dem BASIC-Start will nun der BASIC-Interpreter eine Null sehen, das garantiert der POKE12288,0 (die Adresse mußt Du anpassen für einen anderen BASIC-Start). NEW schreibt ab dem BASIC-Start ein leeres BASIC-Programm in den Speicher und setzt alle anderen BASIC-Pointer für die Variablen dahinter, damit stimmen die Pointer auch - natürlich sind alle Variablen jetzt auch gelöscht.


    Falls Du jetzt Daten 'zwischen' BASIC-Stub und Original-Programm laden willst, solltest Du es jetzt tun (mit ",8,1"), da Du danach die Pointer nochmal mit NEW korrigieren mußt. Ein BASIC-Programm ab $3001 würde dann natürlich gelöscht.


    Im weiteren LOAD mit ",8" lädt jetzt das Original-Programm an $3001.


    Du kannst es beliebig ändern und wie oben bereits beschrieben zusammen mit POKE44,8 wieder abspeichern, mit BASIC-Stub und mit allen Daten zwischen BASIC-Stub und Hauptprogramm.


    Quote

    Und noch eine Frage: Wie kann ich danach an meinem Programm weiter arbeiten? Ich sehe es ja nicht mehr.

    Ich habe meinen Beitrag #30 in der Zwischenzeit noch ergänzt. Sobald der BASIC-Stub ausgeführt wurde, ist der BASIC-Start wieder so, daß Du das Hauptprogramm auflisten und ändern kannst (abspeichern wie gesagt immer mit POKE44,8 vorher).


    ...


    Wichtig nochmal - das Gesamtprogramm mußt Du immer an den normalen BASIC-Start laden (ist, wie gesagt "ab Einschaltmeldung" auch immer so gegeben). Wenn das Programm nach LOAD und RUN mal 'hängt' und nach Drücken der STOP-Taste immer noch der BASIC-Stub angezeigt wird, dann war der BASIC-Start schon hochgesetzt.

    Dann lieber einen Packer nehmen, der mehrere Dateien in eine einzige, ausführbare Datei quetscht, die nach dem Start alle Einzeldateien an die richtige Speicheradresse entpackt und das Hauptprogramm startet.

    Einen Packer setzt man erst ganz zum Schluß auf das Ergebnis an, wenn sonst alles läuft.


    In der Entwicklungsphase ist der als zusätzlicher Build-Schritt nur ein Klotz am Bein.

    ich hab das mal ausprobiert mit einem beliebigen BASIC-Programm (ohne Abspeichern von irgendwas unter dem BASIC). Das Ding hatte vorher 14 Blocks belegt, danach 54. Soweit so gut. Wenn ich es dann lade und LIST eingebe, steht da nur die 2020'er-Zeile. Erstens: wieso? Was ist mit dem Original-Listing passiert? Ich kann also nicht daran weiter arbeiten. Außerdem bekomme ich bei Eingabe von RUN einen "Syntax Error in 14" und der Rechner hängt sich auf.

    Erstens: weil jetzt am (normalen) BASIC-Start eben der BASIC-Stub steht.


    Das "Original-Listing" steht jetzt im Speicher ab $3001 und ist für LIST nicht "erreichbar", da mit dem Ende des BASIC-Stubs für LIST nichts mehr zu listen ist. Genausowenig wie LIST das Maschinenprogramm anzeigt, das bei vielen One-Filern hinter dem SYS steht.


    Mit dem POKE44,48 in der BASIC-Zeile wird zunächst nur der Zeiger auf den BASIC-Start geändert. Nur diese eine Speicherstelle. Mehr macht der POKE nicht! Die Magie passiert im RUN-Befehl: der *interne* BASIC-Zeiger, der in den tokenisierten BASIC-Text zeigt, wird zurückgesetzt auf den BASIC-Start - der ist aber jetzt bei $3001 und zeigt in die Nutzlast (also, dein "Original-Programm"). Dann werden noch die Variablen gelöscht - ganz normal für RUN - und dann arbeitet der Interpreter den BASIC-Text im Speicher, jetzt ab $3001 ab.


    Ab diesem Zeitpunkt ist das Programm dann auch (wieder) mit LIST auflistbar und editierbar.


    Die geänderte Version mußt Du aber wiederum mit vorangestelltem POKE44,8 abspeichern, damit der BASIC-Stub und die Daten zwischen BASIC-Stub und Nutzlast auch wieder 'mitkommen'.


    ...


    Wenn ich deinen Versuch, den One-Filer nach Anleitung zu bauen zu Gesicht bekomme, kann ich dir problemlos sagen, was schiefgelaufen ist.


    Und noch als Nachtrag: wenn Du das mit dem One-Filer richtig hinbekommst, erübrigt sich natürlich auch das Ändern der VIC-Bank ...


    Nachtrag, die 2. - wenn Du das Gesamtprogramm lädst und mit RUN startest, muß der BASIC-Start schon auf dem Original-Wert von $0801 stehen, das ist aber "ab Einschaltmeldung" immer gegeben. Lädst Du das Gesamtprogramm aber (versehentlich) an den bereits hochgesetzten BASIC-Start, dann wird der BASIC-Stub den BASIC-Start nicht noch weiter hochschieben und damit hängt die Prozedur im Stub. Das ist kein Fehler, sondern erwartetes Verhalten.

    Arggh. Jetzt - nach der Verlegung der VIC-Bank nach $8000 - habe ich Probleme mit den Sprites. Den Bildschirmspeicher habe ich bei $8800 und die 4 Sprites habe ich an den Positionen 0-3 (also ab $8000) abgelegt. Die Sprite-Pointer setze ich an den Adressen 2040 + 8*16^3 und 2041 + 8*16^3. Aber ich bekomme komplett vollgemalte Sprites (also überall 255 bzw $FF). Ich kapiere das nicht... Grrr

    Die Sprite-Pointer stehen jetzt natürlich am Ende des "neuen" Bildschirmspeichers. Nur so nebenbei bemerkt. :whistling:

    Hatte ich schon versucht. Mit 43/44. Hab das gleich in Zeile 0 gemacht. Aber dann korrumpiert BASIC mein Programm. Ich könnte das sicher vor dem Laden des Programms festlegen, aber das will ich nicht. Der User soll das Programm einfach per LOAD laden und gleich loslegen können.

    In dem von mir genannten Thread steht in Beitrag #8 eine genaue Anleitung und in Beitrag #11 im Anhang ein Beispiel, das genau nach dieser Anleitung gebaut wurde.


    Ich würde dir *dringend* empfehlen, dich mehr mit dem Speicheraufbau des C64 vertraut zu machen. Heißt hier: nimm mal den Monitor von VICE her und schau dir mit dem M-Kommando ab $0800 bis ca. $30xx an, wie das Programm im Speicher liegt.


    Die Änderung von 43/44 passiert nur an einer Stelle, im BASIC-Stub ("2020 POKE44,48:RUN") - *nicht* in dem "Nutzlast"-Hauptprogramm! Und was hier auch *nicht* passiert ist, daß das Ändern von 43/44 irgendwie das BASIC-Programm an die richtige Stelle schiebt. Wenn Du nach meiner Erklärung den One-Filer baust, stehen anschließend zwei BASIC-Programme im Speicher: Der BASIC-Stub bei $0801 und das Hauptprogramm ab $3001. Und dazwischen die Grafikdaten.

    TAB() arbeitet bei der Ausgabe auf dem Bildschirm nicht mit Leerzeichen, sondern Cursor right, und damit bleiben "Reste" stehen.

    Okay, genauer hinsehen hilft manchmal ... Zeile 40 löscht die vorgesehenen Positionen auf dem Bildschirm und Zeile 50 druckt dann die Zahlen in die geleerten Felder. Mich hatte allerdings irritiert, daß Du da 5x die gleiche Zahl ausdruckst.


    Wenn es aber auch noch darum geht, Zahlen z.B. sauber rechtsbündig auszugeben, kommt man um eine Aufbereitung mit Zeichenkettenfunktionen nicht herum - es erspart einem auch ein 'Flickern', wenn die Zahl zwischenzeitlich gelöscht und dann neu geprintet wird, und ist z.B. bei einer Druckerausgabe unumgänglich. Und dann landet man automatisch bei einer Lösung ähnlich wie in Beitrag #14 (einfach für Zahlen ohne Nachkommastellen) oder wie in meinem vorherigen Beitrag #18 (etwas aufwendiger).


    Rechtsbündige Ausgabe ohne Nachkommastellen in einer fixen Formatbreite (hier auch 11 Stellen):

    Code
    1. PRINT RIGHT$("{9 SPACE}"+STR$(INT(X+.5)),11)

    Es sind nur 9 Leerzeichen vorne nötig, da STR$() einer einstelligen Zahl bereits eine Zeichenkette mit 2 Zeichen liefert.

    Hier ist eine weitere Option, die schnell und sauber ist: [...]

    ... aber leider das im Startbeitrag genannte Problem nicht angeht: TAB() arbeitet bei der Ausgabe auf dem Bildschirm nicht mit Leerzeichen, sondern Cursor right, und damit bleiben "Reste" stehen.


    Quote

    Das String-Management ist manchmal langsam und erzeugt nach einer Weile unerwünschten Müll.

    1. Die Garbage Collection funktioniert, und ja, sie ist auf dem C64 nicht optimal implementiert (Laufzeitverhalten quadratisch). Das ist hier im Forum hinlänglich bekannt.


    2. Es braucht trotzdem erst mal eine hohe zweistellige Anzahl an 'aktiven' Strings, bevor das Problem akut wird, d.h. GC-Zeiten von deutlich länger als eine Sekunde auftreten.


    Das heißt, für die allermeisten kleineren Programme in BASIC reichen die vorhandenen Stringverarbeitungsfunktionen völlig aus, und wer was größeres und komplizierteres machen will, schreibt die Anwendung entweder in Maschinencode oder nutzt eins der gängigen Tools, welches eine schnelle GC nachrüstet (ja, die gibt es!).


    ...


    Vor einiger Zeit habe ich mal diese zwei Unterprogramme geschrieben (mit Test-Rig), welche positive und negative Zahlen mit einer vorgegebenen Anzahl Nachkommastellen und Formatbreite ausgeben. Hier mit zwei bzw. drei Nachkommastellen und einer Formatbreite von 11 Zeichen:

    Außer X und X$ werden keine weiteren Variablen gebraucht, was den Einbau in eigene Programme vereinfacht.


    Viele Grüße,


    Michael

    Ist die Adressierungsart nicht eigentlich(TM) dafür da, in der Zeropage eine Sprungtabelle (bzw. Tabelle mit Zeigern auf Daten) aus beliebig zusammengesetzten Pointern anlegen zu können [...]

    Forth wurde hier zwar schon erwähnt, aber evtl. wird es klarer, wenn man die Adressierungsart anders herum liest, z.B.:


    LDA (X,$00)


    Damit erhält man einen kombinierten Adreß- und Datenstapel in der Zeropage, mit X als Stackpointer und einem Offset um auf "tieferliegende" Werte im Stapel zugreifen zu können. Zugriff auf 8-Bit-Daten hat man, wenn man die Adressierungsart ZP,X ebenfalls andersherum liest, also:


    LDA X,$00


    Weil BASIC und KERNAL auf den CBM-8-Bit-Rechnern die Zeropage weitestgehend für sich in Anspruch nehmen, liegt dieser Verwendungszweck leider nicht so nahe. Aber alles, was im weitesten Sinne eine Sprache darstellt, also nur den KERNAL aber keine Routinen von BASIC nutzt, kann z.B. die Zeropage zumindest bis $8F genauso anwenden.


    Es ist immerhin bemerkenswert, daß z.B. INC und DEC auch mit der Adressierungsart ZP,X daherkommen und so das Erhöhen oder Erniedrigen einer Adresse in diesem Zeropage-Stapel unterstützen.