/* This file is part of SIS (SPARC instruction simulator)
Copyright (C) 1995-2017 Free Software Foundation, Inc.
Contributed by Jiri Gaisler, European Space Agency
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "sis.h"
#include
#include
//#define ROM_ENABLED
/* set if UART device cannot handle attributes, terminal oriented IO by default */
int dumbio = 0;
/* set if UARTs are connected to a tty, enable by default */
int tty_setup = 1;
struct pstate sregs[NCPU];
struct estate ebase;
struct evcell evbuf[EVENT_MAX];
int ctrl_c = 0;
int sis_verbose = 0;
char *sis_version = PACKAGE_VERSION;
int nfp = 0;
int ift = 0;
int wrp = 0;
int rom8 = 0;
int uben = 0;
int termsave;
char uart_dev1[128] = "";
char uart_dev2[128] = "";
uint32 last_load_addr = 0;
int nouartrx = 0;
int port = 1234;
int sim_run = 0;
/* RAM and ROM for all systems */
unsigned char romb[ROM_SIZE];
unsigned char ramb[RAM_SIZE];
const struct memsys *ms = &erc32sys;
int cputype = 0; /* 0 = erc32, 2 = leon2,3 = leon3, 5 = riscv */
int sis_gdb_break;
int cpu = 0; /* active cpu */
int ncpu = 1; /* number of cpus to emulate */
int delta = 50; /* time slice for MP simulation */
const struct cpu_arch *arch = &sparc;
uint32 daddr = 0;
/*
static bfd *abfd;
static asymbol **asymbols;
static int symsize = 0;
static int symcount = 0;
*/
/* Forward declarations */
static int batch (struct pstate *sregs, char *fname);
static void init_event (void);
static void disp_mem (uint32 addr, uint32 len);
static ssize_t mygetline (char **lineptr, size_t *n, FILE *stream);
static void symprint();
static uint32 symtoaddr(char *s);
static int
batch(sregs, fname)
struct pstate *sregs;
char *fname;
{
FILE *fp;
char *lbuf = NULL;
size_t len = 0;
size_t slen;
if ((fp = fopen(fname, "r")) == NULL) {
fprintf(stderr, "couldn't open batch file %s\n", fname);
return 0;
}
while (mygetline(&lbuf, &len, fp) > -1) {
slen = strlen(lbuf);
if (slen && (lbuf[slen - 1] == '\n')) {
lbuf[slen - 1] = 0;
printf("sis> %s\n", lbuf);
exec_cmd(lbuf);
}
}
free(lbuf);
fclose(fp);
return 1;
}
static uint64
limcalc (freq)
float32 freq;
{
uint64 unit, lim;
double flim;
char *cmd1, *cmd2;
unit = 1;
lim = -1;
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
lim = VAL(cmd1);
if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) {
if (strcmp(cmd2,"us")==0) unit = 1;
if (strcmp(cmd2,"ms")==0) unit = 1000;
if (strcmp(cmd2,"s")==0) unit = 1000000;
}
flim = (double) lim * (double) unit * (double) freq +
(double) ebase.simtime;
if (flim > ebase.simtime) {
lim = (uint64) flim;
} else {
printf("error in expression\n");
lim = 0;
}
}
return lim;
}
int
exec_cmd(const char *cmd)
{
char *cmd1, *cmd2;
int32 stat;
uint32 len, i, clen, j;
char *cmdsave, *cmdsave2 = NULL;
stat = OK;
if (!cmd)
return stat;
cmdsave = strdup(cmd);
cmdsave2 = strdup (cmd);
if ((cmd1 = strtok (cmdsave2, " \t")) != NULL) {
clen = strlen(cmd1);
if (strncmp(cmd1, "bp", clen) == 0) {
for (i = 0; i < ebase.bptnum; i++) {
printf(" %d : 0x%08x\n", i + 1, ebase.bpts[i]);
}
} else if ((strncmp(cmd1, "+bp", clen) == 0) ||
(strncmp(cmd1, "break", clen) == 0)) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
if (isdigit(cmd1[0]))
len = VAL(cmd1);
/*
else
len = symtoaddr(cmd1);
*/
if (len) {
ebase.bpts[ebase.bptnum] = len & ~0x1;
printf("added breakpoint %d at 0x%08x\n",
ebase.bptnum + 1, ebase.bpts[ebase.bptnum]);
ebase.bptnum += 1;
}
} else {
for (i = 0; i < ebase.bptnum; i++) {
printf(" %d : 0x%08x\n", i + 1, ebase.bpts[i]);
}
}
} else if ((strncmp(cmd1, "-bp", clen) == 0) ||
(strncmp(cmd1, "delete", clen) == 0)) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
i = VAL(cmd1) - 1;
if ((i >= 0) && (i < ebase.bptnum)) {
printf("deleted breakpoint %d at 0x%08x\n", i + 1,
ebase.bpts[i]);
for (; i < ebase.bptnum - 1; i++) {
ebase.bpts[i] = ebase.bpts[i + 1];
}
ebase.bptnum -= 1;
}
}
} else if (strncmp(cmd1, "batch", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
printf("no file specified\n");
} else {
batch(sregs, cmd1);
}
} else if (strncmp(cmd1, "cont", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
stat = run_sim(UINT64_MAX/2, 0);
} else {
stat = run_sim(VAL(cmd1), 0);
}
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "debug", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
sis_verbose = VAL(cmd1);
}
printf("Debug level = %d\n",sis_verbose);
} else if (strncmp(cmd1, "disas", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
daddr = VAL(cmd1);
}
if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) {
len = VAL(cmd2);
} else
len = 16;
printf("\n");
daddr = dis_mem(daddr, len);
printf("\n");
} else if (strncmp(cmd1, "echo", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
printf("%s\n", (&cmdsave[clen+1]));
}
} else if (strncmp(cmd1, "float", clen) == 0) {
arch->display_fpu(sregs);
} else if (strncmp(cmd1, "go", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
len = last_load_addr;
} else {
len = VAL(cmd1);
}
for (i=0; ipc + 4;
}
if ((sregs->pc != 0) && (ebase.simtime == 0))
ms->boot_init ();
printf("resuming at 0x%08x\n",sregs->pc);
if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) {
stat = run_sim(VAL(cmd2), 0);
} else {
stat = run_sim(UINT64_MAX/2, 0);
}
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "gdb", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
port = VAL(cmd1);
if (port < 1024) port = 1024;
}
gdb_remote(port);
} else if (strncmp(cmd1, "help", clen) == 0) {
gen_help();
} else if (strncmp(cmd1, "history", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
ebase.histlen = VAL(cmd1);
for (i=0; i= ebase.histlen)
j = 0;
printf(" %8" PRIu64 " ", sregs[cpu].histbuf[j].time);
dis_mem(sregs[cpu].histbuf[j].addr, 1);
j++;
}
}
} else if (strncmp(cmd1, "load", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
last_load_addr = elf_load(cmd1, 1);
daddr = last_load_addr;
while ((cmd1 = strtok(NULL, " \t\n\r")) != NULL)
last_load_addr = elf_load(cmd1, 1);
} else {
printf("load: no file specified\n");
}
} else if (strncmp(cmd1, "mem", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL)
daddr = VAL(cmd1);
if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL)
len = VAL(cmd2);
else
len = 64;
disp_mem(daddr, len);
daddr += len;
} else if (strncmp(cmd1, "cpu", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
cpu = VAL(cmd1);
if (cpu > NCPU) cpu = NCPU;
}
printf("active cpu: %d\n", cpu);
} else if (strncmp(cmd1, "ncpu", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
ncpu = VAL(cmd1);
if (ncpu > NCPU) ncpu = NCPU;
}
printf("number of online cpus: %d\n", ncpu);
} else if (strncmp(cmd1, "wmem", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL)
daddr = VAL(cmd1);
if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL)
len = VAL(cmd2);
ms->sis_memory_write (daddr, (char *) &len, 4);
} else if (strncmp(cmd1, "perf", clen) == 0) {
cmd1 = strtok(NULL, " \t\n\r");
if ((cmd1 != NULL) &&
(strncmp(cmd1, "reset", strlen(cmd1)) == 0)) {
reset_stat(sregs);
} else
show_stat(sregs);
} else if (strncmp(cmd1, "quit", clen) == 0) {
stat = QUIT;
} else if (strncmp(cmd1, "csr", clen) == 0) {
arch->display_special(&sregs[cpu]);
} else if (strncmp(cmd1, "reg", clen) == 0) {
cmd1 = strtok(NULL, " \t\n\r");
cmd2 = strtok(NULL, " \t\n\r");
if (cmd2 != NULL)
arch->set_register(&sregs[cpu], cmd1, VAL(cmd2), 0);
/*
else if (cmd1 != NULL)
disp_reg(&sregs[cpu], cmd1);
*/
else {
arch->display_registers(&sregs[cpu]);
arch->display_ctrl(&sregs[cpu]);
}
} else if (strncmp(cmd1, "reset", clen) == 0) {
ebase.simtime = 0;
ebase.simstart = 0;
reset_all();
reset_stat(sregs);
} else if (strncmp(cmd1, "run", clen) == 0) {
ebase.simtime = 0;
ebase.simstart = 0;
reset_all();
reset_stat(sregs);
if (last_load_addr != 0) {
for (i=0; ipc != 0) && (ebase.simtime == 0)) ms->boot_init ();
if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
stat = run_sim(UINT64_MAX/2, 0);
} else {
stat = run_sim(VAL(cmd1), 0);
}
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "shell", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
if (system(&cmdsave[clen])) {
/* Silence unused return value warning. */
}
}
/*
} else if (strncmp(cmd1, "sym", clen) == 0) {
symprint ();
*/
} else if (strncmp(cmd1, "step", clen) == 0) {
stat = run_sim(1, 1);
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "tcont", clen) == 0) {
ebase.tlimit = limcalc(ebase.freq);
stat = run_sim(UINT64_MAX/2, 0);
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "tgo", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
len = last_load_addr;
} else {
len = VAL(cmd1);
ebase.tlimit = limcalc(ebase.freq);
}
sregs->pc = len & ~1;
sregs->npc = sregs->pc + 4;
printf("resuming at 0x%08x\n",sregs->pc);
stat = run_sim(UINT64_MAX/2, 0);
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "tlimit", clen) == 0) {
ebase.tlimit = limcalc(ebase.freq);
if (ebase.tlimit != (uint32) -1)
if (sis_verbose)
printf("simulation limit = %u (%.3f ms)\n",
(uint32) ebase.tlimit, ebase.tlimit / ebase.freq / 1000);
} else if (strncmp(cmd1, "tra", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
stat = run_sim(UINT64_MAX/2, 1);
} else {
stat = run_sim(VAL(cmd1), 1);
}
printf("\n");
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "trun", clen) == 0) {
ebase.simtime = 0;
ebase.simstart = 0;
reset_all();
reset_stat(sregs);
if (last_load_addr != 0) {
for (i=0; ipc != 0) && (ebase.simtime == 0)) ms->boot_init ();
ebase.tlimit = limcalc(ebase.freq);
stat = run_sim(UINT64_MAX/2, 0);
daddr = sregs->pc;
ms->sim_halt ();
} else if (strncmp(cmd1, "wp", clen) == 0) {
for (i = 0; i < ebase.wprnum; i++) {
printf(" %d : 0x%08x (read)\n", i + 1, ebase.wprs[i]);
}
for (i = 0; i < ebase.wpwnum; i++) {
printf(" %d : 0x%08x (write)\n", i + 1, ebase.wpws[i]);
}
} else if (strncmp(cmd1, "+wpr", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
ebase.wprs[ebase.wprnum] = VAL(cmd1) & ~0x3;
ebase.wprm[ebase.wprnum] = 3;
printf("added read watchpoint %d at 0x%08x\n",
ebase.wprnum + 1, ebase.wprs[ebase.wprnum]);
ebase.wprnum += 1;
}
} else if (strncmp(cmd1, "-wpr", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
i = VAL(cmd1) - 1;
if ((i >= 0) && (i < ebase.wprnum)) {
printf("deleted read watchpoint %d at 0x%08x\n", i + 1,
ebase.wprs[i]);
for (; i < ebase.wprnum - 1; i++) {
ebase.wprs[i] = ebase.wprs[i + 1];
}
ebase.wprnum -= 1;
}
}
} else if ((strncmp(cmd1, "+wpw", clen) == 0) ||
(strncmp(cmd1, "watch", clen) == 0)) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
ebase.wpws[ebase.wpwnum] = VAL(cmd1) & ~0x3;
ebase.wpwm[ebase.wpwnum] = 3;
printf("added write watchpoint %d at 0x%08x\n",
ebase.wpwnum + 1, ebase.wpws[ebase.wpwnum]);
ebase.wpwnum += 1;
} else {
for (i = 0; i < ebase.wpwnum; i++) {
printf(" %d : 0x%08x (write)\n", i + 1, ebase.wpws[i]);
}
}
} else if (strncmp(cmd1, "-wpw", clen) == 0) {
if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
i = VAL(cmd1) - 1;
if ((i >= 0) && (i < ebase.wpwnum)) {
printf("deleted write watchpoint %d at 0x%08x\n", i + 1,
ebase.wpws[i]);
for (; i < ebase.wpwnum - 1; i++) {
ebase.wpws[i] = ebase.wpws[i + 1];
}
ebase.wpwnum -= 1;
}
}
} else
printf("syntax error\n");
}
if (cmdsave2 != NULL)
free(cmdsave2);
if (cmdsave != NULL)
free(cmdsave);
return stat;
}
void
reset_stat(sregs)
struct pstate *sregs;
{
ebase.tottime = 0.0;
sregs->pwdtime = 0;
sregs->ninst = 0;
sregs->fholdt = 0;
sregs->holdt = 0;
sregs->icntt = 0;
sregs->finst = 0;
sregs->nstore = 0;
sregs->nload = 0;
sregs->nbranch = 0;
ebase.simstart = ebase.simtime;
sregs->l1imiss = 0;
sregs->l1dmiss = 0;
}
void
show_stat(sregs)
struct pstate *sregs;
{
uint64 iinst, ninst, pwdtime;
uint64 stime, atime;
int i;
ninst = 0;
pwdtime = 0;
atime = 0;
if (ebase.tottime == 0.0)
ebase.tottime += 1E-6;
for (i=0; inload / (double) sregs[i].ninst);
printf(" store : %9.2f %%\n",
100.0 * (double) sregs->nstore / (double) sregs[i].ninst);
printf(" branch : %9.2f %%\n",
100.0 * (double) sregs->nbranch / (double) sregs[i].ninst);
printf(" float : %9.2f %%\n",
100.0 * (double) sregs->finst / (double) sregs[i].ninst);
printf(" Integer CPI : %9.2f\n",
((double) (stime - sregs[i].pwdtime - sregs[i].fholdt - sregs[i].finst))
/
(double) (sregs[i].ninst - sregs[i].finst));
printf(" Float CPI : %9.2f\n",
((double) sregs[i].fholdt / (double) sregs[i].finst) + 1.0);
#endif
printf("\n");
}
void
init_bpt(sregs)
struct pstate *sregs;
{
int i;
ebase.bptnum = 0;
ebase.wprnum = 0;
ebase.wpwnum = 0;
ebase.histlen = 0;
for (i=0; i 0)
{
int cc;
char c = 0;
cc = read (new_socket, &c, 1);
if (cc == 0)
{
fprintf (stderr, "client connection closed\n");
return;
}
else if (cc != 1 || c != '\003')
{
fprintf (stderr, "input_interrupt, count = %d c = %d ", cc, c);
if (isprint (c))
fprintf (stderr, "('%c')\n", c);
else
fprintf (stderr, "('\\x%02x')\n", c & 0xff);
return;
}
ctrl_c = 1;
}
}
void
int_handler(int sig)
{
int count;
switch(sig) {
case SIGIO :
if (sim_run) {
check_interrup();
}
break;
case SIGINT :
ctrl_c = 1;
if (!sim_run) {
if (new_socket > 0)
close(new_socket);
else
exit(0);
}
break;
default:
printf("\n\n Signal handler error (%d)\n\n", sig);
}
}
void
init_signals()
{
typedef void (*PFI) ();
static PFI int_tab[2];
int_tab[0] = signal(SIGTERM, int_handler);
int_tab[1] = signal(SIGINT, int_handler);
}
void print_insn_sis(uint32 addr)
{
unsigned char i[4];
ms->sis_memory_read (addr, i, 4);
arch->disas(addr );
}
static void
disp_mem(addr, len)
uint32 addr;
uint32 len;
{
uint32 i;
union {
unsigned char u8[4];
uint32 u32;
} data;
uint32 mem[4], j;
char *p;
for (i = addr & ~3; i < ((addr + len) & ~3); i += 16) {
printf("\n %8X ", i);
for (j = 0; j < 4; j++) {
ms->sis_memory_read ((i + (j * 4)), data.u8, 4);
printf ("%08x ", data.u32);
mem[j] = data.u32;
}
printf(" ");
p = (char *) mem;
for (j = 0; j < 16; j++) {
if (isprint (p[j ^ arch->endian]))
putchar (p[j ^ arch->endian]);
else
putchar('.');
}
}
printf("\n\n");
}
uint32
dis_mem(addr, len)
uint32 addr;
uint32 len;
{
uint32 i, data;
for (i = 0; i < len; i ++) {
ms->sis_memory_read (addr,(char *) &data, 4);
if ((cputype == CPU_RISCV) && ((data & 3) != 3)) {
data &= 0x0ffff;
printf (" %08x: %04x ", addr, data);
} else
printf (" %08x: %08x ", addr, data);
print_insn_sis(addr);
if (i >= 0xfffffffc) break;
printf("\n");
if ((cputype == CPU_RISCV) &&((data & 3) != 3))
addr += 2;
else
addr += 4;
}
return addr;
}
/* Add event to event queue */
void
event(cfunc, arg, delta)
void (*cfunc) ();
int32 arg;
uint64 delta;
{
struct evcell *ev1, *evins;
if (ebase.freeq == NULL) {
printf("Error, too many events in event queue\n");
return;
}
ev1 = &ebase.eq;
delta += ebase.simtime;
while ((ev1->nxt != NULL) && (ev1->nxt->time <= delta)) {
ev1 = ev1->nxt;
}
if (ev1->nxt == NULL) {
ev1->nxt = ebase.freeq;
ebase.freeq = ebase.freeq->nxt;
ev1->nxt->nxt = NULL;
} else {
evins = ebase.freeq;
ebase.freeq = ebase.freeq->nxt;
evins->nxt = ev1->nxt;
ev1->nxt = evins;
}
ev1->nxt->time = delta;
ev1->nxt->cfunc = cfunc;
ev1->nxt->arg = arg;
ebase.evtime = ebase.eq.nxt->time;
}
/* remove event from event queue */
void
remove_event(cfunc, arg)
void (*cfunc) ();
int32 arg;
{
struct evcell *ev1, *evdel;
ev1 = &ebase.eq;
while (ev1->nxt != NULL) {
if ((ev1->nxt->cfunc == cfunc) && ((arg == ev1->nxt->arg) || (arg < 0))){
evdel = ev1->nxt;
ev1->nxt = ev1->nxt->nxt;
evdel->nxt = ebase.freeq;
ebase.freeq = evdel;
}
ev1 = ev1->nxt;
}
ebase.evtime = ebase.eq.nxt->time;
}
static void
last_event (int32 arg)
{
printf("Warning: end of time ... exiting!\n");
exit(0);
}
void
init_event()
{
int32 i;
ebase.eq.nxt = NULL;
ebase.freeq = evbuf;
for (i = 0; i < EVENT_MAX; i++) {
evbuf[i].nxt = &evbuf[i + 1];
}
evbuf[EVENT_MAX - 1].nxt = NULL;
event(last_event, 0, UINT64_MAX);
}
/* Advance simulator time */
void
advance_time(endtime)
uint64 endtime;
{
struct evcell *evrem;
void (*cfunc) ();
uint32 arg;
while (ebase.evtime <= endtime) {
ebase.simtime = ebase.eq.nxt->time;
cfunc = ebase.eq.nxt->cfunc;
arg = ebase.eq.nxt->arg;
evrem = ebase.eq.nxt;
ebase.eq.nxt = ebase.eq.nxt->nxt;
ebase.evtime = ebase.eq.nxt->time;
evrem->nxt = ebase.freeq;
ebase.freeq = evrem;
cfunc(arg);
}
ebase.simtime = endtime;
}
uint32
now()
{
return (uint32) ebase.simtime;
}
void
pwd_enter(struct pstate *sregs)
{
sregs->pwd_mode = 1;
sregs->pwdstart = sregs->simtime;
sregs->hold += delta;
}
int
check_bpt(sregs)
struct pstate *sregs;
{
int32 i;
if (sregs->bphit) {
sregs->bphit = 0;
return 0;
}
for (i = 0; i < (int32) ebase.bptnum; i++) {
if (sregs->pc == ebase.bpts[i])
return BPT_HIT;
}
return 0;
}
int
check_wpr(sregs, address, mask)
struct pstate *sregs;
int32 address;
unsigned char mask;
{
int32 i, msk;
for (i = 0; i < ebase.wprnum; i++) {
msk = ~(mask | ebase.wprm[i]);
if (((address ^ ebase.wprs[i]) & msk) == 0) {
ebase.wpaddress = address;
if (ebase.wphit) return (0);
return (WPT_HIT);
}
}
return (0);
}
int
check_wpw(sregs, address, mask)
struct pstate *sregs;
int32 address;
unsigned char mask;
{
int32 i, msk;
for (i = 0; i < ebase.wpwnum; i++) {
msk = ~(mask | ebase.wpwm[i]);
if (((address ^ ebase.wpws[i]) & msk) == 0) {
ebase.wpaddress = ebase.wpws[i];
if (ebase.wphit) return (0);
return (WPT_HIT);
}
}
return (0);
}
void
reset_all()
{
init_event(); /* Clear event queue */
init_regs(sregs);
ms->reset ();
}
void
sys_reset()
{
reset_all();
sregs[0].trap = 256; /* Force fake reset trap */
}
void
sys_halt()
{
sregs[0].trap = 257; /* Force fake halt trap */
}
/* simulate one core instruction-wise */
static int
run_sim_un(sregs, icount, dis)
struct pstate *sregs;
uint64 icount;
int dis;
{
int irq, mexc, deb;
uint32 *inst;
if (sregs->err_mode) icount = 0;
deb = dis || ebase.histlen || ebase.bptnum;
mexc = irq = 0;
while (icount > 0) {
if (sregs->pwd_mode) {
sregs->simtime = ebase.evtime; /* skip forward to next event */
if (ext_irl[sregs->cpu]) irq = arch->check_interrupts(sregs);
} else {
sregs->icnt = 1;
sregs->fhold = 0;
if (ext_irl[sregs->cpu]) irq = arch->check_interrupts(sregs);
if (!irq) {
#ifdef ROM_ENABLED
mexc = ms->memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
#else
inst = (uint32 *) &ramb[sregs->pc & RAM_MASK];
sregs->inst = *inst;
sregs->hold = 0;
#endif
if (mexc) {
sregs->trap = I_ACC_EXC;
} else {
if (deb) {
if ((ebase.bptnum) && (sregs->bphit = check_bpt(sregs)))
icount = 0;
else {
if (ebase.histlen) {
sregs->histbuf[sregs->histind].addr = sregs->pc;
sregs->histbuf[sregs->histind].time = ebase.simtime;
sregs->histind++;
if (sregs->histind >= ebase.histlen)
sregs->histind = 0;
}
if (dis) {
printf(" %8" PRIu64 " ", ebase.simtime);
dis_mem(sregs->pc, 1);
}
arch->dispatch_instruction(sregs);
icount--;
advance_time(sregs->simtime);
}
} else {
arch->dispatch_instruction(sregs);
icount--;
}
}
} else
sregs->trap = irq + 16;
if (sregs->trap) {
irq = 0;
if ((sregs->err_mode = arch->execute_trap(sregs)) == WPT_HIT) {
sregs->err_mode = 0;
sregs->trap = 0;
icount = 0;
ebase.bpcpu = sregs->cpu;
if (ebase.histlen) {
sregs->histind--;
if (sregs->histind >= ebase.histlen)
sregs->histind = ebase.histlen - 1;
}
}
if (sregs->err_mode) {
ms->error_mode (sregs->pc);
icount = 0;
ebase.bpcpu = sregs->cpu;
}
}
#ifdef STAT
sregs->fholdt += sregs->fhold;
sregs->holdt += sregs->hold;
sregs->icntt += sregs->icnt;
#endif
sregs->simtime += sregs->icnt + sregs->hold + sregs->fhold;
}
if (sregs->simtime >= ebase.evtime)
advance_time(sregs->simtime);
if (ctrl_c) {
icount = 0;
}
}
advance_time(sregs->simtime);
if (sregs->err_mode)
return ERROR;
if (sregs->bphit)
return (BPT_HIT);
if (ebase.wphit)
return (WPT_HIT);
if (ctrl_c) {
return CTRL_C;
}
return TIME_OUT;
}
/* stop simulation after specified time */
static void
sim_timeout(int32 arg)
{
ctrl_c = arg;
}
/* simulate one core time-wise */
static int
run_sim_core(sregs, ntime, deb, dis)
struct pstate *sregs;
uint64 ntime;
int deb;
int dis;
{
int mexc, irq;
mexc = irq = 0;
if (sregs->pwd_mode == 0)
while (ntime > sregs->simtime) {
if (ext_irl[sregs->cpu])
irq = arch->check_interrupts(sregs);
else
irq = 0;
sregs->icnt = 1;
#ifdef ROM_ENABLED
mexc = ms->memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
#else
sregs->inst = *((uint32 *) &ramb[sregs->pc & RAM_MASK]);
sregs->hold = 0;
#endif
#ifdef ENABLE_L1CACHE
if (sregs->l1itags[(sregs->pc >> L1ILINEBITS) & L1IMASK] != (sregs->pc >> L1ILINEBITS)) {
sregs->hold = T_L1IMISS;
sregs->l1itags[(sregs->pc >> L1ILINEBITS) & L1IMASK] = (sregs->pc >> L1ILINEBITS);
sregs->l1imiss++;
}
#endif
sregs->fhold = 0;
if (!irq) {
if (mexc) {
sregs->trap = I_ACC_EXC;
} else {
if (deb) {
if ((ebase.bptnum) && (sregs->bphit = check_bpt(sregs))) {
ntime = sregs->simtime;
ctrl_c = 1;
ebase.bpcpu = sregs->cpu;
break;
}
if (ebase.histlen) {
sregs->histbuf[sregs->histind].addr = sregs->pc;
sregs->histbuf[sregs->histind].time = sregs->simtime;
sregs->histind++;
if (sregs->histind >= ebase.histlen)
sregs->histind = 0;
}
if (dis) {
printf("cpu %d %8" PRIu64 " ", sregs->cpu, sregs->simtime);
dis_mem(sregs->pc, 1);
}
arch->dispatch_instruction(sregs);
} else {
arch->dispatch_instruction(sregs);
}
}
} else
sregs->trap = irq + 16;
if (sregs->trap) {
irq = 0;
if ((sregs->err_mode = arch->execute_trap(sregs)) == WPT_HIT) {
sregs->err_mode = 0;
sregs->trap = 0;
ntime = sregs->simtime;
ctrl_c = 1;
ebase.bpcpu = sregs->cpu;
if (ebase.histlen) {
sregs->histind--;
if (sregs->histind >= ebase.histlen)
sregs->histind = ebase.histlen - 1;
}
break;
}
if (sregs->err_mode) {
ms->error_mode (sregs->pc);
sregs->pwd_mode = 1;
sregs->pwdstart = sregs->simtime;
sregs->simtime = ntime;
ctrl_c = 1;
ebase.bpcpu = sregs->cpu;
break;
}
}
#ifdef STAT
sregs->fholdt += sregs->fhold;
sregs->holdt += sregs->hold;
sregs->icntt += sregs->icnt;
#endif
sregs->simtime += sregs->icnt + sregs->hold + sregs->fhold;
}
else {
sregs->simtime = ntime;
if (ext_irl[sregs->cpu]) irq = arch->check_interrupts(sregs);
}
sregs->lrq = 0;
}
/* time slice simulation of cpu cores in MP system */
static int
run_sim_mp(icount, dis)
uint64 icount;
int dis;
{
uint64 ntime, etime;
int deb, i, j;
int err_mode, bphit, wphit, oldcpu;
err_mode = bphit = wphit = 0;
icount += ebase.simtime;
for(i=0; i ebase.simtime) {
ntime = ebase.simtime + delta;
if (ntime > icount) ntime = icount;
if (ntime > ebase.evtime) ntime = ebase.evtime;
for(i=0; iinit_stdio ();
if (ebase.tlimit > ebase.simtime)
event(sim_timeout, 2, ebase.tlimit - ebase.simtime);
if (ebase.coven)
cov_start(sregs[0].pc);
if ((ncpu == 1) || (icount == 1))
res = run_sim_un(&sregs[cpu], icount, dis);
else
res = run_sim_mp(icount, dis);
remove_event(sim_timeout, -1);
ebase.tottime += get_time() - ebase.starttime;
ms->restore_stdio ();
if ((res == CTRL_C) && (ctrl_c == 2))
printf("\nTime-out limit reached\n");
sim_run = 0;
return res;
}
double get_time (void)
{
double usec;
struct timeval tm;
gettimeofday (&tm, NULL);
usec = ((double) tm.tv_sec) * 1E6 + ((double) tm.tv_usec);
return usec / 1E6;
}
/* Local version of getline() since not all systems supports it */
static const int line_size = 128;
static ssize_t
mygetdelim (char **lineptr, size_t *n, int delim, FILE *stream)
{
int indx = 0;
int c;
/* Sanity checks. */
if (lineptr == NULL || n == NULL || stream == NULL)
return -1;
/* Allocate the line the first time. */
if (*lineptr == NULL)
{
*lineptr = malloc (line_size);
if (*lineptr == NULL)
return -1;
*n = line_size;
}
/* Clear the line. */
memset (*lineptr, '\0', *n);
while ((c = getc (stream)) != EOF)
{
/* Check if more memory is needed. */
if (indx >= *n)
{
*lineptr = realloc (*lineptr, *n + line_size);
if (*lineptr == NULL)
{
return -1;
}
/* Clear the rest of the line. */
memset(*lineptr + *n, '\0', line_size);
*n += line_size;
}
/* Push the result in the line. */
(*lineptr)[indx++] = c;
/* Bail out. */
if (c == delim)
{
break;
}
}
return (c == EOF) ? -1 : indx;
}
static ssize_t
mygetline (char **lineptr, size_t *n, FILE *stream)
{
return mygetdelim (lineptr, n, '\n', stream);
}
/* Coverage support */
#define COV_EXEC 1
#define COV_START 2
#define COV_JMP 4
#define COV_BT 8
#define COV_BNT 16
unsigned char covram[0x01000000/4];
void cov_start(int address)
{
covram[(address >> 2) & RAM_MASK] |= (COV_START | COV_EXEC);
}
void cov_exec(int address)
{
covram[(address >> 2) & RAM_MASK] |= COV_EXEC;
}
void cov_bt(int address1, int address2)
{
covram[(address1 >> 2) & RAM_MASK] |= (COV_BT | COV_EXEC);
covram[(address2 >> 2) & RAM_MASK] |= (COV_START | COV_EXEC);
}
void cov_bnt(int address)
{
covram[(address >> 2) & RAM_MASK] |= (COV_BNT | COV_EXEC);
}
void cov_jmp(int address1, int address2)
{
covram[(address1 >> 2) & RAM_MASK] |= (COV_JMP | COV_EXEC);
covram[(address2 >> 2) & RAM_MASK] |= (COV_START | COV_EXEC);
}
void cov_save(char *name)
{
FILE *fp;
char filename[1024];
int i, j, k, state;
strcpy(filename, name);
strcat(filename, ".cov");
fp = fopen (filename, "w");
state = 0;
for (i=0; i