===================================================================
@@ -26,7 +26,7 @@
#include "c-family/c-common.h"
#include "stor-layout.h"
#include "langhooks.h"
-
+#include "tm_p.h"
/* IDs for all the AVR builtins. */
@@ -253,7 +253,10 @@ avr_register_target_pragmas (void)
gcc_assert (ADDR_SPACE_GENERIC == ADDR_SPACE_RAM);
/* Register address spaces. The order must be the same as in the respective
- enum from avr.h (or designated initializers must be used in avr.c). */
+ enum from avr.h (or designated initializers must be used in avr.c).
+ We always register all address spaces even if some of them make no
+ sense for some targets. Diagnose for non-supported spaces will be
+ emit by TARGET_ADDR_SPACE_DIAGNOSE_USAGE. */
for (i = 0; i < ADDR_SPACE_COUNT; i++)
{
@@ -293,7 +296,7 @@ avr_cpu_cpp_builtins (struct cpp_reader
builtin_define_std ("AVR");
/* __AVR_DEVICE_NAME__ and avr_mcu_types[].macro like __AVR_ATmega8__
- are defined by -D command option, see device-specs file. */
+ are defined by -D command option, see device-specs file. */
if (avr_arch->macro)
cpp_define_formatted (pfile, "__AVR_ARCH__=%s", avr_arch->macro);
@@ -334,7 +337,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)
@@ -391,10 +395,7 @@ /* Define builtin macros so that the use
/* Only supply __FLASH<n> macro if the address space is reasonable
for this target. The address space qualifier itself is still
supported, but using it will throw an error. */
- && avr_addrspace[i].segment < avr_n_flash
- /* Only support __MEMX macro if we have LPM. */
- && (AVR_HAVE_LPM || avr_addrspace[i].pointer_size <= 2))
-
+ && avr_addr_space_supported_p ((addr_space_t) i))
{
const char *name = avr_addrspace[i].name;
char *Name = (char*) alloca (1 + strlen (name));
===================================================================
@@ -37,6 +37,7 @@ extern void avr_asm_output_aligned_decl_
extern void avr_asm_asm_output_aligned_bss (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int, void (*) (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int));
extern void asm_output_external (FILE *file, tree decl, char *name);
extern int avr_progmem_p (tree decl, tree attributes);
+extern bool avr_addr_space_supported_p (addr_space_t, location_t loc = UNKNOWN_LOCATION);
#ifdef RTX_CODE /* inside TREE_CODE */
extern void avr_init_cumulative_args (CUMULATIVE_ARGS*, tree, rtx, tree);
===================================================================
@@ -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,35 @@ cond_string (enum rtx_code code)
}
+/* Return true if rtx X is a CONST or SYMBOL_REF with progmem.
+ This must be used for AVR_TINY only because on other cores
+ the flash memory is not visible in the RAM address range and
+ cannot be read by, say, LD instruction. */
+
+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 +8936,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);
}
@@ -9120,6 +9153,42 @@ avr_attribute_table[] =
};
+/* Return true if we support address space AS for the architecture in effect
+ and false, otherwise. If LOC is not UNKNOWN_LOCATION then also issue
+ a respective error. */
+
+bool
+avr_addr_space_supported_p (addr_space_t as, location_t loc)
+{
+ if (AVR_TINY)
+ {
+ if (loc != UNKNOWN_LOCATION)
+ error_at (loc, "address spaces are not supported for reduced "
+ "Tiny devices");
+ return false;
+ }
+ else if (avr_addrspace[as].segment >= avr_n_flash)
+ {
+ if (loc != UNKNOWN_LOCATION)
+ error_at (loc, "address space %qs not supported for devices with "
+ "flash size up to %d KiB", avr_addrspace[as].name,
+ 64 * avr_n_flash);
+ return false;
+ }
+
+ return true;
+}
+
+
+/* Implement `TARGET_ADDR_SPACE_DIAGNOSE_USAGE'. */
+
+static bool
+avr_addr_space_diagnose_usage (addr_space_t as, location_t loc)
+{
+ return !avr_addr_space_supported_p (as, loc);
+}
+
+
/* Look if DECL shall be placed in program memory space by
means of attribute `progmem' or some address-space qualifier.
Return non-zero if DECL is data that must end up in Flash and
@@ -9190,16 +9259,13 @@ avr_nonconst_pointer_addrspace (tree typ
while (TREE_CODE (target) == ARRAY_TYPE)
target = TREE_TYPE (target);
- /* Pointers to non-generic address space must be const.
- Refuse address spaces outside the device's flash. */
+ /* Pointers to non-generic address space must be const. */
as = TYPE_ADDR_SPACE (target);
if (!ADDR_SPACE_GENERIC_P (as)
- && (!TYPE_READONLY (target)
- || avr_addrspace[as].segment >= avr_n_flash
- /* Also refuse __memx address space if we can't support it. */
- || (!AVR_HAVE_LPM && avr_addrspace[as].pointer_size > 2)))
+ && !TYPE_READONLY (target)
+ && avr_addr_space_supported_p (as))
{
return as;
}
@@ -9263,25 +9329,13 @@ avr_pgm_check_var_decl (tree node)
if (reason)
{
- if (avr_addrspace[as].segment >= avr_n_flash)
- {
- if (TYPE_P (node))
- error ("%qT uses address space %qs beyond flash of %d KiB",
- node, avr_addrspace[as].name, 64 * avr_n_flash);
- else
- error ("%s %q+D uses address space %qs beyond flash of %d KiB",
- reason, node, avr_addrspace[as].name, 64 * avr_n_flash);
- }
- else
- {
- if (TYPE_P (node))
- error ("pointer targeting address space %qs must be const in %qT",
- avr_addrspace[as].name, node);
- else
- error ("pointer targeting address space %qs must be const"
- " in %s %q+D",
- avr_addrspace[as].name, reason, node);
- }
+ if (TYPE_P (node))
+ error ("pointer targeting address space %qs must be const in %qT",
+ avr_addrspace[as].name, node);
+ else
+ error ("pointer targeting address space %qs must be const"
+ " in %s %q+D",
+ avr_addrspace[as].name, reason, node);
}
return reason == NULL;
@@ -9314,18 +9368,6 @@ avr_insert_attributes (tree node, tree *
as = TYPE_ADDR_SPACE (TREE_TYPE (node));
- if (avr_addrspace[as].segment >= avr_n_flash)
- {
- error ("variable %q+D located in address space %qs beyond flash "
- "of %d KiB", node, avr_addrspace[as].name, 64 * avr_n_flash);
- }
- else if (!AVR_HAVE_LPM && avr_addrspace[as].pointer_size > 2)
- {
- error ("variable %q+D located in address space %qs"
- " which is not supported for architecture %qs",
- node, avr_addrspace[as].name, avr_arch->name);
- }
-
if (!TYPE_READONLY (node0)
&& !TREE_READONLY (node))
{
@@ -9566,7 +9608,7 @@ avr_encode_section_info (tree decl, rtx
if (decl && DECL_P (decl)
&& TREE_CODE (decl) != FUNCTION_DECL
&& MEM_P (rtl)
- && SYMBOL_REF == GET_CODE (XEXP (rtl, 0)))
+ && SYMBOL_REF_P (XEXP (rtl, 0)))
{
rtx sym = XEXP (rtl, 0);
tree type = TREE_TYPE (decl);
@@ -9579,7 +9621,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 +9653,19 @@ 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)))
+ {
+ /* Tag symbols for later addition of 0x4000 (AVR_TINY_PM_OFFSET). */
+
+ rtx sym = XEXP (rtl, 0);
+ SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM;
+ }
}
@@ -13698,6 +13754,9 @@ avr_fold_builtin (tree fndecl, int n_arg
#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS avr_addr_space_legitimize_address
+#undef TARGET_ADDR_SPACE_DIAGNOSE_USAGE
+#define TARGET_ADDR_SPACE_DIAGNOSE_USAGE avr_addr_space_diagnose_usage
+
#undef TARGET_MODE_DEPENDENT_ADDRESS_P
#define TARGET_MODE_DEPENDENT_ADDRESS_P avr_mode_dependent_address_p
===================================================================
@@ -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.
===================================================================
@@ -1422,6 +1422,11 @@ const __memx void *pfoo = &foo;
Such code requires at least binutils 2.23, see
@w{@uref{http://sourceware.org/PR13503,PR13503}}.
+@item
+On the reduced Tiny devices like ATtiny40, no address spaces are supported.
+Data can be put into and read from flash memory by means of
+attribute @code{progmem}, see @ref{AVR Variable Attributes}.
+
@end itemize
@subsection M32C Named Address Spaces
@@ -5847,10 +5852,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 +5880,28 @@ 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 and declarations in @code{progmem} and locates
+the objects in flash memory, namely in section @code{.progmem.data}.
+The offset is needed because the flash memory 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,
+no special functions or macros are needed.
+
+@smallexample
+/* var is located in flash memory */
+extern const int var[2] __attribute__((progmem));
+
+int read_var (int i)
+@{
+ return var[i];
+@}
+@end smallexample
+
+@end table
+
@item io
@itemx io (@var{addr})
@cindex @code{io} variable attribute, AVR
===================================================================
@@ -0,0 +1,109 @@
+/* { dg-do run } */
+/* { dg-options "-Wl,--defsym,test6_xdata=0" } */
+
+#ifdef __AVR_TINY__
+#define PM __attribute__((__progmem__))
+#else
+/* On general core, just resort to vanilla C. */
+#define PM /* Empty */
+#endif
+
+#define PSTR(s) (__extension__({ static const char __c[] PM = (s); &__c[0];}))
+
+#define NI __attribute__((noinline,noclone))
+
+const volatile int data[] PM = { 1234, 5678 };
+const volatile int * volatile pdata = &data[1];
+
+int ram[2];
+
+const int myvar PM = 42;
+extern const int xvar __asm ("myvar") PM;
+
+NI int const volatile* get_addr_1 (void)
+{
+ return &data[1];
+}
+
+NI 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();
+}
+
+const char pmSTR[] PM = "01234";
+
+NI const char* get_pmSTR (int i)
+{
+ return pmSTR + 2 + i;
+}
+
+void test_6 (void)
+{
+#ifdef __AVR_TINY__
+ extern const int test6_xdata PM;
+ const char* str = PSTR ("Hallo");
+ if (0 == (__AVR_TINY_PM_BASE_ADDRESS__ & (__UINTPTR_TYPE__) str))
+ __builtin_abort();
+ if (0 == (__AVR_TINY_PM_BASE_ADDRESS__ & (__UINTPTR_TYPE__) test6_xdata))
+ __builtin_abort();
+#endif
+
+ if (get_pmSTR (0)[0] != '0' + 2)
+ __builtin_abort();
+ if (get_pmSTR (1)[0] != '1' + 2)
+ __builtin_abort();
+}
+
+void test_7 (void)
+{
+ if (xvar != 42)
+ __builtin_abort();
+}
+
+int main()
+{
+ test_1();
+ test_2();
+ test_3();
+ test_4();
+ test_5();
+ test_6();
+ test_7();
+ return 0;
+}