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