SWCODEC/IRAM: Save voice IRAM when a plugin initializes its IRAM. Defines two macros for declaring and initializing IRAM. Plugins should use these instead. See mp3_encoder, doom, etc. for details. Further tweaks in buffer restoration after other use. Hiding of some interfaces that should only be used by buffer management.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11544 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2006-11-18 02:18:29 +00:00
parent e2a262ee25
commit acc29d95be
15 changed files with 204 additions and 125 deletions

View File

@ -296,8 +296,8 @@ static unsigned char sim_iram[CODEC_IRAM_SIZE]; /* IRAM codec swap buffer for si
#define CODEC_IRAM_ORIGIN sim_iram
#endif
static unsigned char *iram_buf[2]; /* Ptr to IRAM buffers for normal/voice codecs */
static unsigned char *dram_buf[2]; /* Ptr to DRAM buffers for normal/voice codecs */
static unsigned char *iram_buf[2] = { NULL, NULL }; /* Ptr to IRAM buffers for normal/voice codecs */
static unsigned char *dram_buf[2] = { NULL, NULL }; /* Ptr to DRAM buffers for normal/voice codecs */
static struct mutex mutex_codecthread; /* Mutex to control which codec (normal/voice) is running */
/* Voice state */
@ -307,6 +307,10 @@ static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */
static char *voicebuf;
static size_t voice_remaining;
#ifdef IRAM_STEAL
static bool voice_iram_stolen = false; /* Voice IRAM has been stolen for other use */
#endif
static void (*voice_getmore)(unsigned char** start, int* size);
struct voice_info {
@ -318,15 +322,21 @@ static void voice_thread(void);
#endif /* PLAYBACK_VOICE */
/* --- Shared semi-private interfaces --- */
/* imported */
extern void talk_buffer_steal(void);
#ifdef HAVE_RECORDING
extern void pcm_rec_error_clear(void);
extern unsigned long pcm_rec_status(void);
#endif
/* --- External interfaces --- */
void mp3_play_data(const unsigned char* start, int size,
void (*get_more)(unsigned char** start, int* size))
{
/* must reset the buffer before any playback begins if needed */
if (buffer_state == BUFFER_STATE_TRASHED)
audio_reset_buffer(pcmbuf_get_bufsize());
#ifdef PLAYBACK_VOICE
static struct voice_info voice_clip;
voice_clip.callback = get_more;
@ -366,11 +376,20 @@ void mpeg_id3_options(bool _v1first)
unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
{
unsigned char *buf = audiobuf;
unsigned char *end = audiobufend;
unsigned char *buf, *end;
audio_stop();
if (buffer_size == NULL)
{
/* Special case for talk_init to use */
buffer_state = BUFFER_STATE_TRASHED;
return NULL;
}
buf = audiobuf;
end = audiobufend;
if (talk_buf || !talk_voice_required()
|| buffer_state == BUFFER_STATE_TRASHED)
{
@ -395,17 +414,57 @@ unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
return buf;
}
#ifdef IRAM_STEAL
void audio_iram_steal(void)
{
/* We need to stop audio playback in order to use codec IRAM */
audio_stop();
#ifdef PLAYBACK_VOICE
if (NULL != iram_buf[CODEC_IDX_VOICE])
{
/* Wait for voice to swap back in if current codec was audio */
while (current_codec != CODEC_IDX_VOICE)
yield();
voice_stop();
/* Save voice IRAM - safe to do here since state is known */
memcpy(iram_buf[CODEC_IDX_VOICE], (void *)CODEC_IRAM_ORIGIN,
CODEC_IRAM_SIZE);
voice_iram_stolen = true;
}
else
{
/* Nothing much to do if no voice */
voice_iram_stolen = false;
}
#endif
}
#endif /* IRAM_STEAL */
#ifdef HAVE_RECORDING
unsigned char *audio_get_recording_buffer(size_t *buffer_size)
{
/* don't allow overwrite of voice swap area or we'll trash the
swapped-out voice codec but can use whole thing if none */
unsigned char *end = iram_buf[CODEC_IDX_VOICE] ?
iram_buf[CODEC_IDX_VOICE] : audiobufend;
unsigned char *end;
audio_stop();
talk_buffer_steal();
#ifdef PLAYBACK_VOICE
#ifdef IRAM_STEAL
end = dram_buf[CODEC_IDX_VOICE] ?
dram_buf[CODEC_IDX_VOICE] : audiobufend;
#else
end = iram_buf[CODEC_IDX_VOICE] ?
iram_buf[CODEC_IDX_VOICE] : audiobufend;
#endif /* IRAM_STEAL */
#else
end = audiobufend;
#endif /* PLAYBACK_VOICE */
buffer_state = BUFFER_STATE_TRASHED;
*buffer_size = end - audiobuf;
@ -645,7 +704,6 @@ void audio_flush_and_reload_tracks(void)
void audio_error_clear(void)
{
#ifdef AUDIO_HAVE_RECORDING
extern void pcm_rec_error_clear(void);
pcm_rec_error_clear();
#endif
}
@ -662,7 +720,6 @@ int audio_status(void)
#ifdef HAVE_RECORDING
/* Do this here for constitency with mpeg.c version */
extern unsigned long pcm_rec_status(void);
ret |= pcm_rec_status();
#endif
@ -820,7 +877,6 @@ void voice_stop(void)
/* --- Routines called from multiple threads --- */
#ifdef PLAYBACK_VOICE
static void swap_codec(void)
{
@ -829,8 +885,26 @@ static void swap_codec(void)
logf("swapping out codec:%d", my_codec);
/* Save our current IRAM and DRAM */
#ifdef IRAM_STEAL
if (voice_iram_stolen)
{
logf("swap: iram restore");
voice_iram_stolen = false;
/* Don't swap trashed data into buffer - _should_ always be the case
if voice_iram_stolen is true since the voice has been swapped in
before hand */
if (my_codec == CODEC_IDX_VOICE)
goto skip_iram_swap;
}
#endif
memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN,
CODEC_IRAM_SIZE);
#ifdef IRAM_STEAL
skip_iram_swap:
#endif
memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE);
/* Release my semaphore */
@ -1085,6 +1159,21 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
{
/* Set up new voice data */
struct voice_info *voice_data;
#ifdef IRAM_STEAL
if (voice_iram_stolen)
{
logf("voice: iram restore");
memcpy((void*)CODEC_IRAM_ORIGIN,
iram_buf[CODEC_IDX_VOICE],
CODEC_IRAM_SIZE);
voice_iram_stolen = false;
}
#endif
/* must reset the buffer before any playback
begins if needed */
if (buffer_state == BUFFER_STATE_TRASHED)
audio_reset_buffer(pcmbuf_get_bufsize());
voice_is_playing = true;
trigger_cpu_boost();
voice_data = ev.data;
@ -2809,6 +2898,10 @@ static void audio_fill_file_buffer(
bool had_next_track = audio_next_track() != NULL;
bool continue_buffering;
/* must reset the buffer before use if trashed */
if (buffer_state != BUFFER_STATE_NORMAL)
audio_reset_buffer(pcmbuf_get_bufsize());
if (!audio_initialize_buffer_fill(!start_play))
return ;
@ -3156,10 +3249,6 @@ static void audio_play_start(size_t offset)
/* Wait for any previously playing audio to flush - TODO: Not necessary? */
audio_stop_codec_flush();
/* must reset the buffer before any playback begins if needed */
if (buffer_state != BUFFER_STATE_NORMAL)
audio_reset_buffer(pcmbuf_get_bufsize());
track_changed = true;
playlist_end = false;
@ -3272,14 +3361,34 @@ static void audio_reset_buffer(size_t pcmbufsize)
if (talk_voice_required())
{
#ifdef PLAYBACK_VOICE
#ifdef IRAM_STEAL
filebuflen -= CODEC_IRAM_SIZE + 2*CODEC_SIZE;
#else
filebuflen -= 2*(CODEC_IRAM_SIZE + CODEC_SIZE);
#endif
/* Allow 2 codecs at end of audio buffer */
filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE);
/* If using IRAM for plugins voice IRAM swap buffer must be dedicated
and out of the way of buffer usage or else a call to audio_get_buffer
and subsequent buffer use might trash the swap space. A plugin
initializing IRAM after getting the full buffer would present similar
problem. Options include: failing the request if the other buffer
has been obtained already or never allowing use of the voice IRAM
buffer within the audio buffer. Using buffer_alloc basically
implements the second in a more convenient way. */
iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
#ifdef IRAM_STEAL
/* Allocate voice IRAM swap buffer once */
if (iram_buf[CODEC_IDX_VOICE] == NULL)
iram_buf[CODEC_IDX_VOICE] = buffer_alloc(CODEC_IRAM_SIZE);
dram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
#else
iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE;
#endif
#endif /* IRAM_STEAL */
#endif /* PLAYBACK_VOICE */
}
else
{

View File

@ -467,7 +467,9 @@ static int onplay_menu(int index)
if (current_track->display_index!=viewer.num_tracks ||
global_settings.repeat_mode == REPEAT_ALL)
{
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* will use the mp3 buffer */
#endif
audio_play(0);
viewer.current_playing_track = -1;
}

View File

@ -471,6 +471,9 @@ static const struct plugin_api rockbox_api = {
lcd_set_backdrop,
#endif
#ifdef IRAM_STEAL
plugin_iram_init,
#endif
};
int plugin_load(const char* plugin, void* parameter)
@ -683,10 +686,21 @@ void* plugin_get_audio_buffer(int* buffer_size)
audio_stop();
talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
*buffer_size = audiobufend - audiobuf;
#endif
return audiobuf;
#endif
}
#ifdef IRAM_STEAL
/* Initializes plugin IRAM */
void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
char *iedata, size_t iedata_size)
{
audio_iram_steal();
memcpy(iramstart, iramcopy, iram_size);
memset(iedata, 0, iedata_size);
}
#endif /* IRAM_STEAL */
/* The plugin wants to stay resident after leaving its main function, e.g.
runs from timer or own thread. The callback is registered to later
instruct it to free its resources before a new plugin gets loaded. */

View File

@ -107,7 +107,7 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 35
#define PLUGIN_API_VERSION 36
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
@ -582,6 +582,11 @@ struct plugin_api {
#if LCD_DEPTH > 1
void (*lcd_set_backdrop)(fb_data* backdrop);
#endif
#ifdef IRAM_STEAL
void (*plugin_iram_init)(char *iramstart, char *iramcopy, size_t iram_size,
char *iedata, size_t iedata_size);
#endif
};
/* plugin header */
@ -593,6 +598,7 @@ struct plugin_header {
unsigned char *end_addr;
enum plugin_status(*entry_point)(struct plugin_api*, void*);
};
#ifdef PLUGIN
#ifndef SIMULATOR
extern unsigned char plugin_start_addr[];
@ -607,12 +613,33 @@ extern unsigned char plugin_end_addr[];
const struct plugin_header __header = { \
PLUGIN_MAGIC, TARGET_ID, PLUGIN_API_VERSION, \
NULL, NULL, plugin_start };
#endif
#endif
#endif /* SIMULATOR */
#ifdef USE_IRAM
/* Declare IRAM variables */
#define PLUGIN_IRAM_DECLARE \
extern char iramcopy[]; \
extern char iramstart[]; \
extern char iramend[]; \
extern char iedata[]; \
extern char iend[];
/* Initialize IRAM */
#define PLUGIN_IRAM_INIT(api) \
(api)->plugin_iram_init(iramstart, iramcopy, iramend-iramstart, \
iedata, iend-iedata);
#else
#define PLUGIN_IRAM_DECLARE
#define PLUGIN_IRAM_INIT(api)
#endif /* USE_IRAM */
#endif /* PLUGIN */
int plugin_load(const char* plugin, void* parameter);
void* plugin_get_buffer(int *buffer_size);
void* plugin_get_audio_buffer(int *buffer_size);
#ifdef IRAM_STEAL
void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
char *iedata, size_t iedata_size);
#endif
/* plugin_tsr,
callback returns true to allow the new plugin to load,

View File

@ -39,14 +39,7 @@
#include "st_stuff.h"
PLUGIN_HEADER
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
PLUGIN_IRAM_DECLARE
extern boolean timingdemo, singledemo, demoplayback, fastdemo; // killough
@ -785,13 +778,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
rb->cpu_boost(true);
#endif
#ifdef USE_IRAM
/* We need to stop audio playback in order to use IRAM */
rb->audio_stop();
memcpy(iramstart, iramcopy, iramend-iramstart);
memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
rb->lcd_setfont(0);
@ -830,7 +817,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
if (result < 0)
{
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
rb->cpu_boost(false);
#endif
if( result == -1 ) return PLUGIN_OK; // Quit was selected
else if( result == -2 ) return PLUGIN_ERROR; // Missing base wads

View File

@ -19,7 +19,7 @@
#include "../../plugin.h"
PLUGIN_HEADER
PLUGIN_IRAM_DECLARE
/* variable button definitions */
#if CONFIG_KEYPAD == RECORDER_PAD
@ -102,14 +102,6 @@ short gmbuf[BUF_SIZE*NBUF] IBSS_ATTR;
int quit=0;
struct plugin_api * rb;
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
int retval = 0;
@ -122,10 +114,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
}
rb->lcd_setfont(0);
#ifdef USE_IRAM
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
rb->memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
#if defined(HAVE_ADJUSTABLE_CPU_FREQ)
rb->cpu_boost(true);

View File

@ -14,17 +14,10 @@
#include "plugin.h"
PLUGIN_HEADER
PLUGIN_IRAM_DECLARE
static struct plugin_api* rb;
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
#define SAMP_PER_FRAME 1152
#define SAMPL2 576
#define SBLIMIT 32
@ -2377,10 +2370,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
asm volatile ("move.l #0, %macsr"); /* integer mode */
#endif
#ifdef USE_IRAM
memcpy(iramstart, iramcopy, iramend - iramstart);
memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
rb->lcd_setfont(FONT_SYSFIXED);

View File

@ -31,14 +31,7 @@
#include "video_out.h"
PLUGIN_HEADER
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
PLUGIN_IRAM_DECLARE
struct plugin_api* rb;
@ -319,10 +312,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
if (buffer == NULL)
return PLUGIN_ERROR;
#ifdef USE_IRAM
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
rb->memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
rb->lcd_set_backdrop(NULL);

View File

@ -29,14 +29,7 @@
#include "lib/configfile.h"
PLUGIN_HEADER
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
PLUGIN_IRAM_DECLARE
struct plugin_api* rb;
@ -370,21 +363,10 @@ static int gameProc( void )
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
(void)parameter;
#ifdef USE_IRAM
void* audiobuf;
int audiosize;
#endif
rb = api;
#ifdef USE_IRAM
/* We need to stop audio playback in order to use IRAM, so we grab
the audio buffer - but we don't use it. */
audiobuf = rb->plugin_get_audio_buffer(&audiosize);
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
rb->memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);

View File

@ -21,14 +21,7 @@
#include "rockmacros.h"
PLUGIN_HEADER
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
PLUGIN_IRAM_DECLARE
/* here is a global api struct pointer. while not strictly necessary,
it's nice not to have to pass the api pointer in all function calls
@ -187,10 +180,9 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
audio_buffer_free = plugin_start_addr - (unsigned char *)audio_bufferbase;
#endif
setoptions();
#ifdef USE_IRAM
memcpy(iramstart, iramcopy, iramend-iramstart);
memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
shut=0;
cleanshut=0;

View File

@ -20,6 +20,7 @@
#include "zxconfig.h"
PLUGIN_HEADER
PLUGIN_IRAM_DECLARE
struct plugin_api* rb;
@ -37,14 +38,6 @@ int use_shm = 0;
int small_screen,pause_on_iconify;
int vga_pause_bg;
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
#include "keymaps.h"
#include "zxvid_com.h"
#include "spmain.h"
@ -75,13 +68,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
rb->lcd_set_backdrop(NULL);
rb->splash(HZ, true, "Welcome to ZXBox");
#ifdef USE_IRAM
/* We need to stop audio playback in order to use IRAM */
rb->audio_stop();
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
rb->memset(iedata, 0, iend - iedata);
#endif
PLUGIN_IRAM_INIT(rb)
sp_init();

View File

@ -522,7 +522,7 @@ void talk_init(void)
MAX_FILENAME);
#if CONFIG_CODEC == SWCODEC
audio_stop();
audio_get_buffer(false, NULL); /* Must tell audio to reinitialize */
#endif
reset_state(); /* use this for most of our inits */

View File

@ -62,7 +62,9 @@ extern const char* const file_thumbnail_ext; /* ".talk" for file voicing */
void talk_init(void);
bool talk_voice_required(void); /* returns true if voice codec required */
int talk_get_bufsize(void); /* get the loaded voice file size */
#if CONFIG_CODEC != SWCODEC
int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
#endif
int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */
int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */
int talk_number(long n, bool enqueue); /* say a number */

View File

@ -101,7 +101,12 @@ void audio_error_clear(void);
int audio_get_file_pos(void);
void audio_beep(int duration);
void audio_init_playback(void);
/* Required call when audio buffer is require for some other purpose */
unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size);
#ifdef USE_IRAM
/* Required call when codec IRAM is needed for some other purpose */
void audio_iram_steal(void);
#endif
/* channel modes */
enum rec_channel_modes

View File

@ -283,6 +283,9 @@
#define IDATA_ATTR __attribute__ ((section(".idata")))
#define IBSS_ATTR __attribute__ ((section(".ibss")))
#define USE_IRAM
#if CONFIG_CPU != SH7034
#define IRAM_STEAL
#endif
#else
#define ICODE_ATTR
#define ICONST_ATTR