mirror of
https://github.com/libretro/RetroArch
synced 2025-04-18 14:42:30 +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
99
cheevos.c
99
cheevos.c
@ -156,15 +156,6 @@ enum
|
|||||||
CHEEVOS_DIRTY_ALL = (1 << 9) - 1
|
CHEEVOS_DIRTY_ALL = (1 << 9) - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned size;
|
|
||||||
unsigned type;
|
|
||||||
int bank_id;
|
|
||||||
unsigned value;
|
|
||||||
unsigned previous;
|
|
||||||
} cheevos_var_t;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned type;
|
unsigned type;
|
||||||
@ -605,52 +596,13 @@ static unsigned cheevos_parse_operator(const char **memaddr)
|
|||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
void cheevos_parse_guest_addr(cheevos_var_t *var, unsigned value)
|
||||||
{
|
|
||||||
char *end = NULL;
|
|
||||||
const char *str = *memaddr;
|
|
||||||
unsigned base = 16;
|
|
||||||
|
|
||||||
if (toupper(*str) == 'D' && str[1] == '0' && toupper(str[2]) == 'X')
|
|
||||||
{
|
|
||||||
/* d0x + 4 hex digits */
|
|
||||||
str += 3;
|
|
||||||
var->type = CHEEVOS_VAR_TYPE_DELTA_MEM;
|
|
||||||
}
|
|
||||||
else if (*str == '0' && toupper(str[1]) == 'X')
|
|
||||||
{
|
|
||||||
/* 0x + 4 hex digits */
|
|
||||||
str += 2;
|
|
||||||
var->type = CHEEVOS_VAR_TYPE_ADDRESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var->type = CHEEVOS_VAR_TYPE_VALUE_COMP;
|
|
||||||
|
|
||||||
if (toupper(*str) == 'H')
|
|
||||||
str++;
|
|
||||||
else
|
|
||||||
base = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (var->type != CHEEVOS_VAR_TYPE_VALUE_COMP)
|
|
||||||
{
|
|
||||||
var->size = cheevos_prefix_to_comp_size(*str);
|
|
||||||
|
|
||||||
if (var->size != CHEEVOS_VAR_SIZE_SIXTEEN_BITS)
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var->value = strtol(str, &end, base);
|
|
||||||
*memaddr = end;
|
|
||||||
|
|
||||||
if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS
|
|
||||||
|| var->type == CHEEVOS_VAR_TYPE_DELTA_MEM)
|
|
||||||
{
|
{
|
||||||
rarch_system_info_t *system;
|
rarch_system_info_t *system;
|
||||||
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);
|
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);
|
||||||
|
|
||||||
var->bank_id = -1;
|
var->bank_id = -1;
|
||||||
|
var->value = value;
|
||||||
|
|
||||||
if (system->mmaps.num_descriptors != 0)
|
if (system->mmaps.num_descriptors != 0)
|
||||||
{
|
{
|
||||||
@ -704,6 +656,51 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
|||||||
var->value -= cheevos_locals.meminfo[i].size;
|
var->value -= cheevos_locals.meminfo[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
||||||
|
{
|
||||||
|
char *end = NULL;
|
||||||
|
const char *str = *memaddr;
|
||||||
|
unsigned base = 16;
|
||||||
|
|
||||||
|
if (toupper(*str) == 'D' && str[1] == '0' && toupper(str[2]) == 'X')
|
||||||
|
{
|
||||||
|
/* d0x + 4 hex digits */
|
||||||
|
str += 3;
|
||||||
|
var->type = CHEEVOS_VAR_TYPE_DELTA_MEM;
|
||||||
|
}
|
||||||
|
else if (*str == '0' && toupper(str[1]) == 'X')
|
||||||
|
{
|
||||||
|
/* 0x + 4 hex digits */
|
||||||
|
str += 2;
|
||||||
|
var->type = CHEEVOS_VAR_TYPE_ADDRESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var->type = CHEEVOS_VAR_TYPE_VALUE_COMP;
|
||||||
|
|
||||||
|
if (toupper(*str) == 'H')
|
||||||
|
str++;
|
||||||
|
else
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var->type != CHEEVOS_VAR_TYPE_VALUE_COMP)
|
||||||
|
{
|
||||||
|
var->size = cheevos_prefix_to_comp_size(*str);
|
||||||
|
|
||||||
|
if (var->size != CHEEVOS_VAR_SIZE_SIXTEEN_BITS)
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var->value = strtol(str, &end, base);
|
||||||
|
*memaddr = end;
|
||||||
|
|
||||||
|
if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS
|
||||||
|
|| var->type == CHEEVOS_VAR_TYPE_DELTA_MEM)
|
||||||
|
{
|
||||||
|
cheevos_parse_guest_addr(var, var->value);
|
||||||
#ifdef CHEEVOS_DUMP_ADDRS
|
#ifdef CHEEVOS_DUMP_ADDRS
|
||||||
RARCH_LOG("CHEEVOS var %03d:%08X\n", var->bank_id + 1, var->value);
|
RARCH_LOG("CHEEVOS var %03d:%08X\n", var->bank_id + 1, var->value);
|
||||||
#endif
|
#endif
|
||||||
@ -1072,7 +1069,7 @@ static int cheevos_parse(const char *json)
|
|||||||
Test all the achievements (call once per frame).
|
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)
|
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);
|
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
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif /* __RARCH_CHEEVOS_H */
|
#endif /* __RARCH_CHEEVOS_H */
|
||||||
|
112
command.c
112
command.c
@ -102,6 +102,33 @@ struct command
|
|||||||
bool state[RARCH_BIND_LIST_END];
|
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
|
struct cmd_map
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
@ -157,8 +184,77 @@ static bool command_set_shader(const char *arg)
|
|||||||
return video_driver_set_shader(type, 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[] = {
|
static const struct cmd_action_map action_map[] = {
|
||||||
{ "SET_SHADER", command_set_shader, "<shader path>" },
|
{ "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[] = {
|
static const struct cmd_map map[] = {
|
||||||
@ -199,6 +295,7 @@ static const struct cmd_map map[] = {
|
|||||||
{ "MENU_RIGHT", RETRO_DEVICE_ID_JOYPAD_RIGHT },
|
{ "MENU_RIGHT", RETRO_DEVICE_ID_JOYPAD_RIGHT },
|
||||||
{ "MENU_A", RETRO_DEVICE_ID_JOYPAD_A },
|
{ "MENU_A", RETRO_DEVICE_ID_JOYPAD_A },
|
||||||
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
|
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
|
||||||
|
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool command_get_arg(const char *tok,
|
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));
|
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;
|
char *save = NULL;
|
||||||
const char *tok = strtok_r(buf, "\n", &save);
|
const char *tok = strtok_r(buf, "\n", &save);
|
||||||
|
|
||||||
|
lastcmd_source = source;
|
||||||
|
|
||||||
while (tok)
|
while (tok)
|
||||||
{
|
{
|
||||||
command_parse_sub_msg(handle, tok);
|
command_parse_sub_msg(handle, tok);
|
||||||
tok = strtok_r(NULL, "\n", &save);
|
tok = strtok_r(NULL, "\n", &save);
|
||||||
}
|
}
|
||||||
|
lastcmd_source = cmd_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY)
|
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY)
|
||||||
@ -449,14 +549,18 @@ static void command_network_poll(command_t *handle)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
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,
|
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)
|
if (ret <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buf[ret] = '\0';
|
buf[ret] = '\0';
|
||||||
command_parse_msg(handle, buf);
|
|
||||||
|
command_parse_msg(handle, buf, cmd_network);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -659,7 +763,7 @@ static void command_stdin_poll(command_t *handle)
|
|||||||
*last_newline++ = '\0';
|
*last_newline++ = '\0';
|
||||||
msg_len = last_newline - handle->stdin_buf;
|
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,
|
memmove(handle->stdin_buf, last_newline,
|
||||||
handle->stdin_buf_ptr - msg_len);
|
handle->stdin_buf_ptr - msg_len);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user