AVR: Programmcounter einlesen

Gast #107843
Lesenswert?

Hallo Leute,

um beim AVR-Controller switch-case Listen effektiv programmieren zu
können müsste ich am Kopf der Verzweigung den aktuellen Stand des
Programmcounters auslesen und mittels indirekter Adressierung den
jeweils gewünschten case-Fall aufrufen. Wie lese ich den aktuellen
PC-Stand aus? Gibt es eine andere effektive Möglichkeit für eine
direkte programmgesteuerte Verzweigung?

Gruß Rolli
Gast #107845
Lesenswert?

Danke für den Hinweis!

Habe, wie ich meine, alle Möglichkeiten schon durchprobiert, ohne
Erfolg:

Beim direkten Sprung RJMP muß ich jeweils eine konstante Verschiebung
bzw. ein Label angebeben. Adressierung über Register nicht möglich.

Beim indirekten Sprung IJMP muß ich das Z-Register (R31:R30) mit der
Basisadresse laden. Hierfür brauche ich den aktuellen PC. In der Doku
finde ich keinen Hinweis auf die Register, in denen der PC abgelegt
ist.

Weiter habe ich versucht, den Sprungverteiler per .org-Anweisung auf
eine feste Basisadresse zu legen: akzeptiert der Imagecraft-C-Compiler
nicht in Inline-Assemblermodulen.

Da ich den Sprungverteiler im zeitkritischen Assemblermodul eines
Reglers benötige, brauche ich eine sehr schnelle Variante.

Gruß Rolli
Gast #107847
Lesenswert?

Mein ICC-Compiler macht aus der "einfachen" switch-case-Anweisung eine
recht aufwändige Assembler-Routine mit zahlreichen "cpi"-Abfragen und
darauffolgenden "breq"/"rjmp"-Sprüngen: pro Sprungziel eine
Abfrage, eine Verzweigung und ggf. ein Programmsprung. Für mich ist das
bei einer Vielzahl von Sprungzielen unbrauchbar.

Soweit ich das verstanden habe, muß ich beim "ijmp"-Befehl die
absolute Sprungadresse im Z-Registerpaar ablegen, d.h. vorher mit Hilfe
des aktuellen PC bestimmen. Wenn der Controller zu "PC+Z" springen
würde wäre das ja okay, aber er springt direkt zu "Z".

Verstehe ich da was falsch?
Gast #107848
Lesenswert?

Mein Compiler macht aus komplizierten switch-Anweisungen sehr wohl
eine Sprungtabelle. ;-)

Ja, Du mußt eine absolute Adresse dafür haben, aber warum zum
Geier[tm] brauchst Du denn dafür den aktuellen PC?  Die Absolutadresse
läßt man sich üblicherweise vom Linker eintragen, indem man in der
Sprungtabelle ein Symbol für das Sprungziel hinlegt -- so macht es
jedenfalls der GCC.

.org ist ohnehin tabu, diese Pseudo-Op hat nur für Absolutassemb-
lierung Sinn (wenn also kein Linker im Spiel ist), bei verschieblichen
Objekten bestimmt ja stets erst der Linker, wohin was kommt.  Das war
schon zu CP/M-Zeiten so...
Gast #107849
Lesenswert?

.
.
.
pc_adress:
     ldi r30,low(pc_adress)
     ldi r31,high(pc_adress)
.
.
Durch diesen Code hättest Du den aktuellen PC im Z-Register.
Wieviele Sprungziele hast Du denn?
Ich habe so etwas ähnliches mit einer Tabelle realisiert. In der
Tabelle stehen die Sprungadressen. Einfach die entsprechende Adresse
aus der Tabelle lesen, ins Z-Register und per ijmp springen.
Gast #107851
Lesenswert?

Mache es mit der Tabelle und ijmp.
Du musst die verschiedenen Startadressen in die Tabelle bringen.

Für Branches (relativ) brauchst Du den aktuellen PC.
Da der hier verwendete Befehl ein Jump (absolut) ist, braucht Dich der
aktuelle PC nicht interessieren.

Alle Adressberechnungen macht der Linker für Dich (wenn Du es ihm
richtig sagst).

Wenn es schnell gehen soll, als Notlösung:
Mache es mit einer Sprungtabelle:
LABEL_A:
JMP LABEL0
JMP LABEL1
JMP LABEL2
JMP LABEL3
JMP LABEL4
JMP LABEL5
...

Da jetzt alle JMPs gleichviele Bytes belegen (hoffentlich wird nichts
wegoptimiert), kannst Du mit
JMP LABELA+n*m (m ist die Zahl der Bytes, die ein JMP belegt)
zum LABELn springen.

Schafft das Dein Compiler?

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