From: notaz <notasas@gmail.com>
Date: Wed, 22 Jul 2009 15:46:09 +0000 (+0000)
Subject: more unification; replace some magic bits to defines
X-Git-Tag: v1.85~340
X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d34a42f93fdb8e0dc66875a08571cae2135b14cf;p=picodrive.git

more unification; replace some magic bits to defines

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@708 be3aeb3a-fb24-0410-a615-afba39da0efa
---

diff --git a/platform/common/emu.c b/platform/common/emu.c
index 5f18dd0f..ff17e3be 100644
--- a/platform/common/emu.c
+++ b/platform/common/emu.c
@@ -15,6 +15,7 @@
 #include "lprintf.h"
 #include "config.h"
 #include "plat.h"
+#include "input.h"
 
 #include <pico/pico_int.h>
 #include <pico/patch.h>
@@ -31,7 +32,6 @@ int g_screen_height = SCREEN_HEIGHT;
 
 char *PicoConfigFile = "config.cfg";
 currentConfig_t currentConfig, defaultConfig;
-char noticeMsg[64] = { 0, };
 int state_slot = 0;
 int config_slot = 0, config_slot_current = 0;
 int pico_inp_mode = 0;
@@ -477,18 +477,13 @@ int emu_ReloadRom(char *rom_fname)
 			// TODO: bits 6 & 5
 		}
 		movie_data[0x18+30] = 0;
-		sprintf(noticeMsg, "MOVIE: %s", (char *) &movie_data[0x18]);
+		plat_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);
 	}
 	else
 	{
 		PicoOpt &= ~POPT_DIS_VDP_FIFO;
-		if (Pico.m.pal) {
-			strcpy(noticeMsg, "PAL SYSTEM / 50 FPS");
-		} else {
-			strcpy(noticeMsg, "NTSC SYSTEM / 60 FPS");
-		}
+		plat_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS");
 	}
-	emu_noticeMsgUpdated();
 
 	// load SRAM for this ROM
 	if (currentConfig.EmuOpt & EOPT_USE_SRAM)
@@ -712,15 +707,14 @@ mk_text_out(emu_textOut16, unsigned short, 0xffff)
 #undef mk_text_out
 
 
-void emu_updateMovie(void)
+void update_movie(void)
 {
 	int offs = Pico.m.frame_count*3 + 0x40;
 	if (offs+3 > movie_size) {
 		free(movie_data);
 		movie_data = 0;
-		strcpy(noticeMsg, "END OF MOVIE.");
+		plat_status_msg("END OF MOVIE.");
 		lprintf("END OF MOVIE.\n");
-		emu_noticeMsgUpdated();
 	} else {
 		// MXYZ SACB RLDU
 		PicoPad[0] = ~movie_data[offs]   & 0x8f; // ! SCBA RLDU
@@ -840,10 +834,8 @@ int emu_SaveLoadGame(int load, int sram)
 	// make save filename
 	saveFname = emu_GetSaveFName(load, sram, state_slot);
 	if (saveFname == NULL) {
-		if (!sram) {
-			strcpy(noticeMsg, load ? "LOAD FAILED (missing file)" : "SAVE FAILED  ");
-			emu_noticeMsgUpdated();
-		}
+		if (!sram)
+			plat_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");
 		return -1;
 	}
 
@@ -929,14 +921,13 @@ int emu_SaveLoadGame(int load, int sram)
 		}
 		else	ret = -1;
 		if (!ret)
-			strcpy(noticeMsg, load ? "GAME LOADED  " : "GAME SAVED        ");
+			plat_status_msg(load ? "GAME LOADED" : "GAME SAVED");
 		else
 		{
-			strcpy(noticeMsg, load ? "LOAD FAILED  " : "SAVE FAILED       ");
+			plat_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");
 			ret = -1;
 		}
 
-		emu_noticeMsgUpdated();
 		return ret;
 	}
 }
@@ -955,8 +946,7 @@ void emu_changeFastForward(int set_on)
 		currentConfig.EmuOpt &= ~4;
 		currentConfig.EmuOpt |= 0x40000;
 		is_on = 1;
