mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-04 14:57:45 -04:00
32x: drc: new debug facility (pdb). Few fixes thanks to it.
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@863 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
parent
2368651527
commit
5686d93123
14 changed files with 708 additions and 33 deletions
407
cpu/debug.c
Normal file
407
cpu/debug.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* vim:shiftwidth=2:expandtab
|
||||
* PDB, the PicoDrive debugger
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../pico/pico_int.h"
|
||||
#include "debug.h"
|
||||
|
||||
static char pdb_pending_cmds[128];
|
||||
static char pdb_event_cmds[128];
|
||||
|
||||
static struct pdb_cpu {
|
||||
void *context;
|
||||
int type;
|
||||
int id;
|
||||
const char *name;
|
||||
unsigned int bpts[16];
|
||||
int bpt_count;
|
||||
int icount;
|
||||
} pdb_cpus[5];
|
||||
static int pdb_cpu_count;
|
||||
|
||||
static int pdb_global_icount;
|
||||
|
||||
#ifdef PDB_NET
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug_net.h"
|
||||
|
||||
static int pdb_net_sock = -1;
|
||||
|
||||
int pdb_net_connect(const char *host, const char *port)
|
||||
{
|
||||
struct sockaddr_in sockadr;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
|
||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (sock == -1) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockadr.sin_addr.s_addr = inet_addr(host);
|
||||
sockadr.sin_family = AF_INET;
|
||||
sockadr.sin_port = htons(atoi(port));
|
||||
|
||||
ret = connect(sock, (struct sockaddr *)&sockadr, sizeof(sockadr));
|
||||
if (ret != 0) {
|
||||
perror("pdb_net: connect");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("pdb_net: connected to %s:%s\n", host, port);
|
||||
|
||||
pdb_net_sock = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdb_net_send(struct pdb_cpu *cpu, unsigned int pc)
|
||||
{
|
||||
packet_t packet;
|
||||
int ret;
|
||||
|
||||
if (pdb_net_sock < 0)
|
||||
return 0; // not connected
|
||||
|
||||
if (cpu->type == PDBCT_SH2) {
|
||||
SH2 *sh2 = cpu->context;
|
||||
int rl = offsetof(SH2, macl) + sizeof(sh2->macl);
|
||||
packet.header.type = PDBCT_SH2;
|
||||
packet.header.cpuid = cpu->id;
|
||||
packet.regs[0] = pc;
|
||||
memcpy(&packet.regs[1], sh2->r, rl);
|
||||
packet.regs[1+24+0] = sh2->pdb_io_csum[0];
|
||||
packet.regs[1+24+1] = sh2->pdb_io_csum[1];
|
||||
packet.header.len = 4 + rl + 4*2;
|
||||
sh2->pdb_io_csum[0] = sh2->pdb_io_csum[1] = 0;
|
||||
}
|
||||
|
||||
ret = send(pdb_net_sock, &packet, sizeof(packet.header) + packet.header.len, MSG_NOSIGNAL);
|
||||
if (ret != sizeof(packet.header) + packet.header.len) {
|
||||
if (ret < 0)
|
||||
perror("send");
|
||||
else
|
||||
printf("send: %d/%d\n", ret, sizeof(packet.header) + packet.header.len);
|
||||
close(pdb_net_sock);
|
||||
pdb_net_sock = -1;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#define pdb_net_send(a,b) 0
|
||||
#endif // PDB_NET
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#endif
|
||||
|
||||
static char *my_readline(const char *prompt)
|
||||
{
|
||||
char *line = NULL;
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
line = readline("(pdb) ");
|
||||
if (line == NULL)
|
||||
return NULL;
|
||||
if (line[0] != 0)
|
||||
add_history(line);
|
||||
#else
|
||||
size_t size = 0;
|
||||
ssize_t ret;
|
||||
|
||||
printf("(pdb) ");
|
||||
fflush(stdout);
|
||||
ret = getline(&line, &size, stdin);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
if (ret > 0 && line[ret - 1] == '\n')
|
||||
line[ret - 1] = 0;
|
||||
#endif
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
static struct pdb_cpu *context2cpu(const void *context)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < pdb_cpu_count; i++)
|
||||
if (pdb_cpus[i].context == context)
|
||||
return &pdb_cpus[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_token(char *buf, int blen, const char *str)
|
||||
{
|
||||
const char *p, *s, *e;
|
||||
int len;
|
||||
|
||||
p = str;
|
||||
while (isspace_(*p))
|
||||
p++;
|
||||
if (*p == 0)
|
||||
return NULL;
|
||||
if (*p == ';') {
|
||||
strcpy(buf, ";");
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
s = p;
|
||||
while (*p != 0 && *p != ';' && !isspace_(*p))
|
||||
p++;
|
||||
e = p;
|
||||
while (isspace_(*e))
|
||||
e++;
|
||||
|
||||
len = p - s;
|
||||
if (len > blen - 1)
|
||||
len = blen - 1;
|
||||
memcpy(buf, s, len);
|
||||
buf[len] = 0;
|
||||
return e;
|
||||
}
|
||||
|
||||
static const char *get_arg(char *buf, int blen, const char *str)
|
||||
{
|
||||
if (*str == ';')
|
||||
return NULL;
|
||||
return get_token(buf, blen, str);
|
||||
}
|
||||
|
||||
enum cmd_ret_e {
|
||||
CMDRET_DONE, // ..and back to prompt
|
||||
// CMDRET_PROMPT, // go to prompt
|
||||
CMDRET_CONT_DO_NEXT, // continue and do remaining cmds on next event
|
||||
CMDRET_CONT_REDO, // continue and redo all cmds on next event
|
||||
};
|
||||
|
||||
static int do_print(struct pdb_cpu *cpu, const char *args)
|
||||
{
|
||||
int i;
|
||||
elprintf(EL_STATUS, "cpu %d (%s)", cpu->id, cpu->name);
|
||||
if (cpu->type == PDBCT_SH2) {
|
||||
SH2 *sh2 = cpu->context;
|
||||
printf("PC,SR %08x, %03x\n", sh2->pc, sh2->sr & 0x3ff);
|
||||
for (i = 0; i < 16/2; i++)
|
||||
printf("R%d,%2d %08x,%08x\n", i, i + 8, sh2->r[i], sh2->r[i + 8]);
|
||||
printf("gb,vb %08x,%08x\n", sh2->gbr, sh2->vbr);
|
||||
printf("IRQs/mask: %02x/%02x\n", Pico32x.sh2irqi[sh2->is_slave],
|
||||
Pico32x.sh2irq_mask[sh2->is_slave]);
|
||||
printf("cycles %d/%d (%d)\n", sh2->cycles_done, sh2->cycles_aim, (signed int)sh2->sr >> 12);
|
||||
}
|
||||
return CMDRET_DONE;
|
||||
}
|
||||
|
||||
static int do_step_all(struct pdb_cpu *cpu, const char *args)
|
||||
{
|
||||
char tmp[32];
|
||||
if (!get_arg(tmp, sizeof(tmp), args)) {
|
||||
printf("step_all: missing arg\n");
|
||||
return CMDRET_DONE;
|
||||
}
|
||||
|
||||
pdb_global_icount = atoi(tmp);
|
||||
return CMDRET_CONT_DO_NEXT;
|
||||
}
|
||||
|
||||
static int do_continue(struct pdb_cpu *cpu, const char *args)
|
||||
{
|
||||
char tmp[32];
|
||||
if (get_arg(tmp, sizeof(tmp), args))
|
||||
cpu->icount = atoi(tmp);
|
||||
return CMDRET_CONT_DO_NEXT;
|
||||
}
|
||||
|
||||
static int do_step(struct pdb_cpu *cpu, const char *args)
|
||||
{
|
||||
cpu->icount = 1;
|
||||
return do_continue(cpu, args);
|
||||
}
|
||||
|
||||
static int do_waitcpu(struct pdb_cpu *cpu, const char *args)
|
||||
{
|
||||
char tmp[32];
|
||||
if (!get_arg(tmp, sizeof(tmp), args)) {
|
||||
printf("waitcpu: missing arg\n");
|
||||
return CMDRET_DONE;
|
||||
}
|
||||
if (strcmp(tmp, cpu->name) == 0)
|
||||
return CMDRET_DONE;
|
||||
|
||||
return CMDRET_CONT_REDO;
|
||||
}
|
||||
|
||||
static int do_help(struct pdb_cpu *cpu, const char *args);
|
||||
|
||||
static struct {
|
||||
const char *cmd;
|
||||
const char *help;
|
||||
int (*handler)(struct pdb_cpu *cpu, const char *args);
|
||||
} pdb_cmds[] = {
|
||||
{ "help", "", do_help },
|
||||
{ "continue", "[insns]", do_continue },
|
||||
{ "step", "[insns]", do_step },
|
||||
{ "step_all", "<insns>", do_step_all },
|
||||
{ "waitcpu", "<cpuname>", do_waitcpu },
|
||||
{ "print", "", do_print },
|
||||
};
|
||||
|
||||
static int do_help(struct pdb_cpu *cpu, const char *args)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(pdb_cmds); i++)
|
||||
printf("%s %s\n", pdb_cmds[i].cmd, pdb_cmds[i].help);
|
||||
return CMDRET_DONE;
|
||||
}
|
||||
|
||||
static int do_comands(struct pdb_cpu *cpu, const char *cmds)
|
||||
{
|
||||
const char *p = cmds;
|
||||
while (p != NULL)
|
||||
{
|
||||
const char *pcmd;
|
||||
char cmd[32];
|
||||
int i, len;
|
||||
int ret = 0;
|
||||
|
||||
pcmd = p;
|
||||
p = get_token(cmd, sizeof(cmd), p);
|
||||
if (p == NULL)
|
||||
break;
|
||||
if (cmd[0] == ';')
|
||||
continue;
|
||||
|
||||
len = strlen(cmd);
|
||||
for (i = 0; i < ARRAY_SIZE(pdb_cmds); i++)
|
||||
if (strncmp(pdb_cmds[i].cmd, cmd, len) == 0) {
|
||||
ret = pdb_cmds[i].handler(cpu, p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(pdb_cmds)) {
|
||||
printf("bad cmd: %s\n", cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
// skip until next command
|
||||
while (1) {
|
||||
p = get_token(cmd, sizeof(cmd), p);
|
||||
if (p == NULL || cmd[0] == ';')
|
||||
break;
|
||||
}
|
||||
|
||||
pdb_event_cmds[0] = 0;
|
||||
if (ret == CMDRET_CONT_DO_NEXT) {
|
||||
pdb_pending_cmds[0] = 0;
|
||||
if (p != NULL)
|
||||
strcpy(pdb_event_cmds, p);
|
||||
return 0;
|
||||
}
|
||||
if (ret == CMDRET_CONT_REDO) {
|
||||
if (pcmd != pdb_pending_cmds)
|
||||
strncpy(pdb_pending_cmds, pcmd, sizeof(pdb_pending_cmds));
|
||||
return 0;
|
||||
}
|
||||
pdb_pending_cmds[0] = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void do_prompt(struct pdb_cpu *cpu)
|
||||
{
|
||||
static char prev[128];
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
char *line, *cline;
|
||||
|
||||
line = my_readline("(pdb) ");
|
||||
if (line == NULL)
|
||||
break;
|
||||
if (line[0] == 0)
|
||||
cline = prev;
|
||||
else {
|
||||
cline = line;
|
||||
strncpy(prev, line, sizeof(prev));
|
||||
}
|
||||
|
||||
ret = do_comands(cpu, cline);
|
||||
free(line);
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pdb_register_cpu(void *context, int type, const char *name)
|
||||
{
|
||||
int i = pdb_cpu_count;
|
||||
memset(&pdb_cpus[i], 0, sizeof(pdb_cpus[i]));
|
||||
pdb_cpus[i].context = context;
|
||||
pdb_cpus[i].type = type;
|
||||
pdb_cpus[i].id = pdb_cpu_count;
|
||||
pdb_cpus[i].name = name;
|
||||
pdb_cpus[i].icount = -1;
|
||||
pdb_cpu_count++;
|
||||
}
|
||||
|
||||
void pdb_step(void *context, unsigned int pc)
|
||||
{
|
||||
struct pdb_cpu *cpu = context2cpu(context);
|
||||
int i;
|
||||
|
||||
if (pdb_net_send(cpu, pc) < 0)
|
||||
goto prompt;
|
||||
|
||||
if (pdb_pending_cmds[0] != 0)
|
||||
if (do_comands(cpu, pdb_pending_cmds))
|
||||
goto prompt;
|
||||
|
||||
// breakpoint?
|
||||
for (i = 0; i < cpu->bpt_count; i++)
|
||||
if (cpu->bpts[i] == pc)
|
||||
goto prompt;
|
||||
|
||||
// hit num of insns?
|
||||
if (pdb_global_icount > 0)
|
||||
if (--pdb_global_icount == 0)
|
||||
goto prompt;
|
||||
|
||||
if (cpu->icount > 0)
|
||||
if (--(cpu->icount) == 0)
|
||||
goto prompt;
|
||||
|
||||
return;
|
||||
|
||||
prompt:
|
||||
if (pdb_event_cmds[0] != 0)
|
||||
if (!do_comands(cpu, pdb_event_cmds))
|
||||
return;
|
||||
|
||||
printf("%s @%08x\n", cpu->name, pc);
|
||||
do_prompt(cpu);
|
||||
}
|
||||
|
||||
void pdb_command(const char *cmd)
|
||||
{
|
||||
strncpy(pdb_pending_cmds, cmd, sizeof(pdb_pending_cmds));
|
||||
pdb_pending_cmds[sizeof(pdb_pending_cmds) - 1] = 0;
|
||||
}
|
||||
|
||||
void pdb_cleanup(void)
|
||||
{
|
||||
pdb_cpu_count = 0;
|
||||
}
|
||||
|
31
cpu/debug.h
Normal file
31
cpu/debug.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
#ifdef PDB
|
||||
|
||||
enum {
|
||||
PDBCT_SH2,
|
||||
};
|
||||
|
||||
void pdb_register_cpu(void *context, int type, const char *name);
|
||||
void pdb_cleanup(void);
|
||||
void pdb_step(void *context, unsigned int pc);
|
||||
void pdb_command(const char *cmd);
|
||||
|
||||
#else
|
||||
|
||||
#define pdb_register_cpu(a,b,c)
|
||||
#define pdb_cleanup()
|
||||
#define pdb_step(a,b)
|
||||
#define pdb_command(a)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(PDB) && defined(PDB_NET)
|
||||
|
||||
int pdb_net_connect(const char *host, const char *port);
|
||||
|
||||
#else
|
||||
|
||||
#define pdb_net_connect(a,b) 0
|
||||
|
||||
#endif
|
126
cpu/debug_net.c
Normal file
126
cpu/debug_net.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug_net.h"
|
||||
|
||||
static const char * const regnames[] = {
|
||||
"PC",
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
|
||||
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "SP",
|
||||
"PC2", "PC3", "PR", "SR", "GBR", "VBR", "MACH", "MACL",
|
||||
"MEM0", "MEM1", // mem i/o csums
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int pc_trace[5][4], pc_trace_p[5] = { 0, };
|
||||
struct addrinfo *ai, *ais, hints;
|
||||
int sock = -1, sock1, sock2;
|
||||
struct sockaddr_in6 sa;
|
||||
packet_t packet1, packet2;
|
||||
int i, ret, cnt, cpuid;
|
||||
socklen_t sal;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
ret = getaddrinfo("::", "1234", &hints, &ais);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
for (ai = ais; ai != NULL; ai = ai->ai_next) {
|
||||
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (sock == -1)
|
||||
continue;
|
||||
|
||||
ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
|
||||
if (ret != 0) {
|
||||
close(sock);
|
||||
sock = -1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ais);
|
||||
|
||||
if (sock == -1) {
|
||||
perror("failed to bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = listen(sock, SOMAXCONN);
|
||||
if (ret != 0) {
|
||||
perror("failed to listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sal = sizeof(sa);
|
||||
sock1 = accept(sock, (struct sockaddr *)&sa, &sal);
|
||||
if (sock1 == -1) {
|
||||
perror("failed to accept");
|
||||
return -1;
|
||||
}
|
||||
printf("client1 connected\n");
|
||||
|
||||
sal = sizeof(sa);
|
||||
sock2 = accept(sock, (struct sockaddr *)&sa, &sal);
|
||||
if (sock2 == -1) {
|
||||
perror("failed to accept");
|
||||
return -1;
|
||||
}
|
||||
printf("client2 connected\n");
|
||||
|
||||
for (cnt = 0; ; cnt++)
|
||||
{
|
||||
#define tmp_size (4+4 + 24*4 + 2*4)
|
||||
ret = recv(sock1, &packet1, tmp_size, MSG_WAITALL);
|
||||
if (ret != tmp_size) {
|
||||
if (ret < 0)
|
||||
perror("recv1");
|
||||
else
|
||||
printf("recv1 %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
ret = recv(sock2, &packet2, tmp_size, MSG_WAITALL);
|
||||
if (ret != tmp_size) {
|
||||
if (ret < 0)
|
||||
perror("recv2");
|
||||
else
|
||||
printf("recv2 %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cpuid = packet1.header.cpuid;
|
||||
if (memcmp(&packet1, &packet2, sizeof(packet1.header) + packet1.header.len) == 0) {
|
||||
pc_trace[cpuid][pc_trace_p[cpuid]++ & 3] = packet1.regs[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(int *)&packet1.header != *(int *)&packet2.header)
|
||||
printf("%d: header\n", cnt);
|
||||
|
||||
// check regs (and stuff)
|
||||
for (i = 0; i < 1+24+2; i++)
|
||||
if (packet1.regs[i] != packet2.regs[i])
|
||||
printf("%d: %3s: %08x %08x\n", cnt, regnames[i], packet1.regs[i], packet2.regs[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
printf("--\nCPU %d, trace:", cpuid);
|
||||
for (i = 0; i < 4; i++)
|
||||
printf(" %08x", pc_trace[cpuid][pc_trace_p[cpuid]++ & 3]);
|
||||
printf(" %08x\n", packet1.regs[0]);
|
||||
|
||||
for (i = 0; i < 24+1; i++)
|
||||
printf("%3s: %08x %08x\n", regnames[i], packet1.regs[i], packet2.regs[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
9
cpu/debug_net.h
Normal file
9
cpu/debug_net.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
typedef struct {
|
||||
struct {
|
||||
unsigned char type;
|
||||
unsigned char cpuid;
|
||||
unsigned short len;
|
||||
} header;
|
||||
unsigned int regs[32];
|
||||
} packet_t;
|
||||
|
|
@ -241,30 +241,45 @@
|
|||
#define EOP_MSR_REG(rm) EOP_C_MSR_REG(A_COND_AL,rm)
|
||||
|
||||
|
||||
// XXX: AND, RSB, *C, MVN will break if 1 insn is not enough
|
||||
// XXX: AND, RSB, *C, will break if 1 insn is not enough
|
||||
static void emith_op_imm2(int cond, int s, int op, int rd, int rn, unsigned int imm)
|
||||
{
|
||||
int ror2;
|
||||
u32 v;
|
||||
|
||||
if (op == A_OP_MOV) {
|
||||
switch (op) {
|
||||
case A_OP_MOV:
|
||||
rn = 0;
|
||||
if (~imm < 0x100) {
|
||||
if (~imm < 0x10000) {
|
||||
imm = ~imm;
|
||||
op = A_OP_MVN;
|
||||
}
|
||||
} else if (imm == 0)
|
||||
return;
|
||||
break;
|
||||
|
||||
for (v = imm, ror2 = 0; v != 0 || op == A_OP_MOV; v >>= 8, ror2 -= 8/2) {
|
||||
case A_OP_EOR:
|
||||
case A_OP_SUB:
|
||||
case A_OP_ADD:
|
||||
case A_OP_ORR:
|
||||
case A_OP_BIC:
|
||||
if (s == 0 && imm == 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
for (v = imm, ror2 = 0; ; ror2 -= 8/2) {
|
||||
/* shift down to get 'best' rot2 */
|
||||
for (; v && !(v & 3); v >>= 2)
|
||||
ror2--;
|
||||
|
||||
EOP_C_DOP_IMM(cond, op, s, rn, rd, ror2 & 0x0f, v & 0xff);
|
||||
|
||||
v >>= 8;
|
||||
if (v == 0)
|
||||
break;
|
||||
if (op == A_OP_MOV)
|
||||
op = A_OP_ORR;
|
||||
if (op == A_OP_MVN)
|
||||
op = A_OP_BIC;
|
||||
rn = rd;
|
||||
}
|
||||
}
|
||||
|
@ -414,6 +429,9 @@ static int emith_xbranch(int cond, void *target, int is_call)
|
|||
#define emith_add_r_imm(r, imm) \
|
||||
emith_op_imm(A_COND_AL, 0, A_OP_ADD, r, imm)
|
||||
|
||||
#define emith_adc_r_imm(r, imm) \
|
||||
emith_op_imm(A_COND_AL, 0, A_OP_ADC, r, imm)
|
||||
|
||||
#define emith_sub_r_imm(r, imm) \
|
||||
emith_op_imm(A_COND_AL, 0, A_OP_SUB, r, imm)
|
||||
|
||||
|
|
|
@ -180,13 +180,18 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
|
|||
EMIT(imm, u32); \
|
||||
} while (0)
|
||||
|
||||
// 2 - adc, 3 - sbb
|
||||
#define emith_add_r_imm(r, imm) \
|
||||
emith_arith_r_imm(0, r, imm)
|
||||
|
||||
#define emith_or_r_imm(r, imm) \
|
||||
emith_arith_r_imm(1, r, imm)
|
||||
|
||||
#define emith_adc_r_imm(r, imm) \
|
||||
emith_arith_r_imm(2, r, imm)
|
||||
|
||||
#define emith_sbc_r_imm(r, imm) \
|
||||
emith_arith_r_imm(3, r, imm) // sbb
|
||||
|
||||
#define emith_and_r_imm(r, imm) \
|
||||
emith_arith_r_imm(4, r, imm)
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "sh2.h"
|
||||
#include "compiler.h"
|
||||
#include "../drc/cmn.h"
|
||||
#include "../debug.h"
|
||||
|
||||
// features
|
||||
#define PROPAGATE_CONSTANTS 1
|
||||
|
@ -68,12 +69,14 @@ static char sh2dasm_buff[64];
|
|||
#define do_host_disasm(x)
|
||||
#endif
|
||||
|
||||
#if (DRC_DEBUG & 4)
|
||||
static void REGPARM(3) *sh2_drc_announce_entry(void *block, SH2 *sh2, u32 sr)
|
||||
#if (DRC_DEBUG & 4) || defined(PDB)
|
||||
static void REGPARM(3) *sh2_drc_log_entry(void *block, SH2 *sh2, u32 sr)
|
||||
{
|
||||
if (block != NULL)
|
||||
if (block != NULL) {
|
||||
dbg(4, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
|
||||
sh2->pc, block, (signed int)sr >> 12);
|
||||
pdb_step(sh2, sh2->pc);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
#endif
|
||||
|
@ -216,10 +219,15 @@ static void REGPARM(1) (*sh2_drc_entry)(SH2 *sh2);
|
|||
static void (*sh2_drc_dispatcher)(void);
|
||||
static void (*sh2_drc_exit)(void);
|
||||
static void (*sh2_drc_test_irq)(void);
|
||||
|
||||
static u32 REGPARM(2) (*sh2_drc_read8)(u32 a, SH2 *sh2);
|
||||
static u32 REGPARM(2) (*sh2_drc_read16)(u32 a, SH2 *sh2);
|
||||
static u32 REGPARM(2) (*sh2_drc_read32)(u32 a, SH2 *sh2);
|
||||
static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
|
||||
static void REGPARM(2) (*sh2_drc_write8_slot)(u32 a, u32 d);
|
||||
static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
|
||||
static void REGPARM(2) (*sh2_drc_write16_slot)(u32 a, u32 d);
|
||||
static int REGPARM(3) (*sh2_drc_write32)(u32 a, u32 d, SH2 *sh2);
|
||||
|
||||
extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
|
||||
|
||||
|
@ -242,6 +250,7 @@ static void flush_tcache(int tcid)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if LINK_BRANCHES
|
||||
// add block links (tracked branches)
|
||||
static int dr_add_block_link(u32 target_pc, void *jump, int tcache_id)
|
||||
{
|
||||
|
@ -259,6 +268,7 @@ static int dr_add_block_link(u32 target_pc, void *jump, int tcache_id)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *dr_find_block(block_desc *tab, u32 addr)
|
||||
{
|
||||
|
@ -848,7 +858,7 @@ static int emit_memhandler_read_(int size, int ram_check)
|
|||
arg1 = rcache_get_tmp_arg(1);
|
||||
emith_move_r_r(arg1, CONTEXT_REG);
|
||||
|
||||
#if 1
|
||||
#ifndef PDB_NET
|
||||
if (ram_check && Pico.rom == (void *)0x02000000 && Pico32xMem->sdram == (void *)0x06000000) {
|
||||
int tmp = rcache_get_tmp();
|
||||
emith_and_r_r_imm(tmp, arg0, 0xfb000000);
|
||||
|
@ -859,14 +869,14 @@ static int emit_memhandler_read_(int size, int ram_check)
|
|||
emith_eor_r_imm_c(DCOND_EQ, arg0, 1);
|
||||
emith_read8_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
|
||||
EMITH_SJMP3_MID(DCOND_NE);
|
||||
emith_call_cond(DCOND_NE, p32x_sh2_read8);
|
||||
emith_call_cond(DCOND_NE, sh2_drc_read8);
|
||||
EMITH_SJMP3_END();
|
||||
break;
|
||||
case 1: // 16
|
||||
EMITH_SJMP3_START(DCOND_NE);
|
||||
emith_read16_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
|
||||
EMITH_SJMP3_MID(DCOND_NE);
|
||||
emith_call_cond(DCOND_NE, p32x_sh2_read16);
|
||||
emith_call_cond(DCOND_NE, sh2_drc_read16);
|
||||
EMITH_SJMP3_END();
|
||||
break;
|
||||
case 2: // 32
|
||||
|
@ -874,7 +884,7 @@ static int emit_memhandler_read_(int size, int ram_check)
|
|||
emith_read_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
|
||||
emith_ror_c(DCOND_EQ, arg0, arg0, 16);
|
||||
EMITH_SJMP3_MID(DCOND_NE);
|
||||
emith_call_cond(DCOND_NE, p32x_sh2_read32);
|
||||
emith_call_cond(DCOND_NE, sh2_drc_read32);
|
||||
EMITH_SJMP3_END();
|
||||
break;
|
||||
}
|
||||
|
@ -884,13 +894,13 @@ static int emit_memhandler_read_(int size, int ram_check)
|
|||
{
|
||||
switch (size) {
|
||||
case 0: // 8
|
||||
emith_call(p32x_sh2_read8);
|
||||
emith_call(sh2_drc_read8);
|
||||
break;
|
||||
case 1: // 16
|
||||
emith_call(p32x_sh2_read16);
|
||||
emith_call(sh2_drc_read16);
|
||||
break;
|
||||
case 2: // 32
|
||||
emith_call(p32x_sh2_read32);
|
||||
emith_call(sh2_drc_read32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -974,7 +984,7 @@ static void emit_memhandler_write(int size, u32 pc, int delay)
|
|||
break;
|
||||
case 2: // 32
|
||||
emith_move_r_r(ctxr, CONTEXT_REG);
|
||||
emith_call(p32x_sh2_write32);
|
||||
emith_call(sh2_drc_write32);
|
||||
break;
|
||||
}
|
||||
rcache_invalidate();
|
||||
|
@ -1050,10 +1060,11 @@ static void emit_block_entry(void)
|
|||
host_arg2reg(arg1, 1);
|
||||
host_arg2reg(arg2, 2);
|
||||
|
||||
#if (DRC_DEBUG & 4)
|
||||
#if (DRC_DEBUG & 4) || defined(PDB)
|
||||
emit_do_static_regs(1, arg2);
|
||||
emith_move_r_r(arg1, CONTEXT_REG);
|
||||
emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
|
||||
emith_call(sh2_drc_announce_entry);
|
||||
emith_call(sh2_drc_log_entry);
|
||||
rcache_invalidate();
|
||||
#endif
|
||||
emith_tst_r_r(arg0, arg0);
|
||||
|
@ -1256,10 +1267,6 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
|
|||
}
|
||||
branch_target_count = tmp;
|
||||
memset(branch_target_ptr, 0, sizeof(branch_target_ptr[0]) * branch_target_count);
|
||||
#if !LINK_BRANCHES
|
||||
// for debug
|
||||
branch_target_count = 0;
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------
|
||||
// 2nd pass: actual compilation
|
||||
|
@ -2479,6 +2486,7 @@ end_op:
|
|||
else
|
||||
emith_tst_r_imm(sr, T);
|
||||
|
||||
#if LINK_BRANCHES
|
||||
if (find_in_array(branch_target_pc, branch_target_count, target_pc) >= 0) {
|
||||
// local branch
|
||||
// XXX: jumps back can be linked already
|
||||
|
@ -2492,7 +2500,9 @@ end_op:
|
|||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// can't resolve branch locally, make a block exit
|
||||
emit_move_r_imm32(SHR_PC, target_pc);
|
||||
rcache_clean();
|
||||
|
@ -2622,6 +2632,11 @@ static void sh2_generate_utils(void)
|
|||
int arg0, arg1, arg2, sr, tmp;
|
||||
void *sh2_drc_write_end, *sh2_drc_write_slot_end;
|
||||
|
||||
sh2_drc_write32 = p32x_sh2_write32;
|
||||
sh2_drc_read8 = p32x_sh2_read8;
|
||||
sh2_drc_read16 = p32x_sh2_read16;
|
||||
sh2_drc_read32 = p32x_sh2_read32;
|
||||
|
||||
host_arg2reg(arg0, 0);
|
||||
host_arg2reg(arg1, 1);
|
||||
host_arg2reg(arg2, 2);
|
||||
|
@ -2679,7 +2694,7 @@ static void sh2_generate_utils(void)
|
|||
tmp = rcache_get_reg_arg(1, SHR_SR);
|
||||
emith_clear_msb(tmp, tmp, 22);
|
||||
emith_move_r_r(arg2, CONTEXT_REG);
|
||||
emith_call(p32x_sh2_write32);
|
||||
emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
|
||||
rcache_invalidate();
|
||||
// push PC
|
||||
rcache_get_reg_arg(0, SHR_SP);
|
||||
|
@ -2722,7 +2737,6 @@ static void sh2_generate_utils(void)
|
|||
EMITH_SJMP_START(DCOND_NE);
|
||||
emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp)); // return
|
||||
EMITH_SJMP_END(DCOND_NE);
|
||||
// since PC is up to date, jump to it's block instead of returning
|
||||
emith_call(sh2_drc_test_irq);
|
||||
emith_jump_ctx(offsetof(SH2, drc_tmp));
|
||||
|
||||
|
@ -2763,6 +2777,50 @@ static void sh2_generate_utils(void)
|
|||
emith_ctx_read(arg2, offsetof(SH2, write16_tab));
|
||||
emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
|
||||
|
||||
#ifdef PDB_NET
|
||||
// debug
|
||||
#define MAKE_READ_WRAPPER(func) { \
|
||||
void *tmp = (void *)tcache_ptr; \
|
||||
emith_ret_to_ctx(offsetof(SH2, drc_tmp)); \
|
||||
emith_call(func); \
|
||||
emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
|
||||
emith_addf_r_r(arg2, arg0); \
|
||||
emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
|
||||
emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
|
||||
emith_adc_r_imm(arg2, 0x01000000); \
|
||||
emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
|
||||
emith_jump_ctx(offsetof(SH2, drc_tmp)); \
|
||||
func = tmp; \
|
||||
}
|
||||
#define MAKE_WRITE_WRAPPER(func) { \
|
||||
void *tmp = (void *)tcache_ptr; \
|
||||
emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
|
||||
emith_addf_r_r(arg2, arg1); \
|
||||
emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
|
||||
emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
|
||||
emith_adc_r_imm(arg2, 0x01000000); \
|
||||
emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
|
||||
emith_move_r_r(arg2, CONTEXT_REG); \
|
||||
emith_jump(func); \
|
||||
func = tmp; \
|
||||
}
|
||||
|
||||
MAKE_READ_WRAPPER(sh2_drc_read8);
|
||||
MAKE_READ_WRAPPER(sh2_drc_read16);
|
||||
MAKE_READ_WRAPPER(sh2_drc_read32);
|
||||
MAKE_WRITE_WRAPPER(sh2_drc_write8);
|
||||
MAKE_WRITE_WRAPPER(sh2_drc_write8_slot);
|
||||
MAKE_WRITE_WRAPPER(sh2_drc_write16);
|
||||
MAKE_WRITE_WRAPPER(sh2_drc_write16_slot);
|
||||
MAKE_WRITE_WRAPPER(sh2_drc_write32);
|
||||
#if (DRC_DEBUG & 2)
|
||||
host_dasm_new_symbol(sh2_drc_read8);
|
||||
host_dasm_new_symbol(sh2_drc_read16);
|
||||
host_dasm_new_symbol(sh2_drc_read32);
|
||||
host_dasm_new_symbol(sh2_drc_write32);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rcache_invalidate();
|
||||
#if (DRC_DEBUG & 2)
|
||||
host_dasm_new_symbol(sh2_drc_entry);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <string.h>
|
||||
#include "sh2.h"
|
||||
#include "../debug.h"
|
||||
#include "compiler.h"
|
||||
|
||||
#define I 0xf0
|
||||
|
@ -12,6 +13,7 @@ int sh2_init(SH2 *sh2, int is_slave)
|
|||
|
||||
memset(sh2, 0, sizeof(*sh2));
|
||||
sh2->is_slave = is_slave;
|
||||
pdb_register_cpu(sh2, PDBCT_SH2, is_slave ? "ssh2" : "msh2");
|
||||
#ifdef DRC_SH2
|
||||
ret = sh2_drc_init(sh2);
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,7 @@ typedef struct SH2_
|
|||
void *p_da;
|
||||
void *p_sdram;
|
||||
void *p_rom;
|
||||
unsigned int pdb_io_csum[2];
|
||||
|
||||
// interpreter stuff
|
||||
int icount; // cycles left in current timeslice
|
||||
|
|
|
@ -7,6 +7,17 @@ endif
|
|||
ifeq "$(profile)" "2"
|
||||
CFLAGS += -fprofile-use
|
||||
endif
|
||||
ifeq "$(pdb)" "1"
|
||||
DEFINES += PDB
|
||||
OBJS += cpu/debug.o
|
||||
ifeq "$(pdb_net)" "1"
|
||||
DEFINES += PDB_NET
|
||||
endif
|
||||
ifeq "$(readline)" "1"
|
||||
DEFINES += HAVE_READLINE
|
||||
LDFLAGS += -lreadline
|
||||
endif
|
||||
endif
|
||||
ifeq "$(pprof)" "1"
|
||||
DEFINES += PPROF
|
||||
OBJS += platform/linux/pprof.o
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "plat.h"
|
||||
#include <cpu/debug.h>
|
||||
#include <version.h>
|
||||
|
||||
|
||||
|
@ -34,6 +35,12 @@ void parse_cmd_line(int argc, char *argv[])
|
|||
else if (strcasecmp(argv[x], "-loadstate") == 0) {
|
||||
if (x+1 < argc) { ++x; load_state_slot = atoi(argv[x]); }
|
||||
}
|
||||
else if (strcasecmp(argv[x], "-pdb") == 0) {
|
||||
if (x+1 < argc) { ++x; pdb_command(argv[x]); }
|
||||
}
|
||||
else if (strcasecmp(argv[x], "-pdb_connect") == 0) {
|
||||
if (x+2 < argc) { pdb_net_connect(argv[x+1], argv[x+2]); x += 2; }
|
||||
}
|
||||
else {
|
||||
unrecognized = 1;
|
||||
break;
|
||||
|
|
|
@ -12,6 +12,8 @@ use_sh2drc = 1
|
|||
#drc_debug_interp = 1
|
||||
#profile = 1
|
||||
|
||||
all: mkdirs PicoDrive
|
||||
|
||||
-include Makefile.local
|
||||
|
||||
ifndef ARCH
|
||||
|
@ -27,7 +29,7 @@ CFLAGS += -mcpu=arm920t
|
|||
DEFINES += ARM
|
||||
endif
|
||||
|
||||
CC = $(CROSS)gcc
|
||||
CC ?= $(CROSS)gcc
|
||||
|
||||
# frontend
|
||||
OBJS += io.o emu.o blit.o in_evdev.o plat.o sndout_oss.o log_io.o
|
||||
|
@ -70,8 +72,6 @@ vpath %.asm = ../..
|
|||
|
||||
DIRS += platform/linux zlib unzip
|
||||
|
||||
all: mkdirs PicoDrive
|
||||
|
||||
include ../common/common.mak
|
||||
include ../common/revision.mak
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ void host_dasm(void *addr, int len)
|
|||
if (name != NULL)
|
||||
printf("%s:\n", name);
|
||||
|
||||
printf(" %08lx ", (long)vma);
|
||||
printf(" %08lx ", (long)vma);
|
||||
vma += print_insn_func(vma, &di);
|
||||
printf("\n");
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#define SIMPLE_WRITE_SOUND 0
|
||||
#define mix_32_to_16l_stereo_lvl mix_32_to_16l_stereo
|
||||
|
||||
#define EL_LOGMASK (EL_STATUS|EL_ANOMALY|EL_UIO|EL_IDLE)
|
||||
// EL_VDPDMA|EL_ASVDP|EL_SR | EL_BUSREQ|EL_Z80BNK | EL_32X)
|
||||
#define EL_LOGMASK (EL_STATUS|EL_ANOMALY|EL_UIO)
|
||||
// EL_VDPDMA|EL_ASVDP|EL_SR | EL_IDLE | EL_BUSREQ|EL_Z80BNK | EL_32X)
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue