Speicheradressierung 8051
-
Hallo zusammen.
Ich habe eine Frage zur Speicheradressierung vom 8051.Der Stackpointer hat nach RESET den Wert 0x07
MOV A, #0x12 //Inhalt 0x12 in A
MOV B, #0x34 //Inhalt 0x34 in B
MOV SP, #0x56 //Inhalt 0x56 in SP
PUSH ACC //legt ACC im Stack ab
PUSH B //legt B im Stack ab
POP ACC //liest ACC vom Stack zurück
POP B //liest B vom Stack zurück
CALL Ende
Ende: JMP $Inhalte?
Akku: _____0x34______ B: ______0x12________ SP: _____0x58________
0x56: ______00________ 0x57: _______12_____
0x58: ______00________ 0x59: _______00_______Verstehe die Zuordnung nicht? Hat jemand eine gute Erklärung oder ein PDF zur erklärung?
Gruss Andreas
-
Ich gehe davon aus, dass es sich um eine Hausaufgabe handelt. Du solltest deshalb alle benötigten Hilfsmittel eigentlich schon haben. Du brauchst zumindest eine Referenz der 8051-Befehle. Zu dem von dir benutzten Assembler (welchen?) brauchst du noch eine Assembler-Referenz. Zumindest musst du herauskriegen können, zu welchem 8051-Befehl die Assembler-Instruktion CALL und JMP umgesetzt werden. Ich habe mal ACALL und AJMP angenommen.
Mit einem Debugger gehts einfach, manuell ist es ein bisschen schwieriger: Du musst die Speicheradressen des fertigen Programms herausfinden. Angenommen, das Programm beginnt bei Addresse 0, so sähe das Ganze so aus:
//Adr was wohin danach 0000 MOV A, #0x12 // 0x12 nach A | A = 12 0002 MOV B, #0x34 // 0x34 nach B | B = 34 0005 MOV SP, #0x56 // 0x56 nach SP | SP = 56 0008 PUSH ACC // ACC nach Stack | SP = 57, 0x57 = ACC (0x12) 000A PUSH B // B nach Stack | SP = 58, 0x58 = B (0x34) 000C POP ACC // Stack nach ACC | SP = 57, ACC = 34 (ehemaliges B) 000E POP B // Stack nach B | SP = 56, B = 12 (ehemaliges ACC) 0010 ACALL Ende | SP = 58, 0x57 = PCL (0x12), 0x58 = PCH (0x00) 0012 Ende: AJMP $
(Da ja alles hexadezimal ist, habe ich ab und zu das "0x" weggelassen)
Der Scherz bei der Sache ist, dass der Stackpointer (SP) nach zwei PUSH und zwei POP wieder am Anfang ist. Durch das CALL werden die vorigen Werte überschrieben, und zwar mit der Adresse des Befehls, der nach dem CALL kommt. Dorthin würde ein RET hinspringen. Diese Adresse ist 0x12. 0x12 ist also nicht nur der Ausgangswert von A (bzw. ACC), sondern auch die Adresse von 'Ende:...'.
Vor dem CALL steht SP auf 56. Das CALL inkrementiert SP um 1 (-> 57) und schreibt den niederwertigen Anteil der Rückkehradresse (0x12) auf den Stack, danach wird SP noch einmal inkrementiert (-> 58) und der höherwertige Anteil (0x00, weil sich das Programm ganz weit vorne befindet) auf den Stack. Diese Vorgehensweise wird in jeder Referenz beschrieben.
A (auch Akku oder ACC genannt) und B wurden quasi ausgetauscht, weil sich PUSH-POP in LIFO-Manier verhalten. Der zuletzt gepushte Wert wird zuerst gepopt. Ein PUSH B - POP ACC bedeutet also, dass ACC jetzt den Wert von B hat. Das nächste POP holt sich den Wert, der davor gepusht worden ist.
viele grüße
ralph
-
Als Assembler dient Keil A51. Den "rechten" Teil habe ich soweit verstanden.
Zu den Adressen:
Nach dem Befehl MOV SP, #0x56 springt die Adresse zu 0008 da es die nächste Adresse ist nach dem Anfangswert 0x07 vom Stackpointer?Oder ist es so das der Befehl:
MOV: 1 opcode byte und 2 mal 2-byte Adressen, eine für Quelle und eine für Ziel hat und somit in 3 Adressen schreibt.
Pop und Push: 1 opcode byte und einmal 2-byte Adresse hat und somit in 2 Adressen schreibt?Danke und schöne Grüsse
-
MrMulugulu schrieb:
Als Assembler dient Keil A51. Den "rechten" Teil habe ich soweit verstanden.
Zu den Adressen:
Nach dem Befehl MOV SP, #0x56 springt die Adresse zu 0008 da es die nächste Adresse ist nach dem Anfangswert 0x07 vom Stackpointer?Nein. Vergiss das ganz schnell! Die Aussage "Der Stackpointer hat nach RESET den Wert 0x07" hat überhaupt keine Bedeutung für diese Aufgabe. Es ist nämlich völlig egal, welchen Wert SP zu Beginn hat, da er mit "MOV SP, #0x56" überschrieben wird. Der alte Wert 0x07 geht verloren und SP hat nun den neuen Wert 0x56. Das hat auf den PC (program counter) keinerlei Auswirkung.
Oder ist es so das der Befehl:
MOV: 1 opcode byte und 2 mal 2-byte Adressen, eine für Quelle und eine für Ziel hat und somit in 3 Adressen schreibt.
Pop und Push: 1 opcode byte und einmal 2-byte Adresse hat und somit in 2 Adressen schreibt?Überwiegend ja. Der Assembler bildet allerdings aus "MOV A,..." und "MOV B,..." unterschiedliche Maschinenbefehle. "MOV A, #0x12" wird zu "74 12" und "MOV B, #0x34" wird zu "75 F0 34". Das erste Mal braucht man also 2 Bytes und das zweite Mal 3 Bytes. Wenn 2 Bytes an die Adresse 0000 geschrieben wird, dann ist die nächste freie Adresse 2 Bytes weiter: 0000 + 2 = 0002. Wenn danach 3 Bytes an die Adresse 0002 geschrieben wird, dann ist die nächste freie Adresse 3 Bytes weiter: 0002 + 3 = 0005. Die angegebenen Adressen sind also die Startnummern der jeweiligen Befehle. Verbraucht der Befehl mehrere Bytes, dann ist die nächste Startnummer entsprechend höher. Disassembliert sieht dein Programm dann so aus:
Adresse Maschinenbefehle Mnemonics 0000 74 12 MOV A, #0x12 0002 75 F0 34 MOV B, #0x34 0005 75 81 56 MOV SP, #0x56 0008 C0 E0 PUSH ACC 000A C0 F0 PUSH B 000C D0 E0 POP ACC 000E D0 F0 POP B 0010 00 12 ACALL Ende 0012 00 00 Ende: AJMP $
Du siehst, dass die PUSH- und POP-Befehle 2 Bytes verbrauchen, 1 Byte für opcode und nur 1 Byte für die RAM-Adresse der Register.
viele grüße
ralph
-
Wieso macht er denn aus den beiden mov Befehlen unterschiedliche Byte längen?.
Danke erstmal für die Hilfe
-
SYSA schrieb:
Wieso macht er denn aus den beiden mov Befehlen unterschiedliche Byte längen?
Sonst wär's keine Banane mehr :).
Das haben die Designer des 8051-Chips im Jahre 1980 so entschieden. Andere Prozessoren haben wiederum andere Eigenarten. Es gibt aber häufig "Kurzformen", wenn es um den Akkumulator geht.
viele grüße
ralph
-
Das war jetzt nicht die Frage woher weiß ich wann er was macht
-
SYSA schrieb:
Das war jetzt nicht die Frage woher weiß ich wann er was macht
Ohne Kommas wird der Sinn nicht klar.
-
Das war jetzt nicht die Frage. Woher weiß ich, wann er wieviele Bytes belegt?
-
SYSA schrieb:
Woher weiß ich, wann er wieviele Bytes belegt?
Für die Prozessoren gibt es Datenblätter, in denen unter anderem steht, welche Maschinenbefehle sie verstehen, wie die zugehörige Syntax lautet und was sie daraus machen. Der Assembler setzt nur diese* Syntax in Maschinenbefehle um. Manchmal gibt es aber mehrere Möglichkeiten, einen Assemblerbefehl in Maschinensprache umzusetzen, man denke an "mov ax, -1" beim 80386. Was der Assembler dann tatsächlich macht, lässt sich nur mit einem Disassembler erforschen. Allzuviele Freiheiten sollte sich ein Assembler nicht herausnehmen, sonst ist es kein Assembler mehr, sondern ein Compiler.
viele grüße
ralph* AT&T-Syntax mal außen vor gelassen.
-
SYSA schrieb:
Das war jetzt nicht die Frage. Woher weiß ich, wann er wieviele Bytes belegt?
Als Faustregel gilt: wenn mehrere Möglichkeiten der Kodierung existieren, wird die Kürzeste gewählt. Ausnahmen kann davon es bei Befehlen mit relativer Adressierung geben (typisch z.B. bei bedingten Sprüngen) - hier können sich auch Unterschiede in der Architektur des Assemblers manifestieren.