Showing results for 
Search instead for 
Did you mean: 
Honored Contributor I

How do I get smallest NIOS2 code footprint possible?



I am trying to shrink my NIOS2 boot code to as small as possible so that it takes up the minimum amount of on-board RAM possible. 


I have disabled all possible drivers in the BSP editor and have enabled the small C library. 


When I write the following program: 


while( 1 ) 



the code footprint is still around 3kB. 


I understand that the CRT will take up a little space, but the objdump shows that I'm linking in, among other things, "alt_release_fd, close, _do_ctors, _do_dtors, alt_get_errno, and various other seemingly irrelevant pieces of code". 


Is there a way to get rid of these bits of code that I don't really need? Can I build code without the HAL? 


Thank you 

Scott Wild
0 Kudos
5 Replies
Honored Contributor I

You can write code without the majority of the HAL. 


The boot sequence is that a small assembler stub sets up the cache and clears BSS, then it calls alt_main which sets up the drivers and calls main. 


If you write your own version of alt_main then you can exclude all the functions you mention above. Of course a number of things won't work (like printf) but if you don't need them then that's no loss. 


Replacing the assembler code at the reset vector is possible too, but probably won't gain you anything as you would have to write code to do the same thing.
Honored Contributor I

In the past I removed a lot of that crud (WTF does it call close() when main returns!) by renaming my function alt_main() instead of main() - since a lot of the code that faffed about with libc setup/teardown for stdio was in alt_main(). 


But in the end I gave up and used completely custom linker scripts and my own code at the reset vector. You only need about 4 instructions before jumping into C. 


Since I don't use interrupts for anything (the code's main loop polls the hardware registers), the only interrupt/exception entries are fatal traps - so the execption code dumps all the registers into a 'save area' and leaves the system in a state where outside code can read memory (in my case the nios writes to a pio location that puts itself into reset!)
Honored Contributor I

Take a look at the small hello world C example at NIOS 2 EDS, My code has 900 bytes and does several things.. 

Also disable some startup crap, some stuff that checks if u initialized and finished, etc. on BSP Editor
Honored Contributor I

For overhead, I have: 

5 instructions at the reset vector (followed by 12 bytes pad) - these set %gp, %sp and %et then jump to the C. 

38 instructions at the exception vector to save all the registers (relative to %et), generate an external interrupt and loopstop. 

8 instructions in the C prologue that save registers in a stack frame - I didn't manage to persuade gcc not to do this [1] - even though the function has no epilogue (to reverse the prologue). 

This means my C starts at offset 0xdc in the code memory block. 


The 2.5k of code does multichannel hdlc (including bitstuffing - 6.5k of lookup table) aggredate 4Mbps. A second nios with a massive 7.5k code handles the timers and retransmittions and the interface to the outside world. 


[1] I didn't try that hard! If I'd managed to, there'd be no references to %sp in the assembler, so I could (in theory) have told gcc -fcall-used-sp and generated another free register. Letting it have %bt, %ba, %r1 (never ever used) and %ta (I don't return from traps) as extra registers would be easier, but I managed to adjust the C to avoid any on-stack variables without doing so.
Honored Contributor I

Thanks for the help guys. 


My code footprint is much smaller now.