Forum: Mikrocontroller und Digitale Elektronik AVR Studio verändert ASM Code nicht nachvollziehbar (zumindest für mich nicht nachvollziehbar.)


von Andre S. (stollenwerk)


Lesenswert?

Hallo zusammen,

AVR Studio treibt mich noch zur Verzweiflung...
Ich habe das folgende Stück Code (Minimalbeispiel):
1
tst r0
2
brne bad
3
rjmp 1
4
bad: jmp 0
5
nop

Wenn ich das ganze auf dem ATmega flashe und dann im Disassembler 
angucke, bzw. durchsteppe finde ich das folgende:
1
1:        tst r0
2
+00000000:   2000        TST     R0               Test for Zero or Minus
3
2:        brne bad
4
+00000001:   F409        BRNE    PC+0x02          Branch if not equal
5
3:        rjmp 1
6
+00000002:   CFFE        RJMP    PC-0x0001        Relative jump
7
@00000003: bad
8
4:        bad: jmp 0
9
+00000003:   940C0000    JMP     0x00000000       Jump
10
5:        nop
11
+00000005:   0000        NOP                      No operation

Kann mir jemand erklären, warum aus dem rjmp 1 ein RJMP PC-0x0001 wird 
??
Ich hab das ganze jetzt durch ein zweites Label und ein BREQ zu dem 
Label anstelle von dem rjmp gelöst, aber ich würde trotzdem gerne den 
Fehler an meiner Überlegung hierüber verstehen...

Gruß und besten Dank

von Matthias L. (Gast)


Lesenswert?

>arum aus dem rjmp 1 ein RJMP PC-0x0001 wird

Die Frage ist eher, warum steht dort eine Eins???

Dort sollte ein Label stehen, welches dann als Sprungadresse gewertet 
wird.

von Helmut (Gast)


Lesenswert?

>warum aus dem rjmp 1 ein RJMP PC-0x0001 wird
Relativ Jump 1 ergibt PC + 1 da 1 kein Label
Relativ jump 5 ergibt pc + 5

von Andre S. (stollenwerk)


Lesenswert?

wie überspringe ich denn dann eine Instruktion (also ohne Labels) ??

von Michael Wilhelm (Gast)


Lesenswert?

Schau dir mal die diversen SKIPs an.

MW

von Helmut (Gast)


Lesenswert?

jmp 1 anstelle von rjmp 1 geht dann

jmp 0 geht schlieslich auch

von Andre S. (stollenwerk)


Lesenswert?

Ahhh, ich glaube, ich hab mein Problem falsch ausgedrückt.

Ich hätte erwartet, dass rjump 1 zu RJUMP  PC+0x0001 und nicht zu 
-0x0001 auf der Hardware wird. rjump 2 wird z.B. entsprechend zu 
RJUMP-0x0000.

Also warum ändert AVR Studio das Argument. Der Offset ist übrigens auch 
abhängig von dem Code davon/danach. An einer anderen Stelle im Code 
werden diese Zeilen zu etwas anderem auf der Hardware compiliert.

von Benedikt K. (benedikt)


Lesenswert?

Eigentlich erwartet (R)JMP ja eine absolute Adresse, die dann vom 
Assembler entsprechend umgesetzt wird.
RJMP PC+1 sollte daher richtiger sein als RJMP 1.

von Andre S. (stollenwerk)


Lesenswert?

lt. Datenblatt erwartet rjmp den relativen Offset. der PC ist danach PC 
= PC + k + 1, wobei k das Argument ist.

von Gast (Gast)


Lesenswert?

Vielleicht, weil "0" und "1" als
feste Adressen interpretiert werden?

tst r0
brne bad
rjmp 1       <<<<<<<<<<< rjmp Code-Adresse 0x0001
bad: jmp 0   <<<<<<<<<<< rjmp Code-Adresse 0x0000
nop

probier mal das:

retry:
  tst r0
  brne bad
  rjmp good

bad:
  jmp retry

good:
  nop

von Johannes M. (johnny-m)


Lesenswert?

Andre Stollenwerk wrote:
> lt. Datenblatt erwartet rjmp den relativen Offset. der PC ist danach PC
> = PC + k + 1, wobei k das Argument ist.
Schau mal in die Befehlssatzdoku. Da steht ziemlich eindeutig, dass im 
Assembler Labels verwendet werden, die automatisch in einen relativen 
Offset umgewandelt werden. M.a.W.: Der Assembler bastelt sich das k 
selber.

Was hindert Dich eigentlich daran, ein Label zu verwenden? Einfach vor 
das nop ein entsprechendes Label, und dann das Argument vom rjmp 
entsprechend anpassen.

Benedikt K. wrote:
> Eigentlich erwartet (R)JMP ja eine absolute Adresse, die dann vom
> Assembler entsprechend umgesetzt wird.
> RJMP PC+1 sollte daher richtiger sein als RJMP 1.
Im Prinzip richtig, aber auf PC kann man so nicht zugreifen. Der 
Assembler interpretiert 1 als absolute Adresse. Da der rjmp an der 
Stelle 0x0002 steht, muss dementsprechend um "-1" gehopst werden, um an 
die Stelle "1" zu gelangen.

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Vielleicht, weil "0" und "1" als
> feste Adressen interpretiert werden?
Genau.

von Gast (Gast)


Lesenswert?

Ich rate aus eigener böser Erfahrung von der
Verwendung von PC+x ab, auch wenn Assembler
meine Welt ist.
Die Verwendung von Label kostet nichts.

Das angeführte Beispiel bestätigt genau dies.

von Andre S. (stollenwerk)


Lesenswert?

