mirror of
https://github.com/libretro/RetroArch
synced 2025-04-01 13:20:43 +00:00
Merge pull request #3068 from libretro/command-ram
Add support for reading/writing core RAM over the command interface
This commit is contained in:
commit
b59f7c0276
131
cheevos.c
131
cheevos.c
@ -156,15 +156,6 @@ enum
|
||||
CHEEVOS_DIRTY_ALL = (1 << 9) - 1
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned size;
|
||||
unsigned type;
|
||||
int bank_id;
|
||||
unsigned value;
|
||||
unsigned previous;
|
||||
} cheevos_var_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned type;
|
||||
@ -605,6 +596,68 @@ static unsigned cheevos_parse_operator(const char **memaddr)
|
||||
return op;
|
||||
}
|
||||
|
||||
void cheevos_parse_guest_addr(cheevos_var_t *var, unsigned value)
|
||||
{
|
||||
rarch_system_info_t *system;
|
||||
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);
|
||||
|
||||
var->bank_id = -1;
|
||||
var->value = value;
|
||||
|
||||
if (system->mmaps.num_descriptors != 0)
|
||||
{
|
||||
const struct retro_memory_descriptor *desc;
|
||||
const struct retro_memory_descriptor *end;
|
||||
|
||||
if (cheevos_locals.console_id == CHEEVOS_CONSOLE_GAMEBOY_ADVANCE)
|
||||
{
|
||||
/* Patch the address to correctly map it to the mmaps */
|
||||
if (var->value < 0x8000)
|
||||
{
|
||||
/* Internal RAM */
|
||||
var->value += 0x3000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Work RAM */
|
||||
var->value += 0x2000000 - 0x8000;
|
||||
}
|
||||
}
|
||||
else if (cheevos_locals.console_id == CHEEVOS_CONSOLE_PC_ENGINE)
|
||||
{
|
||||
var->value += 0x1f0000;
|
||||
}
|
||||
|
||||
desc = system->mmaps.descriptors;
|
||||
end = desc + system->mmaps.num_descriptors;
|
||||
|
||||
for (; desc < end; desc++)
|
||||
{
|
||||
if ((var->value & desc->select) == desc->start)
|
||||
{
|
||||
var->bank_id = desc - system->mmaps.descriptors;
|
||||
var->value = var->value - desc->start + desc->offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sizeof(cheevos_locals.meminfo) / sizeof(cheevos_locals.meminfo[0]); i++)
|
||||
{
|
||||
if (var->value < cheevos_locals.meminfo[i].size)
|
||||
{
|
||||
var->bank_id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
var->value -= cheevos_locals.meminfo[i].size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
||||
{
|
||||
char *end = NULL;
|
||||
@ -647,63 +700,7 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
||||
if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS
|
||||
|| var->type == CHEEVOS_VAR_TYPE_DELTA_MEM)
|
||||
{
|
||||
rarch_system_info_t *system;
|
||||
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);
|
||||
|
||||
var->bank_id = -1;
|
||||
|
||||
if (system->mmaps.num_descriptors != 0)
|
||||
{
|
||||
const struct retro_memory_descriptor *desc;
|
||||
const struct retro_memory_descriptor *end;
|
||||
|
||||
if (cheevos_locals.console_id == CHEEVOS_CONSOLE_GAMEBOY_ADVANCE)
|
||||
{
|
||||
/* Patch the address to correctly map it to the mmaps */
|
||||
if (var->value < 0x8000)
|
||||
{
|
||||
/* Internal RAM */
|
||||
var->value += 0x3000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Work RAM */
|
||||
var->value += 0x2000000 - 0x8000;
|
||||
}
|
||||
}
|
||||
else if (cheevos_locals.console_id == CHEEVOS_CONSOLE_PC_ENGINE)
|
||||
{
|
||||
var->value += 0x1f0000;
|
||||
}
|
||||
|
||||
desc = system->mmaps.descriptors;
|
||||
end = desc + system->mmaps.num_descriptors;
|
||||
|
||||
for (; desc < end; desc++)
|
||||
{
|
||||
if ((var->value & desc->select) == desc->start)
|
||||
{
|
||||
var->bank_id = desc - system->mmaps.descriptors;
|
||||
var->value = var->value - desc->start + desc->offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sizeof(cheevos_locals.meminfo) / sizeof(cheevos_locals.meminfo[0]); i++)
|
||||
{
|
||||
if (var->value < cheevos_locals.meminfo[i].size)
|
||||
{
|
||||
var->bank_id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
var->value -= cheevos_locals.meminfo[i].size;
|
||||
}
|
||||
}
|
||||
cheevos_parse_guest_addr(var, var->value);
|
||||
#ifdef CHEEVOS_DUMP_ADDRS
|
||||
RARCH_LOG("CHEEVOS var %03d:%08X\n", var->bank_id + 1, var->value);
|
||||
#endif
|
||||
@ -1072,7 +1069,7 @@ static int cheevos_parse(const char *json)
|
||||
Test all the achievements (call once per frame).
|
||||
*****************************************************************************/
|
||||
|
||||
static const uint8_t *cheevos_get_memory(const cheevos_var_t *var)
|
||||
uint8_t *cheevos_get_memory(const cheevos_var_t *var)
|
||||
{
|
||||
if (var->bank_id >= 0)
|
||||
{
|
||||
|
13
cheevos.h
13
cheevos.h
@ -48,6 +48,19 @@ bool cheevos_set_cheats(void);
|
||||
|
||||
void cheevos_set_support_cheevos(bool state);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned size;
|
||||
unsigned type;
|
||||
int bank_id;
|
||||
unsigned value;
|
||||
unsigned previous;
|
||||
} cheevos_var_t;
|
||||
|
||||
void cheevos_parse_guest_addr(cheevos_var_t *var, unsigned value);
|
||||
uint8_t *cheevos_get_memory(const cheevos_var_t *var);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_H */
|
||||
|
114
command.c
114
command.c
@ -102,6 +102,33 @@ struct command
|
||||
bool state[RARCH_BIND_LIST_END];
|
||||
};
|
||||
|
||||
enum cmd_source_t { cmd_none, cmd_stdin, cmd_network };
|
||||
static enum cmd_source_t lastcmd_source;
|
||||
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY)
|
||||
static int lastcmd_net_fd;
|
||||
static struct sockaddr_storage lastcmd_net_source;
|
||||
static socklen_t lastcmd_net_source_len;
|
||||
#endif
|
||||
|
||||
static bool command_reply(const char * data, size_t len)
|
||||
{
|
||||
#ifdef HAVE_STDIN_CMD
|
||||
if (lastcmd_source == cmd_stdin)
|
||||
{
|
||||
fwrite(data, 1,len, stdout);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY)
|
||||
if (lastcmd_source == cmd_network)
|
||||
{
|
||||
sendto(lastcmd_net_fd, data, len, 0, (struct sockaddr*)&lastcmd_net_source, lastcmd_net_source_len);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
struct cmd_map
|
||||
{
|
||||
const char *str;
|
||||
@ -157,8 +184,77 @@ static bool command_set_shader(const char *arg)
|
||||
return video_driver_set_shader(type, arg);
|
||||
}
|
||||
|
||||
static bool command_read_ram(const char *arg)
|
||||
{
|
||||
#ifdef HAVE_CHEEVOS
|
||||
cheevos_var_t var;
|
||||
const uint8_t * data;
|
||||
unsigned nbytes;
|
||||
int i;
|
||||
char reply[256];
|
||||
strcpy(reply, "READ_CORE_RAM ");
|
||||
char * reply_at = reply + strlen("READ_CORE_RAM ");
|
||||
strcpy(reply_at, arg);
|
||||
|
||||
cheevos_parse_guest_addr(&var, strtoul(reply_at, (char**)&reply_at, 16));
|
||||
data = cheevos_get_memory(&var);
|
||||
|
||||
if (data)
|
||||
{
|
||||
unsigned nbytes = strtol(reply_at, NULL, 10);
|
||||
|
||||
for (i=0;i<nbytes;i++)
|
||||
{
|
||||
sprintf(reply_at+3*i, " %.2X", data[i]);
|
||||
}
|
||||
reply_at[3*nbytes] = '\n';
|
||||
command_reply(reply, reply_at+3*nbytes+1 - reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(reply_at, " -1\n");
|
||||
command_reply(reply, reply_at+strlen(" -1\n") - reply);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool command_write_ram(const char *arg)
|
||||
{
|
||||
#ifdef HAVE_CHEEVOS
|
||||
cheevos_var_t var;
|
||||
uint8_t * data;
|
||||
unsigned nbytes;
|
||||
int i;
|
||||
char reply[256];
|
||||
|
||||
cheevos_parse_guest_addr(&var, strtoul(arg, (char**)&arg, 16));
|
||||
data = cheevos_get_memory(&var);
|
||||
|
||||
if (!data) return false;
|
||||
|
||||
while (*arg)
|
||||
{
|
||||
*data = strtoul(arg, (char**)&arg, 16);
|
||||
data++;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct cmd_action_map action_map[] = {
|
||||
{ "SET_SHADER", command_set_shader, "<shader path>" },
|
||||
#ifdef HAVE_CHEEVOS
|
||||
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>" },
|
||||
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ..." },
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct cmd_map map[] = {
|
||||
@ -182,7 +278,7 @@ static const struct cmd_map map[] = {
|
||||
{ "CHEAT_TOGGLE", RARCH_CHEAT_TOGGLE },
|
||||
{ "SCREENSHOT", RARCH_SCREENSHOT },
|
||||
{ "MUTE", RARCH_MUTE },
|
||||
{ "OSK", RARCH_OSK },
|
||||
{ "OSK", RARCH_OSK },
|
||||
{ "NETPLAY_FLIP", RARCH_NETPLAY_FLIP },
|
||||
{ "SLOWMOTION", RARCH_SLOWMOTION },
|
||||
{ "VOLUME_UP", RARCH_VOLUME_UP },
|
||||
@ -199,6 +295,7 @@ static const struct cmd_map map[] = {
|
||||
{ "MENU_RIGHT", RETRO_DEVICE_ID_JOYPAD_RIGHT },
|
||||
{ "MENU_A", RETRO_DEVICE_ID_JOYPAD_A },
|
||||
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
|
||||
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
|
||||
};
|
||||
|
||||
static bool command_get_arg(const char *tok,
|
||||
@ -264,16 +361,19 @@ static void command_parse_sub_msg(command_t *handle, const char *tok)
|
||||
msg_hash_to_str(MSG_RECEIVED));
|
||||
}
|
||||
|
||||
static void command_parse_msg(command_t *handle, char *buf)
|
||||
static void command_parse_msg(command_t *handle, char *buf, enum cmd_source_t source)
|
||||
{
|
||||
char *save = NULL;
|
||||
const char *tok = strtok_r(buf, "\n", &save);
|
||||
|
||||
lastcmd_source = source;
|
||||
|
||||
while (tok)
|
||||
{
|
||||
command_parse_sub_msg(handle, tok);
|
||||
tok = strtok_r(NULL, "\n", &save);
|
||||
}
|
||||
lastcmd_source = cmd_none;
|
||||
}
|
||||
|
||||
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY)
|
||||
@ -449,14 +549,18 @@ static void command_network_poll(command_t *handle)
|
||||
for (;;)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
lastcmd_net_fd = handle->net_fd;
|
||||
lastcmd_net_source_len = sizeof(lastcmd_net_source);
|
||||
ssize_t ret = recvfrom(handle->net_fd, buf,
|
||||
sizeof(buf) - 1, 0, NULL, NULL);
|
||||
sizeof(buf) - 1, 0, (struct sockaddr*)&lastcmd_net_source, &lastcmd_net_source_len);
|
||||
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
buf[ret] = '\0';
|
||||
command_parse_msg(handle, buf);
|
||||
|
||||
command_parse_msg(handle, buf, cmd_network);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -659,7 +763,7 @@ static void command_stdin_poll(command_t *handle)
|
||||
*last_newline++ = '\0';
|
||||
msg_len = last_newline - handle->stdin_buf;
|
||||
|
||||
command_parse_msg(handle, handle->stdin_buf);
|
||||
command_parse_msg(handle, handle->stdin_buf, cmd_stdin);
|
||||
|
||||
memmove(handle->stdin_buf, last_newline,
|
||||
handle->stdin_buf_ptr - msg_len);
|
||||
|
Loading…
x
Reference in New Issue
Block a user