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