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