mikrocontroller.net

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


Autor: Andre S. (stollenwerk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

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

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

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andre S. (stollenwerk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie überspringe ich denn dann eine Instruktion (also ohne Labels) ??

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau dir mal die diversen SKIPs an.

MW

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jmp 1 anstelle von rjmp 1 geht dann

jmp 0 geht schlieslich auch

Autor: Andre S. (stollenwerk)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andre S. (stollenwerk)
Datum:

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

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andre S. (stollenwerk)
Datum:

Bewertung
0 lesenswert
nicht 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??

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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. :-)

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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-...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.