1 /* This file is part of SIS (SPARC instruction simulator) 2 3 Copyright (C) 1995-2024 Free Software Foundation, Inc. 4 Contributed by Jiri Gaisler, European Space Agency 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 /* This must come before any other includes. */ 20 #include "defs.h" 21 22 #include <signal.h> 23 #include <string.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <sys/fcntl.h> 27 #include "sis.h" 28 #include "libiberty.h" 29 #include "bfd.h" 30 #include <dis-asm.h> 31 #include "sim-config.h" 32 33 #include "sim/sim.h" 34 #include "gdb/signals.h" 35 36 #define PSR_CWP 0x7 37 38 extern struct disassemble_info dinfo; 39 extern struct pstate sregs; 40 extern struct estate ebase; 41 42 extern int ctrl_c; 43 extern int nfp; 44 extern int ift; 45 extern int rom8; 46 extern int wrp; 47 extern int uben; 48 extern int sis_verbose; 49 extern char *sis_version; 50 extern struct estate ebase; 51 extern struct evcell evbuf[]; 52 extern struct irqcell irqarr[]; 53 extern int irqpend, ext_irl; 54 extern int sparclite; 55 extern int dumbio; 56 extern int sparclite_board; 57 extern int termsave; 58 extern char uart_dev1[], uart_dev2[]; 59 60 int sis_gdb_break = 1; 61 62 host_callback *sim_callback; 63 64 int 65 run_sim(struct pstate *sregs, uint64_t icount, int dis) 66 { 67 int mexc, irq; 68 69 if (sis_verbose) 70 (*sim_callback->printf_filtered) (sim_callback, "resuming at %x\n", 71 sregs->pc); 72 init_stdio(); 73 sregs->starttime = get_time(); 74 irq = 0; 75 if ((sregs->pc != 0) && (ebase.simtime == 0)) 76 boot_init(); 77 while (!sregs->err_mode & (icount > 0)) { 78 79 sregs->fhold = 0; 80 sregs->hold = 0; 81 sregs->icnt = 1; 82 83 if (sregs->psr & 0x080) 84 sregs->asi = 8; 85 else 86 sregs->asi = 9; 87 88 #if 0 /* DELETE ME! for debugging purposes only */ 89 if (sis_verbose > 1) 90 if (sregs->pc == 0 || sregs->npc == 0) 91 printf ("bogus pc or npc\n"); 92 #endif 93 mexc = memory_iread (sregs->pc, &sregs->inst, &sregs->hold); 94 #if 0 /* DELETE ME! for debugging purposes only */ 95 if (sis_verbose > 2) 96 printf("pc %x, np %x, sp %x, fp %x, wm %x, cw %x, i %08x\n", 97 sregs->pc, sregs->npc, 98 sregs->r[(((sregs->psr & 7) << 4) + 14) & 0x7f], 99 sregs->r[(((sregs->psr & 7) << 4) + 30) & 0x7f], 100 sregs->wim, 101 sregs->psr & 7, 102 sregs->inst); 103 #endif 104 if (sregs->annul) { 105 sregs->annul = 0; 106 sregs->icnt = 1; 107 sregs->pc = sregs->npc; 108 sregs->npc = sregs->npc + 4; 109 } else { 110 if (ext_irl) irq = check_interrupts(sregs); 111 if (!irq) { 112 if (mexc) { 113 sregs->trap = I_ACC_EXC; 114 } else { 115 if ((sis_gdb_break) && (sregs->inst == 0x91d02001)) { 116 if (sis_verbose) 117 (*sim_callback->printf_filtered) (sim_callback, 118 "SW BP hit at %x\n", sregs->pc); 119 sim_halt(); 120 restore_stdio(); 121 clearerr(stdin); 122 return BPT_HIT; 123 } else 124 dispatch_instruction(sregs); 125 } 126 icount--; 127 } 128 if (sregs->trap) { 129 irq = 0; 130 sregs->err_mode = execute_trap(sregs); 131 } 132 } 133 advance_time(sregs); 134 if (ctrl_c) { 135 icount = 0; 136 } 137 } 138 sim_halt(); 139 sregs->tottime += get_time() - sregs->starttime; 140 restore_stdio(); 141 clearerr(stdin); 142 if (sregs->err_mode) 143 error_mode(sregs->pc); 144 if (sregs->err_mode) 145 return ERROR; 146 if (sregs->bphit) { 147 if (sis_verbose) 148 (*sim_callback->printf_filtered) (sim_callback, 149 "HW BP hit at %x\n", sregs->pc); 150 return BPT_HIT; 151 } 152 if (ctrl_c) { 153 ctrl_c = 0; 154 return CTRL_C; 155 } 156 return TIME_OUT; 157 } 158 159 static int ATTRIBUTE_PRINTF (3, 4) 160 fprintf_styled (void *stream, enum disassembler_style style, 161 const char *fmt, ...) 162 { 163 int ret; 164 FILE *out = (FILE *) stream; 165 va_list args; 166 167 va_start (args, fmt); 168 ret = vfprintf (out, fmt, args); 169 va_end (args); 170 171 return ret; 172 } 173 174 SIM_DESC 175 sim_open (SIM_OPEN_KIND kind, struct host_callback_struct *callback, 176 struct bfd *abfd, char * const *argv) 177 { 178 179 int argc = 0; 180 int stat = 1; 181 int freq = 0; 182 183 sim_callback = callback; 184 185 argc = countargv (argv); 186 while (stat < argc) { 187 if (argv[stat][0] == '-') { 188 if (strcmp(argv[stat], "-v") == 0) { 189 sis_verbose++; 190 } else 191 if (strcmp(argv[stat], "-nfp") == 0) { 192 nfp = 1; 193 } else 194 if (strcmp(argv[stat], "-ift") == 0) { 195 ift = 1; 196 } else 197 if (strcmp(argv[stat], "-sparclite") == 0) { 198 sparclite = 1; 199 } else 200 if (strcmp(argv[stat], "-sparclite-board") == 0) { 201 sparclite_board = 1; 202 } else 203 if (strcmp(argv[stat], "-dumbio") == 0) { 204 dumbio = 1; 205 } else 206 if (strcmp(argv[stat], "-wrp") == 0) { 207 wrp = 1; 208 } else 209 if (strcmp(argv[stat], "-rom8") == 0) { 210 rom8 = 1; 211 } else 212 if (strcmp(argv[stat], "-uben") == 0) { 213 uben = 1; 214 } else 215 if (strcmp(argv[stat], "-uart1") == 0) { 216 if ((stat + 1) < argc) 217 strcpy(uart_dev1, argv[++stat]); 218 } else 219 if (strcmp(argv[stat], "-uart2") == 0) { 220 if ((stat + 1) < argc) 221 strcpy(uart_dev2, argv[++stat]); 222 } else 223 if (strcmp(argv[stat], "-nogdb") == 0) { 224 sis_gdb_break = 0; 225 } else 226 if (strcmp(argv[stat], "-freq") == 0) { 227 if ((stat + 1) < argc) { 228 freq = strtol(argv[++stat], (char **)NULL, 0); 229 } 230 } else 231 if (strncmp(argv[stat], "--sysroot=", sizeof("--sysroot=") - 1) == 0) { 232 /* Ignore until we start to support this. */ 233 } else { 234 (*sim_callback->printf_filtered) (sim_callback, 235 "unknown option %s\n", 236 argv[stat]); 237 } 238 } else 239 bfd_load(argv[stat]); 240 stat++; 241 } 242 243 if (sis_verbose) { 244 (*sim_callback->printf_filtered) (sim_callback, "\n SIS - SPARC instruction simulator %s\n", sis_version); 245 (*sim_callback->printf_filtered) (sim_callback, " Bug-reports to Jiri Gaisler ESA/ESTEC (jgais@wd.estec.esa.nl)\n"); 246 if (nfp) 247 (*sim_callback->printf_filtered) (sim_callback, "no FPU\n"); 248 if (sparclite) 249 (*sim_callback->printf_filtered) (sim_callback, "simulating Sparclite\n"); 250 if (dumbio) 251 (*sim_callback->printf_filtered) (sim_callback, "dumb IO (no input, dumb output)\n"); 252 if (sis_gdb_break == 0) 253 (*sim_callback->printf_filtered) (sim_callback, "disabling GDB trap handling for breakpoints\n"); 254 if (freq) 255 (*sim_callback->printf_filtered) (sim_callback, " ERC32 freq %d Mhz\n", freq); 256 } 257 258 sregs.freq = freq ? freq : 15; 259 #ifdef F_GETFL 260 termsave = fcntl(0, F_GETFL, 0); 261 #endif 262 INIT_DISASSEMBLE_INFO(dinfo, stdout,(fprintf_ftype)fprintf, 263 fprintf_styled); 264 #ifdef HOST_LITTLE_ENDIAN 265 dinfo.endian = BFD_ENDIAN_LITTLE; 266 #else 267 dinfo.endian = BFD_ENDIAN_BIG; 268 #endif 269 reset_all(); 270 ebase.simtime = 0; 271 init_sim(); 272 init_bpt(&sregs); 273 reset_stat(&sregs); 274 275 /* Fudge our descriptor for now. */ 276 return (SIM_DESC) 1; 277 } 278 279 void 280 sim_close(SIM_DESC sd, int quitting) 281 { 282 283 exit_sim(); 284 #ifdef F_SETFL 285 fcntl(0, F_SETFL, termsave); 286 #endif 287 } 288 289 SIM_RC 290 sim_load(SIM_DESC sd, const char *prog, bfd *abfd, int from_tty) 291 { 292 bfd_load (prog); 293 return SIM_RC_OK; 294 } 295 296 SIM_RC 297 sim_create_inferior(SIM_DESC sd, bfd *abfd, char * const *argv, 298 char * const *env) 299 { 300 bfd_vma start_address = 0; 301 if (abfd != NULL) 302 start_address = bfd_get_start_address (abfd); 303 304 ebase.simtime = 0; 305 reset_all(); 306 reset_stat(&sregs); 307 sregs.pc = start_address & ~3; 308 sregs.npc = sregs.pc + 4; 309 return SIM_RC_OK; 310 } 311 312 int 313 sim_store_register(SIM_DESC sd, int regno, const void *buf, int length) 314 { 315 const unsigned char *value = buf; 316 int regval; 317 318 regval = (value[0] << 24) | (value[1] << 16) 319 | (value[2] << 8) | value[3]; 320 set_regi(&sregs, regno, regval); 321 return length; 322 } 323 324 325 int 326 sim_fetch_register(SIM_DESC sd, int regno, void *buf, int length) 327 { 328 get_regi(&sregs, regno, buf); 329 return -1; 330 } 331 332 uint64_t 333 sim_write (SIM_DESC sd, uint64_t addr, const void *buffer, uint64_t length) 334 { 335 int i; 336 const unsigned char *data = buffer; 337 338 for (i = 0; i < length; i++) { 339 sis_memory_write ((addr + i) ^ EBT, &data[i], 1); 340 } 341 return length; 342 } 343 344 uint64_t 345 sim_read (SIM_DESC sd, uint64_t addr, void *buffer, uint64_t length) 346 { 347 int i; 348 unsigned char *data = buffer; 349 350 for (i = 0; i < length; i++) { 351 sis_memory_read ((addr + i) ^ EBT, &data[i], 1); 352 } 353 return length; 354 } 355 356 void 357 sim_info(SIM_DESC sd, bool verbose) 358 { 359 show_stat(&sregs); 360 } 361 362 int simstat = OK; 363 364 void 365 sim_stop_reason(SIM_DESC sd, enum sim_stop *reason, int *sigrc) 366 { 367 368 switch (simstat) { 369 case CTRL_C: 370 *reason = sim_stopped; 371 *sigrc = GDB_SIGNAL_INT; 372 break; 373 case OK: 374 case TIME_OUT: 375 case BPT_HIT: 376 *reason = sim_stopped; 377 *sigrc = GDB_SIGNAL_TRAP; 378 break; 379 case ERROR: 380 *sigrc = 0; 381 *reason = sim_exited; 382 } 383 ctrl_c = 0; 384 simstat = OK; 385 } 386 387 /* Flush all register windows out to the stack. Starting after the invalid 388 window, flush all windows up to, and including the current window. This 389 allows GDB to do backtraces and look at local variables for frames that 390 are still in the register windows. Note that strictly speaking, this 391 behavior is *wrong* for several reasons. First, it doesn't use the window 392 overflow handlers. It therefore assumes standard frame layouts and window 393 handling policies. Second, it changes system state behind the back of the 394 target program. I expect this to mainly pose problems when debugging trap 395 handlers. 396 */ 397 398 static void 399 flush_windows (void) 400 { 401 int invwin; 402 int cwp; 403 int win; 404 int ws; 405 406 /* Keep current window handy */ 407 408 cwp = sregs.psr & PSR_CWP; 409 410 /* Calculate the invalid window from the wim. */ 411 412 for (invwin = 0; invwin <= PSR_CWP; invwin++) 413 if ((sregs.wim >> invwin) & 1) 414 break; 415 416 /* Start saving with the window after the invalid window. */ 417 418 invwin = (invwin - 1) & PSR_CWP; 419 420 for (win = invwin; ; win = (win - 1) & PSR_CWP) 421 { 422 uint32_t sp; 423 int i; 424 425 sp = sregs.r[(win * 16 + 14) & 0x7f]; 426 #if 1 427 if (sis_verbose > 2) { 428 uint32_t fp = sregs.r[(win * 16 + 30) & 0x7f]; 429 printf("flush_window: win %d, sp %x, fp %x\n", win, sp, fp); 430 } 431 #endif 432 433 for (i = 0; i < 16; i++) 434 memory_write (11, sp + 4 * i, &sregs.r[(win * 16 + 16 + i) & 0x7f], 2, 435 &ws); 436 437 if (win == cwp) 438 break; 439 } 440 } 441 442 void 443 sim_resume(SIM_DESC sd, int step, int siggnal) 444 { 445 simstat = run_sim(&sregs, UINT64_MAX, 0); 446 447 if (sis_gdb_break) flush_windows (); 448 } 449 450 void 451 sim_do_command(SIM_DESC sd, const char *cmd) 452 { 453 exec_cmd(&sregs, cmd); 454 } 455 456 char ** 457 sim_complete_command (SIM_DESC sd, const char *text, const char *word) 458 { 459 return NULL; 460 } 461 462 char * 463 sim_memory_map (SIM_DESC sd) 464 { 465 return NULL; 466 } 467 468 #if 0 /* FIXME: These shouldn't exist. */ 469 470 int 471 sim_insert_breakpoint(int addr) 472 { 473 if (sregs.bptnum < BPT_MAX) { 474 sregs.bpts[sregs.bptnum] = addr & ~0x3; 475 sregs.bptnum++; 476 if (sis_verbose) 477 (*sim_callback->printf_filtered) (sim_callback, "inserted HW BP at %x\n", addr); 478 return 0; 479 } else 480 return 1; 481 } 482 483 int 484 sim_remove_breakpoint(int addr) 485 { 486 int i = 0; 487 488 while ((i < sregs.bptnum) && (sregs.bpts[i] != addr)) 489 i++; 490 if (addr == sregs.bpts[i]) { 491 for (; i < sregs.bptnum - 1; i++) 492 sregs.bpts[i] = sregs.bpts[i + 1]; 493 sregs.bptnum -= 1; 494 if (sis_verbose) 495 (*sim_callback->printf_filtered) (sim_callback, "removed HW BP at %x\n", addr); 496 return 0; 497 } 498 return 1; 499 } 500 501 #endif 502