-		strcpy(noticeMsg, "FAST FORWARD   ");
-		emu_noticeMsgUpdated();
+		plat_status_msg("FAST FORWARD");
 	}
 	else if (!set_on && is_on) {
 		PsndOut = set_PsndOut;
@@ -971,31 +961,31 @@ void emu_RunEventsPico(unsigned int events)
 {
 	if (events & (1 << 3)) {
 		pico_inp_mode++;
-		if (pico_inp_mode > 2) pico_inp_mode = 0;
+		if (pico_inp_mode > 2)
+			pico_inp_mode = 0;
 		switch (pico_inp_mode) {
-			case 2: strcpy(noticeMsg, "Input: Pen on Pad      "); break;
-			case 1: strcpy(noticeMsg, "Input: Pen on Storyware"); break;
-			case 0: strcpy(noticeMsg, "Input: Joytick         ");
+			case 2: plat_status_msg("Input: Pen on Pad"); break;
+			case 1: plat_status_msg("Input: Pen on Storyware"); break;
+			case 0: plat_status_msg("Input: Joystick");
 				PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
 				break;
 		}
-		emu_noticeMsgUpdated();
 	}
 	if (events & (1 << 4)) {
 		PicoPicohw.page--;
-		if (PicoPicohw.page < 0) PicoPicohw.page = 0;
-		sprintf(noticeMsg, "Page %i                 ", PicoPicohw.page);
-		emu_noticeMsgUpdated();
+		if (PicoPicohw.page < 0)
+			PicoPicohw.page = 0;
+		plat_status_msg("Page %i", PicoPicohw.page);
 	}
 	if (events & (1 << 5)) {
 		PicoPicohw.page++;
-		if (PicoPicohw.page > 6) PicoPicohw.page = 6;
-		sprintf(noticeMsg, "Page %i                 ", PicoPicohw.page);
-		emu_noticeMsgUpdated();
+		if (PicoPicohw.page > 6)
+			PicoPicohw.page = 6;
+		plat_status_msg("Page %i", PicoPicohw.page);
 	}
 }
 
-void emu_DoTurbo(int *pad, int acts)
+static void do_turbo(int *pad, int acts)
 {
 	static int turbo_pad = 0;
 	static unsigned char turbo_cnt[3] = { 0, 0, 0 };
@@ -1019,3 +1009,105 @@ void emu_DoTurbo(int *pad, int acts)
 	*pad |= turbo_pad & (acts >> 8);
 }
 
+static void run_ui_events(unsigned int which)
+{
+	if (which & (PEV_STATE_LOAD|PEV_STATE_SAVE))
+	{
+		int do_it = 1;
+		if ( emu_checkSaveFile(state_slot) &&
+				(((which & PEV_STATE_LOAD) && (currentConfig.EmuOpt & EOPT_CONFIRM_LOAD)) ||
+				 ((which & PEV_STATE_SAVE) && (currentConfig.EmuOpt & EOPT_CONFIRM_SAVE))) )
+		{
+			const char *nm;
+			char tmp[64];
+			int keys, len;
+
+			strcpy(tmp, (which & PEV_STATE_LOAD) ? "LOAD STATE?" : "OVERWRITE SAVE?");
+			len = strlen(tmp);
+			nm = in_get_key_name(-1, -PBTN_MA3);
+			snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);
+			len = strlen(tmp);
+			nm = in_get_key_name(-1, -PBTN_MBACK);
+			snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);
+
+			plat_status_msg_busy_first(tmp);
+
+			in_set_blocking(1);
+			while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK))
+				;
+			while ( !((keys = in_menu_wait_any(50)) & (PBTN_MA3|PBTN_MBACK)) )
+				;
+			if (keys & PBTN_MBACK)
+				do_it = 0;
+			while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK))
+				;
+			in_set_blocking(0);
+		}
+		if (do_it) {
+			plat_status_msg_busy_first((which & PEV_STATE_LOAD) ? "LOADING GAME" : "SAVING GAME");
+			PicoStateProgressCB = plat_status_msg_busy_next;
+			emu_SaveLoadGame((which & PEV_STATE_LOAD) ? 1 : 0, 0);
+			PicoStateProgressCB = NULL;
+		}
+	}
+	if (which & PEV_SWITCH_RND)
+	{
+		plat_video_toggle_renderer();
+	}
+	if (which & (PEV_SSLOT_PREV|PEV_SSLOT_NEXT))
+	{
+		if (which & PEV_SSLOT_PREV) {
+			state_slot -= 1;
+			if (state_slot < 0)
+				state_slot = 9;
+		} else {
+			state_slot += 1;
+			if (state_slot > 9)
+				state_slot = 0;
+		}
+
+		plat_status_msg("SAVE SLOT %i [%s]", state_slot,
+			emu_checkSaveFile(state_slot) ? "USED" : "FREE");
+	}
+	if (which & PEV_MENU)
+		engineState = PGS_Menu;
+}
+
+void emu_update_input(void)
+{
+	unsigned int allActions[2] = { 0, 0 }, events;
+	static unsigned int prevEvents = 0;
+
+	/* FIXME: player2 */
+	allActions[0] = in_update();
+
+	PicoPad[0] = allActions[0] & 0xfff;
+	PicoPad[1] = allActions[1] & 0xfff;
+
+	if (allActions[0] & 0x7000) do_turbo(&PicoPad[0], allActions[0]);
+	if (allActions[1] & 0x7000) do_turbo(&PicoPad[1], allActions[1]);
+
+	events = (allActions[0] | allActions[1]) & PEV_MASK;
+
+	// volume is treated in special way and triggered every frame
+	if (events & (PEV_VOL_DOWN|PEV_VOL_UP))
+		plat_update_volume(1, events & PEV_VOL_UP);
+
+	if ((events ^ prevEvents) & PEV_FF) {
+		emu_changeFastForward(events & PEV_FF);
+		plat_update_volume(0, 0);
+//		reset_timing = 1;
+	}
+
+	events &= ~prevEvents;
+
+// TODO	if (PicoAHW == PAHW_PICO)
+//		RunEventsPico(events);
+	if (events)
+		run_ui_events(events);
+	if (movie_data)
+		update_movie();
+
+	prevEvents = (allActions[0] | allActions[1]) & PEV_MASK;
+}
+
diff --git a/platform/common/emu.h b/platform/common/emu.h
index 808bcb02..a064da62 100644
--- a/platform/common/emu.h
+++ b/platform/common/emu.h
@@ -26,7 +26,11 @@ extern int g_screen_height;
 #define EOPT_GZIP_SAVES   (1<<3)
 #define EOPT_MMUHACK      (1<<4)
 #define EOPT_NO_AUTOSVCFG (1<<5)
+#define EOPT_16BPP        (1<<7)
 #define EOPT_RAM_TIMINGS  (1<<8)
+#define EOPT_CONFIRM_SAVE (1<<9)
+#define EOPT_EN_CD_LEDS   (1<<10)
+#define EOPT_CONFIRM_LOAD (1<<11)
 #define EOPT_A_SN_GAMMA   (1<<12)
 #define EOPT_PSYNC        (1<<13)
 
