Making better use of virtual addresses

Georg-Johann Lay <[email protected]> Fri, 18 Nov 2016 12:16:55 +0100
Newsgroups gmane.comp.hardware.avr.gcc
Message-ID <[email protected]>
Some of the more recent avr devices support reading from flash by LD 
instructions.  The flash memory can be accessed by a virtual address 
(VMA) which is offset by a specific value from the load address (LMA).

For example, on ATtiny40 (a reduced Tiny with only 16 GPRs) the offset 
is 0x4000, and on ATtiny817 (a recent Tiny) the offset is 0x8000.

The ATtiny40 doesn't even support LPM so that using the VMA RAM address 
is the only way to read data from flash.

Unfortunately, the linker description files don't reflect this feature, 
and .rodata is still located in RAM.  The situation is treated as always 
by putting read-only data into .progmem.  Since avr-gcc v7, the compiler 
adds an offset of 0x4000 to all symbol values, so that no special 
functions are needed to access progmem data.

A much better and simpler solution would be to remove .rodata from RAM 
and put it into flash by means of an appropriate linker description file 
avrtiny.x like so:


   .text :
   {
     ...
   }  > text
   .rodata ADDR(.text) + SIZEOF (.text) + __RODATA_PM_OFFSET__ :
   {
     *(.rodata)
     *(.rodata*)
     *(.gnu.linkonce.r*)
   }  AT> text
   .data :
   {
      PROVIDE (__data_start = .) ;
     *(.data)
     *(.data*)
     *(.gnu.linkonce.d*)
     . = ALIGN(2);
      _edata = . ;
      PROVIDE (__data_end = .) ;
   }  > data AT> text
   ...

The pm offset could be hard coded or provided by the linker script, or 
even be provided by a command option like --def-sym.  In my example, 
it's defined in the ld script:

__RODATA_PM_OFFSET__ = DEFINED(__RODATA_PM_OFFSET__) ? 
__RODATA_PM_OFFSET__ : 0x4000;


All this is completely transparent to the C code and to the compiler: 
Just avoid the progmem stuff and write plain vanilla C!

Only the handling of -mabsdata, which is a new option in avr-gcc v7 to 
support LDS / STS on reduced Tiny, has to be more conservative and 
reject LDS / STS for objects in .rodata.

For "classical" devices like ATtiny817 (not yet supported) such 
restrictions to LDS / STS don't apply because they can address the full 
16-bit range of (virtual) RAM addresses.

What's even better, on ATtiny817 the whole memory is linearised, and it 
also provides virtual addresses for EEPROM (0x1400), Flash (0x8000) and 
RAM (0x3e00, 0x3f00 for smaller devices like ATtiny417).

Are there plans to change the ld scripts to accommodate this address layout?

Are there plans to support ATtiny416/417/816/816?

Johann


Attached is a delta against avrtiny.x which I used to play with ATtiny40.

_______________________________________________
AVR-GCC-list mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
avrtiny.x.diff (text/x-patch, 1.1 KB)
diff --git a/avrtiny.x b/avrtiny.x
index 75c5892..89b02c3 100644
--- a/avrtiny.x
+++ b/avrtiny.x
@@ -10,6 +10,7 @@ __DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH_
 __FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 2;
 __LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 2;
 __SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 4;
+__RODATA_PM_OFFSET__ = DEFINED(__RODATA_PM_OFFSET__) ? __RODATA_PM_OFFSET__ : 0x4000;
 MEMORY
 {
   text   (rx)   : ORIGIN = 0x0, LENGTH = __TEXT_REGION_LENGTH__
@@ -162,13 +163,17 @@ SECTIONS
     KEEP (*(.fini0))
      _etext = . ;
   }  > text
+  .rodata ADDR(.text) + SIZEOF (.text) + __RODATA_PM_OFFSET__ :
+  {
+    *(.rodata)
+    *(.rodata*)
+    *(.gnu.linkonce.r*)
+  }  AT> text
   .data          :
   {
      PROVIDE (__data_start = .) ;
     *(.data)
      *(.data*)
-    *(.rodata)  /* We need to include .rodata here if gcc is used */
-     *(.rodata*) /* with -fdata-sections.  */
     *(.gnu.linkonce.d*)
     . = ALIGN(2);
      _edata = . ;