Is it possible to select a memory region for specific global (RW or RO) variables?This would be different from the usual region for the RW/RO data. Effectively I need the loader to copy from the image to multiple locations. Ideally I would like to do this via a C code pragma or attribute directly in the C code, but a linker script or similar would also be a possibility.
Sure, you can use the attribute directive.For example: int Var1 _attribute__ (section (".mem_data")); int Var2; This would place the Var1 in the specified memory section, while Var2 is still in the default memory region. The same method applies to functions.
Fantastic thanks! Judging from other similar threads, and the fact that Nios uses a global pointer register I was losing hope.Presumable the address calculation for such global data make take a couple of instructions if it cannot be reached from the GP + immediate offset.
The compiler uses gp relative addressing for data items in the .sdata.* (etc) sections (small data section). As well as the immediate reduction in code size, using gp relative addressing significantly reduces the register pressure on the compiler - making it much less likely that other variables will have to be spilled to the stack.IIRC, by default the compiler puts anything 8 bytes or smaller into the 'small' section. For external data the actual data must be in the small data segment if any of the external references are (otherwise the linker gives a 'relocation won't fit' error). For some reason Altera changed things between gcc3 and gcc4 so that external items are never (in ggc4) assigned to the sdata segment. Another problem with multiple segments is that (last time I looked at least) the linker script puts the their initialisation data immediately following the .code, and adds code to copy them to the required place. This is all hopeless when your code is a small tightly coupled memory block. There are also some issues with GP relative addressing, the altera build won't ever us it for 'symbol + constant' - eg if you put a 'struct' in the sdata segment. There are fixes for that on the wiki. It can also be worth assigning a 'global register variable' to base of a large struct that contains (up to 32k) of variables. The compiler will actually generate better code for this than the GP relative addressing used for 'small' data items. (The small data code uses the gcc feature designed for 'page 0' addresses - so gcc doesn't know there is a register involved, so array accesses (in particular) could be optimised further.) The other Altera gcc4 fubar is that they forced switch statement jump tables into the .code segment rather than using a .rodata segment. If you have tightly coupled code and data you need to link the .rodata with the .data, not the .code. If you boot method doesn't need it, you don't need read/write access to code memory (and it would be horribly slow as well).
--- Quote Start --- Another problem with multiple segments is that (last time I looked at least) the linker script puts the their initialisation data immediately following the .code, and adds code to copy them to the required place. This is all hopeless when your code is a small tightly coupled memory block. --- Quote End --- That's not a problem - for reliability I need to keep the complete image including all initialised data in the code ITCM, and write protect it so that there is no chance that the image can be corrupted by a rogue pointer access. What I want is to locate some const structures to a specific TCM for use by a DMA engine. The BSP settings allow you to select whether the .rodata and .rwdata sections are copied into their runtime location. If I create a new section, how can I get the crt to also copy this into place? --- Quote Start --- It can also be worth assigning a 'global register variable' to base of a large struct that contains (up to 32k) of variables. The compiler will actually generate better code for this than the GP relative addressing used for 'small' data items. --- Quote End --- Thanks, that is very useful to know.
I had a problem because I have 12k of lookup table that needed to go into a specific memory block (tightly coupled to the 2nd cpu) but the code area is only 8k. I didn't want to 'waste' internal memory just for the boot code.However, since I was only using the IDE for some experiments (testing custom instructions) I didn't look too hard. I'd discovered the linking mess earlier and used my own linker script. You could just force the initialisation data into the code segment, and copy it yourself. Or look at what generates alt_main() - I think that is where the copies get done - and get the extra copies added there.