Hallo zusammen,
vieleicht wurde meine Problematik schon einmal durchgesprochen. Ich
konnte aber leider keinen passenden Post finden.
Nun zum Problem...
Hardware: ATmega8515
Firmware: Assembler
Ich habe in einem Register einen Wert zwischen 1 und 32 stehen.
Nun habe ich gedacht, dass ich den Z-Pointer an den Anfang meiner
Lookup-Tabelle setze und anschließend den Pointer mit dem Registerwert
addiere. In der Lookup-Tabelle sollen sich aber nur Sprungbefehle für
Unterprogramme befinden. Funktioniert das überhaupt??
Aufbau der Tabelle:
Lookup:
.dw rjmp Prg1 ;Programm 1 aufrufen
.dw rjmp Prg2 ;Programm 2 aufrufen
.dw rjmp Prg3 ;Programm 3 aufrufen
etc...
Zum zweiten stell ich mir die Frage mit welchem Befehl ich den Pointer
dazu bringe auch wirklich zu springen. "lpm" wird ja nicht
funktionieren.
Über Lösungsansätze wäre ich sehr dankbar.
Mfg
Julien
>Nun habe ich gedacht, dass ich den Z-Pointer an den Anfang meiner>Lookup-Tabelle setze und anschließend den Pointer mit dem>Registerwert addiere. In der Lookup-Tabelle sollen sich aber nur>Sprungbefehle für>Unterprogramme befinden. Funktioniert das überhaupt??
Und ob das funktioniert. Zur Realisierung dieses Vorhabens (Stichwort:
indirekte Adressierung des Programmspeichers) gibt es zwei Befehle:
icall und ijmp (der lpm-Befehl hat hiermit nichts zu tun!).
Hier ein Codebeispiel mit "icall", das dem Thread
http://www.mikrocontroller.net/forum/read-1-157002.html#157316
entstammt:
menu:
; immer zuerst "low", und dann "high"!
ldi zl,low(Sprungtabelle)
ldi zh,high(Sprungtabelle)
add zl, r16 ; Überlauf nicht ausgeschlossen!
adc zh, _0 ; Ggf. aufgetretenen Überlauf berücksichtigen
icall
ret
menue1:
; hier menue1
ret
menue2:
; hier menue2
ret
menue3:
; hier menue3
ret
menue4:
; hier menue4
ret
Sprungtabelle:
rjmp menue1
rjmp menue2
rjmp menue3
rjmp menue4
Aber Achtung - Falle: bei den verschiedenen AVRs sind die rjmp/jmp
befehle (je nach FLASH ausstattung) unterschielich lang. Eventuell
musst Du den Index erst *2 nehmen (Das gleiche "Problem" wie mit den
interruptvektoren.)
>Muß in der Sprungtabelle dann gar kein .db oder .dw verwendet werden?
Nein, gerade nicht, das ist ja der Clou daran. Es ist
selbstverständlich möglich, das mit einer Tabelle zu proggen, in der
tatsächlich nur die Sprungziele als Daten stehen (also keine
Sprung*instruktionen* "rjmp ..."), aber wie Du siehst, ist das
umständlicher, weil dann noch das Lesen der Daten mit "lpm"s nötig
ist:
Achtung: Code nur aus dem Kopf hingeschrieben; nicht getestet; keine
Haftung für Fehler aller Art...
> .dw rjmp ... Gibt's eigentlich schon, dann hättest du im Register> einfach das Byte, das den Befehl "rjmp" repräsentiert, oder?
Der Assembler erwartet hinter ".DW" eine Liste von Konstanten (nur
eine einzige Konstante geht natürlich auch), die irgendwo im Programm
definiert sind. "rjmp" ist jedoch keine Konstante, sondern das
"Gerüst" einer Instruktion. "rjmp Sprungmarke" ist ebenfalls keine
Konstante, sondern eine "komplette" Instruktion (mit dem OpCode
1100kkkkkkkkkkkk; in den k's ist die Sprungzieladresse codiert). rjmp
"gewaltsam" als Konstante zu definieren ist nicht möglich - der
Assember läßt es (verständlicherweise) nicht zu. Damit ist alles
gesagt.
Wenn Du das Wort, das den Befehl "rjmp Sprungmarke" repräsentiert, in
ein Register(-paar) einlesen willst, mußt Du einfach
Label:
rjmp Sprungmarke
ohne ein ".DW" vornedran hinschreiben, den Z-Pointer auf "Label"
setzen und zweimal lpm wie im letzten Beispiel von mir gezeigt
anwenden.
Eine eigene Frage?
Dieser Thread ist über 21 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.