Skip to content

Commit ef6a786

Browse files
Store constant tables in PROGMEM on AVR
When compiling for an Arduino Uno, this saves 4546 bytes of RAM (5860 -> 1214) at the expense of 302 additional bytes of code. Most of this additional code is used by the AES implementation, probably because the use of special PROGMEM loading instructions reduces the optimization's freedom with regard to instruction ordering and register assignment.
1 parent acb75c5 commit ef6a786

File tree

1 file changed

+37
-10
lines changed

1 file changed

+37
-10
lines changed

src/lmic/oslmic.h

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,16 +222,43 @@ u2_t os_crc16 (xref2u1_t d, uint len);
222222
#define TABLE_GET_OSTIME(table, index) table_get_ostime(RESOLVE_TABLE(table), index)
223223
#define TABLE_GET_U1_TWODIM(table, index1, index2) table_get_u1(RESOLVE_TABLE(table)[index1], index2)
224224

225-
inline u1_t table_get_u1(const u1_t *table, size_t index) { return table[index]; }
226-
inline s1_t table_get_s1(const s1_t *table, size_t index) { return table[index]; }
227-
inline u2_t table_get_u2(const u2_t *table, size_t index) { return table[index]; }
228-
inline s2_t table_get_s2(const s2_t *table, size_t index) { return table[index]; }
229-
inline u4_t table_get_u4(const u4_t *table, size_t index) { return table[index]; }
230-
inline s4_t table_get_s4(const s4_t *table, size_t index) { return table[index]; }
231-
inline ostime_t table_get_ostime(const ostime_t *table, size_t index) { return table[index]; }
232-
233-
// Declare a table
234-
#define CONST_TABLE(type, name) const type RESOLVE_TABLE(name)
225+
#if defined(__AVR__)
226+
#include <avr/pgmspace.h>
227+
// Macro to define the getter functions. This loads data from
228+
// progmem using pgm_read_xx, or accesses memory directly when the
229+
// index is a constant so gcc can optimize it away;
230+
#define TABLE_GETTER(postfix, type, pgm_type) \
231+
inline type table_get ## postfix(const type *table, size_t index) { \
232+
if (__builtin_constant_p(table[index])) \
233+
return table[index]; \
234+
return pgm_read_ ## pgm_type(&table[index]); \
235+
}
236+
237+
TABLE_GETTER(_u1, u1_t, byte);
238+
TABLE_GETTER(_s1, s1_t, byte);
239+
TABLE_GETTER(_u2, u2_t, word);
240+
TABLE_GETTER(_s2, s2_t, word);
241+
TABLE_GETTER(_u4, u4_t, dword);
242+
TABLE_GETTER(_s4, s4_t, dword);
243+
244+
// This assumes ostime_t is 4 bytes, so error out if it is not
245+
typedef int check_sizeof_ostime_t[(sizeof(ostime_t) == 4) ? 0 : -1];
246+
TABLE_GETTER(_ostime, ostime_t, dword);
247+
248+
// For AVR, store constants in PROGMEM, saving on RAM usage
249+
#define CONST_TABLE(type, name) const type PROGMEM RESOLVE_TABLE(name)
250+
#else
251+
inline u1_t table_get_u1(const u1_t *table, size_t index) { return table[index]; }
252+
inline s1_t table_get_s1(const s1_t *table, size_t index) { return table[index]; }
253+
inline u2_t table_get_u2(const u2_t *table, size_t index) { return table[index]; }
254+
inline s2_t table_get_s2(const s2_t *table, size_t index) { return table[index]; }
255+
inline u4_t table_get_u4(const u4_t *table, size_t index) { return table[index]; }
256+
inline s4_t table_get_s4(const s4_t *table, size_t index) { return table[index]; }
257+
inline ostime_t table_get_ostime(const ostime_t *table, size_t index) { return table[index]; }
258+
259+
// Declare a table
260+
#define CONST_TABLE(type, name) const type RESOLVE_TABLE(name)
261+
#endif
235262

236263
// ======================================================================
237264
// AES support

0 commit comments

Comments
 (0)