| /* This file is part of SIS (SPARC instruction simulator) | |
| Copyright (C) 1995-2022 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/>. */ | |
| /* This must come before any other includes. */ | |
| #include "defs.h" | |
| #include <signal.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <sys/fcntl.h> | |
| #include "sis.h" | |
| #include <dis-asm.h> | |
| #include "sim-config.h" | |
| #include <inttypes.h> | |
| #define VAL(x) strtol(x,(char **)NULL,0) | |
| /* Structures and functions from readline library */ | |
| #include "readline/readline.h" | |
| #include "readline/history.h" | |
| /* Command history buffer length - MUST be binary */ | |
| #define HIST_LEN 64 | |
| extern struct disassemble_info dinfo; | |
| extern struct pstate sregs; | |
| extern struct estate ebase; | |
| extern int ctrl_c; | |
| extern int nfp; | |
| extern int ift; | |
| extern int wrp; | |
| extern int rom8; | |
| extern int uben; | |
| extern int sis_verbose; | |
| extern char *sis_version; | |
| extern struct estate ebase; | |
| extern struct evcell evbuf[]; | |
| extern struct irqcell irqarr[]; | |
| extern int irqpend, ext_irl; | |
| extern int termsave; | |
| extern int sparclite; | |
| extern int dumbio; | |
| extern char uart_dev1[]; | |
| extern char uart_dev2[]; | |
| extern uint32_t last_load_addr; | |
| #ifdef ERA | |
| extern int era; | |
| #endif | |
| int | |
| run_sim(struct pstate *sregs, uint64_t icount, int dis) | |
| { | |
| int irq, mexc, deb; | |
| sregs->starttime = get_time(); | |
| init_stdio(); | |
| if (sregs->err_mode) icount = 0; | |
| deb = dis || sregs->histlen || sregs->bptnum; | |
| irq = 0; | |
| while (icount > 0) { | |
| mexc = memory_iread (sregs->pc, &sregs->inst, &sregs->hold); | |
| sregs->icnt = 1; | |
| if (sregs->annul) { | |
| sregs->annul = 0; | |
| sregs->pc = sregs->npc; | |
| sregs->npc = sregs->npc + 4; | |
| } else { | |
| sregs->fhold = 0; | |
| if (ext_irl) irq = check_interrupts(sregs); | |
| if (!irq) { | |
| if (mexc) { | |
| sregs->trap = I_ACC_EXC; | |
| } else { | |
| if (deb) { | |
| if ((sregs->bphit = check_bpt(sregs)) != 0) { | |
| restore_stdio(); | |
| return BPT_HIT; | |
| } | |
| if (sregs->histlen) { | |
| sregs->histbuf[sregs->histind].addr = sregs->pc; | |
| sregs->histbuf[sregs->histind].time = ebase.simtime; | |
| sregs->histind++; | |
| if (sregs->histind >= sregs->histlen) | |
| sregs->histind = 0; | |
| } | |
| if (dis) { | |
| printf(" %8" PRIu64 " ", ebase.simtime); | |
| dis_mem(sregs->pc, 1, &dinfo); | |
| } | |
| } | |
| dispatch_instruction(sregs); | |
| icount--; | |
| } | |
| } | |
| if (sregs->trap) { | |
| irq = 0; | |
| sregs->err_mode = execute_trap(sregs); | |
| if (sregs->err_mode) { | |
| error_mode(sregs->pc); | |
| icount = 0; | |
| } | |
| } | |
| } | |
| advance_time(sregs); | |
| if (ctrl_c || (sregs->tlimit <= ebase.simtime)) { | |
| icount = 0; | |
| if (sregs->tlimit <= ebase.simtime) sregs->tlimit = -1; | |
| } | |
| } | |
| sregs->tottime += get_time() - sregs->starttime; | |
| restore_stdio(); | |
| if (sregs->err_mode) | |
| return ERROR; | |
| if (ctrl_c) { | |
| ctrl_c = 0; | |
| return CTRL_C; | |
| } | |
| return TIME_OUT; | |
| } | |
| int | |
| fprintf_styled (void *stream, enum disassembler_style style, | |
| const char *fmt, ...) | |
| { | |
| int ret; | |
| FILE *out = (FILE *) stream; | |
| va_list args; | |
| va_start (args, fmt); | |
| ret = vfprintf (out, fmt, args); | |
| va_end (args); | |
| return ret; | |
| } | |
| int | |
| main(int argc, char **argv) | |
| { | |
| int cont = 1; | |
| int stat = 1; | |
| int freq = 14; | |
| int copt = 0; | |
| char *cfile, *bacmd; | |
| char *cmdq[HIST_LEN]; | |
| int cmdi = 0; | |
| int i; | |
| int lfile = 0; | |
| cfile = 0; | |
| for (i = 0; i < 64; i++) | |
| cmdq[i] = 0; | |
| printf("\n SIS - SPARC instruction simulator %s, copyright Jiri Gaisler 1995\n", sis_version); | |
| printf(" Bug-reports to jgais@wd.estec.esa.nl\n\n"); | |
| while (stat < argc) { | |
| if (argv[stat][0] == '-') { | |
| if (strcmp(argv[stat], "-v") == 0) { | |
| sis_verbose += 1; | |
| } else if (strcmp(argv[stat], "-c") == 0) { | |
| if ((stat + 1) < argc) { | |
| copt = 1; | |
| cfile = argv[++stat]; | |
| } | |
| } else if (strcmp(argv[stat], "-nfp") == 0) | |
| nfp = 1; | |
| else if (strcmp(argv[stat], "-ift") == 0) | |
| ift = 1; | |
| else if (strcmp(argv[stat], "-wrp") == 0) | |
| wrp = 1; | |
| else if (strcmp(argv[stat], "-rom8") == 0) | |
| rom8 = 1; | |
| else if (strcmp(argv[stat], "-uben") == 0) | |
| uben = 1; | |
| else if (strcmp(argv[stat], "-uart1") == 0) { | |
| if ((stat + 1) < argc) | |
| strcpy(uart_dev1, argv[++stat]); | |
| } else if (strcmp(argv[stat], "-uart2") == 0) { | |
| if ((stat + 1) < argc) | |
| strcpy(uart_dev2, argv[++stat]); | |
| } else if (strcmp(argv[stat], "-freq") == 0) { | |
| if ((stat + 1) < argc) | |
| freq = VAL(argv[++stat]); | |
| } else if (strcmp(argv[stat], "-sparclite") == 0) { | |
| sparclite = 1; | |
| #ifdef ERA | |
| } else if (strcmp(argv[stat], "-era") == 0) { | |
| era = 1; | |
| #endif | |
| } else if (strcmp(argv[stat], "-dumbio") == 0) { | |
| dumbio = 1; | |
| } else { | |
| printf("unknown option %s\n", argv[stat]); | |
| usage(); | |
| exit(1); | |
| } | |
| } else { | |
| lfile = stat; | |
| } | |
| stat++; | |
| } | |
| if (nfp) | |
| printf("FPU disabled\n"); | |
| #ifdef ERA | |
| if (era) | |
| printf("ERA ECC emulation enabled\n"); | |
| #endif | |
| sregs.freq = freq; | |
| INIT_DISASSEMBLE_INFO(dinfo, stdout, (fprintf_ftype) fprintf, | |
| (fprintf_styled_ftype) fprintf_styled); | |
| #ifdef HOST_LITTLE_ENDIAN | |
| dinfo.endian = BFD_ENDIAN_LITTLE; | |
| #else | |
| dinfo.endian = BFD_ENDIAN_BIG; | |
| #endif | |
| #ifdef F_GETFL | |
| termsave = fcntl(0, F_GETFL, 0); | |
| #endif | |
| using_history(); | |
| init_signals(); | |
| ebase.simtime = 0; | |
| reset_all(); | |
| init_bpt(&sregs); | |
| init_sim(); | |
| if (lfile) | |
| last_load_addr = bfd_load(argv[lfile]); | |
| #ifdef STAT | |
| reset_stat(&sregs); | |
| #endif | |
| if (copt) { | |
| bacmd = (char *) malloc(256); | |
| strcpy(bacmd, "batch "); | |
| strcat(bacmd, cfile); | |
| exec_cmd(&sregs, bacmd); | |
| } | |
| while (cont) { | |
| if (cmdq[cmdi] != 0) { | |
| #if 0 | |
| remove_history(cmdq[cmdi]); | |
| #else | |
| remove_history(cmdi); | |
| #endif | |
| free(cmdq[cmdi]); | |
| cmdq[cmdi] = 0; | |
| } | |
| cmdq[cmdi] = readline("sis> "); | |
| if (cmdq[cmdi] && *cmdq[cmdi]) | |
| add_history(cmdq[cmdi]); | |
| if (cmdq[cmdi]) | |
| stat = exec_cmd(&sregs, cmdq[cmdi]); | |
| else { | |
| puts("\n"); | |
| exit(0); | |
| } | |
| switch (stat) { | |
| case OK: | |
| break; | |
| case CTRL_C: | |
| printf("\b\bInterrupt!\n"); | |
| case TIME_OUT: | |
| printf(" Stopped at time %" PRIu64 " (%.3f ms)\n", ebase.simtime, | |
| ((double) ebase.simtime / (double) sregs.freq) / 1000.0); | |
| break; | |
| case BPT_HIT: | |
| printf("breakpoint at 0x%08x reached\n", sregs.pc); | |
| sregs.bphit = 1; | |
| break; | |
| case ERROR: | |
| printf("IU in error mode (%d)\n", sregs.trap); | |
| stat = 0; | |
| printf(" %8" PRIu64 " ", ebase.simtime); | |
| dis_mem(sregs.pc, 1, &dinfo); | |
| break; | |
| default: | |
| break; | |
| } | |
| ctrl_c = 0; | |
| stat = OK; | |
| cmdi = (cmdi + 1) & (HIST_LEN - 1); | |
| } | |
| return 0; | |
| } | |