307 lines
8.5 KiB
C
307 lines
8.5 KiB
C
/* m68k_scp.c: 68k simulator SCP extension
|
|
|
|
Copyright (c) 2009-2010 Holger Veit
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
Holger Veit BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Holger Veit et al shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Holger Veit et al.
|
|
|
|
17-Jul-10 HV Initial version
|
|
*/
|
|
|
|
#include "sim_defs.h"
|
|
#include "m68k_cpu.h"
|
|
#include <ctype.h>
|
|
|
|
static t_bool symtrace = TRUE;
|
|
static void m68k_sim_init(void);
|
|
static t_stat hdump_cmd(int32 arg,char* buf);
|
|
static t_stat symset_cmd(int32 arg,char* buf);
|
|
static t_stat symclr_cmd(int32 arg,char* buf);
|
|
static t_stat symlist_cmd(int32 arg,char* buf);
|
|
static t_stat symtrace_cmd(int32 arg,char* buf);
|
|
|
|
static CTAB m68k_sim_cmds[] = {
|
|
{"STEP", &run_cmd, RU_STEP,
|
|
"s{tep} {n} simulate n instructions\n" },
|
|
{"HEXDUMP", &hdump_cmd, 0,
|
|
"hex{dump} range dump memory\n" },
|
|
{"SYMSET", &symset_cmd, 0,
|
|
"syms{et} name=value define symbolic name for disassembler/tracer\n"},
|
|
{"SYMCLR",&symclr_cmd, 0,
|
|
"symc{lr} {-a|name} clear symbolic name / all symbolic names\n"},
|
|
{"SYMLIST", &symlist_cmd, 0,
|
|
"syml{ist} [name] list symbol table\n"},
|
|
{"SYMTRACE", &symtrace_cmd, 1,
|
|
"symt{race} enable symbolic tracing\n"},
|
|
{"NOSYMTRACE", &symtrace_cmd, 0,
|
|
"nosymt{race} disable symbolic tracing\n"},
|
|
{0,0,0,0}
|
|
};
|
|
|
|
void (*sim_vm_init)(void) = &m68k_sim_init;
|
|
|
|
typedef struct _symhash {
|
|
struct _symhash* nnext;
|
|
struct _symhash* vnext;
|
|
char* name;
|
|
t_addr val;
|
|
} SYMHASH;
|
|
#define SYMHASHSIZE 397
|
|
|
|
static SYMHASH *symbyname = 0;
|
|
static SYMHASH *symbyval = 0;
|
|
|
|
static void sym_clearall(void)
|
|
{
|
|
int i;
|
|
SYMHASH *p,*n;
|
|
|
|
if (!symbyname) return;
|
|
for (i=0; i<SYMHASHSIZE; i++) {
|
|
p = symbyname[i].nnext;
|
|
while ((n = p) != 0) {
|
|
p = p->nnext;
|
|
free(n->name);
|
|
free(n);
|
|
}
|
|
symbyname[i].nnext = symbyval[i].vnext = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void m68k_sim_init(void)
|
|
{
|
|
int i;
|
|
sim_vm_cmd = m68k_sim_cmds;
|
|
|
|
sym_clearall();
|
|
symbyname = (SYMHASH*)calloc(sizeof(SYMHASH),SYMHASHSIZE);
|
|
symbyval = (SYMHASH*)calloc(sizeof(SYMHASH),SYMHASHSIZE);
|
|
for (i=0; i<SYMHASHSIZE; i++)
|
|
symbyval[i].vnext = symbyname[i].nnext = 0;
|
|
|
|
symtrace = TRUE;
|
|
}
|
|
|
|
static int getnhash(const char* name)
|
|
{
|
|
int i, nhash = 0;
|
|
for (i=0; name[i]; i++) {
|
|
nhash += name[i];
|
|
}
|
|
return nhash % SYMHASHSIZE;
|
|
}
|
|
|
|
static int getvhash(t_addr val)
|
|
{
|
|
return val % SYMHASHSIZE;
|
|
}
|
|
|
|
static t_bool sym_lookupname(const char *name,SYMHASH **n)
|
|
{
|
|
int hash = getnhash(name);
|
|
SYMHASH *p = symbyname[hash].nnext;
|
|
while (p && strcmp(name,p->name)) p = p->nnext;
|
|
*n = p;
|
|
return p != 0;
|
|
}
|
|
|
|
static t_bool sym_lookupval(t_addr val, SYMHASH **v)
|
|
{
|
|
int hash = getvhash(val);
|
|
SYMHASH *p = symbyval[hash].vnext;
|
|
while (p && p->val != val) p = p->vnext;
|
|
*v = p;
|
|
return p != 0;
|
|
}
|
|
|
|
static t_bool sym_enter(const char* name,t_addr val)
|
|
{
|
|
int nhash = getnhash(name);
|
|
int vhash = getvhash(val);
|
|
SYMHASH *v, *n, *e;
|
|
|
|
if (sym_lookupname(name,&n) || sym_lookupval(val,&v)) return FALSE;
|
|
n = symbyname[nhash].nnext;
|
|
v = symbyval[vhash].vnext;
|
|
e = (SYMHASH*)malloc(sizeof(SYMHASH));
|
|
e->nnext = n;
|
|
e->vnext = v;
|
|
e->name = malloc(strlen(name)+1);
|
|
strcpy(e->name,name);
|
|
e->val = val;
|
|
symbyname[nhash].nnext = symbyval[vhash].vnext = e;
|
|
return TRUE;
|
|
}
|
|
|
|
static t_bool sym_delete(const char* name)
|
|
{
|
|
int hash = getnhash(name);
|
|
SYMHASH *p, *q, **n, **v;
|
|
n = &symbyname[hash].nnext;
|
|
while ((p = *n) != 0) {
|
|
if (!strcmp(p->name,name)) { /*found*/
|
|
hash = getvhash(p->val);
|
|
v = &symbyval[hash].vnext;
|
|
while ((q = *v) != 0) {
|
|
if (q->val == p->val) { /*found*/
|
|
*v = q->vnext;
|
|
break;
|
|
}
|
|
v = &(q->vnext);
|
|
}
|
|
*n = p->nnext;
|
|
free(p->name);
|
|
free(p);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static t_stat symset_cmd(int32 arg,char* buf)
|
|
{
|
|
char *name,*vstr;
|
|
t_addr val;
|
|
|
|
if ((name = strtok(buf, "= ")) == 0) return SCPE_2FARG;
|
|
if ((vstr = strtok(NULL, " \t\n")) == 0) return SCPE_2FARG;
|
|
val = strtol(vstr, 0, 16);
|
|
if (!sym_enter(name, val))
|
|
printf("Name or value already exists\n");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat symclr_cmd(int32 arg,char* buf)
|
|
{
|
|
char* token;
|
|
if (buf[0] == '-' && buf[1]=='a') {
|
|
sym_clearall();
|
|
return SCPE_OK;
|
|
} else {
|
|
token = strtok(buf," \t\n");
|
|
if (!token) return SCPE_2FARG;
|
|
return sym_delete(token) ? SCPE_OK : SCPE_ARG;
|
|
}
|
|
}
|
|
|
|
static t_stat symlist_cmd(int32 arg,char* buf)
|
|
{
|
|
int i;
|
|
SYMHASH* n;
|
|
char *name;
|
|
t_bool found = FALSE;
|
|
|
|
name = strtok(buf," \t\n");
|
|
if (name) {
|
|
if (sym_lookupname(name,&n))
|
|
printf(" %s = 0x%08x\n",n->name,n->val);
|
|
else
|
|
printf("Unknown\n");
|
|
} else {
|
|
for (i=0; i<SYMHASHSIZE; i++) {
|
|
n = symbyname[i].nnext;
|
|
while (n) {
|
|
printf(" %s = 0x%08x\n",n->name,n->val);
|
|
n = n->nnext;
|
|
found = TRUE;
|
|
}
|
|
}
|
|
if (!found) printf("Symbol table is empty\n");
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat symtrace_cmd(int32 arg,char* buf)
|
|
{
|
|
if (!*buf)
|
|
symtrace = arg ? TRUE : FALSE;
|
|
|
|
printf("Symbolic tracing %sabled\n",symtrace ? "en" : "dis");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static void putascii(uint32* buf)
|
|
{
|
|
int i;
|
|
putchar('|');
|
|
for (i=0; i<16; i++) {
|
|
if (isprint(buf[i])) putchar(buf[i]);
|
|
else putchar('.');
|
|
}
|
|
putchar('|');
|
|
}
|
|
|
|
static t_stat hdump_cmd(int32 arg, char* buf)
|
|
{
|
|
int i;
|
|
t_addr low, high, base, top;
|
|
char *token;
|
|
uint32 byte[16];
|
|
t_bool ascii = FALSE;
|
|
t_bool first = TRUE;
|
|
|
|
if (buf[0]=='-' && buf[1]=='a') {
|
|
ascii = TRUE;
|
|
buf += 2;
|
|
while (*buf && isspace(*buf)) buf++;
|
|
}
|
|
memset(byte,0,sizeof(uint32)*16);
|
|
|
|
token = strtok(buf,"- \t\n");
|
|
if (!token) return SCPE_2FARG;
|
|
low = strtol(token,0,16);
|
|
token = strtok(NULL,"- \t\n");
|
|
if (!token) return SCPE_2FARG;
|
|
high = strtol(token,0,16);
|
|
|
|
base = low - (low % 16);
|
|
top = (high + 15) - ((high+15) % 16);
|
|
for (; base<top; base++) {
|
|
if ((base % 16)==0) {
|
|
if (!first && ascii) putascii(byte);
|
|
printf("\n%08x: ",base);
|
|
first = FALSE;
|
|
}
|
|
if (base < low) printf(" ");
|
|
else if (base > high) printf(" ");
|
|
else {
|
|
i = base %16;
|
|
if (ReadPB(base,byte+i) != SCPE_OK) printf("?? ");
|
|
else printf("%02x ",byte[i] & 0xff);
|
|
}
|
|
}
|
|
if (!first && ascii) putascii(byte);
|
|
putchar('\n');
|
|
return SCPE_OK;
|
|
}
|
|
|
|
char* m68k_getsym(t_addr val,const char* fmt, char* outbuf)
|
|
{
|
|
SYMHASH *v;
|
|
if (symtrace && sym_lookupval(val,&v))
|
|
return v->name;
|
|
else {
|
|
sprintf(outbuf,fmt,val);
|
|
return outbuf;
|
|
}
|
|
}
|
|
|