summaryrefslogtreecommitdiffstats
path: root/func.c
diff options
context:
space:
mode:
Diffstat (limited to 'func.c')
-rw-r--r--func.c1362
1 files changed, 1362 insertions, 0 deletions
diff --git a/func.c b/func.c
new file mode 100644
index 0000000..5269e0c
--- /dev/null
+++ b/func.c
@@ -0,0 +1,1362 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include "sis.h"
+#include <inttypes.h>
+#include <sys/time.h>
+
+//#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 = "2.14";
+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; i<ncpu; i++) {
+ sregs[i].pc = len & ~1;
+ sregs[i].npc = sregs->pc + 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<ncpu; i++) {
+ if (sregs[i].histbuf != NULL)
+ free(sregs[i].histbuf);
+ sregs[i].histbuf = (struct histype *) calloc(ebase.histlen, sizeof(struct histype));
+ sregs[i].histind = 0;
+ }
+ printf("trace history length = %d\n\r", ebase.histlen);
+
+ } else {
+ j = sregs[cpu].histind;
+ for (i = 0; i < ebase.histlen; i++) {
+ if (j >= 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; i<ncpu; i++) {
+ sregs[i].pc = last_load_addr & ~3;
+ sregs[i].npc = sregs[i].pc + 4;
+ }
+ }
+ if ((sregs->pc != 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; i<ncpu; i++) {
+ sregs[i].pc = last_load_addr & ~3;
+ sregs[i].npc = sregs[i].pc + 4;
+ }
+ }
+ if ((sregs->pc != 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;
+
+}
+
+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; i<ncpu; i++) {
+ if (sregs[i].pwd_mode) {
+ sregs[i].pwdtime += sregs[i].simtime - sregs[i].pwdstart;
+ sregs[i].pwdstart = sregs[i].simtime;
+ }
+ ninst += sregs[i].ninst;
+ pwdtime += sregs[i].pwdtime;
+ }
+ stime = ebase.simtime - ebase.simstart; /* Total simulated time */
+ printf ("\n Frequency : %4.1f MHz\n", ebase.freq);
+ printf(" Cycles : %" PRIu64 "\n", stime);
+ printf(" Instructions : %" PRIu64 "\n", ninst);
+ printf(" Simulated time : %.2f s\n",
+ (double) (stime) / 1000000.0 / ebase.freq);
+ printf(" System perf. : %.2f MOPS\n",
+ (double) ninst / ((double) (stime) / ebase.freq));
+ printf(" Real-time perf. : %.2f %%\n",
+ 100.0 / (ebase.tottime / ((double) (stime) / (ebase.freq * 1.0E6))));
+ printf(" Simulator perf. : %.2f MIPS\n",
+ (double)(ninst / ebase.tottime / 1E6));
+ printf(" Wall time : %.2f s\n\n", ebase.tottime);
+ printf (" Core MIPS MFLOPS CPI Util\n");
+ for (i=0; i<ncpu; i++) {
+#ifdef STAT
+ iinst = sregs[i].ninst - sregs[i].finst - sregs[i].nload - sregs[i].nstore -
+ sregs[i].nbranch;
+#endif
+
+ stime = sregs[i].simtime - ebase.simstart + 1; /* Core simulated time */
+ printf (" %d %5.2f %5.2f %5.2f %5.2f %%\n", i,
+ ebase.freq * (double) (sregs[i].ninst - sregs[i].finst) /
+ (double) (stime - sregs[i].pwdtime),
+ ebase.freq * (double) sregs[i].finst / (double) (stime - sregs[i].pwdtime),
+ (double) (stime - sregs[i].pwdtime) / (double) (sregs[i].ninst + 1),
+ 100.0 * (1.0 - ((double) sregs[i].pwdtime / (double) stime)));
+ }
+
+#ifdef STAT
+ printf (" integer : %9.2f %%\n", 100.0 * (double) iinst / (double) sregs[i].ninst);
+ printf(" load : %9.2f %%\n",
+ 100.0 * (double) sregs->nload / (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<ncpu; i++) {
+ sregs[i].histind = 0;
+ sregs[i].histbuf = NULL;
+ }
+ ebase.tlimit = 0;
+}
+
+/* taken from gdbserver */
+static void
+check_interrup ()
+{
+ fd_set readset;
+ struct timeval immediate = { 0, 0 };
+
+ /* Protect against spurious interrupts. This has been observed to
+ be a problem under NetBSD 1.4 and 1.5. */
+
+ FD_ZERO (&readset);
+ FD_SET (new_socket, &readset);
+ if (select (new_socket + 1, &readset, 0, 0, &immediate) > 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)
+ void (*cfunc) ();
+{
+ struct evcell *ev1, *evdel;
+
+ ev1 = &ebase.eq;
+ while (ev1->nxt != NULL) {
+ if (ev1->nxt->cfunc == cfunc) {
+ 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
+ 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;
+ int err_mode, bphit, wphit, oldcpu;
+
+ err_mode = bphit = wphit = 0;
+ icount += ebase.simtime;
+ for(i=0; i<ncpu; i++) {
+ if (sregs[i].err_mode) {
+ icount = 0;
+ err_mode = 1;
+ }
+ }
+ while (icount > ebase.simtime) {
+ ntime = ebase.simtime + delta;
+ if (ntime > icount) ntime = icount;
+ for(i=0; i<ncpu; i++) {
+ deb = dis || ebase.histlen || ebase.bptnum;
+ etime = ntime;
+ run_sim_core(&sregs[i], ntime, deb, dis);
+ err_mode |= sregs[i].err_mode;
+ bphit |= sregs[i].bphit;
+ wphit |= ebase.wphit;
+ if (sregs[i].simtime < etime)
+ etime = sregs[i].simtime;
+ }
+ advance_time(etime);
+ if (ctrl_c) {
+ icount = 0;
+ }
+ }
+
+ oldcpu = cpu;
+ cpu = ebase.bpcpu;
+ if (err_mode == NULL_HIT)
+ return NULL_HIT;
+ if (err_mode)
+ return ERROR;
+ if (bphit)
+ return (BPT_HIT);
+ if (wphit)
+ return (WPT_HIT);
+ if (ctrl_c) {
+ return CTRL_C;
+ }
+ cpu = oldcpu;
+ return TIME_OUT;
+}
+
+int
+run_sim(icount, dis)
+ uint64 icount;
+ int dis;
+{
+ int res;
+
+ ctrl_c = 0;
+ sim_run = 1;
+ ebase.starttime = get_time();
+ ms->init_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);
+ 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<RAM_SIZE/4; i+=32) {
+ k =0;
+ for (j=0; j<32; j++) {
+ k |= covram[i+j];
+ }
+ if (k || state) {
+ fprintf(fp, "%08x : ", ebase.ramstart + i*4);
+ for (j=0; j<32; j++) {
+ if (state)
+ covram[i+j] |= COV_EXEC;
+ if (covram[i+j] & COV_START)
+ state = 1;
+ if (covram[i+j] & (COV_JMP | COV_BT | COV_BNT))
+ state = 0;
+ if ((ebase.ramstart + (i+j)*4) == sregs[0].pc)
+ state = 0;
+ covram[i+j] &= ~0x6;
+ fprintf(fp, "%x ", covram[i+j]);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ printf("\nsaved code coverage to %s\n", filename);
+ fclose(fp);
+}