Forum: Mikrocontroller und Digitale Elektronik LOW() und HIGH() funktionieren nicht in AVRStudio


von Luke (Gast)


Lesenswert?

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

von Robert D. (d0rni)


Lesenswert?

zeige doch mal deinen Code. Eventuell hast du beim copy & paste was 
falsch gemacht.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Luke (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

Hi

>Ich bin jetzt echt ratlos!

Warum nimmst du nicht den richtigen Assembler vom AVR Studio?

MfG Spess

von Luke (Gast)


Lesenswert?

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!

von Yalu X. (yalu) (Moderator)


Lesenswert?

low() und high() heißen beim GNU-Assembler lo8() und hi8(). Aber da 
scheinen noch andere Dinge komisch bis fehlerhaft zu sein.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.