I run code that is compiled as a single compilation unit, and with all the functions inlined (they are small, or only called once). This helps the compiler never have to save any local variables (or other temporaries) on the stack.
Using 'global pointer' relative addressing for all the main data and io (the 64k range covers 48k for 'memory' and 16k or 'io') also removes a lot of register pressure, cuts down code size and makes the code faster.
I did have to fix gcc so the compiler would use gp relative addressing for structure members.
Apart from working out how to get the jtag debugger (etc) to load the code, it is probably easier to do everything outside the IDE where you aren't constrained by what the IDE writers assume you want to do - which seems to be 'run the tuturial'.
Maybe I should find time to put a minmal linker script on the wiki!
This one might work - not sure if it assigns all the required sections though.
Most of the lines save all the registers on any interrupt.
/* Minimal linker script for a Nios cpu tightly coupled memory
*
* The SDRAM is mapped at it's own boundary (16M-32M) in spite of
* a probably splurious warning from the SOPC builder.
*/
OUTPUT_FORMAT("elf32-littlenios2")
OUTPUT_ARCH(nios2)
/* Address of some io */
io_base = 0x20000;
MEMORY
{
nios_code (x) : ORIGIN = 0x8000, LENGTH = 8k
nois_data (rw) : ORIGIN = 0x14000, LENGTH = 12k
sdram (rw) : ORIGIN = 16M, LENGTH = 16M
}
/* The nios_data memory (and some io) is accessible from %gp */
_gp = 128k - 16k;
/* Constants for building instructions by hand */
RA_SHIFT = 32 - 5;
RB_SHIFT = RA_SHIFT - 5;
RC_SHIFT = RB_SHIFT - 5;
OP_SHIFT = RC_SHIFT - 6;
IMM16_SHIFT = 6;
/* Instuctions to set %gp */
SET_GP_HI = 0 << RA_SHIFT | 26 << RB_SHIFT | ((_gp + 32768) >> 16) << IMM16_SHIFT | 0x34;
SET_GP_LO = 26 << RA_SHIFT | 26 << RB_SHIFT | (_gp & 0xffff) << IMM16_SHIFT | 0x4;
/* addi instructions to set %sp and %et from %gp (IMM16 offset added later) */
SET_SP = 26 << RA_SHIFT | 27 << RB_SHIFT | 0x4;
SET_ET = 26 << RA_SHIFT | 24 << RB_SHIFT | 0x4;
SECTIONS
{
/* code */
nios_code : {
LONG(SET_GP_HI)
LONG(SET_GP_LO)
LONG(SET_SP | ((nios_stack_top - _gp) & 0xffff) << IMM16_SHIFT)
LONG(SET_ET | ((nios_reg_save - _gp) & 0xffff) << IMM16_SHIFT)
LONG(c_main << 4 | 1) /* jmpi c_main */
. = 0x20;
/* Save all registers in area addressed by 'et' (base memory area) */
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 0) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 1) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 2) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 3) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 4) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 5) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 6) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 7) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 8) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 9) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 10) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 11) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 12) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 13) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 14) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 15) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 16) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 17) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 18) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 19) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 20) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 21) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 22) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 23) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 24) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 25) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 26) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 27) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 28) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 29) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 30) | 0x15)
LONG(24 << RA_SHIFT | ((1 << RB_SHIFT | 4 << IMM16_SHIFT) * 31) | 0x15)
/* Save control registers 7 (exception cause) and 12 (badaddr) via r2
* as registers 32 and 33. */
LONG(2 << RC_SHIFT | 0x26 << OP_SHIFT | 7 << IMM16_SHIFT | 0x3a)
LONG(24 << RA_SHIFT | 2 << RB_SHIFT | (4 * 32) << IMM16_SHIFT | 0x15)
LONG(2 << RC_SHIFT | 0x26 << OP_SHIFT | 12 << IMM16_SHIFT | 0x3a)
LONG(24 << RA_SHIFT | 2 << RB_SHIFT | (4 * 33) << IMM16_SHIFT | 0x15)
LONG(. << 4 | 1) /* loopstop */
*(.code*)
} >nios_code
/* Some 'tightly coupled data memory' */
nios_data : {
nios_reg_save = .;
. = . + 256;
nios_stack_top = .;
*(.sdata*)
*(.data*)
*(.rodata)
} >nios_data
sdram : {
*(.bss.sdram)
} >sdram
.comment 0 : { *(.comment) }
/* Anything from any unexpected section ends up here and
* generates an error because this overlaps another section */
unwanted _gp : { *(*) }
}