avr-gcc-list
[Top][All Lists]
Advanced

[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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]