Hello, Guest the thread was viewed2.3k times and contains 13 replies

last post from Zirias/Excess at the

BASICload -- MC loader für BASIC

  • So, dann möchte ich hier auch mal etwas vorstellen, was für meinen Beitrag zu "BASIC-Weihnachten" entstanden ist. Ich hatte ja früh die Idee, "nette" Musik einzubinden und dazu einen möglichst minimalen SID-Player für BASIC zu schreiben (der wird später auch noch separat veröffentlicht). Problem war dann, obwohl der nicht allzu viel kann, war der Code doch für ein abzutippendes BASIC-Programm recht groß -- 64 Zeilen DATA-Wüste nur für den Player waren es beim ersten Versuch. Außerdem dauerte da natürlich auch der Start recht lange .. DATA/READ und POKE sind nicht gerade flott.


    Also habe ich mir etwas überlegt, um das besser zu machen. Die Idee war schnell, dass in den BASIC Zeilen einfach direkt der MC-Code als hex steht. Leider pfuscht da der Tokenizer rein, die Sequenz "DEF" wird z.B. in ein Token übersetzt. Also mussten noch Anführungszeichen drumherum.


    Das Ergebnis ist ein kleines (PC) Tool, das ein PRG mit dem Maschinencode nimmt und passenden BASIC-Source ausgibt, inklusive einer kleinen Laderoutine, die "klassisch" per DATA/POKE in den Datasettenpuffer geschrieben wird. Diese Routine liest dann die Hex-Strings und springt am Ende direkt zu dem geladenen Maschinencode (es wird erwartet, dass die Ladeadresse auch die Einsprungadresse ist).


    Im Ergebnis wird das BASIC Programm ein gutes Stück kleiner als mit klassischem DATA/POKE und die Geschwindigkeit ist um ein Vielfaches besser. Falls man viele sich wiederholende Bytes hat wird das Abtippen schwieriger (Nullen zählen) -- das kann man dann aber elegant durch crunchen (z.B. mit exomizer) umgehen.


    Source: https://github.com/Zirias/c64_basicload
    Da ist auch ein kleines README -- Aufruf z.B. mit basicload <mycode.prg >loader.bas.


    Einen win32 build hänge ich mal an ;)


    Hier noch der kommentierte Source der Laderoutine:

  • Örks! Ich habe aus Versehen einen Build von einem alten (nicht veröffentlichten) Stand hochgeladen, der noch keinen Parameter für die Startzeilennummer kann. Kann das leider nicht mehr löschen/editieren :(


    Der Anhang im Eingangspost ist Müll!


    Hier im Anhang kommt der Build, der auch wirklich zu der Version auf Github passt :) Jetzt auch "gestrippt" (also ohne Debugging-Symbole).


    Übrigens, der C-Code ist, mehr oder weniger bewusst, "gemurkst". Es ging darum, möglichst schnell ein funktionierendes Tool für meinen Beitrag zum Heftchen zu haben. Nichtsdestotrotz funktioniert's natürlich ;) Über den ASM Code des Loaders habe ich allerdings etwas länger nachgedacht, der sollte ja so kurz wie nur möglich werden. Wenn jemand noch eine Möglichkeit findet weiter zu kürzen, bitte posten ;)

  • ich wuerde evtl versuchen bei hexloop eine tabelle zu benutzen, das koennte ein paar bytes rausholen.
    leider hab ich noch nicht richtig verstanden was das prg machen soll.


    es laed eine "string" prg nach und springt dann in dieses?


    ich stelle mir das so vor

    ob das funktioniert hab ich jetzt nich getestet und wie die geschwindigkeit ist, ist auch fraglich.
    auch ob das kuerzer wird hab ich jetzt nicht nachgezaehlt.
    evtl kannst ja was draus machen.


    salute

  • leider hab ich noch nicht richtig verstanden was das prg machen soll.

    Also, am einfachsten sieht man das wohl an einem Beispiel: Wenn ich es auf meine Uhr (in der Version mit Systemzeichensatz) "loslasse" kommt folgendes "BASIC" heraus:

    Zum Vergleich der "klassische" Ansatz, der das gesamte Maschinenprogramm aus DATA-Zeilen lädt:

    Die Version mit meinem Tool ist hier gute 10 Zeilen kürzer und in einem Bruchteil der Zeit geladen und gestartet ;)


    Deine Idee mit Tabelle kann ich mir mal anschauen, denke aber das verkürzt den Code weniger als der zusätzliche Platz, den die Tabelle braucht?

  • ah alles klar jetzt leuchtet mir das ein.
    ja denke auch das die version mit der tabelle nicht die schlauste ist, sah ich aber auch erst jetzt beim nachzaehlen der
    bytes in deiner routine.


    was mir aber auffaellt ist der check auf alpha numeric und nummeric
    evtl ist das hier ja nicht :D kuerzer


    gut das prueft halt nich auf richtigkeit der eingabe ne

    Code
    1. HEXDIG CMP #'a' (alphabetic digit?)
    2. BCC SKIP (no, skip next part)
    3. SBC #6 (sub seven)
    4. SKIP SBC #'0' (convert to value)
  • gut das prueft halt nich auf richtigkeit der eingabe ne

    Das tut mein originaler Code auch nicht. Wozu auch, soll ja etwas parsen, was vom Tool generiert ist, und wenn es um abtippen geht, wie für das BASIC Magazin hier, hat man hoffentlich einen Checksummer ;)


    Ziel war wirklich nur so klein und schnell wie möglich ;)

    evtl ist das hier ja nicht :D kuerzer

    Hm, wenn ich jetzt nichts übersehe ist das genau gleich lang wie meine Variante:

    Code
    1. sbc #$30
    2. cmp #$11
    3. bcc digit
    4. sbc #$7
    5. digit: [...]
  • Wenn der Source explizit zum Abtippen vorgesehen ist, wäre noch ein Prüfsummenalgorithmus wichtig.
    Ich hab mal ein ähnliches Programm geschrieben (aber nie veröffentlicht), mit dem ich z.B. dies und dies erzeugt habe. Als "Kodierung" sind dabei sowohl Dezimalbytes als auch Strings möglich, da bei sehr kurzen zu bearbeitenden Programmen das längere Dekoderprogramm schwerer wiegt als die höhere Nutzdatendichte der Strings.


    Das Dekoderprogramm ist zwar nur Basic und damit langsam, aber da das Ergebnis in eine neue Datei geschrieben wird, finde ich das nicht schlimm: Das abgetippte Programm lässt man so eh nur ein einziges Mal laufen.

  • @Mac Bacon -- das ist ein etwas anderer Anwendungsfall ;) Hier ging es ja grundsätzlich um BASIC-Programme, ich wollte aber Maschinencode mit einbinden. Das wird "klassisch" mit DATA/POKE gelöst, in der Regel auch ohne zusätzliche Prüfung. Das hier optimiert Platzbedarf und Geschwindigkeit. Für die Sicherheit beim Abtippen sollte IMHO lieber ein separater Checksummer sorgen, damit das abzutippende Programm nicht unnötig aufgebläht wird. (man tippt ja nur einmal ab, führt aber eventuell viele male aus ...)

    [...] da bei sehr kurzen zu bearbeitenden Programmen das längere Dekoderprogramm schwerer wiegt als die höhere Nutzdatendichte der Strings.

    Das hier ist ja genau für ein "etwas größeres" MC-Fragment entstanden, wo das eben nicht so ist. Bei kleineren Routinen lohnt sich das selbstverständlich nicht, auch nicht für die Ladegeschwindigkeit.


    (edit, OT -- verdammt lustiger Thread mit dem abtippbaren disk image ... :D )

  • hm ist das evtl 2 bytes kuerzer und erfuellt die selbe function?


    hab halt schon lange nix mehr am cevi gemacht, von daher is mein verstaendniss deiner routinen gerade nicht das beste ;D

  • Das ist doch gleich lang? ?( würde aber auch nicht funktionieren, weil so $fb ja nie gelöscht würde -- der gelesene wert würde also zu einem fixen #$ff "konvergieren" ;)


    Wenn noch mehr Leute so eifrig Kürzungsmöglichkeiten suchen könnte man glatt einen Wettbewerb draus machen :D

  • @Bagitman ich habe es natürlich selbst getestet -- konnte bei mir keine Schwierigkeiten finden. Anders wäre es sicher bei "repetitivem" code, aber der verwirrt auch (wenn auch weniger) in DATA zeilen und das lässt sich wie gesagt durch crunchen umgehen.


    Kann schon gut sein, dass das individuell verschieden ist. Aber die Größenunterschiede allein sind schon sehr deutlich -- in DATA zeilen braucht ein Byte des Codes, bei Annahme einer Normalverteilung, im Schnitt 3,6 Zeichen -- gegenüber genau 2 Zeichen mit diesen Hex Strings. Wenn es um Startgeschwindigkeit geht reden wir sogar von Größenordnungen -- gemessen habe ich allerdings noch nicht :)

  • So, habe jetzt mal beide Varianten für die Uhr gemessen mit

    Code
    1. 100 print ti
    2. ti$="000000":run

    Ergebnis ist


    Komplett aus DATA: 288 jiffies
    Mit meinem Loader: 56 jiffies


    Verhältnis ist hier also ca 5:1. Und die Uhr ist ja noch ein relativ kleines Progrämmchen, da hat das laden des Loaders selbst noch einen spürbaren Anteil ;)