Zugriff auf C-Array (Progmem) aus Inlineassembler AVR 8-Bit.

#6788776
Lesenswert?

Hallo,

ich habe ein kleines Problem (welches vermutlich irgendwo schon bis in's 
letzte Detail erklärt ist... nur finde ich diese Stelle nicht).

Programmiersprache ist C++ (gcc-avr), µC ist ein ATmega32u4

Ich habe ein paar Arrays im C++-Teil meines Projektes. Diese folgen 
durchweg diesem Schema:
1
extern "C"
2
{
3
  PROGMEM volatile const uint8_t data[64] = // volatile?! why?
4
  {
5
    0,1,2,3,...
6
  };
7

8
  volatile uint8_t offset = 0;
9
}

Ich muss in einem kleinen inline-assembly Teil auf vier verschiedene 
davon zugreifen, d.h. ich kann nicht einfach den g++ die Addresse in's 
Z-register (bzw. X/Y) schieben lassen sondern muss irgendwie "direkt" an 
die Adresse herankommen.
1
      "ldi        r30, pm_lo8(data)                                   \n\t"
2
      "ldi        r31, pm_hi8(data)                                   \n\t"
3
      "lds        r16, (offset)             ; range [0..255] !        \n\t"
4
      "asr        r16                       ; shift down by two bits  \n\t"
5
      "asr        r16                       ; so range is [0...63]    \n\t"
6
      "add        r30, r16                  ; add offset              \n\t"
7
      "adc        r31, r0                   ; add carry (and r0=0)    \n\t"
8
      "lpm        r17, Z                    ; load value into r17     \n\t"

Dabei habe ich verschiedene Probleme:

1. Wenn ich das Array ohne einen (zusätzlichen) 'volatile' anlege, 
bekomme ich einen 'undefined reference "data"'... und ich verstehe nicht 
warum?!
2. Es ist bestimmt ein dummer (Verständnis-)Fehler, aber die Werte die 
ich in 'r17' erhalte, sind nicht die aus dem Array sonder 
"irgendeinwasauchimmer"...

Es ist nicht das erste Mal, dass ich Assembler schreibe, wohl aber für 
AVR... Wenn also jemand so freundlich wäre, mir das Brett vorm Kopf 
abzumontieren? Ich würde gern verstehen, was ich da Dümmliches tue...

Vielen lieben Dank,
Stefan
#6788859
Lesenswert?

Stefan F. schrieb:
> Ich muss in einem kleinen inline-assembly Teil auf vier verschiedene
> davon zugreifen, d.h. ich kann nicht einfach den g++ die Addresse in's
> Z-register (bzw. X/Y) schieben lassen

Warum nicht?

> 1. Wenn ich das Array ohne einen (zusätzlichen) 'volatile' anlege,
> bekomme ich einen 'undefined reference "data"'... und ich verstehe nicht
> warum?!

Meine Vermutung: Wenn du aus dem C++-Code nicht darauf zugreifst und es 
auch in den Operandenlsten deines asm-Blocks nicht erwähnst, meint der 
Compiler, es wäre unbenutzt und wirft es raus.
Gast #6788871
Lesenswert?

Rolf M. schrieb:

> Meine Vermutung: Wenn du aus dem C++-Code nicht darauf zugreifst und es
> auch in den Operandenlsten deines asm-Blocks nicht erwähnst, meint der
> Compiler, es wäre unbenutzt und wirft es raus.

Könnte so sein, ja. Compiler sind halt ziemlich doof, halten sich aber 
für intelligent, sogar für so intelligent, um die Einschübe der wirklich 
Intelligenten (also der Menschen) missachten zu dürfen...

Naja, zumindest, bis man ihnen klar gemacht hat, was sie nicht 
missachten dürfen...
#6788872
Lesenswert?

Rolf M. schrieb:
> Stefan F. schrieb:
>> Ich muss in einem kleinen inline-assembly Teil auf vier verschiedene
>> davon zugreifen, d.h. ich kann nicht einfach den g++ die Addresse in's
>> Z-register (bzw. X/Y) schieben lassen
>
> Warum nicht?

Weil es dafür zu viele sind. Ich habe drei Addressregister die ich mir 
"vorfüllen" lassen könnte (X,Y,Z). Ich habe aber vier Arrays auf die ich 
zugreifen muss.

>> 1. Wenn ich das Array ohne einen (zusätzlichen) 'volatile' anlege,
>> bekomme ich einen 'undefined reference "data"'... und ich verstehe nicht
>> warum?!
>
> Meine Vermutung: Wenn du aus dem C++-Code nicht darauf zugreifst und es
> auch in den Operandenlsten deines asm-Blocks nicht erwähnst, meint der
> Compiler, es wäre unbenutzt und wirft es raus.

Es wird aus dem C++-Code ebenfalls darauf zugegriffen. Es ist also 
vorhanden. Sogar in derselben Source-Datei. Und der Zugriff aus C++ 
funktioniert.
#6788909
Lesenswert?

Interessant...

... es funktioniert, wenn ich dies tue:
1
extern "C"
2
{
3
  PROGMEM volatile const uint8_t data[64] =
4
  {
5
    ...
6
  };
7

8
  volatile uint8_t offset = 0;
9
}
1
"ldi        r30, lo8(data)                                      \n\t"
2
"ldi        r31, hi8(data)                                      \n\t"
3
"lds        r16, (offset)             ; range [0..255] !        \n\t"
4
"lsr        r16                       ; shift down by two bits  \n\t"
5
"lsr        r16                       ; so range is [0...63]    \n\t"
6
"add        r30, r16                  ; add offset              \n\t"
7
"adc        r31, r0                   ; add carry (and r0=0)    \n\t"
8
"lpm        r17, Z                    ; load value into r17     \n\t"

Mit lo8()/hi8() anstelle von pm_lo8()/pm_hi8() bekomme ich jetzt die 
richtige Adresse und die richtigen Daten aus dem Array. Das Array liegt 
aber definitiv im PROGMEM. Siehe "lpm"... Zugriff auf der C++-Seite 
erfolgt über pgm_read_byte_near().

Hmm,... jetzt habe ich zwar eine funktionierende Lösung allerdings beißt 
sich diese mit dem was ich dazu in "diverser" Dokumentation finde...

Das mit dem "volatile" ist auch irritierend. /me --> confused... :-)
Gast #6788970
Lesenswert?

Stefan F. schrieb:
> extern "C"

Brauchst du nicht wenn du sowieso mit C++ arbeitest

Du musst dem Compiler/Linker nur das "used" verkaufen.


Siehe:
1
extern  const uint8_t  data[2] __attribute__((progmem)); 
2
extern  uint8_t offset;
3

4
const uint8_t  data[2] __attribute__((progmem,used )) =
5
{
6
    14,12
7
};
8

9
uint8_t offset __attribute__((used)) = 0;

Und dann tuts auch dein ASM Code
Gast #6789124
Lesenswert?

c-hater schrieb:
> Könnte so sein, ja. Compiler sind halt ziemlich doof, halten sich aber
> für intelligent, sogar für so intelligent, um die Einschübe der wirklich
> Intelligenten (also der Menschen) missachten zu dürfen...
>
> Naja, zumindest, bis man ihnen klar gemacht hat, was sie nicht
> missachten dürfen...

viell blahblah abba keine hilfe1
anung schenst du ja nicht zu habben

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren