Forum: Mikrocontroller und Digitale Elektronik AVR: Programmcounter einlesen


von Rolli (Gast)


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

von Peter D. (peda)


Lesenswert?

Wozu interessiert Dich der PC ?

Springe einfach dahin, wo Du weitermachen willst.

Bei bis 10 Werten ist je ein Vergleich am effektivsten.
Sind es mehr und aufeinanderfolgend, kann man IJMP verwenden.


Peter

von Rolli (Gast)


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

von Jörg Wunsch (Gast)


Lesenswert?

Beim IJMP brauchst Du nur die Zieladresse, die lädst Du ins
Z-Registerpaar.

Sieh Dir einfach an, wie ein Compiler das macht.

von Rolli (Gast)


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?

von Jörg Wunsch (Gast)


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

von thkais (Gast)


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.

von Peter D. (peda)


Lesenswert?

"Durch diesen Code hättest Du den aktuellen PC im Z-Register."

Ja aber wozu ist das nütze ???

Der AVR kennt keinen BranchBackward Befehl.


Peter

von Profi (Gast)


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?

von thkais (Gast)


Lesenswert?

@Peter: Der Nutzen entzieht sich mir ebenfalls - aber die Frage ist
beantwortet ;)

von Rolli (Gast)


Lesenswert?

Danke für die Hinweise!

So gehts natürlich ganz einfach.

Gruß Rolli

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.