@@ -64,7 +68,6 @@ typedef struct _currentConfig_t {
 extern currentConfig_t currentConfig, defaultConfig;
 extern char *PicoConfigFile;
 extern int rom_loaded;
-extern char noticeMsg[64];
 extern int state_slot;
 extern int config_slot, config_slot_current;
 extern unsigned char *movie_data;
@@ -90,14 +93,18 @@ enum TPicoGameState {
 
 int   emu_ReloadRom(char *rom_fname);
 int   emu_SaveLoadGame(int load, int sram);
+
 int   emu_ReadConfig(int game, int no_defaults);
 int   emu_WriteConfig(int game);
+void  emu_packConfig(void);
+void  emu_unpackConfig(void);
 void  emu_writelrom(void);
+
 char *emu_GetSaveFName(int load, int is_sram, int slot);
 int   emu_checkSaveFile(int slot);
 void  emu_setSaveStateCbs(int gz);
-void  emu_updateMovie(void);
-int   emu_cdCheck(int *pregion, char *fname_in);
+
+void  emu_update_input(void);
 int   emu_findBios(int region, char **bios_file);
 void  emu_textOut8 (int x, int y, const char *text);
 void  emu_textOut16(int x, int y, const char *text);
@@ -105,10 +112,8 @@ char *emu_makeRomId(void);
 void  emu_getGameName(char *str150);
 void  emu_changeFastForward(int set_on);
 void  emu_RunEventsPico(unsigned int events);
-void  emu_DoTurbo(int *pad, int acts);
-void  emu_packConfig(void);
-void  emu_unpackConfig(void);
 void  emu_shutdownMCD(void);
+int   emu_cdCheck(int *pregion, char *fname_in);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/platform/common/input.h b/platform/common/input.h
index 14eb303f..cf7a0991 100644
--- a/platform/common/input.h
+++ b/platform/common/input.h
@@ -16,6 +16,30 @@
 
 #define PBTN_MENU  (1 << 10)
 
+/* ui events */
+#define PEVB_VOL_DOWN   30
+#define PEVB_VOL_UP     29
+#define PEVB_STATE_LOAD 28
+#define PEVB_STATE_SAVE 27
+#define PEVB_SWITCH_RND 26
+#define PEVB_SSLOT_PREV 25
+#define PEVB_SSLOT_NEXT 24
+#define PEVB_MENU       23
+#define PEVB_FF         22
+
+#define PEV_VOL_DOWN    (1 << PEVB_VOL_DOWN)
+#define PEV_VOL_UP      (1 << PEVB_VOL_UP)
+#define PEV_STATE_LOAD  (1 << PEVB_STATE_LOAD)
+#define PEV_STATE_SAVE  (1 << PEVB_STATE_SAVE)
+#define PEV_SWITCH_RND  (1 << PEVB_SWITCH_RND)
+#define PEV_SSLOT_PREV  (1 << PEVB_SSLOT_PREV)
+#define PEV_SSLOT_NEXT  (1 << PEVB_SSLOT_NEXT)
+#define PEV_MENU        (1 << PEVB_MENU)
+#define PEV_FF          (1 << PEVB_FF)
+
+#define PEV_MASK 0x7fc00000
+
+
 enum {
 	IN_DRVID_UNKNOWN = 0,
 	IN_DRVID_GP2X,
diff --git a/platform/common/menu.c b/platform/common/menu.c
index 32bf12fd..74e7a6d2 100644
--- a/platform/common/menu.c
+++ b/platform/common/menu.c
@@ -1286,19 +1286,19 @@ me_bind_action me_ctrl_actions[15] =
 // "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"
 me_bind_action emuctrl_actions[] =
 {
-	{ "Load State       ", 1<<28 },
-	{ "Save State       ", 1<<27 },
-	{ "Prev Save Slot   ", 1<<25 },
-	{ "Next Save Slot   ", 1<<24 },
-	{ "Switch Renderer  ", 1<<26 },
-	{ "Volume Down      ", 1<<30 },
-	{ "Volume Up        ", 1<<29 },
-	{ "Fast forward     ", 1<<22 },
-	{ "Enter Menu       ", 1<<23 },
-	{ "Pico Next page   ", 1<<21 },
-	{ "Pico Prev page   ", 1<<20 },
-	{ "Pico Switch input", 1<<19 },
-	{ NULL,                0     }
+	{ "Load State       ", 1 << PEVB_STATE_LOAD },
+	{ "Save State       ", 1 << PEVB_STATE_SAVE },
+	{ "Prev Save Slot   ", 1 << PEVB_SSLOT_PREV },
+	{ "Next Save Slot   ", 1 << PEVB_SSLOT_NEXT },
+	{ "Switch Renderer  ", 1 << PEVB_SWITCH_RND },
+	{ "Volume Down      ", 1 << PEVB_VOL_DOWN },
+	{ "Volume Up        ", 1 << PEVB_VOL_UP },
+	{ "Fast forward     ", 1 << PEVB_FF },
+	{ "Enter Menu       ", 1 << PEVB_MENU },
+	{ "Pico Next page   ", 1 << 21 }, /* TODO */
+	{ "Pico Prev page   ", 1 << 20 },
+	{ "Pico Switch input", 1 << 19 },
+	{ NULL,                0 }
 };
 
 static int key_config_loop_wrap(menu_id id, int keys)
diff --git a/platform/common/plat.h b/platform/common/plat.h
index aa584222..43ee39fc 100644
--- a/platform/common/plat.h
+++ b/platform/common/plat.h
@@ -17,7 +17,6 @@ void  emu_Init(void);
 void  emu_Deinit(void);
 void  emu_Loop(void);
 
-void emu_noticeMsgUpdated(void);
 int  emu_getMainDir(char *dst, int len);
 void menu_romload_prepare(const char *rom_name);
 void menu_romload_end(void);
@@ -26,12 +25,21 @@ void plat_early_init(void);
 void plat_init(void);
 void plat_finish(void);
 
+/* to be used while emulation is starting or running */
+void plat_status_msg(const char *format, ...);
+
+/* used before things blocking for a while (these funcs redraw on return) */
+void plat_status_msg_busy_first(const char *msg);
+void plat_status_msg_busy_next(const char *msg);
+
 /* menu: enter (switch bpp, etc), begin/end drawing */
 void plat_video_menu_enter(int is_rom_loaded);
 void plat_video_menu_begin(void);
 void plat_video_menu_end(void);
 
+void plat_video_toggle_renderer(void);
 void plat_validate_config(void);
+void plat_update_volume(int has_changed, int is_up);
 
 int  plat_is_dir(const char *path);
 int  plat_wait_event(int *fds_hnds, int count, int timeout_ms);
diff --git a/platform/gizmondo/emu.c b/platform/gizmondo/emu.c
index 90f66400..3a5c23cb 100644
--- a/platform/gizmondo/emu.c
+++ b/platform/gizmondo/emu.c
@@ -38,8 +38,9 @@ static int snd_cbuf_samples = 0, snd_all_samples = 0;
 static void blit(const char *fps, const char *notice);
 static void clearArea(int full);
 
-void emu_noticeMsgUpdated(void)
+void plat_status_msg(const char *format, ...)
 {
+	/* TODO */
 	noticeMsgTime = GetTickCount();
 }
 
@@ -446,7 +447,7 @@ static void updateKeys(void)
 	static unsigned int prevEvents = 0;
 	int i;
 
-	/* FIXME: port to input fw */
+	/* FIXME: port to input fw, merge with emu.c:emu_update_input() */
 	keys = Framework_PollGetButtons();
 	if (keys & PBTN_HOME)
 		engineState = PGS_Menu;
diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c
index 46dc3aa0..f27b2850 100644
--- a/platform/gp2x/emu.c
+++ b/platform/gp2x/emu.c
@@ -18,7 +18,6 @@
 #include "../common/fonts.h"
 #include "../common/emu.h"
 #include "../common/config.h"
-#include "../common/input.h"
 #include "../linux/sndout_oss.h"
 #include "version.h"
 
@@ -42,6 +41,7 @@ static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
 static struct timeval noticeMsgTime = { 0, 0 };	// when started showing
 static int osd_fps_x;
 static int gp2x_old_gamma = 100;
+static char noticeMsg[40];
 unsigned char *PicoDraw2FB = NULL;  // temporary buffer for alt renderer
 int reset_timing = 0;
 
@@ -49,12 +49,17 @@ int reset_timing = 0;
 #define PICO_PEN_ADJUST_Y 2
 static int pico_pen_x = 320/2, pico_pen_y = 240/2;
 
-static void emu_msg_cb(const char *msg);
 static void emu_msg_tray_open(void);
 
 
-void emu_noticeMsgUpdated(void)
+void plat_status_msg(const char *format, ...)
 {
+	va_list vl;
+
+	va_start(vl, format);
+	vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);
+	va_end(vl);
+
 	gettimeofday(&noticeMsgTime, 0);
 }
 
@@ -89,7 +94,7 @@ void emu_Init(void)
 	mkdir("cfg", 0777);
 
 	PicoInit();
-	PicoMessage = emu_msg_cb;
+	PicoMessage = plat_status_msg_busy_next;
 	PicoMCDopenTray = emu_msg_tray_open;
 	PicoMCDcloseTray = menu_loop_tray;
 }
@@ -182,12 +187,10 @@ static void osd_text(int x, int y, const char *text)
 
 static void draw_cd_leds(void)
 {
-//	static
 	int old_reg;
-//	if (!((Pico_mcd->s68k_regs[0] ^ old_reg) & 3)) return; // no change // mmu hack problems?
 	old_reg = Pico_mcd->s68k_regs[0];
 
-	if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
+	if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP)) {
 		// 8-bit modes
 		unsigned int col_g = (old_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
 		unsigned int col_r = (old_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
@@ -250,7 +253,7 @@ static void blit(const char *fps, const char *notice)
 {
 	int emu_opt = currentConfig.EmuOpt;
 
-	if (PicoOpt&0x10)
+	if (PicoOpt & POPT_ALT_RENDERER)
 	{
 		// 8bit fast renderer
 		if (Pico.m.dirtyPal) {
@@ -265,7 +268,7 @@ static void blit(const char *fps, const char *notice)
 		// do actual copy
 		vidCpyM2((unsigned char *)g_screen_ptr+320*8, PicoDraw2FB+328*8);
 	}
-	else if (!(emu_opt&0x80))
+	else if (!(emu_opt & EOPT_16BPP))
 	{
 		// 8bit accurate renderer
 		if (Pico.m.dirtyPal)
@@ -313,23 +316,20 @@ static void blit(const char *fps, const char *notice)
 	if (PicoAHW & PAHW_PICO)
 		draw_pico_ptr();
 
-	//gp2x_video_wait_vsync();
 	gp2x_video_flip();
 
-	if (!(PicoOpt&0x10)) {
+	if (!(PicoOpt & POPT_ALT_RENDERER)) {
 		if (!(Pico.video.reg[1]&8)) {
-			if (currentConfig.EmuOpt&0x80) {
+			if (currentConfig.EmuOpt & EOPT_16BPP)
 				DrawLineDest = (unsigned short *) g_screen_ptr + 320*8;
-			} else {
+			else
 				DrawLineDest = (unsigned char  *) g_screen_ptr + 320*8;
-			}
 		} else {
 			DrawLineDest = g_screen_ptr;
 		}
 	}
 }
 
-
 // clears whole screen or just the notice area (in all buffers)
 static void clearArea(int full)
 {
@@ -344,12 +344,27 @@ static void clearArea(int full)
 	}
 }
 
+void plat_status_msg_busy_next(const char *msg)
+{
+	clearArea(0);
+	blit("", msg);
+
+	/* assumption: msg_busy_next gets called only when
+	 * something slow is about to happen */
+	reset_timing = 1;
+}
+
+void plat_status_msg_busy_first(const char *msg)
+{
+	gp2x_memcpy_all_buffers(g_screen_ptr, 0, 320*240*2);
+	plat_status_msg_busy_next(msg);
+}
 
 static void vidResetMode(void)
 {
-	if (PicoOpt&0x10) {
+	if (PicoOpt & POPT_ALT_RENDERER) {
 		gp2x_video_changemode(8);
-	} else if (currentConfig.EmuOpt&0x80) {
+	} else if (currentConfig.EmuOpt & EOPT_16BPP) {
 		gp2x_video_changemode(16);
 		PicoDrawSetColorFormat(1);
 		PicoScanBegin = EmuScanBegin16;
@@ -358,7 +373,7 @@ static void vidResetMode(void)
 		PicoDrawSetColorFormat(2);
 		PicoScanBegin = EmuScanBegin8;
 	}
-	if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
+	if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP)) {
 		// setup pal for 8-bit modes
 		localPal[0xc0] = 0x0000c000; // MCD LEDs
 		localPal[0xd0] = 0x00c00000;
@@ -375,37 +390,30 @@ static void vidResetMode(void)
 	else gp2x_video_RGB_setscaling(0, (PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 240);
 }
 
-
-static void emu_msg_cb(const char *msg)
+void plat_video_toggle_renderer(void)
 {
-	if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
-		// 8-bit renderers
-		gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
-		osd_text(4, 232, msg);
-		gp2x_memcpy_all_buffers((char *)g_screen_ptr+320*232, 320*232, 320*8);
-	} else {
-		// 16bit accurate renderer
-		gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
-		osd_text(4, 232, msg);
-		gp2x_memcpy_all_buffers((char *)g_screen_ptr+320*232*2, 320*232*2, 320*8*2);
-	}
-	gettimeofday(&noticeMsgTime, 0);
-	noticeMsgTime.tv_sec -= 2;
+	if (PicoOpt & POPT_ALT_RENDERER) {
+		PicoOpt &= ~POPT_ALT_RENDERER;
+		currentConfig.EmuOpt |= EOPT_16BPP;
+	} else if (!(currentConfig.EmuOpt & EOPT_16BPP))
+		PicoOpt |= POPT_ALT_RENDERER;
+	else
+		currentConfig.EmuOpt &= ~EOPT_16BPP;
 
-	/* assumption: emu_msg_cb gets called only when something slow is about to happen */
-	reset_timing = 1;
-}
+	vidResetMode();
 
-static void emu_state_cb(const char *str)
-{
-	clearArea(0);
-	blit("", str);
+	if (PicoOpt & POPT_ALT_RENDERER) {
+		plat_status_msg(" 8bit fast renderer");
+	} else if (currentConfig.EmuOpt & EOPT_16BPP) {
+		plat_status_msg("16bit accurate renderer");
+	} else {
+		plat_status_msg(" 8bit accurate renderer");
+	}
 }
 
 static void emu_msg_tray_open(void)
 {
-	strcpy(noticeMsg, "CD tray opened");
-	gettimeofday(&noticeMsgTime, 0);
+	plat_status_msg("CD tray opened");
 }
 
 static void RunEventsPico(unsigned int events)
@@ -460,14 +468,20 @@ static void RunEventsPico(unsigned int events)
 	PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y);
 }
 
-static void update_volume(int has_changed, int is_up)
+void plat_update_volume(int has_changed, int is_up)
 {
 	static int prev_frame = 0, wait_frames = 0;
 	int vol = currentConfig.volume;
+	int need_low_volume = 0;
+	gp2x_soc_t soc;
+
+	soc = soc_detect();
+	if ((PicoOpt & POPT_EN_STEREO) && soc == SOCID_MMSP2)
+		need_low_volume = 1;
 
 	if (has_changed)
 	{
-		if (vol < 5 && (PicoOpt&8) && prev_frame == Pico.m.frame_count - 1 && wait_frames < 12)
+		if (need_low_volume && vol < 5 && prev_frame == Pico.m.frame_count - 1 && wait_frames < 12)
 			wait_frames++;
 		else {
 			if (is_up) {
@@ -479,13 +493,14 @@ static void update_volume(int has_changed, int is_up)
 			sndout_oss_setvol(vol, vol);
 			currentConfig.volume = vol;
 		}
-		sprintf(noticeMsg, "VOL: %02i", vol);
-		gettimeofday(&noticeMsgTime, 0);
+		plat_status_msg("VOL: %02i", vol);
 		prev_frame = Pico.m.frame_count;
 	}
 
-	// set the right mixer func
-	if (!(PicoOpt&8)) return; // just use defaults for mono
+	if (need_low_volume)
+		return;
+
+	/* set the right mixer func */
 	if (vol >= 5)
 		PsndMix_32_to_16l = mix_32_to_16l_stereo;
 	else {
@@ -494,120 +509,6 @@ static void update_volume(int has_changed, int is_up)
 	}
 }
 
-static void RunEvents(unsigned int which)
-{
-	if (which & 0x1800) // save or load (but not both)
-	{
-		int do_it = 1;
-		if ( emu_checkSaveFile(state_slot) &&
-				(( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) || // load
-				 (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) // save
-		{
-			const char *nm;
-			char tmp[64];
-			int keys, len;
-
-			strcpy(tmp, (which & 0x1000) ? "LOAD STATE? " : "OVERWRITE SAVE? ");
-			len = strlen(tmp);
-			nm = in_get_key_name(-1, -PBTN_MA3);
-			snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);
-			len = strlen(tmp);
-			nm = in_get_key_name(-1, -PBTN_MBACK);
-			snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);
-
-			blit("", tmp);
-
-			in_set_blocking(1);
-			while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK));	// wait for release
-			while ( !((keys = in_menu_wait_any(50)) & (PBTN_MA3|PBTN_MBACK)) ); // .. press
-			if (keys & PBTN_MBACK)
-				do_it = 0;
-			while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK));	// .. release
-			in_set_blocking(0);
-
-			clearArea(0);
-		}
-		if (do_it) {
-			osd_text(4, 232, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME");
-			PicoStateProgressCB = emu_state_cb;
-			gp2x_memcpy_all_buffers(g_screen_ptr, 0, 320*240*2);
-			emu_SaveLoadGame((which & 0x1000) >> 12, 0);
-			PicoStateProgressCB = NULL;
-		}
-
-		reset_timing = 1;
-	}
-	if (which & 0x0400) // switch renderer
-	{
-		if      (  PicoOpt&0x10)             { PicoOpt&=~0x10; currentConfig.EmuOpt |= 0x80; }
-		else if (!(currentConfig.EmuOpt&0x80)) PicoOpt|= 0x10;
-		else   currentConfig.EmuOpt &= ~0x80;
-
-		vidResetMode();
-
-		if (PicoOpt&0x10) {
-			strcpy(noticeMsg, " 8bit fast renderer");
-		} else if (currentConfig.EmuOpt&0x80) {
-			strcpy(noticeMsg, "16bit accurate renderer");
-		} else {
-			strcpy(noticeMsg, " 8bit accurate renderer");
-		}
-
-		emu_noticeMsgUpdated();
-	}
-	if (which & 0x0300)
-	{
-		if(which&0x0200) {
-			state_slot -= 1;
-			if(state_slot < 0) state_slot = 9;
-		} else {
-			state_slot += 1;
-			if(state_slot > 9) state_slot = 0;
-		}
-		sprintf(noticeMsg, "SAVE SLOT %i [%s]", state_slot, emu_checkSaveFile(state_slot) ? "USED" : "FREE");
-		emu_noticeMsgUpdated();
-	}
-	if (which & 0x0080) {
-		engineState = PGS_Menu;
-	}
-}
-
-static void updateKeys(void)
-{
-	unsigned int allActions[2] = { 0, 0 }, events;
-	static unsigned int prevEvents = 0;
-
-	/* FIXME: player2 */
-	allActions[0] = in_update();
-
-	PicoPad[0] = allActions[0] & 0xfff;
-	PicoPad[1] = allActions[1] & 0xfff;
-
-	if (allActions[0] & 0x7000) emu_DoTurbo(&PicoPad[0], allActions[0]);
-	if (allActions[1] & 0x7000) emu_DoTurbo(&PicoPad[1], allActions[1]);
-
-	events = (allActions[0] | allActions[1]) >> 16;
-
-	// volume is treated in special way and triggered every frame
-	if (events & 0x6000)
-		update_volume(1, events & 0x2000);
-
-	if ((events ^ prevEvents) & 0x40) {
-		emu_changeFastForward(events & 0x40);
-		update_volume(0, 0);
-		reset_timing = 1;
-	}
-
-	events &= ~prevEvents;
-
-	if (PicoAHW == PAHW_PICO)
-		RunEventsPico(events);
-	if (events) RunEvents(events);
-	if (movie_data) emu_updateMovie();
-
-	prevEvents = (allActions[0] | allActions[1]) >> 16;
-}
-
 
 static void updateSound(int len)
 {
@@ -639,7 +540,7 @@ void emu_startSound(void)
 		sndout_oss_start(PsndRate, 16, (PicoOpt&8)>>3);
 		sndout_oss_setvol(currentConfig.volume, currentConfig.volume);
 		PicoWriteSound = updateSound;
-		update_volume(0, 0);
+		plat_update_volume(0, 0);
 		memset(sndBuffer, 0, sizeof(sndBuffer));
 		PsndOut = sndBuffer;
 		PsndRate_old = PsndRate;
@@ -931,8 +832,8 @@ void emu_Loop(void)
 			} else {
 				// it is quite common for this implementation to leave 1 fame unfinished
 				// when second changes, but we don't want buffer to starve.
-				if(PsndOut && pframes_done < target_fps && pframes_done > target_fps-5) {
-					updateKeys();
+				if (PsndOut && pframes_done < target_fps && pframes_done > target_fps-5) {
+					emu_update_input();
 					SkipFrame(1); pframes_done++;
 				}
 
@@ -947,7 +848,7 @@ void emu_Loop(void)
 		if (currentConfig.Frameskip >= 0) // frameskip enabled
 		{
 			for(i = 0; i < currentConfig.Frameskip; i++) {
-				updateKeys();
+				emu_update_input();
 				SkipFrame(1); pframes_done++; frames_done++;
 				if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled
 					gettimeofday(&tval, 0);
@@ -968,12 +869,12 @@ void emu_Loop(void)
 				reset_timing = 1;
 				continue;
 			}
-			updateKeys();
+			emu_update_input();
 			SkipFrame(tval.tv_usec < lim_time+target_frametime*2); pframes_done++; frames_done++;
 			continue;
 		}
 
-		updateKeys();
+		emu_update_input();
 		PicoFrame();
 
 		// check time
@@ -1007,17 +908,18 @@ void emu_Loop(void)
 
 	emu_changeFastForward(0);
 
-	if (PicoAHW & PAHW_MCD) PicoCDBufferFree();
+	if (PicoAHW & PAHW_MCD)
+		PicoCDBufferFree();
 
 	// save SRAM
-	if((currentConfig.EmuOpt & 1) && SRam.changed) {
-		emu_state_cb("Writing SRAM/BRAM..");
+	if ((currentConfig.EmuOpt & EOPT_USE_SRAM) && SRam.changed) {
+		plat_status_msg_busy_first("Writing SRAM/BRAM...");
 		emu_SaveLoadGame(0, 1);
 		SRam.changed = 0;
 	}
 
 	// if in 8bit mode, generate 16bit image for menu background
-	if ((PicoOpt&0x10) || !(currentConfig.EmuOpt&0x80))
+	if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP))
 		emu_forcedFrame(POPT_EN_SOFTSCALE);
 }
 
diff --git a/platform/linux/in_evdev.c b/platform/linux/in_evdev.c
index c2589a9b..7795b69e 100644
--- a/platform/linux/in_evdev.c
+++ b/platform/linux/in_evdev.c
@@ -441,8 +441,8 @@ static const struct {
 	{ BTN_Y,	6 },
 	{ KEY_ENTER,	7 },
 	{ BTN_START,	7 },
-	{ BTN_TL,	27 },	/* save state */
-	{ BTN_TR,	28 },	/* load state */
+	{ BTN_TL,	PEVB_STATE_LOAD },
+	{ BTN_TR,	PEVB_STATE_SAVE },
 };
 
 #define DEF_BIND_COUNT (sizeof(in_evdev_def_binds) / sizeof(in_evdev_def_binds[0]))
diff --git a/platform/pandora/emu.c b/platform/pandora/emu.c
index 85c634fe..cce52196 100644
--- a/platform/pandora/emu.c
+++ b/platform/pandora/emu.c
@@ -53,8 +53,14 @@ static void emu_msg_cb(const char *msg);
 static void emu_msg_tray_open(void);
 
 
-void emu_noticeMsgUpdated(void)
+void plat_status_msg(const char *format, ...)
 {
+	va_list vl;
+
+	va_start(vl, format);
+	vsnprintf(noticeMsg, sizeof(noticeMsg), fmt, vl);
+	va_end(vl);
+
 	gettimeofday(&noticeMsgTime, 0);
 }
 
@@ -460,59 +466,6 @@ static void emu_msg_tray_open(void)
 	gettimeofday(&noticeMsgTime, 0);
 }
 
