Konstanten, Variablen, Lables & Symbole, was für ein Durcheinander! :-O

  • Konstanten, Variablen, Lables & Symbole, was für ein Durcheinander! :-O

    Hallo allerseits

    Ich beschäftige mich jetzt ein wenig mit Assmbler auf dem C64 und schaue
    mir das eine oder andere Tutorial und den einen oder anderen Source Code an.

    Jetzt ist mir etwas aufgefallen, dass mir ein wenig Bauchweh macht:
    Kann mir bitte jemand erklären, was genau in ACME oder generell in
    Assemlber für den C64 (nicht unbedingt in Assembler für andere Systeme)
    eine Variabel, was eine Konstante und was ein Symbol und was ein Label ist???

    Ich dachte eine Konstante sei ein fester Wert, der immer gross geschrieben
    wird. Zum Beispiel "SCREENSIZE". Der wird dann auch nie geändert.
    Wenn ich mir jetzt aber den Source von C64 Assmbler Spielen angucke, dann
    wimmelt es von "Konstanten", die werden aber andauernd fleissig abgeändert
    und neue Werte zugeordnet.
    Also sind das Variablen die einfach gross geschrieben werden? :S ?(

    Oder sind Variablen solche Speicherbereiche, die ich mir SELBST
    anlege, zum Beispiel in der Zeropage:
    meineVariabel = $00
    meineVariabel = #0

    Und Konstanten solche, die der Assmbler für mich irgendwo im
    Speicher anlegt:
    meineKONSTANTE = !byte 00

    Und was genau sind Symbole und Labels? Wo ist der Unterschied zu Variablen
    und Konstanten?

    Sorry, ich bin da ein wenig pingelig und finde es sehr verwirrend, wenn die
    Begriffe allzu frei miteinander ausgetauscht werden (falls es sich dabei um
    unterschideliche Dinge handelt). Könnte da jemand ein wenig Ordnung ins
    Chaos bringen oder weiss jemand einen guten Text der das erklärt?
    Die ACME Dokumentation ist nicht schlecht, aber ich fürchte dafür nicht
    ausreichend und wohl auch nicht dafür gedacht.

    Liebe Grüsse,
    Markie
  • Aus Blitz BASIC, PAWN, Turbo Pascal, PHP, DIV und C# weiss ich, daß man Konstanten nie ändern kann. Man setzt sie einmal und das wars.
    Variablen sind, wie der Name es verrät, variabel also dynamisch einsetzbar (man kann ihre Inhalte verändern).
    Labels sind nichts weiter als Sprungadresse, zu denen man hinspringen kann, wenn man dies möchte. Sie ersetzen sozusagen die Zeilennummern (z.B. GOTO 100 in BASIC).
    Bei Symbolen kann ich dir leider nicht weiterhelfen. Denke aber mal, daß sie im Prinzip das gleiche wie Variablen sind, nur daß sie Symbole beinhalten können (Strings in BASIC).

    Korrigiert mich bitte, wenn ich falsch liege.
  • SCREENSIZE=4

    Dann wird überall SCREENSIZE durch 4 ersetzt.

    Oft sieht man:

    spieleranzahl: .byte $44

    massenmord:
    lda #0
    sta spieleranzahl
    rts

    jesuseffekt:
    lda spieleranzahl
    clc
    adc #1
    sta spieleranzahl
    rts

    spieleranzahl ist nur eine Speicherstelle die auf das Byte zeigt

    jesuseffekt zeigt auch auf eine Speicherstelle zu der man zum ersten befehl kommt, damit man mit jsr jesuseffekt dorthin springen kann.
    Wer den C64 nicht ehrt ist des x64ers nicht wert.
  • Wird sicher schwierig, allgemeingültige Definitionen zu finden, an denen niemand was auszusetzen hat. :D
    Ok, fangen wir mit dem Zeug an, wo es wohl am wenigsten Widerspruch gibt:
    -Eine Variable zeichnet sich dadurch aus, dass sie variabel ist, also geändert werden kann.
    -Eine Konstante ist hingegen konstant.
    So weit, so gut.

    Bei Konstanten kann man unterscheiden zwischen Literalen (bei LDA #3 ist 3 ein Literal) und symbolischen Konstanten (wie z.B. in LDA #petscii_CLEAR, wobei petscii_CLEAR irgendwann vorher auf den Wert 147 gesetzt wurde). Aus der Bezeichnung "symbolische Konstante" kann man schon ableiten, dass Literale eben keine Symbole sind.

    Symbol kann man als Überbegriff von Variablen und symbolischen Konstanten ansehen: damit ist also gemeint, dass man einen Wert über einen Namen anspricht. Ob der Wert konstant oder variabel ist, ist an dieser Stelle egal, in beiden Fällen handelt es sich bei dem Namen um ein Symbol.

    Label ist die Bezeichnung für ein Symbol, dem automatisch vom Assembler die aktuelle Speicheradresse zugewiesen wird, d.h. die Anfangsadresse einer Datentabelle oder der Einsprungpunkt in eine Maschinenroutine. Vermutlich werden aber eine Menge Leute nicht zwischen "Labels" und "Symbolen" unterscheiden und stattdessen beide Begriffe synonym verwenden. Tatsächlich haben die Docs und die Sourcen von früheren ACME-Versionen nur den Begriff "Label" benutzt, die Aufteilung in Labels und Symbole habe ich erst später vorgenommen.

    Einige Programmiersprachen unterscheiden explizit zwischen Variablen und symbolischen Konstanten (z.B. C und dessen Präprozessor), andere implementieren die symbolischen Konstanten über Variablen (z.B. ACME - wer so eine "konstante Variable" nachträglich ändert, hat halt selber Schuld).
    Und selbst wenn Variablen und symbolische Konstanten komplett voneinander getrennt sind, kann es vorkommen, dass symbolische Konstanten nachträglich geändert werden können. Das ist z.B. der Fall in C und dessen Präprozessor, auch wenn sowas natürlich nur in absoluten Ausnahmefällen gemacht wird.
    Das GROSSSCHREIBEN von symbolischen Konstanten ist einfach nur eine beliebte Konvention.

    In ACME ist es so, dass unter der Haube sämtliche Symbole Variablen sind, also änderbar. In der Praxis sind aber bei einem normalen Assemblerlauf so gut wie alle Symbole konstant. "Echte", d.h. änderbare Variablen braucht man eigentlich nur für Schleifenzähler. Wohlgemerkt, dies gilt für den Assemblerlauf! Was das assemblierte 6502-Programm zu seiner Laufzeit für Variablen benutzt, ist eine völlig andere Baustelle.

    Beispiel:

    Quellcode

    1. beep lda voice
    2. sta soundchip_voice
    3. lda #SOUND_BEEP
    4. sta soundchip_action
    5. rts
    6. voice !by 0 ; Variable für das Programm, nicht für den Assembler!

    "beep" ist ein Symbol, und zwar ein Label.
    "voice" ist ein Symbol, und auch ein Label (für den Assembler). Für das 6502-Programm bezeichnet es eine Byte-Variable.
    "soundchip_voice", "soundchip_action" und "SOUND_BEEP" sind Symbole. Aber keine Labels, sondern symbolische Konstanten. Sie würden in einer Art Header-Datei für die verwendete Hardware explizite Werte zugewiesen bekommen; die anderen Symbole (also die Labels) werden automatisch vom Assembler zugewiesen.
    "0" ist ein Literal und somit eine Konstante.
    Yes, I'm the guy responsible for the ACME cross assembler

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Mac Bacon ()

  • Noch ein Nachtrag (hab's zumindest noch nicht gelesen):

    Die Konstanten können i. d. R. sowohl als Adresse als auch Werte benutzt werden. Beispiel:

    Quellcode

    1. testbyte=2
    2. lda #testbyte
    3. sta testbyte
    4. ->
    5. lda #$02
    6. sta $02
    Read'n'Blast my jump'n'stop-text-sprite-scroller Select A Move

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

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Hexworx ()

  • Hier mal ein paar Beispiele:

    BorderColor = $d020
    Unabrückbar ist die Rahmenfarbe durch die Speichestelle $d020 bestimmt. Immer die gleiche Adresse, aber variabler Inhalt. Im Code schreibe ich sta BorderColor.


    PlayerNumberofLives = $02
    Enthält die (aktuelle) Anzahl der Leben des Spielers. Und zwar in der von mir ausgesuchten Speicherstelle $02. Dies ist quasi eine Variable. Im Code werde ich sie öfter auslesen (lda PlayerNumberofLives). Auch kann ich mir aussuchen *wo*, d.h. in welcher SPeicherstelle der Wert abgespeichert wird. Könnte ich später auf Speicherstelle $fe verschieben, ohne im ganzen Code alles entsprechend ändern zu müssen.


    CONST_NumberofLivesAtStart = 3
    Dies ist eine von mir gewählte Konstante (literal). Im Code nutze ich sie (statt des Wertes 3). So kann ich später leicht den Wert noch anpassen, ohne im Code nach jeder Nutzung des Wertes suchen zu müssen. Dieser Wert ist *nicht* in Speicherstelle 3 gespeichert - deshalb habe ich dick "CONST" (für Konstante) davorgeschrieben. Das muss mich daran erinnern, sie stets mit einer # davor zu nutzen. Es geht mir ja um den festen Wert, nicht um einen evtl. flexiblen Speicherinhalt. Deshalb: lda #CONST_NumberofLivesAtStart !!
    Ein lda CONST_NumberofLivesAtStart würde mir nicht den gewünschten Wert 3, sondern den Inhalt von Speicherstelle 3 in den Accu laden!! Ein Klassiker unter den Fehlern :)


    CONST_Char_Leerzeichen = $20
    Auch eine Konstante. Sie enthält genau den Wert eines Zeichens aus dem Zeichensatz. Im Code schreibe ich lda #CONST_Char_Leerzeichen. Sollte ich später lieber ein anderes Zeichen verwenden wollen oder mein Zeichen befindet sich in einem fremden Zeichensatz an anderer Stelle, so brauche ich nur den Wert der Konstanten ändern.


    Label_MainMenu
    Ein Label ist quasi wie eine komfortablere Basic-Zeilennummer. Um z.B. ins Hauptmenü zu springen schreibe ich nicht jmp $1000 (falls das Menu dort beginnt), sondern jmp Label_MainMenu. Sehr übersichtlich und zudem praktisch, da beim Einfügen oder Löschen von Zeilen schnell mal der Anfang "verrutscht". Ein Label entspricht am Ende also nur einer bestimmen Speicherstelle.


    NumberofLives
    !Byte 0
    Dies ist eigentlich auch ein Label, aber es zeigt nicht auf einen bestimmten Teil einer Prozedur, sondern auf einen Wert. Es wird als Variable genutzt, denn der Wert, auf den das Label zeigt enthält die aktuelle Anzahl Leben. Anders als im Variable-Beispiel oben habe ich die exakte Speicherstelle aber nicht im Vorwege festgelegt, sondern sie ist irgendwo im Code (nämlich genau bei dem Label) und rutscht somit beim Coden schon mal im Speicher auf und ab. Ist mir aber egal, da ich den Wert ja nie per exakter Speicherstellen-Kenntnis lesen werde (sprich: lda $2e45, falls der Wert gerade dort zu finden ist), sonder stets per lda NumberofLives.



    Edit:Shice, ich tippe zu langsam... ;)
    "...please come again - when I´m not working!"
  • Ganz ehrlich, für mich macht das Gespräch über Variablen dann besonders Sinn, wenn ich mit einem Interpreter oder Compiler arbeite, für einen Compiler ist das natürlich Gold wert, zu wissen, was ich als Konstante und was als Variable nutzen möchte. Ein Assembler ist meiner Erfahrung nach einem Präprozesser ähnlicher als einem Compiler. Was kann ein Assembler schon mit dem Wissen anfangen, dass etwas eine Konstante ist (außer Meckern). Habe ich bisher nicht als seine Aufgabe gesehen. Und wenn ich mal wieder richtig zur Sau gemacht werden will, nehme ich mir eine Hochsprache und einen Compiler und stelle ihn auf höchste Stufe (man will ja was haben für's Geld).
  • Oah!! Wow!
    Vielen herzlichen Dank für all die super tollen Ausführungen und Erklärungen!!

    Super nett von Euch! :ilikeit: :thumbup:

    Ich glaub jetzt habe ich ein wenig gemerkt wo ich etwas nicht verstehe:
    Nämlich bei der Deklaration (Definition gibt's bei Assembler wohl nicht?)
    und Initialisierung von... Variablen und Symbolischen Konstanten!
    Entweder hab ich das vergessen oder nie richtig gelernt... :/

    Squidward hat ein paar Beispiele gemacht:

    - PlayerNumberofLives = $02
    - CONST_NumberofLivesAtStart = 3
    - CONST_Char_Leerzeichen = $20


    Sind das die Deklarationen die man genau so in ACME eingibt?

    Falls ja, und so sieht es aus, in anderen Source Code sehe ich
    ähnliches, habe ich ein echtes Problem, denn:

    PlayerNumberofLives und CONST_NumberofLivesAtStart unterscheiden
    sich in der Deklaration ausschlisslich dadurch, dass PlayerNumberofLives
    einen hexadezimalen Wert zugewiesen bekommt ($02) und
    CONST_NumberofLivesAtStart einen dezimalen (3).
    Im ersten Fall ist es doch so, dass der Wert der in der Variable
    PlayerNumberofLives später einmal gespeichert wird, EXAKT
    im Speicher in der Speicherstelle $02, also dezimal auch 02 gespeichert
    wird. Nicht wahr? Also egal wieviele Leben der Spieler hat, das steht
    an der Speicherstelle 02 oder $02.
    Bei CONST_NumberofLivesAtStart soll es jetzt plötzlich anders sein?
    Der Wert (3) bezeichnet nicht die Speicherstelle, sondern wofür
    CONST_NumberofLivesAtStart steht. Niemand weiss also, wo genau
    der Wert 3, bzw. der Inhalt von CONST_NumberofLivesAtStart
    gespeichert wird, nicht?
    Mein Problem ist jetzt, ich dachte ob man eine Zahl als hexadezimal
    schreibt, $02 oder dezimal, 2, ist völlig egal!!
    Wenn das aber so wäre, dann könnte ich doch auch schreiben:
    PlayerNumberofLives = 2
    CONST_NumberofLivesAtStart = $03
    Und das müsste dann ja auch gehen... Oder?
    Aber dann wäre ja das eine plötzlich eine symbolische Konstante
    (PlayerNumberofLives) und das andere eine Variable, nicht?
    Und das NUR weil ich einmal eine Zahl als Hex schreibe ($02)
    und einmal als Dezimal (2)?
    Stimmt das?

    Oder wie behandelt ACME das?
    Werden Zuweisungen mit Hexzahlen automatisch als Speicherstellen
    interpretiert und solche mit Dezimalzahlen IMMER als Werte / Inhalte
    mit unbekannten Speicherstellen?
    Falls ja, wie sieht es dann mit dem Beispiel mit dem Leerzeichen aus:
    - CONST_Char_Leerzeichen = $20
    Das müsste doch dann auf die Speicherstelle $20 (=32) zeigen, bzw.
    CONST_Char_Leerzeichen wäre eine Variable, die da ($20) abgespeichert
    wird. Und der Inhalt wäre dann eben nicht (!) $20 (PETSCII code für
    Space) sondern ohne Initialisierung irgend etwas undefiniertes
    das zufällig an Speicherstelle $20 (32) steht...?

    Ich glaube mir ist die Syntax nicht klar, wie genau mit dem ACME
    eine symbolische Konstante deklariert (definiert) wird / werden kann,
    also wann etwas NICHT auf eine Speicherstelle zeigt / zeigen kann
    (all möglichen Syntaxen dafür bitte!) und wann etwas auf
    eine Speicherstelle zeigt?
    Mir ist nicht klar, wie ACME unterscheiden kann, wann ich einer Zahl
    einen Namen geben will, eben eine symbolische Konstante will, und
    wann ich einer Speicherstelle einen Namen geben will?
    Worauf achtet ACME da ganz genau? Wie wird das unterschieden?
    Liegt es nur am $ Zeichen oder wie?

    Könnte mir das bitte mal jemand in allen möglichen Syntax formen
    zeigen und erklären was der Unterschied ist?
    Ist es nur das "$"???
    Ist es wie ich hier vermutet habe, dass eine Hexzahl immer einen
    Speicher meint und eine Dezimalzahl eben keinen Speicher,
    sondern einen Wert der an unbekannter Stelle gespeichert
    wird? - Und folglich dass das Beispiel mit CONST_Char_Leerzeichen = $20
    sehr schlecht, bzw. falsch ist, da eben nicht $20 = Leerzeichen drin
    steht, sondern etwas unbekanntes *AN* der Speicherstelle $20?

    Tut mir leid wenn ich immernoch ein Durcheinander habe.
    Aber ich glaube wir kommen der Sache näher...

    :schande:
  • Ich glaub du denkst da viel zu kompliziert. Dem Ottonormalassembler teilst du mit nem Label/Symbol/Whatever einfach irgendeiner Buchstabenfolge irgendeinen Zahlenwert zu, damit du dir die Ziffernfolge nicht merken muss (man kann sich Worte wie "Pferd", "Dodecahedron" etc. einfach besser merken als 57389 oder ähnliches, daher ist das eine Arbeitserleichterung).

    Hexadezimal., dezimal, binär oder oktal (ok, letzteres vielleicht auch eher nicht) rechnet der Assembler ebenfalls für einen um, wieder Arbeit gespart.

    Ob ein Label nun ein Opcodeparameter, eine Adresse innerhalb des Codes, ne Variable oder was sonst auch immer ist hängt ausschliesslich davon ab, wie du es verwendest. Mehrfachnutzung in unterschiedlichen Funktionen ist möglich und auch nicht unbedingt selten :)
    "<Lieblingskalenderspruch bitte hier vorstellen>"
  • Quellcode

    1. EINEADRESSE = $1234
    2. EINECONST = $ff
    3. ICHBINEINLABEL lda $1f2f ;Das Label ist nur eine Sprungmarke. Dann wird aus Speicherzelle
    4. ;$1f2f geladen.
    5. sta EINEADRESSE ;und es wird in EINEADRESSE, also nach $1234, gespeichert.
    6. ;(Dezimal:4660)
    7. lda #EINECONST ;Hier wird der Wert von EINECONST geladen (also $ff, 255)
    8. sta $02 ;und nach Speicherzelle $02 gespeichert. Zeropage braucht nur 2 Stellen ;)
    9. lda EINECONST ;ALARM: bei dieser Schreibweise interpretiert der Compiler es so dass aus
    10. ;Speicherzelle $FF (also 255) ein Wert eingelesen werden soll.
    11. sta $124f ;und der wird dann nach $124f gespeichert.
    Alles anzeigen
    Nicht die Art der Definition legt also fest, was der Compiler draus macht, sondern die Art des Aufrufes.
    GREETINGS PROFESSOR FALKEN
    A STRANGE GAME.
    THE ONLY WINNING MOVE IS NOT TO PLAY.
    HOW ABOUT A NICE GAME OF CHESS?
  • Markie schrieb:

    Könnte mir das bitte mal jemand in allen möglichen Syntax formen
    zeigen und erklären was der Unterschied ist?
    Ist es nur das "$"???
    test_a = $20 ; das ist eine Adresse oder ein Bytewert, je nachdem, wie Du es verwendest
    test_a = 32 ; exakt das Gleiche in dezimaler Schreibweise
    test_a = %00100000 ; exakt das Gleiche in binärer Schreibweise

    data_a = #$20 ist ein Daten-Bytewert - KEINE Adresse !

    und das ist die Krux, bei der man aufpassen muß, da hier oft Flüchttigkeitsfehler entstehen ...:

    LDA test_a ; läd den Inhalt von ZP-Adresse $20 in den Akku
    LDA #test_a ; läd den Wert #$20 in den Akku


    [vorsicht Halbwissen] afaik hatte Mac Bacon bei ACME mal genau bei dieser Verwechselungsgefahr einen Workarount geschaffen, der Warnungen ausgibt [/vorsicht Halbwissen]

    LDA data_a ; läd den Wert #$20 in den Akku

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von GI-Joe ()

  • @Markie:

    Wie 'Claude' schon schreib: Denk nicht zu kompliziert: Name = Zahl. Ob daraus nun eine Speicheradresse oder ein Wert wird, steht doch in deiner Macht. Vielleicht bin ích auch 'frühzeitlich versaut', aber sehe jedenfalls überhaupt kein Problem, aus dem man einen Roman machen müsste :nixwiss: .
    Read'n'Blast my jump'n'stop-text-sprite-scroller Select A Move

    Ex-TLI (The Level 99 Industries) & Ex-TNP (The New Patriots) & Ex-TEA (The East Agents) & ?
  • Claude Server schrieb:

    Ich glaub du denkst da viel zu kompliziert.
    This. :D

    GI-Joe schrieb:

    test_a = $20 ; das ist eine Adresse oder ein Bytewert, je nachdem, wie Du es verwendest
    [...]
    und das ist die Krux, bei der man aufpassen muß, da hier oft Flüchttigkeitsfehler entstehen ...:

    LDA test_a ; läd den Inhalt von ZP-Adresse $20 in den Akku
    LDA #test_a ; läd den Wert #$20 in den Akku


    [vorsicht Halbwissen] afaik hatte Mac Bacon bei ACME mal genau bei dieser Verwechselungsgefahr einen Workarount geschaffen, der Warnungen ausgibt [/vorsicht Halbwissen]
    Ja, siehe hier. Ich assembliere nicht mehr ohne dieses Feature (Au weia, es ist jetzt schon seit über zwei Jahren in ACME enthalten, und ich hab immer noch keine offiziellen Docs dafür geschrieben).
    Im dortigen Thread habe ich bei der Erklärung auch die Ausnahmen erwähnt; es gibt eben doch ein paar seltene Fälle, in denen man eine Adresse als Wert oder einen Wert als Adresse benutzen will - genau dies dürfte auch der Grund sein, warum Assembler traditionellerweise eben keinen solchen Unterschied machen: Man findet immer einen Fall, wo eine entsprechende Restriktion den Programmierer einfach nur behindert.
    Yes, I'm the guy responsible for the ACME cross assembler
  • Knopf gelöst [SOLVED - vorerst mal... ;-)]

    Nochmal: Vielen Dank für die Hilfe!! :)

    Ich möchte mich speziell auch bei Mac Bacon bedanken!
    Er hat sich wirklich extrem Mühe gegeben, ein wirklich gute Übersicht über
    Variablen, Konstanten, Symbole und Labels zu geben. Und die ist auch sehr
    verständlich und hat vielleicht gar nicht soviel mit meinem Problem zu tun.
    Vielen Dank! :) :D :thumbsup: :thumbsup: :ilikeit:

    Ok, jetzt nochmal kurz zur Sache:
    Andere haben es auch schon angesprochen, BladeRunner und Gi-Joe jetzt
    explizit: Das Problem mit dem #-Zeichen vor einer Variablen oder einer
    Konstanten, sprich, WIE auf ein Wert zugegriffen wird.
    Vielen Dank!!
    Ich glaub da war ein grösseres Problem von mir. Und das dürfte anderen
    Anfängern auch so gehen. Nämlich:

    Wenn ich mir den Source Code von anderen ansehe, dann steht da
    zum Beispiel drin:

    VICBASE = $D000
    BORDERCOLOR = $D020
    NUMBEROFLIVES = 3
    STEP = 2
    ROOMSIZE = 16
    TILEWIDTH = 4 * 8

    Es scheint mir offensichtlich, dass VICBASE und BORDERCOLOR nur
    über die Adresse benutzt wird, sprich man das nutzt, um die
    Werte in den entsprechenden Adressen im VIC zu ändern.

    Ganz anders ist es aber mit NUMBEROFLIVES, STEP, ROOMSIZE
    und TILEWIDTH!
    Hier will man wohl kaum die Inhalte der Speicherstellen haben, sondern
    eben die KONSTANTEN Zahlen 3, 2, 16 und 32 (4 * 8)!

    Was ich jetzt nicht verstehe:
    Wenn ich richtig verstanden habe, dann ist der Unterschied nur in der
    Benutzung:
    sta VICBASE ; <-- Schreibt Acc. nach adresse VICBASE = $D020
    lda #STEP ; <-- Lädt die Nummer 2 in den Acc.


    Meine Frage jetzt:
    Wenn man so die Konstanten (oder Variablen - hängt ja nur vom User
    ab, bzw. ob er die "KONSTANTEN" nachträglich ändert) deklariert,
    dann müsste es doch so sein, dass:
    NUMBEROFLIVES an der Speicherstelle 3 eingerichtet wird (und STEP
    an Speicherstelle 2) und grundsätzlich ein Byte gross ist (bzw. eigentlich
    ein Pointer auf die Speicherstelle 3 ist). Nicht wahr?

    Aha! Moment! Jetzt hab ich glaub was wichtiges begriffen:
    Ich dachte, wenn man deklariert:
    NUMBEROFLIVES = 3
    dass dann an der Speicherstelle 3 eine Variabel eingerichtet wird.
    Das wäre ja katastrophal, weil dann der Speicher dort vielleicht
    überschrieben würde! ...! =O
    Und das ist ja nicht gemeint,. bzw. gewollt mit "3"!

    Ich meine es gibt ja Programmcode der sieht etwa so aus:
    TEMPVAR_1 = $32
    TEMPVAR_2 = $33
    TEMPVAR_3 = $34

    MAX_ANZAHL_LEVELS = 50

    Wenn MAX_ANZAHL_LEVELS jetzt fest "eingerichtet" würde,
    dann würde es an der Speicherstelle 50 = $32 eingerichtet.
    Genau da ist aber die TEMPVAR_1 schon!
    - Ich nehme an $32 - $34 sind benutzte Speicherstellen in
    der Zeropage?
    Die eine Variable (50) würde also die andere ($32 = 50) überschreiben...

    In WIRKLICHKEIT ist "NUMBEROFLIVES" und eigentlich ALLE
    Variablen, Konstenten und Symbole nur ein "Pointer", der wird
    suksessive im Programmcode angelegt, bzw. evtl. in einem
    Datenbereich, ist ein oder zwei Byte gross und der ZEIGT auf
    Speicherstellen. Bei "NUMBEROFLIVES" auf die Speicherstelle 3.
    DESWEGEN hat es dann katastrophale Folgen wenn man schreibt:
    lda NUMBEROFLIVES
    Dann wird nämlich standartmässig der Pointer dereferenziert, sprich
    der Inhalt der Speicherstelle geladen, anstatt die Speichernummer (3).

    Also genau das Problem mit dem #!

    Oh Mann! Ich glaub das ist wirklich enorm wichtig und jetzt hab ich
    was sehr, seeehr wichtiges (wieder) begriffen!!

    Vielen herzlichen Dank an alle!!!

    :thumbsup: :thumbup: :thumbsup: :D

    Ok, dazu muss ich jetzt noch ein wenig experimentieren.
    Falls ich noch eine Unklarheit hab werd ich ungeniert hier
    oder an anderen Speicherstellen wieder fragen... ;) :D ^^

    Postmortem: Ok, das ist zwar tricky.
    Aber das geile daran ist, wenn man es begriffen hat, welch
    unglaubliche MACHT man damit (Assembler und das ganze)
    über den Rechner und den Speicher hat... Fast schon unheimlich
    diese Macht, nicht? ...May the Force be with You! ;) :D


    LG,
    Markie


    EDIT: Hmmm...
    EINE kleine Frage hab ich noch:

    Wenn ich angebe:
    myVariable = !byte $20, $ff

    Dann ist myVariable ein Symbol / Label / Variable mit dem Inhalt
    $20 und $ff, nicht wahr? Bzw. ein "Pointer" der auf eine Speicherstelle
    zeigt mit $20 als Inhalt und der nächsten Speicherstelle mit $ff.
    Die Frage: Wo genau im Speicher wird $20 und $ff abgelegt?
    Ich weiss dass ich mit myVariable darauf zugreiffen kann und
    dass mich als User / Programmierer nicht interessieren muss wo
    das ist.
    Aber ich möchte wissen wie der Assembler funktioniert, bzw.
    wie das UNTER der Haube genau aussieht... :search:
    Das ist jetzt wahrscheinlich eine Frage für Mac Bacon...?

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von Markie ()

  • Markie schrieb:

    Wenn MAX_ANZAHL_LEVELS jetzt fest "eingerichtet" würde,
    dann würde es an der Speicherstelle 50 = $32 eingerichtet.
    Nein. Speicheradressen existieren auf der Ebene der Maschinensprache. Labels, Konstanten und Variablen sidn aber Dinge aus der Welt des Assemblers, also des Übersetzungsprogrammes. Der ordnet dem Namen (Symbol) einen Zahlenwert zu und setzt diesen in den erzeugten Maschienncode ein, wenn es so im Sourcecode steht.

    Ob der Maschiennbefehl diesen Wert nun als unmitteklbaren Wert (immediate) verwendet oder als Speicheradresse, oder gar noch ein Indexregister draudfaddiert- das legt der Adressierungsmodus fest. Beispiel sind das Doppelkreuz '#wert' für einen unmittelbaren Wert, keine weiteren Zeichen für den Inhalt der jeweiligen Speicheradresse, oder auch komplexere Dinge wie (wert,Y).

    Und manche Assembler können symbolische Werte auch für interme Berechnungen während der Übersetzung verwenden, z.B. wenn man eine Sequenz mehrmals hintereinander erzeugen will- dabei taucht der Wert des Symboles im erzeugten Maschinencode gar nicht auf.
  • Grundsätzlich gilt zunächst, daß Assembler nicht nur eine typenlose Programmiersprache ist (es gibt keine feste Zuweisung von char, int, pointer usw), sondern auch eine nahezu deklarationslose. Die Unterscheidung, ob ein Symbol eine Konstante ist oder eine Variable oder sonst etwas, existiert nur in Deinem Kopf. Herkömmliche Assembler unterscheiden zunächst überhaupt nicht zwischen Konstanten oder Labels oder Variablen. Es gibt lediglich ein Symbol, das über einen Zahlwert verfügt, wobei der Wertebereich des Zahlwertes abhängig vom Assembler ist. Wie dieses Symbol verwendet wird, also welche Bedeutung es in einem Programm hat, ergibt sich erst jeweils durch den konkreten Assemblerbefehl aufgrund der Adressierungsart:

    Quellcode

    1. foo: equ $12
    2. lda foo ; foo wird als Adresse verwendet
    3. lda #foo ; foo wird als Konstante verwendet
    4. lda (foo),y ; foo ist ein Zeiger auf der Zeropage

    Bei Assemblern, die ein Listing ausgeben, findet man häufig am Ende eine Auflistung aller verwendeten Symbole, z. B.

    Quellcode

    1. [ 89] 'graphik.farbe_weiss' = $c0 / 192
    2. ...
    3. [ 110] 'graphik.zeichensatz' = $700 / 1792
    Obwohl das Symbol "graphik.farbe_weiss" im Programm als Konstante verwendet wird, ist es für den Assembler das gleiche wie die Adresse "graphik.zeichensatz". Sofern der Assembler nicht ausdrücklich über Spezialbefehle verfügt, mit denen man einem Symbol zusätzlich bestimmte Eigenschaften zuweisen kann, sind alle diese Symbole absolut gleichwertig.

    Warum macht man das?
    1.) Es ist einfach. Für den Assembler als auch für den Programmierer. Man muß sich nicht um eine explizite Deklaration von Symbolen kümmern wie in Hochsprachen. Man kann für sich selbst Konventionen einführen, daß man a) Konstanten alle groß schreibt oder b) bei den Namen von Konstanten ein "const" davorsetzt, muß es aber nicht.
    2.) In einem Assemblerprogramm ist durchaus nicht immer klar, ob ein Symbol eine Adresse oder ein Label oder eine Konstante ist. Folgende Beispiele:

    Mit EQU lassen sich Labels definieren:

    Quellcode

    1. foo: equ $ff9f ; foo ist die Adresse einer Romroutine
    2. jsr foo ; Rufe eine Routine im Rom bei Adresse $ff9f auf
    Labels können als Konstante verwendet werden:

    Quellcode

    1. Hier ist foo ein Label, an dessen Stelle im Programm ein String abgelegt ist.
    2. ldy #foo & $ff ; Lade die Adresse von foo als Konstante
    3. lda #foo >> 8
    4. jmp string_ausgeben
    5. ...
    6. foo: byte 'Hier steht ein String', 0
    Mit EQU lassen sich Variablen definieren:

    Quellcode

    1. foo: equ $cfe0
    2. lda #foo & $ff
    3. sta $2
    4. lda #foo >> 8
    5. sta $3
    6. Jetzt enthält $2/$3 einen Zeiger auf die Variable.
    Labels als konstanter Bytewert in einem Array:

    Quellcode

    1. string_0: byte 'Hier steht der erste String', 0
    2. string_1: byte 'Hier steht der zweite String', 0
    3. addr_low: byte string_0 & $ff ; Hier steht der untere Teil des 16-Bit-Zeigers auf den String
    4. byte string_1 & $ff
    5. ...
    6. addr_high:
    7. byte string_0 >> 8 ; Hier steht der obere Teil des 16-Bit-Zeigers auf den String
    8. byte string_1 >> 8
    9. stringindex_ausgeben:
    10. ; X enthält den Index auf einen String
    11. ldy addr_low, x
    12. lda addr_high, x
    13. jmp string_ausgeben
    14. ...
    15. ldx #<irgendeine Stringnummer>
    16. jsr stringindex_ausgeben
    Alles anzeigen
    Labels und Konstante zur Erzeugung einer Adresse:

    Quellcode

    1. byteliste:
    2. byte $11
    3. byte $22
    4. ...
    5. offset: equ $3f
    6. lda byteliste + offset
    7. In A steht der Wert aus der Speicherzelle byteliste+offset

    Also nochmal:
    Symbole im Assemblertext sind zunächst nichts weiteres als Bezeichner, denen ein ganz bestimmter Zahlenwert zugewiesen wird. Das kann entweder explizit im Programmcode angegeben werden, z. B. durch

    Quellcode

    1. foo: equ <wert>
    oder implizit durch den Assembler, der Labels im Programm automatisch die aktuelle Programmadresse zuweist:

    Quellcode

    1. ldx #7
    2. loop: dex ; "loop" erhält automatisch den Wert der Adresse, an der der Befehl "dex" im Speicher steht.
    3. bne loop
    Wie das Symbol nachher verwendet wird, liegt völlig in den Händen des Programmierers.
  • Hallo!!

    Wow! Super!
    Vielen Dank!
    Das muss ich aber erst eine Weile verdauen...!
    Nur kurz: Was genau ist "equ"?
    Im Befehlssatz des C64, bzw. des 6502 CPUs scheint
    es nicht zu sein. Auch in der ACME Dokumentation scheint
    es nicht drin zu sein. Ist das also ein Befehl für andere
    Assembler? Ich frage nur weil ich das nicht kenne.
    Du schreibst auch "foo: " und "loop: ".
    In ACME (den ich grad verwende) braucht es glaub keinen
    Doppelpunkt.
    Darf ich fragen für welchen Assembler und welche Platform
    diese Syntax ist?