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