More pies

Friday, June 4, 2010

Low stack usage mod replacement

I was using an ATTiny2313 (128 bytes of ram) and started to run out of ram right at the end of a project and I was in a rush to finish (and didn’t want to buy more parts) so I thought I’s have a go at reducing ram usage.

First I tried building with O3, inline functions and packed structures. This didn’t gain me enough ram so I had a look at what nm said was going on in the binary. The one chunk of the output which stood out was the following.


0000072a T __divmodhi4
0000072a T _div
0000073e t __divmodhi4_neg2
00000744 t __divmodhi4_exit
00000746 t __divmodhi4_neg1
00000750 T __udivmodhi4
00000758 t __udivmodhi4_loop
00000766 t __udivmodhi4_ep

GCC was inserting a load of division routines into the code as the chip doesn’t have the hardware to do division. I wasn’t doing any division in my code as such but I was using the mod operator for calculations in a ring buffer implementation. These routines which were causing registers to be pushed onto the stack along with return addresses. One ISR was pushing 14 registers onto the stack (partly because of this) along with the return addresses for the division functions.

To reduce stack usage I created a replacement macro for doing mod operations to avoid having to use the built in functions. All values used are unsigned values. This would need to be adapted to work on signed values and only works in my implementation because a is guaranteed to be less than 2b.


#ifdef LSMOD
#define MOD(a,b) \
((a>=b) ? a-b : a)
#else
#define MOD(a,b) \
(a % b)
#endif

The resulting binary was a few bytes bigger (as it was output in multiple places unlike the function which was just called in multiple places) but only caused the ISR mentioned before to push 9 bytes onto the stack and it doesn’t call any other functions so no return addresses need to be stored.

posted by eaterofpies at 23:42  

Powered by WordPress