AVR Studio verändert ASM Code nicht nachvollziehbar (zumindest für mich nicht nachvollziehbar.)

OP #961707
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
OP #961775
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.
Gast #961790
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
#961795
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.
OP #961807
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??
#961809
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
Gast #961822
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!
Gast #961830
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. :-)
Gast #961865
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.
Gast #961876
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren