Forum: Mikrocontroller und Digitale Elektronik Lookup-Tabelle mit Sprungbefehlen


von Julien M. (Gast)


Lesenswert?

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

von Santa Klaus (Gast)


Lesenswert?

>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

von Werner B. (wernerb)


Lesenswert?

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

von Julien M. (Gast)


Lesenswert?

Vielen Dank für die schnellen Antworten.

Soweit ist mir alles klar.
Muß in der Sprungtabelle dann gar kein .db oder .dw verwendet werden?

von Santa Klaus (Gast)


Lesenswert?

>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...
1
menu:
2
   ; immer zuerst "low", und dann "high"!
3
   ldi zl, low(Sprungtabelle)
4
   ldi zh, high(Sprungtabelle)
5
   add zl, r16  ; Überlauf nicht ausgeschlossen!
6
   adc zh, _0   ; Ggf. aufgetretenen Überlauf berücksichtigen
7
8
   ; Sprungziel aus Tabelle mit zwei "lpm"s lesen
9
   ; Reihenfolge: erst High-Byte, dann Low-Byte
10
   lsl zl
11
   rol zh
12
   inc zl
13
   lpm         ; Sprungziel-High-Byte --> r0
14
   mov r1, r0
15
   dec zl
16
   lpm         ; Sprungziel-Low-Byte --> r0
17
   ; Registerpaar r1:r0 enthält jetzt das Sprungziel,
18
   ; muß in Registerpaar zh:zl kopiert werden
19
   mov zl, r0
20
   mov zh, r1
21
   icall
22
   ret
23
24
menue1:
25
   ; hier menue1
26
ret
27
28
menue2:
29
   ; hier menue2
30
ret
31
32
menue3:
33
   ; hier menue3
34
ret
35
36
menue4:
37
   ; hier menue4
38
ret
39
40
Sprungtabelle:
41
.DW menue1
42
.DW menue2
43
.DW menue3
44
.DW menue4

PS: ".DW rjmp ..." gibt es grundsätzlich nicht!

von Philipp Burch (Gast)


Lesenswert?

.dw rjmp ... Gibt's eigentlich schon, dann hättest du im Register
einfach das Byte, das den Befehl "rjmp" repräsentiert, oder?

von Santa Klaus (Gast)


Lesenswert?

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

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.