Forum: Mikrocontroller und Digitale Elektronik Instruction Set von den Atmel AVR-RISC Mikrocontrollern


von Bernd_Stein (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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 :)

von spess53 (Gast)


Lesenswert?

Hi

Kann es sein, das du dich seit dem 4.5. damit herumschlägst?

Beitrag "Buch AVR von Günter Schmitt durcharbeiten"

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

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)

von Dr.PillePalle (Gast)


Lesenswert?

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

von Dr.PillePalle (Gast)


Lesenswert?

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!

von Bernd_Stein (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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).

von Karl H. (kbuchegg)


Lesenswert?

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.

von Bernd_Stein (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

Hi

Lenk mal nicht ab. Oder bist du mit dem Durchlesen der Antworten noch 
nicht weiter als bis dahin gekommen.

MfG Spess

von Bernd_Stein (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.