Currently progmem attribute works the same way on the reduced core (no LPM, 16
GPRs) and on the ordinary cores (with LPM, 32 GPRs).
As we have a linearized memory model on reduced core and flash memory is
visible in the RAM address range (starting at 0x4000), it would make sense if
the compiler added that offset.
Attached is a tentative patch that adds this feature to avr-gcc together with a
small test program that demonstrates some use cases.
If this does not break anything (e.g. because the current practice is to use
progmem together with hand-crafted offsets and / or inline assembly) and the
feedback is positive, I would propose the change to gcc-patches.
Johann
gcc/
* doc/extend.texi (AVR Variable Attributes) [progmem]: Add
documentation how it works on reduced Tiny cores.
* avr.c (AVR_SYMBOL_FLAG_TINY_PM): New macro.
(avr_address_tiny_pm_p): New static function.
(avr_print_operand_address) [AVR_TINY]: Add AVR_TINY_PM_OFFSET
if the address is in progmem.
(avr_assemble_integer): Same.
(avr_encode_section_info) [AVR_TINY]: Set AVR_SYMBOL_FLAG_TINY_PM
for symbol_ref in progmem.
* avr.h (AVR_TINY_PM_OFFSET): New macro.
* avr-c.c (avr_cpu_cpp_builtins): Use it instead of magic 0x4000
when built-in def'ing __AVR_TINY_PM_BASE_ADDRESS__.
Index: config/avr/avr-c.c
===================================================================
--- config/avr/avr-c.c (revision 237643)
+++ config/avr/avr-c.c (working copy)
@@ -334,7 +334,8 @@ start address. This macro shall be used
it has been mapped to the data memory. For AVR_TINY devices
(ATtiny4/5/9/10/20 and 40) mapped program memory starts at 0x4000. */
- cpp_define (pfile, "__AVR_TINY_PM_BASE_ADDRESS__=0x4000");
+ cpp_define_formatted (pfile, "__AVR_TINY_PM_BASE_ADDRESS__=0x%x",
+ AVR_TINY_PM_OFFSET);
}
if (AVR_HAVE_EIJMP_EICALL)
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c (revision 237643)
+++ config/avr/avr.c (working copy)
@@ -80,6 +80,10 @@
((SYMBOL_REF_FLAGS (sym) & AVR_SYMBOL_FLAG_PROGMEM) \
/ SYMBOL_FLAG_MACH_DEP)
+/* (AVR_TINY only): Symbol has attribute progmem */
+#define AVR_SYMBOL_FLAG_TINY_PM \
+ (SYMBOL_FLAG_MACH_DEP << 4)
+
#define TINY_ADIW(REG1, REG2, I) \
"subi " #REG1 ",lo8(-(" #I "))" CR_TAB \
"sbci " #REG2 ",hi8(-(" #I "))"
@@ -2161,12 +2165,30 @@ cond_string (enum rtx_code code)
}
+static bool
+avr_address_tiny_pm_p (rtx x)
+{
+ if (CONST == GET_CODE (x))
+ x = XEXP (XEXP (x, 0), 0);
+
+ if (SYMBOL_REF_P (x))
+ return SYMBOL_REF_FLAGS (x) & AVR_SYMBOL_FLAG_TINY_PM;
+
+ return false;
+}
+
/* Implement `TARGET_PRINT_OPERAND_ADDRESS'. */
/* Output ADDR to FILE as address. */
static void
avr_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr)
{
+ if (AVR_TINY
+ && avr_address_tiny_pm_p (addr))
+ {
+ addr = plus_constant (Pmode, addr, AVR_TINY_PM_OFFSET);
+ }
+
switch (GET_CODE (addr))
{
case REG:
@@ -8909,6 +8931,12 @@ avr_assemble_integer (rtx x, unsigned in
return true;
}
+ if (AVR_TINY
+ && avr_address_tiny_pm_p (x))
+ {
+ x = plus_constant (Pmode, x, AVR_TINY_PM_OFFSET);
+ }
+
return default_assemble_integer (x, size, aligned_p);
}
@@ -9579,7 +9607,8 @@ avr_encode_section_info (tree decl, rtx
/* PSTR strings are in generic space but located in flash:
patch address space. */
- if (-1 == avr_progmem_p (decl, attr))
+ if (!AVR_TINY
+ && -1 == avr_progmem_p (decl, attr))
as = ADDR_SPACE_FLASH;
AVR_SYMBOL_SET_ADDR_SPACE (sym, as);
@@ -9610,6 +9639,17 @@ avr_encode_section_info (tree decl, rtx
if (addr_attr && !DECL_EXTERNAL (decl))
SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_ADDRESS;
}
+
+ if (AVR_TINY
+ && decl
+ && VAR_DECL == TREE_CODE (decl)
+ && -1 == avr_progmem_p (decl, DECL_ATTRIBUTES (decl))
+ && MEM_P (rtl)
+ && SYMBOL_REF_P (XEXP (rtl, 0)))
+ {
+ rtx sym = XEXP (rtl, 0);
+ SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM;
+ }
}
Index: config/avr/avr.h
===================================================================
--- config/avr/avr.h (revision 237643)
+++ config/avr/avr.h (working copy)
@@ -74,6 +74,8 @@ enum
|| avr_arch->have_rampd)
#define AVR_HAVE_EIJMP_EICALL (avr_arch->have_eijmp_eicall)
+#define AVR_TINY_PM_OFFSET (0x4000)
+
/* Handling of 8-bit SP versus 16-bit SP is as follows:
FIXME: DRIVER_SELF_SPECS has changed.
Index: doc/extend.texi
===================================================================
--- doc/extend.texi (revision 237587)
+++ doc/extend.texi (working copy)
@@ -5847,10 +5847,12 @@ attribute accomplishes this by putting r
section whose name starts with @code{.progmem}.
This attribute works similar to the @code{section} attribute
-but adds additional checking. Notice that just like the
-@code{section} attribute, @code{progmem} affects the location
-of the data but not how this data is accessed.
+but adds additional checking.
+@table @asis
+@item @bullet{}@tie{} Ordinary AVR cores with 32 general purpose registers:
+@code{progmem} affects the location
+of the data but not how this data is accessed.
In order to read data located with the @code{progmem} attribute
(inline) assembler must be used.
@smallexample
@@ -5873,6 +5875,13 @@ normally resides in the data memory (RAM
See also the @ref{AVR Named Address Spaces} section for
an alternate way to locate and access data in flash memory.
+@item @bullet{}@tie{}Reduced AVR Tiny cores like ATtiny40:
+The compiler adds @code{0x4000}
+to the addresses of objects in @code{progmem}. This is needed because the
+flash is visible in the RAM address space starting at address @code{0x4000}.
+Data in @code{progmem} can be accessed by means of ordinary C@tie{}code.
+@end table
+
@item io
@itemx io (@var{addr})
@cindex @code{io} variable attribute, AVR
#ifdef __AVR_TINY__
#define PM __attribute__((__progmem__))
#else
/* On general core, just resort to vanilla C. */
#define PM /* Empty */
#endif
const volatile int data[] PM = { 1234, 5678 };
const volatile int * volatile pdata = &data[1];
int ram[2];
__attribute__((noinline,noclone))
int const volatile* get_addr_1 (void)
{
return &data[1];
}
__attribute__((noinline,noclone))
int const volatile* get_addr_x (int x)
{
return &data[x];
}
void test_1 (void)
{
if (data[0] != 1234)
__builtin_abort();
if (data[1] != 5678)
__builtin_abort();
}
void test_2 (void)
{
if (data[1] != 5678)
__builtin_abort();
}
void test_3 (void)
{
if (&data[1] != pdata)
__builtin_abort();
}
void test_4 (void)
{
if (5678 != *get_addr_1())
__builtin_abort();
if (5678 != *get_addr_x(1))
__builtin_abort();
}
void test_5 (void)
{
__builtin_memcpy (&ram, (void*) &data, 4);
if (ram[0] - ram[1] != 1234 - 5678)
__builtin_abort();
}
int main()
{
test_1();
test_2();
test_3();
test_4();
test_5();
return 0;
}
_______________________________________________
AVR-GCC-list mailing list
AVR-GCC-list@nongnu.org
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list