/* 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