-#if 0
-static void RunEventsPico(unsigned int events, unsigned int gp2x_keys)
-{
-	int ret, px, py, lim_x;
-	static int pdown_frames = 0;
-
-	emu_RunEventsPico(events);
-
-	if (pico_inp_mode == 0) return;
-
-	// for F200
-	ret = gp2x_touchpad_read(&px, &py);
-	if (ret >= 0)
-	{
-		if (ret > 35000)
-		{
-			if (pdown_frames++ > 5)
-				PicoPad[0] |= 0x20;
-
-			pico_pen_x = px;
-			pico_pen_y = py;
-			if (!(Pico.video.reg[12]&1)) {
-				pico_pen_x -= 32;
-				if (pico_pen_x <   0) pico_pen_x = 0;
-				if (pico_pen_x > 248) pico_pen_x = 248;
-			}
-			if (pico_pen_y > 224) pico_pen_y = 224;
-		}
-		else
-			pdown_frames = 0;
-
-		//if (ret == 0)
-		//	PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
-	}
-
-	PicoPad[0] &= ~0x0f; // release UDLR
-	if (gp2x_keys & GP2X_UP)    pico_pen_y--;
-	if (gp2x_keys & GP2X_DOWN)  pico_pen_y++;
-	if (gp2x_keys & GP2X_LEFT)  pico_pen_x--;
-	if (gp2x_keys & GP2X_RIGHT) pico_pen_x++;
-
-	lim_x = (Pico.video.reg[12]&1) ? 319 : 255;
-	if (pico_pen_y < 8) pico_pen_y = 8;
-	if (pico_pen_y > 224-PICO_PEN_ADJUST_Y) pico_pen_y = 224-PICO_PEN_ADJUST_Y;
-	if (pico_pen_x < 0) pico_pen_x = 0;
-	if (pico_pen_x > lim_x-PICO_PEN_ADJUST_X) pico_pen_x = lim_x-PICO_PEN_ADJUST_X;
-
-	PicoPicohw.pen_pos[0] = pico_pen_x;
-	if (!(Pico.video.reg[12]&1)) PicoPicohw.pen_pos[0] += pico_pen_x/4;
-	PicoPicohw.pen_pos[0] += 0x3c;
-	PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y);
-}
-#endif
 
 static void update_volume(int has_changed, int is_up)
 {
@@ -548,108 +501,6 @@ static void update_volume(int has_changed, int is_up)
 	}
 }
 
