diff options
Diffstat (limited to 'func.c')
-rw-r--r-- | func.c | 1362 |
1 files changed, 1362 insertions, 0 deletions
@@ -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); +} |