Hallo zusammen, wollte nicht noch ein Tread zur Instruction Set (Befehlsbeschreibung) der Atmel AVR-RISC Mikrocontroller aufmachen. Aber die erste Antwort hierauf lautete das ich dies doch machen sollte. Erstens hatte meine Frage nur indirekt mit dem Thema zu tun. Zum anderen war der Tread schon fast 9 Jahre alt. Also, nach der Befehlsfolge LDI r16,$7F SUBI r16,-$01 wird ja das MSB (Most Signed Bit) gesetzt und unter anderem auch das Carry-Flag. Nun steht zum Befehl SUBI => Subtract Immediate (Rd <= Rd - K) als Ausdruck zum Carry-Flag : C: (/Rd7 und K7) oder (K7 und R7) oder (R7 und /Rd7) R (Result) equals Rd after the operation. Nun frage ich : " Welchen Wert soll ich für Rd einsetzen, wenn doch R = Rd ist " ? Ist Rd = #$FF bzw. #$-01 oder #$80 ? Ist die Konstante (K) #$7F oder #$FF bzw. #$-01 ? Bis dann Bernd_Stein
Bernd_Stein schrieb: > C: (/Rd7 und K7) oder (K7 und R7) oder (R7 und /Rd7) > > R (Result) equals Rd after the operation. Das wichtigste Wort hier ist das "after". > Nun frage ich : > > " Welchen Wert soll ich für Rd einsetzen, wenn doch R = Rd ist " ? Das "R = Rd" gilt aber erst nach der Operation. Genau deshalb gibt es das R hier überhaupt, um den Inhalt des Registers von vor der Operation (Rd) von dem Inhalt danach (R) zu unterscheiden. > Ist Rd = #$FF bzw. #$-01 oder #$80 ? Keines der drei. > Ist die Konstante (K) #$7F oder #$FF bzw. #$-01 ? Ähm, ernsthaft jetzt? Ich kann ja noch verstehen, dass es Verwirrung bezüglich des Registerinhalts geben mag (weil das Ergebnis wieder im selben Register landet), aber was die Konstante ist, ist doch wohl sonnenklar, oder?
Bernd_Stein schrieb: > LDI r16,$7F > SUBI r16,-$01 anhand der Doku Syntax: SUBI Rd,K Operands: 16 ≤ d ≤ 31, 0 ≤ K ≤ 255 erwarte ich eigentlich, dass der Assembler einen Fehler oder eine Warnung ausgibt. Wenn er bei dir klaglos weiter arbeitet, scheint er -$01 in eine positive Zahl umzuwandeln, die dann als Operand K benutzt wird. Welche Zahl K das ist, ist IMHO implementationsabhängig. Dazu fällt mir nur ein, deinen Beispielcode im Assembler/Debugger laufen zu lassen und nachzusehen, was anschliessend in r16 steht. Kann ich heute abend mal machen, wenn du das selbst nicht schaffst :)
Hi Kann es sein, das du dich seit dem 4.5. damit herumschlägst? Beitrag "Buch AVR von Günter Schmitt durcharbeiten" MfG Spess
Stefan B. schrieb: > Wenn er bei dir klaglos weiter arbeitet, scheint er -$01 in eine > positive Zahl umzuwandeln, die dann als Operand K benutzt wird. Den Assembler interessieren Zahlen nicht besonders. Den interessieren nur Bitmuster. Und -1 und FF haben bei 2-er Kommplementdarstellung identische Bitmuster. Erwarte nicht, dass in der Assembler-Doku das überall aufgeführt ist. Als Assembler-Programmierer 'weiß' man solche Sachen. Die Doku ist eher so zu lesen, dass K ein Bitmuster mit 8 Bit ist. Wie es entsteht, ist dem Assembler völlig egal. Sie hätten in die Doku auch schreiben können. K > 0 log2( K ) <= 8 K < 0 log2(-K) <= 8 wäre es dann klarer geworden? Wohl kaum Default ist bei einem Assembler normalerweise: alles ist unsigned Gibst du mir negative Zahlen, dann wende ich das 2-er Komplement an und arbeite mit diesem Bitmuster (als positive Zahl) weiter. Das ist eine reine Komfortfunktionalität, die einem die Assembler zur Vefügung stellen, damit man nicht ewig subi r16, #$FF - x + 1 schreiben muss (für x die Zahl einsetzen, in diesem Fall 1)
SUBI r16,-$01 100-(-1)=101 ldi r16,100 +00000015: E604 LDI R16,0x64 Load immediate 50: subi r16,-$1 +00000016: 5F0F SUBI R16,0xFF Subtract immediate carry und halfcarry gesetzt ! und in r16 steht jetzt 101 ($65) Binärarithmetik !! benutzt man zum addieren wenn kein addiw oder addi im Befehlssatz vorhanden mfg
Zweierkomplement Man kann die Subtraktion allerdings auch auf eine Addition zurückführen. Die dazu verwendete Methode heißt Einer- bzw. Zweierkomplementbildung. Beispiel: 101101 = 1100011-110110 = 1100011 + 001001 + 1 = (1)101101 Hierbei wird die zweite Zahl negiert. Diese Zahl heißt Einerkomplement. Dann wird dazu eine 1 addiert. Dieses Ergebnis nennt man Zweierkomplement. Diese Zweierkomplement der zweiten Zahl wird zur ersten Zahl addiert. Das Ergebnis ist dann die Differenz beider Zahlen, wobei die führende 1 gestrichen werden muß. Beispiel: Das gleiche Verfahren funktioniert auch im Dezimalsystem. Hier verwendet man das 9er- bzw. 10er-Komplement. Beispiel: 93-17=76. Neunerkomplement von 17 ist 82. Zehnerkomplement von 17 ist 83. 93+83=176. Streichen der führenden 1 ergibt 76!
Stefan Ernst schrieb: > Das "R = Rd" gilt aber erst nach der Operation. Genau deshalb gibt es > das R hier überhaupt, um den Inhalt des Registers von vor der Operation > (Rd) von dem Inhalt danach (R) zu unterscheiden. > >> Ist Rd = #$FF bzw. #$-01 oder #$80 ? > > Keines der drei. > So, jetzt mal Step by Step. ldi r16,$7F Rd = $7F; K = $7F; R = wahrscheinlich unbestimmt Subi r16,-$01 Rd = $80; K = $FF; R = $80 Also für mich ist Rd nach Ausführung der obigen Befehlssequenz Rd = $80. >> Ist die Konstante (K) #$7F oder #$FF bzw. #$-01 ? > > Ähm, ernsthaft jetzt? Ich kann ja noch verstehen, dass es Verwirrung > bezüglich des Registerinhalts geben mag (weil das Ergebnis wieder im > selben Register landet), aber was die Konstante ist, ist doch wohl > sonnenklar, oder? Jetzt denke ich das auch. Also nach dem ersten Befehl K = $7F nach dem zweiten K = $FF. Nun zum Ausdruck. Da SUBI der letzte Befehl ist. C: (/Rd7 und K7) oder (K7 und R7) oder (R7 und /Rd7) Da für mich Rd = $80, R = $80 und K = $FF ist. Ist für mich der mittlere Ausdruck K7 und R7 für das setzen des Carry-Flags verantwortlich. Bis dann Bernd_Stein
Hi >Da für mich Rd = $80, R = $80 und K = $FF ist. Ist für mich der mittlere >Ausdruck K7 und R7 für das setzen des Carry-Flags verantwortlich. Rd=$7F -> Dein Register vor subi R =$80 -> Dein Register nach subi k =$FF -> deine Konstante So und jetzt rechne nochmal. Übigens, wenn du für jeden Assemblerbefehl ca. 8 Tage brauchst, bist du in etwa 3 Jahren durch. MfG Spess
Bernd_Stein schrieb: > Subi r16,-$01 Rd = $80; K = $FF; R = $80 Nein. > Also für mich ist Rd nach Ausführung der obigen Befehlssequenz Rd = $80. Ja, nach der Ausführung. > C: (/Rd7 und K7) oder (K7 und R7) oder (R7 und /Rd7) > > Da für mich Rd = $80, R = $80 und K = $FF ist. Sag mal, ließt du eigentlich auch die Antworten, die du bekommst, oder überfliegst du die nur flüchtig? Ich dachte eigentlich, ich hätte mich relativ deutlich ausgedrückt, was den Unterschied zwischen Rd und R ausmacht (und wie ich mittlerweile gesehen habe, nicht nur ich, sondern vorher auch schon Karl-Heinz im anderen Thread).
Bernd_Stein schrieb: > So, jetzt mal Step by Step. > > ldi r16,$7F Rd = $7F; K = $7F; R = wahrscheinlich unbestimmt Es gibt kein R im ldi Jeder Befehl steht für sich. Ist ein Befehl fertig, vergisst die CPU alles zu diesem Befehl (mit Ausnahme der Flags im Statusregister). Dann heißt es: Neuer Befehl, neues Glück > Subi r16,-$01 Rd = $80; K = $FF; R = $80 > > Also für mich ist Rd nach Ausführung der obigen Befehlssequenz Rd = $80. Richtig. Aber wir reden von Dingen, die während der Ausführung des Befehls passieren! Während der Ausführung ist Rd gleich $7F, K gleich $FF und R (wird während der Ausführung des Befehls bestimmt) wird zu $80. Daran schliesst sich dann die Phase der Bestimmung der Flags an Danach wird das Ergebnis, welches zur Zeit noch in R parkt, zum endgültigen Ergebnis erklärt und in Rd abgelegt Und erst dann ist der Befehl für die CPU vollständig abgearbeitet und der nächste Befehl kommt drann. Ja, auch ein Assemblerbefehl hat eine Feinstruktur! Er läuft in mehreren Phasen ab. Und während dieser Phasen wird das R benötigt um beschreiben zu können, wie sich der Zustand der Flags aus dem was man ganz vorne in den Befehl hineinstopft ergibt. Ob es in der CPU tatsächlich ein Register namens R gibt, oder ob die Atmel Ingenieure die Verknüpfung anders realisiert haben, entzieht sich meiner Kenntnis. Ich will es auch gar nicht wissen. Für mich ist nur interessant, wie sich der Befehl konzeptionell verhält. Und dieses Verhalten kann man beschreiben, indem man ein (möglicherweise fiktives) Register namens R einführt, indem das bitweise Ergebnis der Subtraktionsoperation zwischengeparkt wird, ehe es dann zum endgültigen Ergebnis im Zielregister wird. Zwischengeparkt deshalb, weil die Vorschrift zur Bestimmung des Carry Bits verlangt, dass sowohl Ausgangszahl in Rd als auch das Ergebnis der Subtraktion vorliegen müssen. Und daher bringt es nichts, wenn man das Ergebnis sofort nach Rd zurückschreibt, dann dann ist die Ausgangszahl weg.
Stefan B. schrieb: >> LDI r16, $7F >> SUBI r16,-$01 > ... > erwarte ich eigentlich, dass der Assembler einen Fehler oder eine > Warnung ausgibt. > ... Ich benutze das AVR-Studio 4.18 Build 700. AVRASM: AVR macro assembler 2.1.42 (build 1796 Sep 15 2009 10:48:36) Ich bekomme hiermit weder einen Error noch eine Warung. Bis dann Bernd_Stein
Hi Lenk mal nicht ab. Oder bist du mit dem Durchlesen der Antworten noch nicht weiter als bis dahin gekommen. MfG Spess
Danke an alle die hier gepostet haben.
Der ausführliche Beitrag von Karl heinz Buchegger mit den Dingen die
während der Ausführungsphase ablaufen, haben mein Verständnis für die
Sache - so denke ich - verbessert. So das ich nun zu diesem Schluß in
Bezugnahme zum Carry-Flag komme.
> C: (/Rd7 und K7) oder (K7 und R7) oder (R7 und /Rd7)
Dazu setze ich während der Befehlsausführungsphase
Rd = $7F, R=$80, K=$FF. Womit alle Ausdrücke das Carry-Flag setzen.
Dies hab ich jetzt mal aus meinem Verständnis geschrieben, ohne nochmals
in die einzelnen Beitrage zu schauen. Falls dies falsch sein sollte,
werde ich mich frühestens morgen wieder damit beschäftigen.
Bis dann
Bernd_Stein
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.