Johannes M. wrote:
> Andre Stollenwerk wrote:
>> lt. Datenblatt erwartet rjmp den relativen Offset. der PC ist danach PC
>> = PC + k + 1, wobei k das Argument ist.
> Schau mal in die Befehlssatzdoku. Da steht ziemlich eindeutig, dass im
> Assembler Labels verwendet werden, die automatisch in einen relativen
> Offset umgewandelt werden. M.a.W.: Der Assembler bastelt sich das k
> selber.
>
> Was hindert Dich eigentlich daran, ein Label zu verwenden? Einfach vor
> das nop ein entsprechendes Label, und dann das Argument vom /rjmp/
> entsprechend anpassen.
Das ganze soll als Inline ASM unter C genutzt werden, und der will das 
da mit einem weiteren Label einfach nicht kompilieren. Der o.g. Code war 
das Minimalbeispiel...

>
> Benedikt K. wrote:
>> Eigentlich erwartet (R)JMP ja eine absolute Adresse, die dann vom
>> Assembler entsprechend umgesetzt wird.
>> RJMP PC+1 sollte daher richtiger sein als RJMP 1.
> Im Prinzip richtig, aber auf PC kann man so nicht zugreifen. Der
> Assembler interpretiert 1 als absolute Adresse. Da der rjmp an der
> Stelle 0x0002 steht, muss dementsprechend um "-1" gehopst werden, um an
> die Stelle "1" zu gelangen.

OK, dann ist das wohl des Rätsels Lösung, aber wie mache ich dann einen 
wirklichen relativen Jump, also einfach eine Zeile überspringen, geht 
das dann nur mit Labels??

von Benedikt K. (benedikt)


Lesenswert?

Johannes M. wrote:
> Benedikt K. wrote:
>> Eigentlich erwartet (R)JMP ja eine absolute Adresse, die dann vom
>> Assembler entsprechend umgesetzt wird.
>> RJMP PC+1 sollte daher richtiger sein als RJMP 1.
> Im Prinzip richtig, aber auf PC kann man so nicht zugreifen. Der
> Assembler interpretiert 1 als absolute Adresse. Da der rjmp an der
> Stelle 0x0002 steht, muss dementsprechend um "-1" gehopst werden, um an
> die Stelle "1" zu gelangen.

Ich habe das selbst noch nie gemacht, aber ELM Chan verwendet das 
überall. Und bei dem scheint das zu funktionieren...

http://elm-chan.org/cc_e.html

von Gast (Gast)


Lesenswert?

Hallo Andre,

bei der Offset-Berechnung für PC+k
findest Du Dich unmittelbar in der Abzählerei
von Instruktions-Code-Größen wieder.
Und wehe, es wird ein rjmp in ein jmp geändert...

Seit 1997 mit AVR in Assembler zugange - mein Rat:
nimm Label!

von Gast (Gast)


Lesenswert?

Anders als bei den skip-Befehlen,
überspringst Du mit PC+k eben nicht Zeilen,
sondern addierst zu dem aktuellen Programmzähler
einen Offset in Wortlänge.
Wenn Du die zu überspringenden Instruktionen
nicht exakt in ihrer Wortlänge ausrechnest,
landest Du im Code-Nirwana. Salopp ausgedrückt.
Früher oder später passiert das und dann gibt
es graue Haare en masse. :-)

von AVRFan (Gast)


Lesenswert?

>aber wie mache ich dann einen
>wirklichen relativen Jump, also einfach eine Zeile überspringen, geht
>das dann nur mit Labels??

Nein, es geht zumindest im Assembler mit "rjmp PC+1".  Analog "rjmp 
PC+38" zum relativen Überspringen der folgenden 38 Instruktionen.  Wie 
hier schon angemerkt wurde erweist sich diese Notation in der Praxis 
aber als sehr fehleranfällig.  Oft schiebt man mal probeweise eine 
Instruktion irgendwo rein.  Übersieht man dann, dass dieser Teil 
zufällig von einem "rjmp PC+n" übersprungen wird, und versäumt, das n 
fünf Zeilen weiter oben auf n+1 zu ändern, dann springt der rjmp um eins 
zu kurz.  Die Ursache für das seltsame Verhalten des Programms, das dies 
wahrscheinlich zeitigt, wird man jedoch fatalerweise bei der 
eingeschobenen Instruktion suchen.

Deshalb: Immer Sprungmarken verwenden, denn dann berechnet der Assembler 
die erforderlichen Sprungadressen bzw. -weiten.

von AVRFan (Gast)


Lesenswert?

Zusatz: Einige wenige Instruktionen, darunter "sts" und "lds", belegen 
im Programmspeicher (Flash) nicht nur ein Wort (16 Bit), sondern zwei. 
Die sind dann bei der Berechnung des n in einem "rjmp PC+n" auch mit 2 
zu berücksichtigen!  Es ist also genaugenommen nicht die reine Anzahl 
der Instruktionen relevant, sondern ihr Platzbedarf im Programmspeicher. 
Zum Überspringen dreier aufeinanderfolgender "sts"-Instruktionen wäre 
"rjmp PC+6" korrekt.

von Stefan E. (sternst)


Lesenswert?

> Das ganze soll als Inline ASM unter C genutzt werden, und der will das
> da mit einem weiteren Label einfach nicht kompilieren.

Welcher Compiler denn?
Beim GCC kannst du auch in Inline ASM einfach lokale Labels verwenden:
http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc#Labels_und_Schleifen

von Johannes M. (johnny-m)


Lesenswert?

Benedikt K. wrote:
> Ich habe das selbst noch nie gemacht, aber ELM Chan verwendet das
> überall. Und bei dem scheint das zu funktionieren...
Ah, das war mir neu. Tja, man lernt nie aus...

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.