| 1 | /* |
| 2 | * This file is part of SIS. |
| 3 | * |
| 4 | * SIS, SPARC instruction simulator. Copyright (C) 1995 Jiri Gaisler, European |
| 5 | * Space Agency |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify it under |
| 8 | * the terms of the GNU General Public License as published by the Free |
| 9 | * Software Foundation; either version 2 of the License, or (at your option) |
| 10 | * any later version. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 15 | * more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public License along with |
| 18 | * this program; if not, write to the Free Software Foundation, Inc., 675 |
| 19 | * Mass Ave, Cambridge, MA 02139, USA. |
| 20 | * |
| 21 | */ |
| 22 | |
| 23 | #include "config.h" |
| 24 | #include <signal.h> |
| 25 | #include <string.h> |
| 26 | #ifdef HAVE_STDLIB_H |
| 27 | #include <stdlib.h> |
| 28 | #endif |
| 29 | #include <stdio.h> |
| 30 | #include <time.h> |
| 31 | #include <sys/fcntl.h> |
| 32 | #include "sis.h" |
| 33 | #include <dis-asm.h> |
| 34 | #include "sim-config.h" |
| 35 | |
| 36 | #define VAL(x) strtol(x,(char **)NULL,0) |
| 37 | |
| 38 | /* Structures and functions from readline library */ |
| 39 | |
| 40 | typedef struct { |
| 41 | char *line; |
| 42 | char *data; |
| 43 | } HIST_ENTRY; |
| 44 | |
| 45 | extern char * readline PARAMS ((char *prompt)); |
| 46 | extern void using_history PARAMS ((void)); |
| 47 | extern void add_history PARAMS ((char *string)); |
| 48 | extern HIST_ENTRY *remove_history PARAMS ((int which)); |
| 49 | |
| 50 | |
| 51 | |
| 52 | /* Command history buffer length - MUST be binary */ |
| 53 | #define HIST_LEN 64 |
| 54 | |
| 55 | extern struct disassemble_info dinfo; |
| 56 | extern struct pstate sregs; |
| 57 | extern struct estate ebase; |
| 58 | |
| 59 | extern int ctrl_c; |
| 60 | extern int nfp; |
| 61 | extern int ift; |
| 62 | extern int wrp; |
| 63 | extern int rom8; |
| 64 | extern int uben; |
| 65 | extern int sis_verbose; |
| 66 | extern char *sis_version; |
| 67 | extern struct estate ebase; |
| 68 | extern struct evcell evbuf[]; |
| 69 | extern struct irqcell irqarr[]; |
| 70 | extern int irqpend, ext_irl; |
| 71 | extern int termsave; |
| 72 | extern int sparclite; |
| 73 | extern int dumbio; |
| 74 | extern char uart_dev1[]; |
| 75 | extern char uart_dev2[]; |
| 76 | extern uint32 last_load_addr; |
| 77 | |
| 78 | #ifdef ERA |
| 79 | extern int era; |
| 80 | #endif |
| 81 | |
| 82 | int |
| 83 | run_sim(sregs, icount, dis) |
| 84 | struct pstate *sregs; |
| 85 | uint64 icount; |
| 86 | int dis; |
| 87 | { |
| 88 | int irq, mexc, deb, asi; |
| 89 | |
| 90 | sregs->starttime = time(NULL); |
| 91 | init_stdio(); |
| 92 | if (sregs->err_mode) icount = 0; |
| 93 | deb = dis || sregs->histlen || sregs->bptnum; |
| 94 | irq = 0; |
| 95 | while (icount > 0) { |
| 96 | |
| 97 | if (sregs->psr & 0x080) |
| 98 | asi = 9; |
| 99 | else |
| 100 | asi = 8; |
| 101 | mexc = memory_read(asi, sregs->pc, &sregs->inst, 2, &sregs->hold); |
| 102 | sregs->icnt = 1; |
| 103 | if (sregs->annul) { |
| 104 | sregs->annul = 0; |
| 105 | sregs->pc = sregs->npc; |
| 106 | sregs->npc = sregs->npc + 4; |
| 107 | } else { |
| 108 | sregs->fhold = 0; |
| 109 | if (ext_irl) irq = check_interrupts(sregs); |
| 110 | if (!irq) { |
| 111 | if (mexc) { |
| 112 | sregs->trap = I_ACC_EXC; |
| 113 | } else { |
| 114 | if (deb) { |
| 115 | if ((sregs->bphit = check_bpt(sregs)) != 0) { |
| 116 | restore_stdio(); |
| 117 | return (BPT_HIT); |
| 118 | } |
| 119 | if (sregs->histlen) { |
| 120 | sregs->histbuf[sregs->histind].addr = sregs->pc; |
| 121 | sregs->histbuf[sregs->histind].time = ebase.simtime; |
| 122 | sregs->histind++; |
| 123 | if (sregs->histind >= sregs->histlen) |
| 124 | sregs->histind = 0; |
| 125 | } |
| 126 | if (dis) { |
| 127 | printf(" %8u ", ebase.simtime); |
| 128 | dis_mem(sregs->pc, 1, &dinfo); |
| 129 | } |
| 130 | } |
| 131 | dispatch_instruction(sregs); |
| 132 | icount--; |
| 133 | } |
| 134 | } |
| 135 | if (sregs->trap) { |
| 136 | irq = 0; |
| 137 | sregs->err_mode = execute_trap(sregs); |
| 138 | if (sregs->err_mode) { |
| 139 | error_mode(sregs->pc); |
| 140 | icount = 0; |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | advance_time(sregs); |
| 145 | if (ctrl_c || (sregs->tlimit <= ebase.simtime)) { |
| 146 | icount = 0; |
| 147 | if (sregs->tlimit <= ebase.simtime) sregs->tlimit = -1; |
| 148 | } |
| 149 | } |
| 150 | sregs->tottime += time(NULL) - sregs->starttime; |
| 151 | restore_stdio(); |
| 152 | if (sregs->err_mode) |
| 153 | return (ERROR); |
| 154 | if (ctrl_c) { |
| 155 | ctrl_c = 0; |
| 156 | return (CTRL_C); |
| 157 | } |
| 158 | return (TIME_OUT); |
| 159 | } |
| 160 | |
| 161 | int |
| 162 | main(argc, argv) |
| 163 | int argc; |
| 164 | char **argv; |
| 165 | { |
| 166 | |
| 167 | int cont = 1; |
| 168 | int stat = 1; |
| 169 | int freq = 14; |
| 170 | int copt = 0; |
| 171 | |
| 172 | char *cfile, *bacmd; |
| 173 | char *cmdq[HIST_LEN]; |
| 174 | int cmdi = 0; |
| 175 | int i; |
| 176 | |
| 177 | cfile = 0; |
| 178 | for (i = 0; i < 64; i++) |
| 179 | cmdq[i] = 0; |
| 180 | printf("\n SIS - SPARC instruction simulator %s, copyright Jiri Gaisler 1995\n", sis_version); |
| 181 | printf(" Bug-reports to jgais@wd.estec.esa.nl\n\n"); |
| 182 | while (stat < argc) { |
| 183 | if (argv[stat][0] == '-') { |
| 184 | if (strcmp(argv[stat], "-v") == 0) { |
| 185 | sis_verbose = 1; |
| 186 | } else if (strcmp(argv[stat], "-c") == 0) { |
| 187 | if ((stat + 1) < argc) { |
| 188 | copt = 1; |
| 189 | cfile = argv[++stat]; |
| 190 | } |
| 191 | } else if (strcmp(argv[stat], "-nfp") == 0) |
| 192 | nfp = 1; |
| 193 | else if (strcmp(argv[stat], "-ift") == 0) |
| 194 | ift = 1; |
| 195 | else if (strcmp(argv[stat], "-wrp") == 0) |
| 196 | wrp = 1; |
| 197 | else if (strcmp(argv[stat], "-rom8") == 0) |
| 198 | rom8 = 1; |
| 199 | else if (strcmp(argv[stat], "-uben") == 0) |
| 200 | uben = 1; |
| 201 | else if (strcmp(argv[stat], "-uart1") == 0) { |
| 202 | if ((stat + 1) < argc) |
| 203 | strcpy(uart_dev1, argv[++stat]); |
| 204 | } else if (strcmp(argv[stat], "-uart2") == 0) { |
| 205 | if ((stat + 1) < argc) |
| 206 | strcpy(uart_dev2, argv[++stat]); |
| 207 | } else if (strcmp(argv[stat], "-freq") == 0) { |
| 208 | if ((stat + 1) < argc) |
| 209 | freq = VAL(argv[++stat]); |
| 210 | } else if (strcmp(argv[stat], "-sparclite") == 0) { |
| 211 | sparclite = 1; |
| 212 | #ifdef ERA |
| 213 | } else if (strcmp(argv[stat], "-era") == 0) { |
| 214 | era = 1; |
| 215 | #endif |
| 216 | } else if (strcmp(argv[stat], "-dumbio") == 0) { |
| 217 | dumbio = 1; |
| 218 | } else { |
| 219 | printf("unknown option %s\n", argv[stat]); |
| 220 | usage(); |
| 221 | exit(1); |
| 222 | } |
| 223 | } else { |
| 224 | last_load_addr = bfd_load(argv[stat]); |
| 225 | } |
| 226 | stat++; |
| 227 | } |
| 228 | if (nfp) |
| 229 | printf("FPU disabled\n"); |
| 230 | #ifdef ERA |
| 231 | if (era) |
| 232 | printf("ERA ECC emulation enabled\n"); |
| 233 | #endif |
| 234 | sregs.freq = freq; |
| 235 | |
| 236 | INIT_DISASSEMBLE_INFO(dinfo, stdout, (fprintf_ftype) fprintf); |
| 237 | dinfo.endian = BFD_ENDIAN_BIG; |
| 238 | |
| 239 | termsave = fcntl(0, F_GETFL, 0); |
| 240 | using_history(); |
| 241 | init_signals(); |
| 242 | ebase.simtime = 0; |
| 243 | reset_all(); |
| 244 | init_bpt(&sregs); |
| 245 | init_sim(); |
| 246 | #ifdef STAT |
| 247 | reset_stat(&sregs); |
| 248 | #endif |
| 249 | |
| 250 | if (copt) { |
| 251 | bacmd = (char *) malloc(256); |
| 252 | strcpy(bacmd, "batch "); |
| 253 | strcat(bacmd, cfile); |
| 254 | exec_cmd(&sregs, bacmd); |
| 255 | } |
| 256 | while (cont) { |
| 257 | |
| 258 | if (cmdq[cmdi] != 0) { |
| 259 | #if 0 |
| 260 | remove_history(cmdq[cmdi]); |
| 261 | #else |
| 262 | remove_history(cmdi); |
| 263 | #endif |
| 264 | free(cmdq[cmdi]); |
| 265 | cmdq[cmdi] = 0; |
| 266 | } |
| 267 | cmdq[cmdi] = readline("sis> "); |
| 268 | if (cmdq[cmdi] && *cmdq[cmdi]) |
| 269 | add_history(cmdq[cmdi]); |
| 270 | if (cmdq[cmdi]) |
| 271 | stat = exec_cmd(&sregs, cmdq[cmdi]); |
| 272 | else { |
| 273 | puts("\n"); |
| 274 | exit(0); |
| 275 | } |
| 276 | switch (stat) { |
| 277 | case OK: |
| 278 | break; |
| 279 | case CTRL_C: |
| 280 | printf("\b\bInterrupt!\n"); |
| 281 | case TIME_OUT: |
| 282 | printf(" Stopped at time %d (%.3f ms)\n", ebase.simtime, |
| 283 | ((double) ebase.simtime / (double) sregs.freq) / 1000.0); |
| 284 | break; |
| 285 | case BPT_HIT: |
| 286 | printf("breakpoint at 0x%08x reached\n", sregs.pc); |
| 287 | sregs.bphit = 1; |
| 288 | break; |
| 289 | case ERROR: |
| 290 | printf("IU in error mode (%d)\n", sregs.trap); |
| 291 | stat = 0; |
| 292 | printf(" %8d ", ebase.simtime); |
| 293 | dis_mem(sregs.pc, 1, &dinfo); |
| 294 | break; |
| 295 | default: |
| 296 | break; |
| 297 | } |
| 298 | ctrl_c = 0; |
| 299 | stat = OK; |
| 300 | |
| 301 | cmdi = (cmdi + 1) & (HIST_LEN - 1); |
| 302 | |
| 303 | } |
| 304 | return 0; |
| 305 | } |
| 306 | |