Optimierungsgrad KERNAL /BASIC - fiktiver Talk

Es gibt 337 Antworten in diesem Thema, welches 62.644 mal aufgerufen wurde. Der letzte Beitrag (16. September 2017 um 00:34) ist von Boulderdash64.

  • Nun sag mir doch, was an einem gepflegten
    ON ... GOSUB
    oder ON ... GOTO in Basic V2
    so grundlegend anders ist als an einem

    switch

    oder CASE .. OF
    in Pascal oder C.

    Die Übersichtlichkeit kann bei einem Rechner wie dem VC 20 mit 3,5 KB RAM gar nicht so sehr leiden,
    in einen so kleinen (heute eig. ungebräuchlichen) Arbeitsspeicher passen gar nicht soviel GOTO's hinein wie ein erfahrener 8-bit-Programmierer wie du bräuchte um die Übersicht zu verlieren :P

  • Bei einem Basic ohne Zeilennummern müßte der Quelltext vermutlich kompiliert werden.

    So weit ich weiß gab es da auch schon mal ein Tool, daß den Textverarbeitungs-Quelltext dann in Basic-Code umgewandelt hat.

    Ansonsten wäre ein GOTO-Adresse vermutlich das schnellste. Man könnte da mit einer Zeilennummerfunktion die Zeilenadresse ermitteln und dann bei häufigen Sprüngen mit GO A dann zur Adresse in A springen.

    Bei Kompilierung wäre ein GO adr auf jeden Fall ein Vorteil, da die Suchvorgänge dann entfallen.

    Grundsätzlich bräuchte man nur ein GO Adresse und eine Zeilennummerfunktion für Zeilenberechnungen. Für Labels wär das mit verlängerten Variablen auch geeignet.

    Das würde dann auch mit RESTORE Adresse funktionieren.


    Schönen Gruß.

  • Nun gut ... dann wird das möglichst frei parametrierbare GOTO / GOSUB ins inoffizielle Pflichtenheft mit aufgenommen.

    Dann macht euch aber bitte auch darüber Gedanken, wie dann noch ein RENUMBER funktionieren soll. Ein GOTO/GOSUB mit berechneter Sprungadresse wäre ein absolute Katastrophe, die Programme noch weniger lesbar und nicht mehr renumerierbar.

    Ausserdem lassen sich mit ON GOTO/GOSUB alle Fälle abdecken.

    Dann lieber eine Erweiterung mit richtigen Labels. Ich hatte mir mal sowas als Mod für das Exbasic Level II für den CBM 3032 gebaut.

  • Die Beschränkung auf 2 Zeichen ist ja noch ein bisschen tiefer verwoben.

    Alle Variablentypen die gleiche Länge von 7 Bytes. An irgendeiner Stelle war es total praktisch, die so abzählen zu können. Vielleicht bei der Suche, was weiss ich... Da sehe ich jedenfalls die erste Schwierigkeit, verschieden lange Namen abzulegen.

    Dann ist der Typ der Variablen platzsparend in den beiden Bit7 des Namens abgelegt: 00=float, 11=Int, 01=String, 10=fn
    Wird das beibehalten, lässt das 7 Bit für den Hash.

    Dann: Soll der Hash schon beim Tokenisieren oder erst zur Laufzeit gebildet werden?
    Zur Laufzeit reichlich teuer,
    beim Tokenisieren noch weiter beschränkt:
    Tokens, Trennzeichen usw. dürfen sich ebenfalls nicht ergeben, wenn die normale Formelauswertung das lesen soll.
    Im Zweifel bleiben 36 Zeichen für den Hash.
    3% Wahrscheinlichkeit einer Kollision bei der 2.Variablen.
    SO macht der Hash keinen Sinn mehr, einfach das 2. Zeichen des Variablennamens hat die gleiche Chance.

    Ein solcher Hash ist sehr nützlich für die Variablensuche, dann kann man nämlich die Variablen in einem (binären) Baum verwalten und hat statt linearer Zeitkomplexität nur noch eine logarithmische. Ist die vermeintlich richtige Variable gefunden, muss man aber natürlich trotzdem alle Zeichen überprüfen.

    Scheint mir im Rahmen der "kleinen Verbesserung" schon zu Aufwändig, da scheint mir eine einfache, sortierte Liste erreichbarer zu sein.


    Ich möchte nochmal den Gedanken hervorkramen, Basic-Zeilen genau wie Strings verwalten zu lassen. Im Grunde sind sie ja Strings, aber da sie für die 4K-Version des Basic entstanden sein dürften, taugt der Aufbau nicht so gut für Änderungen zur Laufzeit.
    String/Zeile im Speicher ablegen, String/Zeile suchen sehe ich als Doppelt im ROM an,
    Programm neu verketten gar als Überflüssig.
    Im Gegenzug sehe ich aber CLR, Garbage Collection, DATA und SAVE als komplizierter an.


    Eventuell liesse sich das DEF FN aufbohren, um nicht nur Funktionen, sondern normalen Basic-Code anzuspringen?

  • Dann macht euch aber bitte auch darüber Gedanken, wie dann noch ein RENUMBER funktionieren soll. Ein GOTO/GOSUB mit berechneter Sprungadresse wäre ein absolute Katastrophe, die Programme noch weniger lesbar und nicht mehr renumerierbar.


    Nur weil User "BIF" nach mir gepostet und von Sprungadressen geschrieben hat, heisst das noch lange nicht, dass meine Idee "frei parametrierbare GOTO /-SUB" auch exakt so gemeint war; ich hatte überhaupt nicht an sowas gedacht, weil es alte Quelltexte incl . Basic-Bytecode sofort schlagartig inkompatibel machen würde :silly:

    Eine berechnete Programmzeilennummer wäre m.E. keine Katastrophe, ebensowenig das beibehalten von Zeilennummern weil es die Idee ON...GOSUB , switch, case..of lediglich paraphrasiert. Der eigentliche Sündenfall ist das GOTO bei exzessiver Verwendung; aber es gibt ja auch REPEAT UNTIL und WHILE .. DO ... und LOOP etc., und selbst wenn diese nicht als TOKEN implementiert sind, ließen sie sich mit wenig Aufwand auf FOR .. NEXT zurückführen. Bingo!

    Davon abgesehen, würden "berechnete Sprünge mit 16 Bit-Sprungadresse als Ziel" (also Binärquark im Bytecode) trotzdem einen Türspalt zurück offenlassen, da sowohl die Sprungziele als Zeilennummer als auch die Sprungziele als CHRGET-Adress-Zeiger stets sich auf einen Zeilenanfang beziehen und somit wechselseitig ineinander rückführbar wären.

    Zitat

    Ausserdem lassen sich mit ON GOTO/GOSUB alle Fälle abdecken.


    Meine Rede; schrieb ich weiter oben doch. :party2:

    Zitat

    Dann lieber eine Erweiterung mit richtigen Labels. Ich hatte mir mal sowas als Mod für das Exbasic Level II für den CBM 3032 gebaut.

    Hmm, weisst du zufällig noch, wieviel Bytes diese Label-Erweiterung beansprucht hat?
    Das neue ROM soll ja nicht zu fett werden :schnitzel:

  • Ich möchte nochmal den Gedanken hervorkramen, Basic-Zeilen genau wie Strings verwalten zu lassen. Im Grunde sind sie ja Strings, aber da sie für die 4K-Version des Basic entstanden sein dürften, taugt der Aufbau nicht so gut für Änderungen zur Laufzeit.
    String/Zeile im Speicher ablegen, String/Zeile suchen sehe ich als Doppelt im ROM an,
    Programm neu verketten gar als Überflüssig.
    Im Gegenzug sehe ich aber CLR, Garbage Collection, DATA und SAVE als komplizierter an.


    Eventuell liesse sich das DEF FN aufbohren, um nicht nur Funktionen, sondern normalen Basic-Code anzuspringen?

    Würdest du die Zeilen dann als doppelt (vorwärts und rückwärts) verkettete Liste im Speicher führen und wie würde die Binärkompatibilität zu alten Basicprogrammen aussehen?

    Der andere Gedanke DEF FN aufbohren, gefällt mir ausnehmend gut. Überhaupt fände ich Erweiterungen "Unter der Haube" prima, bei denen neue (zu Basic >= 3.5 inkompatible) Tokens vermieden würden und der Trick in der Erweiterung der Syntax liegt.

    Folgende Idee kristallisiert sich darum herum:
    - DEF FN für (einzeilige / Mehrzeilige) Funktionen nach Pascal und C- Art;
    - DIM aufbohren: Sobald DIM (als 1. Zeile eines Unterprogramms) mit dem Stacklevel eines GOSUB-Aufrufs (Stackzeiger nicht mehr auf Hauptprogrammebene) aufgerufen wird, werden keine "Redim'd array errors" mehr erzeugt, sondern ein neuer Variablen-Rahmen für lokale Variablen
    - GOSUB Zeilennummer wird ergänzt um eine optionale Liste (Data 1, data2, data3 ...) die für zu übergebende Parameter steht.
    also:
    GOSUB 5600 (value1)
    Vorläufig schlage ich Übergabe "By Value" vor (also intern mit Umkopieren). Evtl. bildet man das ganze konsequent und komplementär mit READ aufseiten des Unterprogramms nach. (READ als 1. Wort nach DIM Klammer auf)
    - RETURN wird um (Rückgabewert) erweitert.

  • Damit die Spaghettiprogrammierer sich noch mehr in den Fuß schießen können?

    Ja bitte! Schlagt mich, quält mich, gebt mir Tiernamen! :roll2:

    Na ehrlich: Es hätte schon einen gewissen Reiz. :wink:

  • Den DIM-Befehl sollte man meiner Meinung nach als Lösch-Befehl umprogrammieren.

    Also :dima,b,c,d: gleich a=0:b=0:c=0:d=0
    und :dima(100): löscht das ganze a-Feld statt error Meldung.

    Bei der Kompatibilität von go Adresse sehe ich keine Probleme, da go ohne to ja sonst eine Fehlemeldung ausgibt.

    Schönen Gruß.

  • Gute Idee! - Wie war es denn bisher bei einfachen Variablen (Nicht Feldern?)

  • Würdest du die Zeilen dann als doppelt (vorwärts und rückwärts) verkettete Liste im Speicher führen und wie würde die Binärkompatibilität zu alten Basicprogrammen aussehen?

    Keine Kompatiblität, damit vermutlich nichts für hier :/
    Keine besonderen Verkettungen, einfach nur Strings mit Null am Ende und Zeilennummern statt Variablennamen.
    Was ich hier nicht erwähnt habe: Variablen würden in einer sortierten Liste abgelegt. damit binär gesucht werden kann.

  • Ich würde mich auch freuen , wenn der User, der den Wunsch in den Raum "geschmissen" hat, die ROM-Routinen für Clear Screen sollten doch auch die Grafik bedienen können, sich mit meinem Posting Nr. 196 befassen würde ...

    Ich, aka "der User", hatte noch keinen Kopf mir das ordentlich rein zu ziehen :bandit:) . Folgt aber wohl noch.

    Ich konnte auf die Schnelle jetzt aber nicht sehen, wie man damit eine Bitmap löschen könnte (vielleicht auch bloß nicht geblickt).

    Ich hatte vor einiger Zeit aufgrund oobdoo's "Frutty Man" eine "Fill"-Routine gebaut (für Plattformen/Leitern etc.), die das mit erschlagen würde:

    Bitte melde dich an, um diesen Anhang zu sehen.

    , d. h., in 64/60 Sek. ist damit in BASIC eine Bitmap gelöscht.

    Oder Speicher horizontal/vertikal mit Bytes/Text/Zeichen/Daten gefüllt:

    Bitte melde dich an, um diesen Anhang zu sehen.
    Bitte melde dich an, um diesen Anhang zu sehen.

    Die (bislang noch vom Befehl getrennte) Startadresse (SYS 979,XXXXX) ließe sich natürlich noch in den SYS/"FILL"-Befehl integrieren. Aus irgendwelchen Gründen hatte ich das damals getrennt behandelt. Das "Ding" ist aber verdammt flexibel/universell einsetzbar (Speicherbereiche füllen/löschen), im Screen horizontale und/oder vertikale Zeichenfolgen/Linien ziehen (Plattformen/Leitern z. B.) etc., braucht aber auch 192 Bytes (läuft/lief halt knirsch im Tape-Buffer).

    BIF: Was ist denn mit dir los =O ? Mal verdammt gute Beiträge von dir :dafuer: !

    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.

    Ex-TLI (The Level 99 Industries) & Ex-TNP (The New Patriots) & Ex-TEA (The East Agents) & ?

  • @Stephan:

    Der DIM-Befehl legt Variablen und Felder an:
    :dim a,b,c,d(100):

    Beim ersten Aufruf werden die Variablen und Felder angelegt und mit Nullen gefüllt, also gelöscht.

    Wenn ich den Ausdruck noch einmal anspringe wird bei a,b,c nichts gemacht und bei d(100) gibt es einen "re`dimed array error".

    Also beim zweiten abarbeiten bleibt der Variablenwert von a,b,c wie er ist und bei Feldern steigt dim mit einer Fehlermeldung aus.

    Schönen Gruß.

  • Danke!

    Bitte melde dich an, um diesen Link zu sehen. (DerUser ;) )
    Danke für die Lebendmeldung! - sehe ich das recht, dass mit:
    d. h., in 64/60 Sek. ist damit in BASIC eine Bitmap gelöscht.

    gemeint ist "von Basic aus" ist eine Bitmap gelöscht?

    Der weiter oben von mir gepostete Versuch, die "Clear screen"-Routine des Kernal aufzubohren, ist noch nicht vollständig. - Natürlich würde ich mich freuen wenn du Zeit findest es dir mal anzuschauen. - Er zeigt meines Erachtens eher, dass man nicht unbedingt Kernal-Routinen "mit Gewalt" aufbohren sollte, zumal Clear Screen dafür alles andere als geeignet erscheint. Man müsste ja manuell vorher auch noch die Zeiger auf die Zeilenanfänge leicht zweckentfremden, zumindest aber mal setzen.

    Einen Vorteil hat meine o.g. Untersuchung dann doch, nämlich zu zeigen wie dicht gestreut "Optimierungsmöglichkeiten" im Kernal/Editor-bereich überhaupt sind. Ich kam auf eine Abschätzung von 3% Platzgewinn. macht 240 Bytes pro 8 KB.

    Wie lang sind denn deine Routinen zum Füllen einer Bitmap? den Sys-Befehlen konnte ich das nicht entnehmen. Es kann ja sein, dass deine Lösung bereits die ausgereiftere ist, die man in ein generalüberholtes ROM stecken könnte ...

    Eine minimale Bitmap-Modus-Routine für ein neues ROM bräuchte m.E. folgendes:
    - Zeiger für Basic-Ende herabsetzen u. Platz schaffen für Bitmap
    - VIC-Bank im CIA-Register setzen (notfalls auf festen Wert für die gebräuchlichste Adresse)
    - VIC-Bitmap-Modus setzen
    - Farbram initialisieren (ggf. mit frei wählbarem Füllbyte, bei Platznot mit "weiß")
    - Zeropage-Zeiger in die Bitmap setzen und hierüber eigentliche Bitmap löschen (ggf. mit frei wählbarem Füllbyte)

    Dann braucht es sicher ein Gegenstück, eine Routine die diese Änderungen (bis auf das Löschen) rückgängig macht, also in den Textmodus zurückschaltet (evtl. mit Zusatzparameter der SAVE aufzurufen erlaubt?) und die man an CLR anhängen könnte. (setzt allerlei Basic-Zeiger auf Normalwerte zurück)

    Und dann noch die allfällige Routine zum Setzen / Löschen eines einzelnen Hires-Bildpunkts (die von Basic aus natürlich auch für den Multicolor-Modus zweckentfremdet werden kann.)

    Bitte melde dich an, um diesen Link zu sehen. (s.unten)
    Danke für die Anregung mit RPEEK, RPOKE bzw. die Anregung den Platz unter dem ROM zu nutzen.

  • Wenn man den Zugriff auf den Bitmap-Speicher durch Peek und Poke vollständig eliminieren könnte (durch entsprechende Grafik-Befehle), könnte man die Bitmap nach $e000 legen und könnte diesen unter Basic 2.0 praktisch nicht nutzbaren Speicherbereich sinnvoll einsetzen. Alternativ könnte man natürlich auch dedizierte Peek und Poke-Befehle für das RAM hinzufügen (RPEEK, RPOKE), um generell den Konflikt zwischen den Speicherbänken aufzulösen.

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

  • Alternativ könnte man natürlich auch dedizierte Peek und Poke-Befehle für das RAM hinzufügen (RPEEK, RPOKE), um generell den Konflikt zwischen den Speicherbänken aufzulösen.

    Wenn man das macht, kann man gleich auch Pointer-Variablen einführen, mit denen man direkt im RAM fuhrwerkt, in dem man die Zielregionen ganz genau so anspricht wie stinkbnormale Variablen. Wär das nicht was Tolles! Nur frag mich jetzt nicht, wie das implementiert gehört. Wenns praktisch und zielorientiert wird, flüchte ich lieber! :aaa:

  • Puh, das wäre aber dann wohl entweder ein ganz neuer Variablentyp, oder ein neuer Operator wie der * in C. Da Pointer auch nicht grade als ultimativer Segen aller Programmiersprachen bekannt sind, würde ich da wohl eher Basic-nah bleiben wollen.

    EDIT: wobei, das hätte auch was: einfach mal die schlimmsten Features aller Sprachen zusammenwerfen: Zeilennummern, Pointer, Tabs als syntaxrelevante Zeichen, ... :D

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

  • Da Pointer auch nicht grade als ultimativer Segen aller Programmiersprachen bekannt sind, würde ich da wohl eher Basic-nah bleiben wollen.

    Ich würde auch lieber Basic-nah bleiben, die interessante Frage ist dabei,
    wie - unter der Bedingung recht knappen ROM-Speicherplatzes, der durch Neuimplementierung erst noch zu schaffen ist ! - mit solchen neu-Konstrukten Basic so angereichert werden kann,

    dass bisherige "langwierige Abläufe" deutlich gestrafft werden können.

    Ich rufe in Erinnerung:
    - Stringverwaltung /GC a la Basic V4
    - Strukturelemente wie Repeat .. until oder while .. loop
    - Funktionen und Prozeduren

    Also im Idealfall, dass (Basic)programme merklich geschmeidiger laufen und angenehmer / übersichtlicher in der Erstellung und schon beim Testen sind, weil die 'übelsten' Performance-Bremsen beseitigt werden.

    Was sind für dich und für euch die krassesten Performance-Bremsen in Basic V2 - ausser der Garbage Collection, aber mit dieser auf einer Stufe stehend?

    Edit: wie wäre es mit einem neuen Datentyp "Bit-Array" mit individuell adressierbaren Bits? evtl. auch nur ein bereits vorhandenes Datenwort / Token mit einer Zusatzbedeutung.
    ich könnte mir vorstellen, das Token 255 für "Pi" (3.14159265...) auch als voreingestellten Feldbezeichner für die Bitmap zu nutzen.

    (Da ich nicht weiß wie ich auf der PC-Tastatur das Pi-Symbol herbekomme ersetze ich es hier durch My = µ .. bitte denkt euch das Pi dazu.)

    10 µ(14*4096 + X*1+ Y*320) = 1: REM PIXEL SETZEN
    20 µ(14*4096 + X*1+ Y*320) = 0: REM PIXEL LOESCHEN

    Edit 2: oder als 2dimensionales Array, wenn Platz für so eine Implementierung ist. Dann übernimmt der Interpreter die komplette Adressberechnung incl. $E000-Offset:
    10 µ(X,Y)= 1
    20 µ(X,Y)= 0

  • Hm, wozu kann man das Bit-Array denn gebrauchen? Für Bitmap-Grafik wohl leider aufgrund der ungünstigen Speicheraufteilung eher nicht. Und ob man in Sprites einzelne Pixel setzen will? Auch scheint mir der Gewinn gegenüber

    10 A=14*4096 + X/8*1 + Y*320: POKE A, (PEEK(A) OR (X%8))

    nicht soooo gewaltig.

    Ein Plot-Befehl, der die seltsame Speicheraufteilung berücksichtigt ist natürlich etwas anderes, der macht die Sache schon deutlich einfacher!

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

  • Das hab ich beim Hinschreiben dann auch bemerkt .. .die Formel im 1. Beispiel war auch nur aus dem Gedächtnis 'hinentworfen' ... so wie dein Beispiel ja auch locker mit der (noch) nichtvorhandenen Modulo-Funktion behende zu Werke geht :D

    Natürlich ergibt das mit dem µ-Feld erst richtig Sinn, wenn man die krude Speicheraufteilung die vom VIC herrührt, den Interpreter machen lässt; desgleichen das AND Inverse-Maske ORA Maske .. also das eigentliche 'Bit-twiddling'

    Edit:
    das Bit-Feld kann ruhig "in sich verdrillt" sein nach den Vorgaben des VIC . Die ergeben dann automatisch bei der visuellen Darstellung das richtige Layout.
    Sofern man es für andere allgemeine Zwecke (SET -Ersatz gemäss Pascal, also "Mengen") verwenden will - macht die "Verdrillung" auch nichts aus, weil wie bei RAM allgemein, die Verdrillung beim Zurück-Lesen ja dieselbe ist wie beim vorhergehenden Schreiben :)