[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] Re: ROM data and far and huge ptrs
From: |
Theodore A. Roth |
Subject: |
Re: [avr-gcc-list] Re: ROM data and far and huge ptrs |
Date: |
Sun, 11 Apr 2004 21:36:30 -0700 (PDT) |
On Sun, 11 Apr 2004, Niklas Brogden wrote:
> Hi everybody,
>
> New here...
>
> Volkmar wrote:
>
> > Look for the attribute PROGMEM in the avr-libc documentation. With
> > this you store the (constant) data directly in flash. But than you
> > need the Program space functions like pgm_read_byte().
> >
> > I think the program space functions and the documentation gives you
> > more information for pointers on ROM constants.
> >
>
> Talking about PROGMEM, pgmspace.h etc.
>
> I was having some difficulty addressing arrays of strings in flash-ROM while
> using variable indexes on an ATmega8. Found out the problem was already
> reported as #13427 in bug reports. I tried having a look att the bug report
> but didn't get any wiser as to the current status of this error. So I was
> wondering:
> a) Is this bug dealt with,
> b) What needs to be done, compiled, downloaded to deal with it and
> c) Is there some simple solution to this problem that I have missed through
> sheer lack of skill?
I think that bug #13427/#13428 is not a bug in gcc, but a bug in the
submitters example code. For reference, here's the example code:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <string.h>
const char foo[] PROGMEM = "foo";
const char bar[] PROGMEM = "bar";
PGM_P Langs[2] PROGMEM = {foo, bar};
int main(void)
{
unsigned char i;
char buf[2][5];
//strcpy_P works fine with constant index
strcpy_P(buf[0], Langs[0]); //correctly copy 'foo'
strcpy_P(buf[1], Langs[1]); //correctly copy 'bar'
//but strcpy_P copy char from wrong address if use variable indexing
for (i=0; i<2; i++)
strcpy_P(buf[i], Langs[i]); //copy garbages!!!
return 1;
}
The problem with the code is that he is trying to dereference Langs to
get the address for foo and bar. The only way to dereference any value
stored in program space (flash) is to read it into memory. Looking at
the generated asm is usually instructive.
Here's foo, bar and Langs:
00000026 <__ctors_end>:
26: 66 6f ori r22, 0xF6 ; 246
28: 6f 00 .word 0x006f ; ????
0000002a <bar>:
2a: 62 61 72 00 bar.
0000002e <Langs>:
2e: 26 00 2a 00 &.*.
Now here's his case that works:
//strcpy_P works fine with constant index
strcpy_P(buf[0], Langs[0]); //correctly copy 'foo'
70: 66 e2 ldi r22, 0x26 ; 38
72: 70 e0 ldi r23, 0x00 ; 0
74: ce 01 movw r24, r28
76: 01 96 adiw r24, 0x01 ; 1
78: 1e d0 rcall .+60 ; 0xb6
This works because gcc optimized out the dereference since it already
know that foo is at 0x0026 in flash (lines 70 and 72). He simply got
lucky that this worked.
Here's the code that didn't work:
//but strcpy_P copy char from wrong address if use variable indexing
for (i=0; i<2; i++)
84: dd 24 eor r13, r13
86: 00 e0 ldi r16, 0x00 ; 0
88: 10 e0 ldi r17, 0x00 ; 0
8a: 8e e2 ldi r24, 0x2E ; 46
8c: e8 2e mov r14, r24
8e: 80 e0 ldi r24, 0x00 ; 0
90: f8 2e mov r15, r24
strcpy_P(buf[i], Langs[i]); //copy garbages!!!
92: ce 01 movw r24, r28
94: 01 96 adiw r24, 0x01 ; 1
96: 80 0f add r24, r16
98: 91 1f adc r25, r17
9a: f7 01 movw r30, r14
9c: 61 91 ld r22, Z+
9e: 71 91 ld r23, Z+
a0: 7f 01 movw r14, r30
a2: 09 d0 rcall .+18 ; 0xb6
The Z pointer is being loaded with 0x002e (the address of Langs in
_flash_). Lines 9c and 9e then dereference Z which means that r23 and
r24 loaded with data sram, thus not gettting the correct addresses of
foo and bar.
The fix is to change the for loop to something like this:
//but strcpy_P copy char from wrong address if use variable indexing
for (i=0; i<2; i++)
{
PGM_P ptr = (PGM_P) pgm_read_word (Langs[i]);
strcpy_P(buf[i], ptr);
}
Which generates this asm:
//but strcpy_P copy char from wrong address if use variable indexing
for (i=0; i<2; i++)
84: dd 24 eor r13, r13
86: 00 e0 ldi r16, 0x00 ; 0
88: 10 e0 ldi r17, 0x00 ; 0
8a: 8e e2 ldi r24, 0x2E ; 46
8c: e8 2e mov r14, r24
8e: 80 e0 ldi r24, 0x00 ; 0
90: f8 2e mov r15, r24
{
PGM_P ptr = (PGM_P) pgm_read_word (Langs[i]);
92: d7 01 movw r26, r14
94: ed 91 ld r30, X+
96: fd 91 ld r31, X+
98: 7d 01 movw r14, r26
9a: 25 91 lpm r18, Z+
9c: 34 91 lpm r19, Z
strcpy_P(buf[i], ptr);
9e: ce 01 movw r24, r28
a0: 01 96 adiw r24, 0x01 ; 1
a2: 80 0f add r24, r16
a4: 91 1f adc r25, r17
a6: b9 01 movw r22, r18
a8: 09 d0 rcall .+18 ; 0xbc
This time Z is used by the LPM insn to get the pointer for foo from
flash.
Hope that helps clear things up. I also hope I didn't get this wrong, if
I did, hopefully someone will catch my mistake. ;-)
---
Ted Roth
PGP Key ID: 18F846E9
Jabber ID: address@hidden
_______________________________________________
avr-gcc-list mailing list
address@hidden
http://www.avr1.org/mailman/listinfo/avr-gcc-list