Add support for reading and writing core RAM over the command interfaces.

This commit is contained in:
Alcaro 2016-06-04 17:41:14 +02:00
parent c63f11f6fd
commit d845093c7b
2 changed files with 176 additions and 60 deletions

122
cheevos.c
View File

@ -605,6 +605,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 +709,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 +1078,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)
{

114
command.c
View File

@ -102,6 +102,33 @@ struct command
bool state[RARCH_BIND_LIST_END];
};
enum lastcmd_source_t { cmd_none, cmd_stdin, cmd_network };
static int lastcmd_source_type;
#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_type == cmd_stdin)
{
fwrite(data, 1,len, stdout);
return true;
}
#endif
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY)
if (lastcmd_source_type == 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,82 @@ static bool command_set_shader(const char *arg)
return video_driver_set_shader(type, arg);
}
#ifdef HAVE_CHEEVOS
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);
#endif
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);
nbytes = strtol(reply_at, NULL, 10);
*reply_at = '\0';
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);
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);
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 +283,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 +300,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,
@ -449,14 +551,20 @@ static void command_network_poll(command_t *handle)
for (;;)
{
char buf[1024];
lastcmd_source_type = cmd_network;
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);
lastcmd_source_type = cmd_none;
}
}
#endif
@ -659,7 +767,9 @@ static void command_stdin_poll(command_t *handle)
*last_newline++ = '\0';
msg_len = last_newline - handle->stdin_buf;
lastcmd_source_type = cmd_stdin;
command_parse_msg(handle, handle->stdin_buf);
lastcmd_source_type = cmd_none;
memmove(handle->stdin_buf, last_newline,
handle->stdin_buf_ptr - msg_len);