-static void RunEvents(unsigned int which)
-{
-	if (which & 0x1800) // save or load (but not both)
-	{
-		int do_it = 1;
-		if ( emu_checkSaveFile(state_slot) &&
-				(( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) ||   // load
-				 (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) { // save
-#if 0
-			unsigned long keys;
-			blit("", (which & 0x1000) ? "LOAD STATE? (Y=yes, X=no)" : "OVERWRITE SAVE? (Y=yes, X=no)");
-			while ( !((keys = gp2x_joystick_read(1)) & (GP2X_X|GP2X_Y)) )
-				usleep(50*1024);
-			if (keys & GP2X_X) do_it = 0;
-			while ( gp2x_joystick_read(1) & (GP2X_X|GP2X_Y) ) // wait for release
-				usleep(50*1024);
-			clearArea(0);
-#endif
-		}
-		if (do_it) {
-			osd_text(4, g_screen_height-16, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME");
-			PicoStateProgressCB = emu_state_cb;
-			//gp2x_memcpy_all_buffers(g_screen_ptr, 0, g_screen_width*g_screen_height*2);
-			emu_SaveLoadGame((which & 0x1000) >> 12, 0);
-			PicoStateProgressCB = NULL;
-		}
-
-		reset_timing = 1;
-	}
-	if (which & 0x0400) // switch renderer
-	{
-		if      (  PicoOpt&0x10)             { PicoOpt&=~0x10; currentConfig.EmuOpt |= 0x80; }
-		else if (!(currentConfig.EmuOpt&0x80)) PicoOpt|= 0x10;
-		else   currentConfig.EmuOpt &= ~0x80;
-
-		vidResetMode();
-
-		if (PicoOpt&0x10) {
-			strcpy(noticeMsg, " 8bit fast renderer");
-		} else if (currentConfig.EmuOpt&0x80) {
-			strcpy(noticeMsg, "16bit accurate renderer");
-		} else {
-			strcpy(noticeMsg, " 8bit accurate renderer");
-		}
-
-		gettimeofday(&noticeMsgTime, 0);
-	}
-	if (which & 0x0300)
-	{
-		if(which&0x0200) {
-			state_slot -= 1;
-			if(state_slot < 0) state_slot = 9;
-		} else {
-			state_slot += 1;
-			if(state_slot > 9) state_slot = 0;
-		}
-		sprintf(noticeMsg, "SAVE SLOT %i [%s]", state_slot, emu_checkSaveFile(state_slot) ? "USED" : "FREE");
-		gettimeofday(&noticeMsgTime, 0);
-	}
-	if (which & 0x0080) {
-		engineState = PGS_Menu;
-	}
-}
-
-static void updateKeys(void)
-{
-	unsigned int allActions[2] = { 0, 0 }, events;
-	static unsigned int prevEvents = 0;
-
-	/* FIXME: combos, player2 */
-	allActions[0] = in_update();
-
-	PicoPad[0] = allActions[0] & 0xfff;
-	PicoPad[1] = allActions[1] & 0xfff;
-
-	if (allActions[0] & 0x7000) emu_DoTurbo(&PicoPad[0], allActions[0]);
-	if (allActions[1] & 0x7000) emu_DoTurbo(&PicoPad[1], allActions[1]);
-
-	events = (allActions[0] | allActions[1]) >> 16;
-
-	// volume is treated in special way and triggered every frame
-	if (events & 0x6000)
-		update_volume(1, events & 0x2000);
-
-	if ((events ^ prevEvents) & 0x40) {
-		emu_changeFastForward(events & 0x40);
-		update_volume(0, 0);
-		reset_timing = 1;
-	}
-
-	events &= ~prevEvents;
-
-/*
-	if (PicoAHW == PAHW_PICO)
-		RunEventsPico(events, keys);
-*/
-	if (events) RunEvents(events);
-	if (movie_data) emu_updateMovie();
-
-	prevEvents = (allActions[0] | allActions[1]) >> 16;
-}
-
 
 static void updateSound(int len)
 {
@@ -892,7 +743,7 @@ void emu_Loop(void)
 				// it is quite common for this implementation to leave 1 fame unfinished
 				// when second changes, but we don't want buffer to starve.
 				if(PsndOut && pframes_done < target_fps && pframes_done > target_fps-5) {
-					updateKeys();
+					emu_update_input();
 					SkipFrame(1); pframes_done++;
 				}
 
@@ -907,7 +758,7 @@ void emu_Loop(void)
 		if (currentConfig.Frameskip >= 0) // frameskip enabled
 		{
 			for(i = 0; i < currentConfig.Frameskip; i++) {
-				updateKeys();
+				emu_update_input();
 				SkipFrame(1); pframes_done++; frames_done++;
 				if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled
 					gettimeofday(&tval, 0);
@@ -928,12 +779,12 @@ void emu_Loop(void)
 				reset_timing = 1;
 				continue;
 			}
-			updateKeys();
+			emu_update_input();
 			SkipFrame(tval.tv_usec < lim_time+target_frametime*2); pframes_done++; frames_done++;
 			continue;
 		}
 
-		updateKeys();
+		emu_update_input();
 		PicoFrame();
 
 		// check time
diff --git a/platform/psp/emu.c b/platform/psp/emu.c
index 500f219e..4063a048 100644
--- a/platform/psp/emu.c
+++ b/platform/psp/emu.c
@@ -48,8 +48,14 @@ static void sound_deinit(void);
 static void blit2(const char *fps, const char *notice, int lagging_behind);
 static void clearArea(int full);
 
-void emu_noticeMsgUpdated(void)
+void plat_status_msg(const char *format, ...)
 {
+	va_list vl;
+
+	va_start(vl, format);
+	vsnprintf(noticeMsg, sizeof(noticeMsg), fmt, vl);
+	va_end(vl);
+
 	noticeMsgTime = sceKernelGetSystemTimeLow();
 }
 
@@ -86,8 +92,7 @@ void emu_msg_cb(const char *msg)
 
 static void emu_msg_tray_open(void)
 {
-	strcpy(noticeMsg, "CD tray opened");
-	noticeMsgTime = sceKernelGetSystemTimeLow();
+	plat_status_msg("CD tray opened");
 }
 
 
@@ -632,9 +637,8 @@ void emu_startSound(void)
 	ret = sceAudio_38553111(samples_block/2, PsndRate, 2); // seems to not need that stupid 64byte alignment
 	if (ret < 0) {
 		lprintf("sceAudio_38553111() failed: %i\n", ret);
-		sprintf(noticeMsg, "sound init failed (%i), snd disabled", ret);
-		noticeMsgTime = sceKernelGetSystemTimeLow();
-		currentConfig.EmuOpt &= ~4;
+		plat_status_msg("sound init failed (%i), snd disabled", ret);
+		currentConfig.EmuOpt &= ~EOPT_EN_SOUND;
 	} else {
 		PicoWriteSound = writeSound;
 		memset32((int *)(void *)sndBuffer, 0, sizeof(sndBuffer)/4);
@@ -804,12 +808,10 @@ static void RunEvents(unsigned int which)
 
 		vidResetMode();
 
-		if (PicoOpt&0x10)
-			strcpy(noticeMsg, "fast renderer");
+		if (PicoOpt & POPT_ALT_RENDERER)
+			plat_status_msg("fast renderer");
 		else if (currentConfig.EmuOpt&0x80)
-			strcpy(noticeMsg, "accurate renderer");
-
-		noticeMsgTime = sceKernelGetSystemTimeLow();
+			plat_status_msg("accurate renderer");
 	}
 	if (which & 0x0300)
 	{
@@ -820,8 +822,8 @@ static void RunEvents(unsigned int which)
 			state_slot += 1;
 			if(state_slot > 9) state_slot = 0;
 		}
-		sprintf(noticeMsg, "SAVE SLOT %i [%s]", state_slot, emu_checkSaveFile(state_slot) ? "USED" : "FREE");
-		noticeMsgTime = sceKernelGetSystemTimeLow();
+		plat_status_msg("SAVE SLOT %i [%s]", state_slot,
+			emu_checkSaveFile(state_slot) ? "USED" : "FREE");
 	}
 }
 
@@ -831,7 +833,7 @@ static void updateKeys(void)
 	static unsigned int prevEvents = 0;
 	int i;
 
-	/* FIXME: port to input fw */
+	/* FIXME: port to input fw, merge with emu.c:emu_update_input() */
 	keys = psp_pad_read(0);
 	if (keys & PSP_CTRL_HOME)
 		sceDisplayWaitVblankStart();
diff --git a/platform/uiq3/engine/main.cpp b/platform/uiq3/engine/main.cpp
index de5ac275..1aa4b025 100644
--- a/platform/uiq3/engine/main.cpp
+++ b/platform/uiq3/engine/main.cpp
@@ -889,9 +889,16 @@ void CGameWindow::RunEvents(TUint32 which)
 }
 
 
-extern "C" void emu_noticeMsgUpdated(void)
+extern "C" void plat_status_msg(const char *format, ...)
 {
-	char *p = noticeMsg;
+	va_list vl;
+	char *p;
+
+	va_start(vl, format);
+	vsnprintf(noticeMsg, sizeof(noticeMsg), fmt, vl);
+	va_end(vl);
+
+	p = noticeMsg;
 	while (*p) {
 		if (*p == ' ') *p = '@';
 		if (*p < '0' || *p > 'Z') { *p = 0; break; }