Commit | Line | Data |
---|---|---|
22c1c7dd | 1 | #include <signal.h> |
9cdd2c6d AC |
2 | #include "sim-main.h" |
3 | #include "sim-options.h" | |
4 | #include "v850_sim.h" | |
5 | ||
6 | #ifdef HAVE_STDLIB_H | |
7 | #include <stdlib.h> | |
8 | #endif | |
9 | ||
10 | #ifdef HAVE_STRING_H | |
11 | #include <string.h> | |
12 | #else | |
13 | #ifdef HAVE_STRINGS_H | |
14 | #include <strings.h> | |
15 | #endif | |
16 | #endif | |
17 | ||
22c1c7dd | 18 | #include "bfd.h" |
22c1c7dd | 19 | |
9cdd2c6d AC |
20 | |
21 | /* For compatibility */ | |
22 | SIM_DESC simulator; | |
22c1c7dd | 23 | |
1ad886c9 DE |
24 | enum interrupt_type |
25 | { | |
26 | int_none, | |
27 | int_reset, | |
28 | int_nmi, | |
29 | int_intov1, | |
30 | int_intp10, | |
31 | int_intp11, | |
32 | int_intp12, | |
33 | int_intp13, | |
34 | int_intcm4, | |
35 | num_int_types | |
36 | }; | |
37 | ||
38 | enum interrupt_cond_type | |
39 | { | |
40 | int_cond_none, | |
41 | int_cond_pc, | |
42 | int_cond_time | |
43 | }; | |
44 | ||
45 | struct interrupt_generator | |
46 | { | |
47 | enum interrupt_type type; | |
48 | enum interrupt_cond_type cond_type; | |
49 | int number; | |
50 | int address; | |
51 | int time; | |
52 | int enabled; | |
53 | struct interrupt_generator *next; | |
54 | }; | |
55 | ||
56 | char *interrupt_names[] = { | |
57 | "", | |
58 | "reset", | |
59 | "nmi", | |
60 | "intov1", | |
61 | "intp10", | |
62 | "intp11", | |
63 | "intp12", | |
64 | "intp13", | |
65 | "intcm4", | |
66 | NULL | |
67 | }; | |
68 | ||
69 | struct interrupt_generator *intgen_list; | |
70 | ||
71 | /* True if a non-maskable (such as NMI or reset) interrupt generator | |
72 | is present. */ | |
73 | ||
74 | static int have_nm_generator; | |
75 | ||
9909e232 JL |
76 | #ifndef INLINE |
77 | #ifdef __GNUC__ | |
78 | #define INLINE inline | |
79 | #else | |
80 | #define INLINE | |
81 | #endif | |
82 | #endif | |
83 | ||
1ad886c9 DE |
84 | /* These default values correspond to expected usage for the chip. */ |
85 | ||
ead4a3f1 | 86 | int v850_debug; |
d81352b8 | 87 | |
d81352b8 | 88 | uint32 OP[4]; |
22c1c7dd | 89 | |
9cdd2c6d | 90 | static struct hash_entry *lookup_hash PARAMS ((SIM_DESC sd, uint32 ins)); |
9909e232 | 91 | static long hash PARAMS ((long)); |
9cdd2c6d | 92 | #if 0 |
9909e232 JL |
93 | static void do_format_1_2 PARAMS ((uint32)); |
94 | static void do_format_3 PARAMS ((uint32)); | |
95 | static void do_format_4 PARAMS ((uint32)); | |
96 | static void do_format_5 PARAMS ((uint32)); | |
97 | static void do_format_6 PARAMS ((uint32)); | |
98 | static void do_format_7 PARAMS ((uint32)); | |
99 | static void do_format_8 PARAMS ((uint32)); | |
100 | static void do_format_9_10 PARAMS ((uint32)); | |
9cdd2c6d | 101 | #endif |
22c1c7dd JL |
102 | |
103 | #define MAX_HASH 63 | |
1ad886c9 | 104 | |
22c1c7dd JL |
105 | struct hash_entry |
106 | { | |
107 | struct hash_entry *next; | |
108 | long opcode; | |
109 | long mask; | |
110 | struct simops *ops; | |
111 | }; | |
112 | ||
113 | struct hash_entry hash_table[MAX_HASH+1]; | |
114 | ||
9909e232 JL |
115 | |
116 | static INLINE long | |
22c1c7dd JL |
117 | hash(insn) |
118 | long insn; | |
119 | { | |
247fccde | 120 | if ( (insn & 0x0600) == 0 |
9909e232 JL |
121 | || (insn & 0x0700) == 0x0200 |
122 | || (insn & 0x0700) == 0x0600 | |
123 | || (insn & 0x0780) == 0x0700) | |
0ef0eba5 | 124 | return (insn & 0x07e0) >> 5; |
1ad886c9 | 125 | |
83fc3bac JL |
126 | if ((insn & 0x0700) == 0x0300 |
127 | || (insn & 0x0700) == 0x0400 | |
128 | || (insn & 0x0700) == 0x0500) | |
129 | return (insn & 0x0780) >> 7; | |
1ad886c9 | 130 | |
83fc3bac | 131 | if ((insn & 0x07c0) == 0x0780) |
0ef0eba5 | 132 | return (insn & 0x07c0) >> 6; |
1ad886c9 | 133 | |
83fc3bac | 134 | return (insn & 0x07e0) >> 5; |
22c1c7dd JL |
135 | } |
136 | ||
137 | static struct hash_entry * | |
9cdd2c6d AC |
138 | lookup_hash (sd, ins) |
139 | SIM_DESC sd; | |
22c1c7dd JL |
140 | uint32 ins; |
141 | { | |
142 | struct hash_entry *h; | |
143 | ||
0ef0eba5 | 144 | h = &hash_table[hash(ins)]; |
22c1c7dd | 145 | |
9909e232 | 146 | while ((ins & h->mask) != h->opcode) |
22c1c7dd JL |
147 | { |
148 | if (h->next == NULL) | |
149 | { | |
9cdd2c6d AC |
150 | sim_io_error (sd, "ERROR looking up hash for 0x%lx, PC=0x%lx", |
151 | (long) ins, (long) PC); | |
22c1c7dd JL |
152 | } |
153 | h = h->next; | |
154 | } | |
155 | return (h); | |
156 | } | |
157 | ||
1ad886c9 DE |
158 | /* FIXME These would more efficient to use than load_mem/store_mem, |
159 | but need to be changed to use the memory map. */ | |
160 | ||
28647e4c JL |
161 | uint8 |
162 | get_byte (x) | |
163 | uint8 *x; | |
22c1c7dd | 164 | { |
28647e4c | 165 | return *x; |
0ef0eba5 JL |
166 | } |
167 | ||
28647e4c JL |
168 | uint16 |
169 | get_half (x) | |
170 | uint8 *x; | |
0ef0eba5 JL |
171 | { |
172 | uint8 *a = x; | |
28647e4c | 173 | return (a[1] << 8) + (a[0]); |
22c1c7dd JL |
174 | } |
175 | ||
28647e4c | 176 | uint32 |
0ef0eba5 JL |
177 | get_word (x) |
178 | uint8 *x; | |
22c1c7dd | 179 | { |
0ef0eba5 | 180 | uint8 *a = x; |
28647e4c | 181 | return (a[3]<<24) + (a[2]<<16) + (a[1]<<8) + (a[0]); |
22c1c7dd JL |
182 | } |
183 | ||
184 | void | |
28647e4c | 185 | put_byte (addr, data) |
0ef0eba5 | 186 | uint8 *addr; |
28647e4c | 187 | uint8 data; |
22c1c7dd | 188 | { |
0ef0eba5 | 189 | uint8 *a = addr; |
28647e4c | 190 | a[0] = data; |
22c1c7dd JL |
191 | } |
192 | ||
0ef0eba5 | 193 | void |
28647e4c | 194 | put_half (addr, data) |
0ef0eba5 | 195 | uint8 *addr; |
28647e4c | 196 | uint16 data; |
0ef0eba5 | 197 | { |
28647e4c JL |
198 | uint8 *a = addr; |
199 | a[0] = data & 0xff; | |
200 | a[1] = (data >> 8) & 0xff; | |
0ef0eba5 JL |
201 | } |
202 | ||
203 | void | |
28647e4c | 204 | put_word (addr, data) |
0ef0eba5 | 205 | uint8 *addr; |
28647e4c | 206 | uint32 data; |
0ef0eba5 JL |
207 | { |
208 | uint8 *a = addr; | |
28647e4c JL |
209 | a[0] = data & 0xff; |
210 | a[1] = (data >> 8) & 0xff; | |
211 | a[2] = (data >> 16) & 0xff; | |
212 | a[3] = (data >> 24) & 0xff; | |
22c1c7dd JL |
213 | } |
214 | ||
1ad886c9 DE |
215 | uint8 * |
216 | map (addr) | |
217 | SIM_ADDR addr; | |
218 | { | |
1ad886c9 DE |
219 | /* Mask down to 24 bits. */ |
220 | addr &= 0xffffff; | |
221 | ||
9cdd2c6d | 222 | if (addr < 0x100000) |
1ad886c9 DE |
223 | { |
224 | /* "Mirror" the addresses below 1MB. */ | |
9cdd2c6d AC |
225 | addr = addr & (simulator->rom_size - 1); |
226 | return (uint8 *) (addr + STATE_MEMORY (simulator)); | |
1ad886c9 | 227 | } |
9cdd2c6d AC |
228 | else if (addr < simulator->low_end) |
229 | { | |
230 | /* chunk is just after the rom */ | |
231 | addr = addr - 0x100000 + simulator->rom_size; | |
232 | return (uint8 *) (addr + STATE_MEMORY (simulator)); | |
233 | } | |
234 | else if (addr >= simulator->high_start) | |
1ad886c9 DE |
235 | { |
236 | /* If in the peripheral I/O region, mirror 1K region across 4K, | |
237 | and similarly if in the internal RAM region. */ | |
238 | if (addr >= 0xfff000) | |
239 | addr &= 0xfff3ff; | |
240 | else if (addr >= 0xffe000) | |
241 | addr &= 0xffe3ff; | |
9cdd2c6d AC |
242 | addr = addr - simulator->high_start + simulator->high_base; |
243 | return (uint8 *) (STATE_MEMORY (simulator)); | |
1ad886c9 DE |
244 | } |
245 | else | |
246 | { | |
9cdd2c6d AC |
247 | sim_io_eprintf (simulator, "segmentation fault: access address: %lx not below %lx or above %lx [ep = %lx]\n", |
248 | (long) addr, | |
249 | (long) simulator->low_end, | |
250 | (long) simulator->high_start, | |
251 | State.regs[30]); | |
247fccde | 252 | |
1ad886c9 DE |
253 | /* Signal a memory error. */ |
254 | State.exception = SIGSEGV; | |
255 | /* Point to a location not in main memory - renders invalid | |
256 | addresses harmless until we get back to main insn loop. */ | |
257 | return (uint8 *) &(State.dummy_mem); | |
258 | } | |
259 | } | |
260 | ||
261 | uint32 | |
262 | load_mem (addr, len) | |
263 | SIM_ADDR addr; | |
264 | int len; | |
265 | { | |
266 | uint8 *p = map (addr); | |
267 | ||
268 | switch (len) | |
269 | { | |
270 | case 1: | |
271 | return p[0]; | |
272 | case 2: | |
273 | return p[1] << 8 | p[0]; | |
274 | case 4: | |
275 | return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; | |
276 | default: | |
277 | abort (); | |
278 | } | |
279 | } | |
280 | ||
281 | void | |
282 | store_mem (addr, len, data) | |
283 | SIM_ADDR addr; | |
284 | int len; | |
285 | uint32 data; | |
286 | { | |
287 | uint8 *p = map (addr); | |
288 | ||
289 | switch (len) | |
290 | { | |
291 | case 1: | |
292 | p[0] = data; | |
293 | return; | |
294 | case 2: | |
295 | p[0] = data; | |
296 | p[1] = data >> 8; | |
297 | return; | |
298 | case 4: | |
299 | p[0] = data; | |
300 | p[1] = data >> 8; | |
301 | p[2] = data >> 16; | |
302 | p[3] = data >> 24; | |
303 | return; | |
304 | default: | |
305 | abort (); | |
306 | } | |
307 | } | |
308 | ||
9cdd2c6d AC |
309 | static void |
310 | sim_memory_init (SIM_DESC sd) | |
22c1c7dd | 311 | { |
1ad886c9 DE |
312 | int totsize; |
313 | ||
9cdd2c6d AC |
314 | if (STATE_MEMORY (sd)) |
315 | zfree (STATE_MEMORY (sd)); | |
316 | ||
317 | totsize = (simulator->rom_size | |
318 | + (sd->low_end - 0x100000) | |
319 | + (0x1000000 - sd->high_start)); | |
320 | ||
321 | sd->high_base = sd->rom_size + (sd->low_end - 0x100000); | |
322 | ||
323 | STATE_MEMORY (sd) = zalloc (totsize); | |
324 | if (!STATE_MEMORY (sd)) | |
22c1c7dd | 325 | { |
9cdd2c6d | 326 | sim_io_error (sd, "Allocation of main memory failed."); |
22c1c7dd | 327 | } |
1ad886c9 | 328 | } |
22c1c7dd | 329 | |
9cdd2c6d AC |
330 | static int |
331 | sim_parse_number (str, rest) | |
332 | char *str, **rest; | |
333 | { | |
334 | if (str[0] == '0' && str[1] == 'x') | |
335 | return strtoul (str, rest, 16); | |
336 | else if (str[0] == '0') | |
337 | return strtoul (str, rest, 16); | |
338 | else | |
339 | return strtoul (str, rest, 10); | |
340 | } | |
341 | ||
342 | static void | |
343 | sim_set_memory_map (sd, spec) | |
344 | SIM_DESC sd; | |
1ad886c9 DE |
345 | char *spec; |
346 | { | |
347 | char *reststr, *nreststr; | |
348 | SIM_ADDR new_low_end, new_high_start; | |
349 | ||
9cdd2c6d AC |
350 | new_low_end = sd->low_end; |
351 | new_high_start = sd->high_start; | |
1ad886c9 | 352 | if (! strncmp (spec, "hole=", 5)) |
22c1c7dd | 353 | { |
1ad886c9 DE |
354 | new_low_end = sim_parse_number (spec + 5, &reststr); |
355 | if (new_low_end < 0x100000) | |
356 | { | |
9cdd2c6d | 357 | sim_io_printf (sd, "Low end must be at least 0x100000\n"); |
1ad886c9 DE |
358 | return; |
359 | } | |
360 | if (*reststr == ',') | |
361 | { | |
362 | ++reststr; | |
363 | new_high_start = sim_parse_number (reststr, &nreststr); | |
364 | /* FIXME Check high_start also */ | |
365 | } | |
9cdd2c6d AC |
366 | sim_io_printf (sd, "Hole goes from 0x%x to 0x%x\n", |
367 | new_low_end, new_high_start); | |
1ad886c9 DE |
368 | } |
369 | else | |
370 | { | |
9cdd2c6d | 371 | sim_io_printf (sd, "Invalid specification for memory map, must be `hole=<m>[,<n>]'\n"); |
1ad886c9 DE |
372 | } |
373 | ||
9cdd2c6d | 374 | if (new_low_end != sd->low_end || new_high_start != sd->high_start) |
1ad886c9 | 375 | { |
9cdd2c6d AC |
376 | sd->low_end = new_low_end; |
377 | sd->high_start = new_high_start; | |
378 | sim_io_printf (sd, "Reconfiguring memory (old contents will be lost)\n"); | |
379 | sim_memory_init (sd); | |
22c1c7dd | 380 | } |
22c1c7dd JL |
381 | } |
382 | ||
1ad886c9 DE |
383 | /* Parse a number in hex, octal, or decimal form. */ |
384 | ||
22c1c7dd | 385 | int |
1ad886c9 DE |
386 | sim_write (sd, addr, buffer, size) |
387 | SIM_DESC sd; | |
22c1c7dd JL |
388 | SIM_ADDR addr; |
389 | unsigned char *buffer; | |
390 | int size; | |
391 | { | |
392 | int i; | |
1ad886c9 | 393 | |
22c1c7dd | 394 | for (i = 0; i < size; i++) |
1ad886c9 DE |
395 | store_mem (addr + i, 1, buffer[i]); |
396 | ||
22c1c7dd JL |
397 | return size; |
398 | } | |
399 | ||
9cdd2c6d | 400 | |
1ad886c9 | 401 | SIM_DESC |
247fccde | 402 | sim_open (kind, cb, abfd, argv) |
1ad886c9 | 403 | SIM_OPEN_KIND kind; |
247fccde AC |
404 | host_callback *cb; |
405 | struct _bfd *abfd; | |
1ad886c9 | 406 | char **argv; |
22c1c7dd | 407 | { |
9cdd2c6d | 408 | SIM_DESC sd = sim_state_alloc (kind, cb); |
22c1c7dd | 409 | struct simops *s; |
9909e232 | 410 | struct hash_entry *h; |
1ad886c9 | 411 | |
9cdd2c6d AC |
412 | /* for compatibility */ |
413 | simulator = sd; | |
1ad886c9 | 414 | |
9cdd2c6d AC |
415 | sd->rom_size = V850_ROM_SIZE; |
416 | sd->low_end = V850_LOW_END; | |
417 | sd->high_start = V850_HIGH_START; | |
418 | ||
419 | /* Allocate memory */ | |
420 | sim_memory_init (sd); | |
421 | ||
422 | if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) | |
423 | return 0; | |
424 | ||
425 | /* getopt will print the error message so we just have to exit if this fails. | |
426 | FIXME: Hmmm... in the case of gdb we need getopt to call | |
427 | print_filtered. */ | |
428 | if (sim_parse_args (sd, argv) != SIM_RC_OK) | |
ead4a3f1 | 429 | { |
9cdd2c6d AC |
430 | /* Uninstall the modules to avoid memory leaks, |
431 | file descriptor leaks, etc. */ | |
432 | sim_module_uninstall (sd); | |
433 | return 0; | |
434 | } | |
435 | ||
436 | /* check for/establish the a reference program image */ | |
437 | if (sim_analyze_program (sd, | |
438 | (STATE_PROG_ARGV (sd) != NULL | |
439 | ? *STATE_PROG_ARGV (sd) | |
440 | : NULL), | |
441 | abfd) != SIM_RC_OK) | |
442 | { | |
443 | sim_module_uninstall (sd); | |
444 | return 0; | |
445 | } | |
446 | ||
447 | /* establish any remaining configuration options */ | |
448 | if (sim_config (sd) != SIM_RC_OK) | |
449 | { | |
450 | sim_module_uninstall (sd); | |
451 | return 0; | |
452 | } | |
453 | ||
454 | if (sim_post_argv_init (sd) != SIM_RC_OK) | |
455 | { | |
456 | /* Uninstall the modules to avoid memory leaks, | |
457 | file descriptor leaks, etc. */ | |
458 | sim_module_uninstall (sd); | |
459 | return 0; | |
ead4a3f1 | 460 | } |
22c1c7dd JL |
461 | |
462 | /* put all the opcodes in the hash table */ | |
463 | for (s = Simops; s->func; s++) | |
464 | { | |
465 | h = &hash_table[hash(s->opcode)]; | |
466 | ||
467 | /* go to the last entry in the chain */ | |
468 | while (h->next) | |
469 | h = h->next; | |
470 | ||
471 | if (h->ops) | |
472 | { | |
1ad886c9 | 473 | h->next = (struct hash_entry *) calloc(1,sizeof(struct hash_entry)); |
22c1c7dd JL |
474 | h = h->next; |
475 | } | |
476 | h->ops = s; | |
477 | h->mask = s->mask; | |
478 | h->opcode = s->opcode; | |
479 | } | |
1ad886c9 | 480 | |
9cdd2c6d | 481 | return sd; |
22c1c7dd JL |
482 | } |
483 | ||
484 | ||
485 | void | |
1ad886c9 DE |
486 | sim_close (sd, quitting) |
487 | SIM_DESC sd; | |
22c1c7dd JL |
488 | int quitting; |
489 | { | |
9cdd2c6d | 490 | sim_module_uninstall (sd); |
22c1c7dd JL |
491 | } |
492 | ||
9cdd2c6d | 493 | static void do_interrupt PARAMS ((SIM_DESC sd, enum interrupt_type)); |
1ad886c9 | 494 | |
8517f62b AC |
495 | int |
496 | sim_stop (sd) | |
497 | SIM_DESC sd; | |
498 | { | |
499 | return 0; | |
500 | } | |
501 | ||
22c1c7dd | 502 | void |
1ad886c9 DE |
503 | sim_resume (sd, step, siggnal) |
504 | SIM_DESC sd; | |
22c1c7dd JL |
505 | int step, siggnal; |
506 | { | |
9cdd2c6d AC |
507 | SIM_ELAPSED_TIME start_time; |
508 | uint32 inst; | |
22c1c7dd | 509 | reg_t oldpc; |
1ad886c9 | 510 | struct interrupt_generator *intgen; |
22c1c7dd | 511 | |
1ad886c9 DE |
512 | if (step) |
513 | State.exception = SIGTRAP; | |
514 | else | |
515 | State.exception = 0; | |
88777ce2 | 516 | |
9cdd2c6d AC |
517 | |
518 | start_time = sim_elapsed_time_get (); | |
1ad886c9 DE |
519 | |
520 | do | |
521 | { | |
247fccde | 522 | struct hash_entry * h; |
1ad886c9 | 523 | /* Fetch the current instruction. */ |
247fccde | 524 | inst = RLW (PC); |
1ad886c9 | 525 | oldpc = PC; |
1ad886c9 | 526 | |
9cdd2c6d | 527 | h = lookup_hash (sd, inst); |
247fccde AC |
528 | OP[0] = inst & 0x1f; |
529 | OP[1] = (inst >> 11) & 0x1f; | |
530 | OP[2] = (inst >> 16) & 0xffff; | |
531 | OP[3] = inst; | |
532 | ||
9cdd2c6d | 533 | /* fprintf (stderr, "PC = %x, SP = %x\n", PC, SP ); */ |
247fccde AC |
534 | |
535 | if (inst == 0) | |
1ad886c9 | 536 | { |
247fccde AC |
537 | fprintf (stderr, "NOP encountered!\n"); |
538 | break; | |
1ad886c9 | 539 | } |
247fccde AC |
540 | |
541 | PC += h->ops->func (); | |
542 | ||
543 | if (oldpc == PC) | |
1ad886c9 | 544 | { |
9cdd2c6d | 545 | sim_io_eprintf (sd, "simulator loop at %lx\n", (long) PC ); |
247fccde | 546 | break; |
1ad886c9 | 547 | } |
247fccde | 548 | |
1ad886c9 DE |
549 | /* Check for and handle pending interrupts. */ |
550 | if (intgen_list && (have_nm_generator || !(PSW & PSW_ID))) | |
551 | { | |
552 | intgen = NULL; | |
553 | for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) | |
554 | { | |
555 | if (intgen->cond_type == int_cond_pc | |
556 | && oldpc == intgen->address | |
557 | && intgen->enabled) | |
558 | { | |
559 | break; | |
560 | } | |
561 | else if (intgen->cond_type == int_cond_time | |
562 | && intgen->enabled) | |
563 | { | |
9cdd2c6d AC |
564 | SIM_ELAPSED_TIME delta; |
565 | delta = sim_elapsed_time_since (start_time); | |
566 | if (delta > intgen->time) | |
1ad886c9 DE |
567 | { |
568 | intgen->enabled = 0; | |
569 | break; | |
570 | } | |
571 | } | |
572 | } | |
573 | if (intgen) | |
9cdd2c6d | 574 | do_interrupt (sd, intgen->type); |
1ad886c9 DE |
575 | } |
576 | else if (State.pending_nmi) | |
577 | { | |
578 | State.pending_nmi = 0; | |
9cdd2c6d | 579 | do_interrupt (sd, int_nmi); |
1ad886c9 DE |
580 | } |
581 | } | |
582 | while (!State.exception); | |
583 | } | |
584 | ||
585 | static void | |
9cdd2c6d AC |
586 | do_interrupt (sd, inttype) |
587 | SIM_DESC sd; | |
1ad886c9 DE |
588 | enum interrupt_type inttype; |
589 | { | |
590 | /* Disable further interrupts. */ | |
591 | PSW |= PSW_ID; | |
592 | /* Indicate that we're doing interrupt not exception processing. */ | |
593 | PSW &= ~PSW_EP; | |
594 | if (inttype == int_reset) | |
595 | { | |
596 | PC = 0; | |
597 | PSW = 0x20; | |
598 | ECR = 0; | |
599 | /* (Might be useful to init other regs with random values.) */ | |
600 | } | |
601 | else if (inttype == int_nmi) | |
602 | { | |
603 | if (PSW & PSW_NP) | |
604 | { | |
605 | /* We're already working on an NMI, so this one must wait | |
606 | around until the previous one is done. The processor | |
607 | ignores subsequent NMIs, so we don't need to count them. */ | |
608 | State.pending_nmi = 1; | |
609 | } | |
610 | else | |
611 | { | |
612 | FEPC = PC; | |
613 | FEPSW = PSW; | |
614 | /* Set the FECC part of the ECR. */ | |
615 | ECR &= 0x0000ffff; | |
616 | ECR |= 0x10; | |
617 | PSW |= PSW_NP; | |
618 | PC = 0x10; | |
619 | } | |
620 | } | |
621 | else | |
622 | { | |
623 | EIPC = PC; | |
624 | EIPSW = PSW; | |
625 | /* Clear the EICC part of the ECR, will set below. */ | |
626 | ECR &= 0xffff0000; | |
627 | switch (inttype) | |
628 | { | |
629 | case int_intov1: | |
630 | PC = 0x80; | |
631 | ECR |= 0x80; | |
632 | break; | |
633 | case int_intp10: | |
634 | PC = 0x90; | |
635 | ECR |= 0x90; | |
636 | break; | |
637 | case int_intp11: | |
638 | PC = 0xa0; | |
639 | ECR |= 0xa0; | |
640 | break; | |
641 | case int_intp12: | |
642 | PC = 0xb0; | |
643 | ECR |= 0xb0; | |
644 | break; | |
645 | case int_intp13: | |
646 | PC = 0xc0; | |
647 | ECR |= 0xc0; | |
648 | break; | |
649 | case int_intcm4: | |
650 | PC = 0xd0; | |
651 | ECR |= 0xd0; | |
652 | break; | |
653 | default: | |
654 | /* Should never be possible. */ | |
655 | abort (); | |
656 | break; | |
657 | } | |
658 | } | |
22c1c7dd JL |
659 | } |
660 | ||
661 | int | |
1ad886c9 DE |
662 | sim_trace (sd) |
663 | SIM_DESC sd; | |
22c1c7dd | 664 | { |
ead4a3f1 MM |
665 | #ifdef DEBUG |
666 | v850_debug = DEBUG; | |
667 | #endif | |
1ad886c9 | 668 | sim_resume (sd, 0, 0); |
ead4a3f1 | 669 | return 1; |
22c1c7dd JL |
670 | } |
671 | ||
672 | void | |
1ad886c9 DE |
673 | sim_info (sd, verbose) |
674 | SIM_DESC sd; | |
22c1c7dd JL |
675 | int verbose; |
676 | { | |
9cdd2c6d | 677 | sim_io_printf (sd, "sim_info\n"); |
22c1c7dd JL |
678 | } |
679 | ||
1ad886c9 | 680 | SIM_RC |
9cdd2c6d | 681 | sim_create_inferior (sd, prog_bfd, argv, env) |
1ad886c9 | 682 | SIM_DESC sd; |
9cdd2c6d | 683 | struct _bfd *prog_bfd; |
22c1c7dd JL |
684 | char **argv; |
685 | char **env; | |
686 | { | |
9cdd2c6d AC |
687 | memset (&State, 0, sizeof (State)); |
688 | if (prog_bfd != NULL) | |
fafce69a | 689 | PC = bfd_get_start_address (prog_bfd); |
1ad886c9 | 690 | return SIM_RC_OK; |
22c1c7dd JL |
691 | } |
692 | ||
2b6b2c6d | 693 | /* All the code for exiting, signals, etc needs to be revamped. |
d81352b8 JL |
694 | |
695 | This is enough to get c-torture limping though. */ | |
1ad886c9 | 696 | |
22c1c7dd | 697 | void |
1ad886c9 DE |
698 | sim_stop_reason (sd, reason, sigrc) |
699 | SIM_DESC sd; | |
22c1c7dd JL |
700 | enum sim_stop *reason; |
701 | int *sigrc; | |
702 | { | |
1ad886c9 DE |
703 | if (State.exception == SIG_V850_EXIT) |
704 | { | |
705 | *reason = sim_exited; | |
706 | *sigrc = State.regs[7]; | |
707 | } | |
22c1c7dd | 708 | else |
1ad886c9 DE |
709 | { |
710 | *reason = sim_stopped; | |
711 | *sigrc = State.exception; | |
712 | } | |
22c1c7dd JL |
713 | } |
714 | ||
715 | void | |
1ad886c9 DE |
716 | sim_fetch_register (sd, rn, memory) |
717 | SIM_DESC sd; | |
22c1c7dd JL |
718 | int rn; |
719 | unsigned char *memory; | |
720 | { | |
88777ce2 | 721 | put_word (memory, State.regs[rn]); |
22c1c7dd JL |
722 | } |
723 | ||
724 | void | |
1ad886c9 DE |
725 | sim_store_register (sd, rn, memory) |
726 | SIM_DESC sd; | |
22c1c7dd JL |
727 | int rn; |
728 | unsigned char *memory; | |
729 | { | |
88777ce2 | 730 | State.regs[rn] = get_word (memory); |
22c1c7dd JL |
731 | } |
732 | ||
9909e232 | 733 | int |
1ad886c9 DE |
734 | sim_read (sd, addr, buffer, size) |
735 | SIM_DESC sd; | |
22c1c7dd JL |
736 | SIM_ADDR addr; |
737 | unsigned char *buffer; | |
738 | int size; | |
739 | { | |
740 | int i; | |
741 | for (i = 0; i < size; i++) | |
1ad886c9 DE |
742 | buffer[i] = load_mem (addr + i, 1); |
743 | ||
22c1c7dd JL |
744 | return size; |
745 | } | |
746 | ||
1ad886c9 DE |
747 | int current_intgen_number = 1; |
748 | ||
9cdd2c6d AC |
749 | static void |
750 | sim_set_interrupt (sd, spec) | |
751 | SIM_DESC sd; | |
1ad886c9 DE |
752 | char *spec; |
753 | { | |
754 | int i, num; | |
755 | char **argv; | |
756 | struct interrupt_generator *intgen, *tmpgen; | |
757 | extern char **buildargv (); | |
758 | ||
759 | argv = buildargv (spec); | |
760 | ||
761 | if (*argv && ! strcmp (*argv, "add")) | |
762 | { | |
763 | /* Create a new interrupt generator object. */ | |
764 | intgen = (struct interrupt_generator *) | |
765 | malloc (sizeof(struct interrupt_generator)); | |
766 | intgen->type = int_none; | |
767 | intgen->cond_type = int_cond_none; | |
768 | intgen->address = 0; | |
769 | intgen->time = 0; | |
770 | intgen->enabled = 0; | |
771 | ++argv; | |
772 | /* Match on interrupt type name. */ | |
773 | for (i = 0; i < num_int_types; ++i) | |
774 | { | |
775 | if (*argv && ! strcmp (*argv, interrupt_names[i])) | |
776 | { | |
777 | intgen->type = i; | |
778 | break; | |
779 | } | |
780 | } | |
781 | if (intgen->type == int_none) | |
782 | { | |
9cdd2c6d | 783 | sim_io_printf (sd, "Interrupt type unknown; known types are\n"); |
1ad886c9 DE |
784 | for (i = 0; i < num_int_types; ++i) |
785 | { | |
9cdd2c6d | 786 | sim_io_printf (sd, " %s", interrupt_names[i]); |
1ad886c9 | 787 | } |
9cdd2c6d | 788 | sim_io_printf (sd, "\n"); |
1ad886c9 DE |
789 | free (intgen); |
790 | return; | |
791 | } | |
792 | ++argv; | |
793 | intgen->address = 0; | |
794 | intgen->time = 0; | |
795 | if (*argv && ! strcmp (*argv, "pc")) | |
796 | { | |
797 | intgen->cond_type = int_cond_pc; | |
798 | ++argv; | |
799 | intgen->address = sim_parse_number (*argv, NULL); | |
800 | } | |
801 | else if (*argv && ! strcmp (*argv, "time")) | |
802 | { | |
803 | intgen->cond_type = int_cond_time; | |
804 | ++argv; | |
805 | intgen->time = sim_parse_number (*argv, NULL); | |
806 | } | |
807 | else | |
808 | { | |
9cdd2c6d | 809 | sim_io_printf (sd, "Condition type must be `pc' or `time'.\n"); |
1ad886c9 DE |
810 | free (intgen); |
811 | return; | |
812 | } | |
813 | /* We now have a valid interrupt generator. Number it and add | |
814 | to the list of generators. */ | |
815 | intgen->number = current_intgen_number++; | |
816 | intgen->enabled = 1; | |
817 | intgen->next = intgen_list; | |
818 | intgen_list = intgen; | |
9cdd2c6d | 819 | sim_io_printf (sd, "Interrupt generator %d (NMI) at pc=0x%x, time=%d.\n", intgen_list->number, intgen_list->address, intgen_list->time); |
1ad886c9 DE |
820 | } |
821 | else if (*argv && !strcmp (*argv, "remove")) | |
822 | { | |
823 | ++argv; | |
824 | num = sim_parse_number (*argv, NULL); | |
825 | tmpgen = NULL; | |
826 | if (intgen_list) | |
827 | { | |
828 | if (intgen_list->number == num) | |
829 | { | |
830 | tmpgen = intgen_list; | |
831 | intgen_list = intgen_list->next; | |
832 | } | |
833 | else | |
834 | { | |
835 | for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) | |
836 | { | |
837 | if (intgen->next != NULL && intgen->next->number == num) | |
838 | { | |
839 | tmpgen = intgen->next; | |
840 | intgen->next = intgen->next->next; | |
841 | break; | |
842 | } | |
843 | } | |
844 | } | |
845 | if (tmpgen) | |
846 | free (tmpgen); | |
847 | else | |
9cdd2c6d | 848 | sim_io_printf (sd, "No interrupt generator numbered %d, ignoring.\n", num); |
1ad886c9 DE |
849 | } |
850 | } | |
851 | else if (*argv && !strcmp (*argv, "info")) | |
852 | { | |
853 | if (intgen_list) | |
854 | { | |
855 | for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) | |
9cdd2c6d AC |
856 | sim_io_printf (sd, "Interrupt generator %d (%s) at pc=0x%x/time=%d%s.\n", |
857 | intgen->number, | |
858 | interrupt_names[intgen->type], | |
859 | intgen->address, | |
860 | intgen->time, | |
861 | (intgen->enabled ? "" : " (disabled)")); | |
1ad886c9 DE |
862 | } |
863 | else | |
864 | { | |
9cdd2c6d | 865 | sim_io_printf (sd, "No interrupt generators defined.\n"); |
1ad886c9 DE |
866 | } |
867 | ||
868 | } | |
869 | else | |
870 | { | |
9cdd2c6d | 871 | sim_io_printf (sd, "Invalid interrupt command, must be one of `add', `remove', or `info'.\n"); |
1ad886c9 DE |
872 | } |
873 | /* Cache the presence of a non-maskable generator. */ | |
874 | have_nm_generator = 0; | |
875 | for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) | |
876 | { | |
877 | if (intgen->type == int_nmi || intgen->type == int_reset) | |
878 | { | |
879 | have_nm_generator = 1; | |
880 | break; | |
881 | } | |
882 | } | |
883 | } | |
884 | ||
885 | void | |
886 | sim_do_command (sd, cmd) | |
887 | SIM_DESC sd; | |
22c1c7dd | 888 | char *cmd; |
1ad886c9 DE |
889 | { |
890 | char *mm_cmd = "memory-map"; | |
891 | char *int_cmd = "interrupt"; | |
892 | ||
893 | if (! strncmp (cmd, mm_cmd, strlen (mm_cmd)) | |
894 | && strchr (" ", cmd[strlen(mm_cmd)])) | |
9cdd2c6d | 895 | sim_set_memory_map (sd, cmd + strlen(mm_cmd) + 1); |
1ad886c9 DE |
896 | |
897 | else if (! strncmp (cmd, int_cmd, strlen (int_cmd)) | |
898 | && strchr (" ", cmd[strlen(int_cmd)])) | |
9cdd2c6d | 899 | sim_set_interrupt (sd, cmd + strlen(int_cmd) + 1); |
1ad886c9 DE |
900 | |
901 | else if (! strcmp (cmd, "help")) | |
902 | { | |
9cdd2c6d AC |
903 | sim_io_printf (sd, "V850 simulator commands:\n\n"); |
904 | sim_io_printf (sd, "interrupt add <inttype> { pc | time } <value> -- Set up an interrupt generator\n"); | |
905 | sim_io_printf (sd, "interrupt remove <n> -- Remove an existing interrupt generator\n"); | |
906 | sim_io_printf (sd, "interrupt info -- List all the interrupt generators\n"); | |
907 | sim_io_printf (sd, "memory-map hole=<m>,<n> -- Set the memory map to have a hole between <m> and <n>\n"); | |
908 | sim_io_printf (sd, "\n"); | |
1ad886c9 DE |
909 | } |
910 | else | |
9cdd2c6d | 911 | sim_io_printf (sd, "\"%s\" is not a valid V850 simulator command.\n", |
1ad886c9 | 912 | cmd); |
22c1c7dd | 913 | } |