Hello, Guest the thread was called3.7k times and contains 91 replays

last post from JeeK at the

Umsetzung von Basic-Befehlen in Maschinensprache

  • Hallo,

    kurz vorneweg: ich habe im Alter zwischen 9-14 den C64 intensiv benutzt und damals leider nie Maschinensprache gelernt. Heute mit 47 Jahren will ich das nachholen (man munkelt, dass es da noch weitere "Verrückte" geben soll).^^ Ich habe mir den 64er Assembler-ist-keine-Alchimie Kurs besorgt und meine ersten Gehversuche gemacht. Soweit so gut. Ich nutze im Moment S-MON. Ich habe festgestellt, dass ich bestimmte Programme in Basic schreiben kann, die ich aber (noch) nicht in Assembler formulieren kann. Einfaches Bespiel: ich möchte die Zeichenfolge "ABCDEF" auf den Bildschirm plotten. In Basic kein Problem:

    10 x=1024

    20 for i=1 to 10

    30 poke x+i,i

    40 next

    Erste Frage: In Assembler könnte ich natürlich auch die o.g. Zeichenkette hinbekommen (über eine Kette von LDA/STA Befehlen: LDA#$01 STA0400 LDA#$02 STA0401 ...) - aber ich frage mich, ob das nicht auch eleganter ginge (so wie in der Basic Schleife)? Meine Versuche über INC sind bisher leider fehlgeschlagen - die Bildschirmposition des zu printenden Zeichens kriege ich gut verändert - aber nicht den Akkumulator-Inhalt.


    Zweite Frage: Ich habe gedacht, dass ich mir mein BASIC Programm einfach mal über SMON in assemblierter Form anschauen könnte und dann sehe ich ja, wie ich es hinbekomme. Allerdings finde ich mein BASIC Programm nicht wirklich im Speicher. Ich habe an Adresse 0801 geschaut. Mit dem SMON Befehl "M 0801", sehe ich auch was, was mein Programm darstellt (richtig?). Aber ich sehe keine "Übersetzung" in Maschinensprache. Wahrscheinlich verstehe ich noch zu wenig, aber ich frage Euch mal: Kann ich irgendwo im Speicher eine in Maschinensprache übersetzte Version meines BASIC Programms finden? Falls ja, wo denn?


    Mit Bitte um Nachsicht für mein begrenztes Wissen :whistling:

    Thx und greetz

    Michael

  • Der Basiccode befindet sich NICHT direkt übersetzt ab $0801!

    Schleifen in Assembler sind auch kein Hexenwerk. Ist in deinem Buch kein Beispiel drin?

    Code
    1. LDY #$00 //Zähler auf Null
    2. Mark: hier Befehle rein, die y-mal ausgeführt werden sollen
    3. INY //Zähler erhöhen
    4. CPY #$40 //wenn noch nicht 64 mal erreicht
    5. BNE Mark //dann weiter
  • Meine Versuche über INC sind bisher leider fehlgeschlagen - die Bildschirmposition des zu printenden Zeichens kriege ich gut verändert - aber nicht den Akkumulator-Inhalt.

    Na ja, deine BASIC-Schleife macht ja nichts anderes, als in jedem Durchlauf auf den aktuellen Wert von i die Zahl 1 draufzuaddieren weil das die implizite Schrittweite ist so lange man mit STEP keine andere festlegt. Auch beim Akkumulator kann man 1 draufaddieren, indem man zB den Befehl ADC #$01 verwendet - allerdings addiert ADC nicht nur das Argument auf den Akkumulator, sondern zusätzlich auch noch eine weitere 1, wenn das Carry-Flag gesetzt ist(*), daher sollte man vor dem ADC noch CLC verwenden, damit das Carry-Bit mit Sicherheit nicht gesetzt ist.


    Kann ich irgendwo im Speicher eine in Maschinensprache übersetzte Version meines BASIC Programms finden?

    Nein, da der C64 nur einen BASIC-Interpreter im ROM hat und keinen Compiler. Der Interpreter liest die (tokenisierte) Version des BASIC-Programms stückchenweise und führt die dabei gefundenen Befehle aus, ohne neuen Maschinencode zu erzeugen.


    (*) Der Sinn dahinter ist der gleiche wie beim Übertrag, wenn man mit Stift und Papier schriftlich Zahlen addiert: Wenn die Summe der Zahlen nicht mehr in den Akku passt wird der Überlauf (=Carry) abgeschnitten und ins Carry-Bit geschrieben, damit man den bei der nächsten Stelle draufaddieren kann und so auch mit Zahlen rechnen kann, die mehr als ein Byte gross sind.

  • Der Basiccode befindet sich NICHT direkt übersetzt ab $0801!

    Schleifen in Assembler sind auch kein Hexenwerk. Ist in deinem Buch kein Beispiel drin?

    Code
    1. LDY #$00 //Zähler auf Null
    2. Mark: hier Befehle rein, die y-mal ausgeführt werden sollen
    3. INY //Zähler erhöhen
    4. CPY #$40 //wenn noch nicht 64 mal erreicht
    5. BNE Mark //dann weiter

    Hi Flyppo,

    danke für Deine Hilfe. Und sorry, dass ich gleich nochmal nachfragen muss. In Deinem Vorschlag ist unter "Mark" genau mein Problem: Wenn ich über STY in die Bildschirm-Adresse 0400 den Y-Wert schreiben möchte - wie kann ich den Wert 0400 ebenfalls erhöhen, damit die Zeichen nebeneinander geplottet werden?

    Grüße

    Michael

  • Ich habe mir den 64er Assembler-ist-keine-Alchimie Kurs besorgt und meine ersten Gehversuche gemacht.

    Das heißt, du hast jetzt ein 64er Sonderheft zum Thema Assembler? Die fand ich auch immer recht gut. Ich persönlich habe mit dem Sonderheft 35 angefangen.


    Ich würde dir empfehlen, erst einmal alle Befehle durchzugehen (sind nicht so viele) und dann erst dazu überzugehen, bestimmte BASIC-Programme in Maschinensprache zu übertragen.


    Der C64 hat einen eingebauten Interpreter, d.h. die BASIC-Programme werden während der Ausführung immer wieder neu in Maschinensprache übersetzt, man kann sich also kein fertiges Maschinenspracheprogramm im Speicher angucken.


    Siehe auch hier:

    https://www.c64-wiki.de/wiki/Interpreter

  • Hallo Michael,


    Ich möchte jetzt keine Werbung machen, aber ich kann dir die Website https://www.retro-programming.de/ wärmstens empfehlen.

    Da beginnt die Assemblerprogrammierung auch damit dass mittels schleifen Zeichen auf den Bildschirm ausgegeben werden. Dort ist es nur ein Zeichen, du müsstest also eine zweite Schleife mit einbauen, die das zu druckende Zeichen auch mit erhöht.

    Dort wird das Ganze aber am PC mittels Cross assembly durchgeführt.

    Ich finde es allerdings sehr einfach und verständlich erklärt.

  • Wenn ich über STY in die Bildschirm-Adresse 0400 den Y-Wert schreiben möchte - wie kann ich den Wert 0400 ebenfalls erhöhen, damit die Zeichen nebeneinander geplottet werden?

    Du könntest den Befehl im RAM modifizieren, aber das ist nicht gerade eine für Anfänger sinnvolle Methode.


    Eine der naheliegendsten Varianten wäre es, den Wert nicht selbst zu addieren sondern die CPU die Arbeit erledigen zu lassen: STA $0400,Y. Damit schreibt die CPU den Inhalt des Akkus an die Speicherstelle, deren Adresse aus der Summe von $0400 und dem aktuellen Wert in Y gebildet wird. Dummerweise willst du aber nicht den Inhalt von A, sondern den von Y schreiben, aber ein STY <adresse>,Y gibt es nicht. Du könntest aber beispielsweise vorher mit TYA den Wert von Y in den Akku kopieren.

  • Ich versuche mal, dein Basic-Programm 1:1 zu übersetzen:


    Code
    1. 10 x=1024
    2.     entfällt
    Code
    1. 20 for i=1 to 10
    2.     LDY #1
    Code
    1. 30 poke x+i,i
    2.     LOOP    TYA
    3.             STA 1024,Y
    Code
    1. 40 next
    2.     INY
    3.     CPY #10
    4.     BNE LOOP
    5.     RTS


    Falls es dir darum geht, Strings auszugeben, so empfehle ich wärmstens die Basic-Routine ab $AB1E.

  • Wenn ich über STY in die Bildschirm-Adresse 0400 den Y-Wert schreiben möchte - wie kann ich den Wert 0400 ebenfalls erhöhen, damit die Zeichen nebeneinander geplottet werden?

    Code
    1. tya
    2. sta $0400,y

    Stichwort "indizierte Adressierung".


    ich kann dir die Website https://www.retro-programming.de/ wärmstens empfehlen.

    Stimmt, die habe ich auch sehr gerne genutzt.

  • Das hat sehr gut funktioniert - danke an Alle! Das Stichwort "indizierte Adressierung" hat mir tatsächlich gefehlt. :thumbsup:


    Jetzt habe ich noch eine weitere Frage: Wenn ich einen längeren Text habe, den ich auf dem Bildschirm zeigen möchte, dann werde ich den ja nicht direkt über eine endlose LDA/STA Kette darstellen, richtig? Ich sehe zum Beispiel bei retro-programming im Code solche Angaben:


    !scr "dies ist eine erste laufschrift! "


    Wenn ich SMON benutze, wie kann ich denn eine solche Variable, die den Text enthält, definieren?

    Grüße und thx

  • Angelehnt an die Profi-Ass-Syntax würde ich - wie bereits erwähnt - die Basic-Rom-Routine nutzen:

    Code
    1. LDA #<text
    2. LDY #>text
    3. JSR $AB1E
    4. ...weiter im Text...
    5. text .ASC "Dies ist mein Beispieltext!",0

    Wobei du das ",0" auch anders schreiben kannst (die meisten Assembler mögen das nicht):

    Code
    1. .BYT 0

    Die 0 nach dem Text ist wichtig, daran wird das Textende erkannt.

  • Wenn ich SMON benutze, wie kann ich denn eine solche Variable, die den Text enthält, definieren?

    Gar nicht, SMON kann keine Variablen. Du müsstest den Text irgendwo frei nach Wunsch im Speicher ablegen und die verwendete Adresse von Hand in die Befehle eintragen, die darauf zugreifen wollen.

  • Gar nicht, SMON kann keine Variablen. Du müsstest den Text irgendwo frei nach Wunsch im Speicher ablegen und die verwendete Adresse von Hand in die Befehle eintragen, die darauf zugreifen wollen.

    Danke Unseen für die Klärung. Hast Du dafür ein Beispiel für mich? Theoretisch verstehe ich, was Du sagst. Aber wie implementiere ich das konrekt und wie rufe ich das dann auf. Sorry für meine lange Leitung.

    Viele Grüße aus Mannheim

    Michael


  • So wie im obigen Beispiel.

    Ist für den ACME und wird mit SYS4096 gestartet.

  • Im SMON sieht das ganze dann so aus:

    d 1000

    ,1000 A2 00 LDX #00

    ,1002 BD 13 10 LDA 1013,X

    ,1005 C9 00 CMP #00

    ,1007 F0 09 BEQ 1012

    ,1009 29 3F AND #3F

    ,100B 9D 00 04 STA 0400,X

    ,100E E8 INX

    ,100F 4C 02 10 JMP 1002

    -----------------------------------

    ,1012 60 RTS

    -----------------------------------

    ,1013 48 PHA

    ,1014 45 4C EOR 4C

    ,1016 4C 4F 20 JMP 204F

    -----------------------------------

    ,1019 57 ***

    ,101A 4F ***

    ,101B 52 ***

    ,101C 4C 44 21 JMP 2144

    -----------------------------------

    ,101F 00 BRK



    Die Daten ab $1013 musst du mit:

    .48

    .45

    .4c

    u.s.w einzeln eintragen.

    Wichtig ist das 00 in Zeile $101F am Ende.

  • Mit dem Heft habe ich auch damals angefangen. Ist schon sehr empfehlenswert. Die Beispiele sind gut, und sogar die KERNAL-API ist dort dokumentiert. So mancher Fachbuchverlag hätte allein dafür ein Extraband verkaufen wollen.

    Ich würde da mal stark empfehlen, geduldig weiter zu lesen. Schleifenprogrammierungen sind da auch gut erklärt.

    Es hat natürlich Gründe, daß X und Y Indexregister genannt werden, und A Akkumulator. Mit einem Blick in den Befehlssatz sollte das offensichtlich sein.

    Statt SMON habe ich allerdings damals schon den Action-Replay-Monitor verwendet. Der macht im Prinzip das gleiche, aber ohne den C64-Speicher zu belegen. Und Freezepoints sind zudem auch beim Debuggen sehr nützlich.

    Mit Macro-Assembler auf C64-Seite habe ich mich auch nicht aufgehalten. Damit habe ich erst angefangen, als der PC meine Rechnersammlung ergänzt hatte.