Hallo, ich habe mich mal daran gemacht, diese Sprungtabelle (http://www.mikrocontroller.net/articles/AVR-Tutorial:_Mehrfachverzweigung#Sprungtabelle) nachzuprogrammieren, bzw. den Quelltext zu kopieren und im Simulator von AVR Studio (4.18) laufen zu lassen. Aber es kompiliert erst garnicht: Für die Zeilen "ldi ZL,low(Sprungtabelle)" und "ldi ZH,high(Sprungtabelle)" meckert der Compiler "Error: garbage at end of line". Und wenn ich "low()"/"high()" durch "lo8()"/"hi8()" ersetze, wird nicht korrekt gesprungen. Genauso funktionieren "pm_lo8()"/"pm_hi8()" nicht. Mittlerweile bin ich etwas ratlos. Habt Ihr eine Idee, was hier schiefläuft? Grüße, Luke
zeige doch mal deinen Code. Eventuell hast du beim copy & paste was falsch gemacht.
Luke schrieb: > AVR Studio (4.18) laufen zu lassen. Aber es kompiliert erst garnicht: kompiliert -> assembliert. Ein Assembler ist kein Compiler > Für die Zeilen "ldi ZL,low(Sprungtabelle)" und "ldi > ZH,high(Sprungtabelle)" meckert der Compiler "Error: garbage at end of > line". Das deutet aber eher darauf hin, dass sich irgend ein nicht sichtbares Zeichen im Editor eingeschlichen hat. Ich schätze mal, dass da beim Copy&Paste irgendwas mitkopiert wurde, was nicht dort sein soll. Wenn es ein Problem mit den High/Low Makros gäbe, gibt es keinen wirklichen Grund, warum der Assembler das nicht auch in der Fehlermeldung anführen sollte. Die Fehlermeldung würde dann eher in die Richtung "Unknown Operand 'HIgh'" oder so ähnlich lauten. 'Garbage at the end of Line', also 'unbekannter 'Dreck' am Zeilenende ist meistens ein Hinweis auf irgendein Zeichen, welches man zwar nicht sieht, welches aber trotzdem dort ist und eigentlich nicht dort sein sollte.
Hallo, hier mein Code:
1 | int main(void) { |
2 | |
3 | // ZL = r30, ZH = r31
|
4 | asm goto ( |
5 | |
6 | "ldi r16,2" "\n" |
7 | "ldi r30, low(Sprungtabelle)" "\n" |
8 | "ldi r31, high(Sprungtabelle)" "\n" |
9 | "add r30, r16" "\n" |
10 | "ldi r16, 0" "\n" |
11 | "adc r31, r16" "\n" |
12 | "ijmp" "\n" |
13 | |
14 | "Sprungtabelle:" "\n" |
15 | "jmp %x0" "\n" |
16 | "jmp %x1" "\n" |
17 | "jmp %x2"
|
18 | :::: l1, l2, l3 |
19 | );
|
20 | |
21 | |
22 | l1:
|
23 | asm("ldi r16,42"); |
24 | goto end; |
25 | |
26 | l2:
|
27 | asm("ldi r16,11"); |
28 | goto end; |
29 | |
30 | l3:
|
31 | asm("ldi r16,0xff"); |
32 | |
33 | end:
|
34 | return 0; |
35 | }
|
Ein Teil der Lösung bestand darin, das ZL und ZH zu ersetzen. Aber "low" und "high" funktionieren immer noch nicht! Ich bin jetzt echt ratlos! Viele Grüße, Luke
Hi >Ich bin jetzt echt ratlos! Warum nimmst du nicht den richtigen Assembler vom AVR Studio? MfG Spess
Hallo, spess53 schrieb: > Warum nimmst du nicht den richtigen Assembler vom AVR Studio? weil ich schon den C-Code "drumherum" habe und den nicht nochmal neu schreiben möchte in Assembler, aber das switch-Statement in C circa 30 Zyklen benötigt und ich die Zyklen für das Programm brauche! Viele Grüße!
low() und high() heißen beim GNU-Assembler lo8() und hi8(). Aber da scheinen noch andere Dinge komisch bis fehlerhaft zu sein.
Luke schrieb: > Hallo, > > spess53 schrieb: >> Warum nimmst du nicht den richtigen Assembler vom AVR Studio? > > weil ich schon den C-Code "drumherum" habe und den nicht nochmal neu > schreiben möchte in Assembler, aber das switch-Statement in C circa 30 > Zyklen benötigt und ich die Zyklen für das Programm brauche! Zeig mal den C-Code. Da gibt es sicher was, wie man das auch in reinem C schneller kriegt.
Die Compilerbauer sind nicht so dumm, wie Anfänger gerne denken.
Ein Switch kann durchaus als Sprungtabelle implementiert werden, sobald
es effektiver ist.
Hier wird allerdings ein Array die bessere Lösung sein (eine Zahl in
eine andere umwandeln).
Karl Heinz schrieb im Beitrag #3560098:
> Zeig mal den C-Code.
Ja.
Der gezeigte Assemblercode ist recht sinnfrei.
LOW und HIGH sind Zeugs vom Atmel-Assembler. Du verwendest den GNU-Assembler (avr-as)mit avr-gcc als Compiler-/Assembler-/Linker-Treiber. Schau dir einfach an, wie avr-gcc das macht:
1 | subi r30,lo8(-(gs(.LSprungtabelle))) |
2 | sbci r31,hi8(-(gs(.LSprungtabelle))) |
3 | ijmp |
4 | .section .progmem.gcc_sw_table,"ax",@progbits |
5 | .p2align 1 |
6 | .LSprungtabelle: |
7 | rjmp .L1 |
8 | rjmp .L2 |
9 | ... |
10 | .text |
11 | .L1: |
12 | ... |
für die kleinen AVRs (mit RJMP) und für die großen (mit JMP):
1 | subi r30,lo8(-(gs(.LSprungtabelle))) |
2 | sbci r31,hi8(-(gs(.LSprungtabelle))) |
3 | jmp __tablejump2__ |
4 | .section .progmem.gcc_sw_table,"a",@progbits |
5 | .p2align 1 |
6 | .LSprungtabelle: |
7 | .word gs(.L1) |
8 | .word gs(.L2) |
9 | ... |
10 | .text |
11 | .L1: |
12 | ... |
Was __tablejump2__ macht siehst du in der libgcc:
1 | DEFUN __tablejump2__ |
2 | lsl r30 |
3 | rol r31 |
4 | ;; FALLTHRU |
5 | ENDF __tablejump2__ |
6 | |
7 | DEFUN __tablejump__ |
8 | #if defined (__AVR_HAVE_LPMX__) |
9 | lpm __tmp_reg__, Z+ |
10 | lpm r31, Z |
11 | mov r30, __tmp_reg__ |
12 | #if defined (__AVR_HAVE_EIJMP_EICALL__) |
13 | eijmp |
14 | #else |
15 | ijmp |
16 | #endif |
17 | |
18 | #else /* !HAVE_LPMX */ |
19 | lpm |
20 | adiw r30, 1 |
21 | push r0 |
22 | lpm |
23 | push r0 |
24 | #if defined (__AVR_HAVE_EIJMP_EICALL__) |
25 | in __tmp_reg__, __EIND__ |
26 | push __tmp_reg__ |
27 | #endif |
28 | ret |
29 | #endif /* !HAVE_LPMX */ |
30 | ENDF __tablejump__ |
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.