Index: apps/main.c =================================================================== --- apps/main.c (revision 31189) +++ apps/main.c (working copy) @@ -155,7 +155,11 @@ { sys_handle_argv(argc, argv); #else -int main(void) INIT_ATTR MAIN_NORETURN_ATTR; +int main(void) +#if (CONFIG_CODEC == SWCODEC) || !defined(HAVE_INIT_ATTR) + INIT_ATTR +#endif + MAIN_NORETURN_ATTR; int main(void) { #endif @@ -198,6 +202,9 @@ global_status.last_volume_change = 0; /* no calls INIT_ATTR functions after this point anymore! * see definition of INIT_ATTR in config.h */ +#if (CONFIG_CODEC != SWCODEC) && defined(HAVE_INIT_ATTR) + core_free_init_section(); +#endif CHART(">root_menu"); root_menu(); } Index: firmware/include/core_alloc.h =================================================================== --- firmware/include/core_alloc.h (revision 31189) +++ firmware/include/core_alloc.h (working copy) @@ -44,4 +44,8 @@ return buflib_get_name(&core_ctx, handle); } +#if (CONFIG_CODEC != SWCODEC) && defined(HAVE_INIT_ATTR) +void core_free_init_section(void); +#endif + #endif /* __CORE_ALLOC_H__ */ Index: firmware/target/sh/archos/audio-archos.c =================================================================== --- firmware/target/sh/archos/audio-archos.c (revision 31189) +++ firmware/target/sh/archos/audio-archos.c (working copy) @@ -70,6 +70,7 @@ unsigned long mas_version_code; #if CONFIG_CODEC == MAS3507D +static void mas_poll_start(void) INIT_ATTR; static void mas_poll_start(void) { unsigned int count; @@ -215,6 +216,7 @@ } #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ +static void setup_sci0(void) INIT_ATTR; static void setup_sci0(void) { /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */ Index: firmware/target/sh/archos/app.lds =================================================================== --- firmware/target/sh/archos/app.lds (revision 31189) +++ firmware/target/sh/archos/app.lds (working copy) @@ -87,10 +87,16 @@ *(.irodata) *(.idata) _iramend = .; + . = ALIGN(0x4); } > IRAM AT> DRAM _iramcopy = LOADADDR(.iram); _noloaddram = LOADADDR(.iram); +#ifdef HAVE_INIT_ATTR + /* .init is the last of the sections that get moved elsewhere. + It is copied to audiobuf by crt0.S */ + _initcopy = LOADADDR(.iram) + _iramend - _iramstart; +#endif .ibss (NOLOAD) : { @@ -99,7 +105,7 @@ . = ALIGN(0x4); _iend = .; } > IRAM - + .stack _noloaddram (NOLOAD) : { *(.stack) @@ -124,6 +130,16 @@ audiobuffer = .; } > DRAM +#ifdef HAVE_INIT_ATTR + .init : AT ( _initcopy ) + { + _initstart = .; + *(.init) + . = ALIGN(0x4); + _initend = .; + } > DRAM +#endif + .audiobufend ENDAUDIOADDR (NOLOAD) : { audiobufend = .; Index: firmware/target/sh/crt0.S =================================================================== --- firmware/target/sh/crt0.S (revision 31189) +++ firmware/target/sh/crt0.S (working copy) @@ -98,114 +98,106 @@ mov #0,r0 ldc r0,gbr - /* .iram copy is done first since it is reclaimed for other - * uninitialized sections */ + mova .sectioncopies,r0 + mov r0,r5 + mova .sectionfills,r0 - /* copy the .iram section */ - mov.l .iramcopy_k,r0 - mov.l .iram_k,r1 - mov.l .iramend_k,r2 - /* Note: We cannot put a PC relative load into the delay slot of a 'bra' - instruction (the offset would be wrong), but there is nothing else to - do before the loop, so the delay slot would be 'nop'. The cmp / bf - sequence is the same length, but more efficient. */ - cmp/hi r1,r2 - bf .noiramcopy -.iramloop: - mov.l @r0+,r3 - mov.l r3,@r1 - add #4,r1 - cmp/hi r1,r2 - bt .iramloop -.noiramcopy: + /* first, copy sections */ +.nextcopy: + mov.l @r5+,r1 /* source for copy */ + mov.l @r5+,r2 /* start of section at destination */ + mov.l @r5+,r3 /* end of section at destination */ - /* zero out .ibss */ - mov.l .iedata_k,r0 - mov.l .iend_k,r1 - bra .iedatastart - mov #0,r2 -.iedataloop: /* backwards is faster and shorter */ - mov.l r2,@-r1 -.iedatastart: - cmp/hi r0,r1 - bt .iedataloop + cmp/eq r1,r2 + bt .skipcopy /* if src == dest, no need to copy */ + + cmp/hi r2,r3 /* don't copy empty sections */ + bf .skipcopy - /* zero out bss */ - mov.l .edata_k,r0 - mov.l .end_k,r1 - bra .edatastart - mov #0,r2 -.edataloop: /* backwards is faster and shorter */ - mov.l r2,@-r1 -.edatastart: - cmp/hi r0,r1 - bt .edataloop +.copyloop: + mov.l @r1+,r4 + mov.l r4,@r2 + add #4,r2 + cmp/hi r2,r3 + bt .copyloop - /* copy the .data section, for rombased execution */ - mov.l .datacopy_k,r0 - mov.l .data_k,r1 - cmp/eq r0,r1 - bt .nodatacopy /* Don't copy if src and dest are equal */ - mov.l .dataend_k,r2 +.skipcopy: + cmp/hi r5,r0 + bt .nextcopy /* copy more sections until fills are reached */ + + /* now, fill sections */ + mova .fillsend,r0 + mov.l .deadbeef_k,r3 /* stack munging with 0xdeadbeef is first */ + +.nextfill: + mov.l @r5+,r1 /* start of section at destination */ + bra .fillsection + mov.l @r5+,r2 /* end of section at destination */ + +.fillloop: + mov.l r3,@-r2 /* backwards is faster and shorter */ +.fillsection: cmp/hi r1,r2 - bf .nodatacopy -.dataloop: - mov.l @r0+,r3 - mov.l r3,@r1 - add #4,r1 - cmp/hi r1,r2 - bt .dataloop -.nodatacopy: + bt .fillloop - /* Munge the main thread stack */ - mov.l .stackbegin_k,r0 - mov.l .stackend_k,r1 - mov r1,r15 - mov.l .deadbeef_k,r2 -.mungeloop: /* backwards is faster and shorter */ - mov.l r2,@-r1 - cmp/hi r0,r1 - bt .mungeloop - + mov #0,r3 /* rest of filling is with zeroes */ + cmp/hi r5,r0 + bt .nextfill /* stop at the end of the table */ + /* call the mainline */ mov.l .main_k,r0 + mov.l .stackend_k,r15 jsr @r0 nop .hoo: bra .hoo nop - .align 2 + .align 4 .vbr_k: .long vectors #ifdef DEBUG .orig_vbr_k: .long 0x09000000 #endif -.iedata_k: - .long _iedata -.iend_k: - .long _iend -.iramcopy_k: - .long _iramcopy -.iram_k: - .long _iramstart -.iramend_k: - .long _iramend -.edata_k: - .long _edata -.end_k: - .long _end -.datacopy_k: + + /* list of sections to copy + * first copy sections where the source may be overwritten */ +.sectioncopies: + /* copy the .iram section */ + .long _iramcopy /* start of section at source */ + .long _iramstart /* start of section at destination */ + .long _iramend /* end of section at destination */ + +#ifdef HAVE_INIT_ATTR + /* copy the .init section */ + .long _initcopy + .long _initstart + .long _initend +#endif + + /* copy the .data section (only needed for rom based execution) */ .long _datacopy -.data_k: .long _datastart -.dataend_k: .long _dataend -.stackbegin_k: + + /* list of sections to fill, must follow list of sections to copy */ + /* first fill uses 0xdeadbeef and rest use 0 */ +.sectionfills: + /* munge the main thread stack */ .long _stackbegin .stackend_k: .long _stackend + + /* zero out .ibss */ + .long _iedata + .long _iend + + /* zero out .bss */ + .long _edata + .long _end +.fillsend: /* end of list of sections to fill */ + .deadbeef_k: .long 0xdeadbeef .main_k: Index: firmware/export/mascodec.h =================================================================== --- firmware/export/mascodec.h (revision 31189) +++ firmware/export/mascodec.h (working copy) @@ -23,7 +23,7 @@ /* unused: int mas_default_read(unsigned short *buf); */ #if CONFIG_CODEC == MAS3507D -int mas_run(unsigned short address); +int mas_run(unsigned short address) INIT_ATTR; #endif int mas_readmem(int bank, int addr, unsigned long* dest, int len); int mas_writemem(int bank, int addr, const unsigned long* src, int len); @@ -34,7 +34,7 @@ int mas_direct_config_write(unsigned char reg, unsigned int val); int mas_codec_writereg(int reg, unsigned int val); int mas_codec_readreg(int reg); -unsigned long mas_readver(void); +unsigned long mas_readver(void) INIT_ATTR; #endif Index: firmware/export/mp3_playback.h =================================================================== --- firmware/export/mp3_playback.h (revision 31189) +++ firmware/export/mp3_playback.h (working copy) @@ -31,7 +31,7 @@ int avc, int channel_config, int stereo_width, int mdb_strength, int mdb_harmonics, int mdb_center, int mdb_shape, bool mdb_enable, - bool superbass); + bool superbass) INIT_ATTR; /* exported just for mpeg.c, to keep the recording there */ #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) Index: firmware/export/dac3550a.h =================================================================== --- firmware/export/dac3550a.h (revision 31189) +++ firmware/export/dac3550a.h (working copy) @@ -41,7 +41,7 @@ extern int dac_volume(unsigned int left, unsigned int right, bool deemph); extern void dac_enable(bool enable); extern void dac_line_in(bool enable); -extern void dac_init(void); +extern void dac_init(void) INIT_ATTR; #endif /* _DAC3550A_H_ */ Index: firmware/export/config.h =================================================================== --- firmware/export/config.h (revision 31189) +++ firmware/export/config.h (working copy) @@ -888,7 +888,7 @@ #endif #if (defined(CPU_PP) || (CONFIG_CPU == AS3525) || (CONFIG_CPU == AS3525v2) || \ - (CONFIG_CPU == IMX31L) || (CONFIG_CPU == IMX233)) \ + (CONFIG_CPU == IMX31L) || (CONFIG_CPU == IMX233) || defined(CPU_SH)) \ && (CONFIG_PLATFORM & PLATFORM_NATIVE) && !defined(BOOTLOADER) /* Functions that have INIT_ATTR attached are NOT guaranteed to survive after * root_menu() has been called. Their code may be overwritten by other data or Index: firmware/core_alloc.c =================================================================== --- firmware/core_alloc.c (revision 31189) +++ firmware/core_alloc.c (working copy) @@ -24,6 +24,14 @@ extern unsigned char *audiobufend; #endif +#if (CONFIG_CODEC != SWCODEC) && defined(HAVE_INIT_ATTR) +/* end of .init section, which may be in the buffer */ +extern unsigned char initend[]; + +/* size of space reserved for .init */ +static size_t init_allocation = 0; +#endif + /* debug test alloc */ static int test_alloc; void core_allocator_init(void) @@ -38,11 +46,32 @@ } #endif +#if (CONFIG_CODEC != SWCODEC) && defined(HAVE_INIT_ATTR) + /* if .init is in the buffer, initially only + * use buffer space after end of .init */ + if (initend > start && initend < audiobufend) { + unsigned char *new_start = ALIGN_UP(initend, sizeof(intptr_t)); + init_allocation = new_start - start; + start = new_start; + } +#endif + buflib_init(&core_ctx, start, audiobufend - start); test_alloc = core_alloc("test", 112); } +#if (CONFIG_CODEC != SWCODEC) && defined(HAVE_INIT_ATTR) +void core_free_init_section(void) +{ + if (init_allocation > 0) + { + buflib_buffer_in(&core_ctx, init_allocation); + init_allocation = 0; + } +} +#endif + bool core_test_free(void) { bool ret = test_alloc > 0; Index: firmware/rom.lds =================================================================== --- firmware/rom.lds (revision 31189) +++ firmware/rom.lds (working copy) @@ -105,6 +105,18 @@ . = ALIGN(0x4); } > FLASH +#ifdef HAVE_INIT_ATTR + .init : + { + _initstart = .; + *(.init) + . = ALIGN(0x4); + _initend = .; + } > FLASH + + _initcopy = LOADADDR(.init); +#endif + .rodata : { *(.rodata) Index: firmware/buflib.c =================================================================== --- firmware/buflib.c (revision 31189) +++ firmware/buflib.c (working copy) @@ -386,6 +386,24 @@ handle->alloc += shift; } +static void +merge_free_blocks(struct buflib_context *ctx, union buflib_data *block) +{ + union buflib_data *next_block; + next_block = block - block->val; + /* Check if we are merging with the free space at alloc_end. */ + if (next_block == ctx->alloc_end) + ctx->alloc_end = block; + /* Otherwise, the next block might still be a "normal" free block, and the + * mid-allocation free means that the buffer is no longer compact. + */ + else { + ctx->compact = false; + if (next_block->val < 0) + block->val += next_block->val; + } +} + /* Shift buffered items up by size bytes, or as many as possible if size == 0. * Set size to the number of bytes freed. */ @@ -408,12 +426,21 @@ return ret; } -/* Shift buffered items down by size bytes */ +/* Extend managed area by adding more space at the start. */ void buflib_buffer_in(struct buflib_context *ctx, int size) { + union buflib_data *block; + size /= sizeof(union buflib_data); - buflib_buffer_shift(ctx, -size); + + /* Move buf_start backwards and create a + * free block spanning the newly added area */ + ctx->buf_start -= size; + block = ctx->buf_start; + block->val = -size; + + merge_free_blocks(ctx, block); } /* Allocate a buffer of size bytes, returning a handle for it */ @@ -591,7 +618,7 @@ { union buflib_data *handle = ctx->handle_table - handle_num, *freed_block = handle_to_block(ctx, handle_num), - *block, *next_block; + *block; /* We need to find the block before the current one, to see if it is free * and can be merged with this one. */ @@ -609,18 +636,7 @@ block = freed_block; block->val = -block->val; } - next_block = block - block->val; - /* Check if we are merging with the free space at alloc_end. */ - if (next_block == ctx->alloc_end) - ctx->alloc_end = block; - /* Otherwise, the next block might still be a "normal" free block, and the - * mid-allocation free means that the buffer is no longer compact. - */ - else { - ctx->compact = false; - if (next_block->val < 0) - block->val += next_block->val; - } + merge_free_blocks(ctx, block); handle_free(ctx, handle); handle->alloc = NULL;