Hallo Besucher, der Thread wurde 9,5k mal aufgerufen und enthält 60 Antworten

letzter Beitrag von tom42 am

Opcode-Dispatchmethoden bzw. Indirekte Sprünge

  • Hallo, ich lese hier schon sehr lange mit.


    Jetzt habe ich mich entschlossen, mal etwas zu schreiben.


    Wer SWEET16 von "THE WOZ" kennt, weiß, dass er sich dort, um zu den Opcode-Handlern zu springen, den rts-Trick verwenden.


    https://en.wikipedia.org/wiki/SWEET16


    http://www.6502.org/source/interpreters/sweet16.htm


    Code
    1. SW16D LDA >SET ;COMMON HIGH BYTE FOR ALL ROUTINES
    2. richtig:
    3. SW16D LDA #>SET ;COMMON HIGH BYTE FOR ALL ROUTINES


    Leider dürfte beim Übertragen auf html die Raute "#" für die immediate-Adressierung verlorengegangen sein. Gebt mehrere solcher Fehler, wenn ich mich erinnern kann, sind aber recht leicht zu finden.


    Egal, darum geht es nicht.
    Woz springt seine Handlerroutinen mit dem rts-Trick an:


    Das geht auch mit einem branch-Befehl. Die 128-Byte-Grenze ist gleich wie Woz's Pagegrenze, wenn man den Dispatcher irgendwo ca. in die Mitte zwischen die eine Hälfte und die andere Hälfte der Opcode-Handler legt.


    Eine Version mit "bne", mittels Poke testbar (Format CBM prg Studio):



    Edit: irgendwie schaffe ich es hier nicht, Code reinzugeben, ich liefere ihn im nächsten Post.


    Die Veränderung zu Woz ist die branch-Methode zwischen den beiden Linien.



    Viel Spaß :)



    Dieser Post soll anregen, über Code-Beispiele passend zum Thread-Titel zu diskutieren und Ideen (auch verrrückte) auszutauschen: z.B. Selbsmodifizierender Code, indirekte Sprünge, Sprungtabellen, Handler-Routinen anspringen usw.

  • Deine Methode benutzt aber selbstmodifizierenden Code und läuft darum nicht im ROM.


    Gängig ist ansonsten noch der Ansprung mit JSR auf einen JMP()-Befehl. Dann können alle angesprungenen Routinen mit einem RTS-Befehl beendet werden und müssen nicht mit einem 3-Byte-JMP Befehl zur Hauptschleife zurückkehren.


    Google mit "Forth 6502 NEXT" fördert auch noch nettes zu Tage. :D

  • Korrekt, läuft nicht im ROM.


    Ziel des Threads ist es, sich über verschiedenste Techniken auszutauschen und pro/kontra zu diskutieren.


    Dieser Post soll anregen, über Code-Beispiele passend zum Thread-Titel zu diskutieren und Ideen (auch verrrückte) auszutauschen: z.B. Selbsmodifizierender Code, indirekte Sprünge, Sprungtabellen, Handler-Routinen anspringen usw.


    Zum jmp - indirekt Befehl:


    Ja, der ist aber glaube ich länger als die Woz-Methode, und hat den Wrap-Around-Bug.



    P.S. Wie kriege ich das "Brainfuck-Code" zu einem normalen Code?

  • Hab' grad meinen ersten Post noch ergänzend editiert.

    Zitat von tom42

    Wie kriege ich das "Brainfuck-Code" zu einem normalen Code?

    Meistens (aber nicht immer), in dem man beim Editieren eine geeignetere Sprache wählt. Aber der Forums-Editor ist eh Scheiße (frißt Leerzeilen, fügt beim Edit Leerzeilen ein, wo vorher keine waren, ersetzt ungefragt "#$00" in code-tags durch was anderes, etc.), darum laß ich jetzt diese Sache auch so wie sie ist...

  • Das Problem sind wahrscheinlich die Kommentarzeilen "; --------------------------" usw

    Code
    1. ; --------------------------

    q.e.d.


    Hieran "erkennt" die Forensoftware, daß es sich um Brainfuck-Code handeln soll. Am besten daher solche Kommentarzeilen meiden. Zusätzlich kann man die Syntax-Hervorhebung manuell abändern, jedoch gibt es leider nicht die Auswahlmöglichkeit "Assembler", so daß man sich mit einem anderen Typ behelfen muß.

    XML
    1. ; --------------------------

    q.e.d.


    Aber der Forums-Editor ist eh Scheiße

    Meine "Lösung" besteht darin, den Code in einem Texteditor zu schreiben, den Forum-Editor auf "BBCode" umzustellen, dort händisch die Codetags einzufügen und dazwischen per Copy&Paste den Code an sich. Beim Zurückschalten in den normalen Editiermodus muß man allerdings aufpassen, daß die Forensoftware immer wieder automatisch Leerzeilen vor und nach dem Code einfügt, die man - sofern gewünscht - ebenfalls manuell wieder entfernen muß.

  • Meine "Lösung" besteht darin, den Code in einem Texteditor zu schreiben, [...]

    Ja, so in etwa hab' ich mich hier auch arrangiert. Gibt - wie Du auch angemerkt hast - aber immer noch erhöhten Blutdruck, wenn man in der vermeintlich finalen Fassung doch noch einen Fehler findet und editieren will. :aerger:


    Unlängst hatten wir noch einen anderen Thread, wo Hauptschleifen mit einem großen case-Statement zwischen waren, da hatte ich noch diese Konstruktion parat:

    Simpel, aber funktioniert, wenn einem die lineare Suchzeit nicht so arg Probleme macht (und man kann ja die häufigsten Werte nach vorne ziehen).

  • Ja, mit Vorsicht geht das.


    Andere Idee (insipiriert durch dein Switch), wie schauts mit binärer Suche aus?


  • Gängig ist ansonsten noch der Ansprung mit JSR auf einen JMP()-Befehl. Dann können alle angesprungenen Routinen mit einem RTS-Befehl beendet werden und müssen nicht mit einem 3-Byte-JMP Befehl zur Hauptschleife zurückkehren.

    Ja, Woz tut genau das in SWEET16:



    http://www.6502.org/source/interpreters/sweet16.htm


    Den Trick kann man auch in Basic nutzen, wenn man nur ein Paar Bytes für eine modifizierte GOTO Zeilennummer "ausgeben" will. GOSUB Zeilennnummer ist komplizierter, wegen Stack-Größe testen usw.


  • So, hier mit jump indirect "jmp (zp-vektor)":


    Die geht dann auch im ROM, sie nutzt ZP-Vektor 2/3.
    Man könnte auch einen Vektor innerhalb des Codes nehmen, dann ist sie aber nicht mehr im ROM lauffähig.
    Selbstmodifizierender Code geht auch mit einem direkten JMP (siehe unten), auch die geht nicht im ROM.

  • und die ebenfalls im ROM benutzbare "rts-Methode" von Wozniak:


  • nur im RAM laufbar, mit Selbstmodifikation eines direkten JMP:



    Die Branch-Methode muss innerhalb der Page bleiben.
    Alle anderen Methoden kann man leicht umbauen, dass das HI-Byte auch in der Jump-Tabelle steht. Dadurch kann man wo immer hinspringen, wo man will.

  • Ja, als 16-bit Adresse, gibts das anders?



    http://www.6502.org/tutorials/6502opcodes.html#JMP:


    JMP (JuMP)


    Affects Flags: none


    MODE SYNTAX HEX LEN TIM
    Absolute JMP $5597 $4C 3 3
    Indirect JMP ($5597) $6C 3 5



    Ja, mein Assemblerdump gibt mir auch $6C

  • Habe nun mit dem CBM Prg Studio die Cycles gezählt, jeweils bis vollzogenem Sprung in die jeweilige Handlerroutine.



    RAM ONLY relativ Jump mit BRANCH: Start bei ldy#OpcodeNr -> 13 Cycles
    RAM ONLY relativ Jump mit SELBSTMOD DIREKT JMP: Start bei ldy#OpcodeNr -> 13 Cycles
    ROM relativ Jump Dispatch mit JMP IND: Start bei ldy#OpcodeNr -> 14 Cycles



    ROM relativ Jump Dispatch mit RTS:



    Variante 1: Start beim LO-Byte auf Stack geben -> 15 Cycles
    Ich denke, man kann das gemeinsame HB am Stack schon vorher für alle
    weiteren Verwendungen lassen.
    Habe ich aber nicht getestet.

    Variante 2: Start am Anfang bei HI-Byte auf Stack geben -> 20 Cycles

  • Ich denke, man kann das gemeinsame HB am Stack schon vorher für alle weiteren Verwendungen lassen.

    Wenn das Datum ge-POP-t ist und bis zur nächsten Verwendung ein Interrupt passiert oder die aufgerufene Routine ihrerseits ein Unterprogramm aufruft oder sonstwie den Stack verwendet, dann war's das.


    Nichts "unterhalb" des Stackpointers sollte in irgendeiner Weise relevant für ein Programm sein.


    Es gibt schon Anwendungsfälle, wo tief unten im Stack (so ab $010x) Daten und/oder Routinen abgelegt werden, nur verlassen die sich dann darauf, daß die gerade laufende Anwendung einen enger begrenzten Stackbedarf hat. Der BASIC-Interpreter nutzt diesen Bereich z.B., um die Zeichenkette einer Float-nach-ASCII-Umwandlung zusammenzubauen.

  • <OT>

    Wieso ist das noch so?
    Untragbar fuer eine Forensoftware und insbesondere ein Forum wie dieses hier.

    Enthusi, es steht Dir als Entwickler frei, dich hinzusetzen und ein Syntax Highlighting für 6502 ASM zu schreiben und es dem Forum ehrenamtlich anzubieten. :dafuer:
    Im Woltlab Addin Shop hat faktisch nichts in der Richtung. Allenfalls VB.NET und C#.

    </OT>