Commit | Line | Data |
---|---|---|
d70b4d42 | 1 | #include <signal.h> |
2934d1c9 MH |
2 | #include "sysdep.h" |
3 | #include "bfd.h" | |
4 | #include "remote-sim.h" | |
2934d1c9 MH |
5 | |
6 | #include "d10v_sim.h" | |
7 | ||
8 | #define IMEM_SIZE 18 /* D10V instruction memory size is 18 bits */ | |
9 | #define DMEM_SIZE 16 /* Data memory */ | |
10 | ||
87178dbd MM |
11 | enum _leftright { LEFT_FIRST, RIGHT_FIRST }; |
12 | ||
7eebfc62 | 13 | int d10v_debug; |
87178dbd | 14 | host_callback *d10v_callback; |
7eebfc62 MM |
15 | long ins_type_counters[ (int)INS_MAX ]; |
16 | long left_nops, right_nops; | |
87178dbd | 17 | |
2934d1c9 MH |
18 | uint16 OP[4]; |
19 | ||
20 | static struct hash_entry *lookup_hash PARAMS ((uint32 ins, int size)); | |
21 | ||
22 | #define MAX_HASH 63 | |
23 | struct hash_entry | |
24 | { | |
25 | struct hash_entry *next; | |
26 | long opcode; | |
27 | long mask; | |
28 | struct simops *ops; | |
29 | }; | |
30 | ||
31 | struct hash_entry hash_table[MAX_HASH+1]; | |
32 | ||
33 | static long | |
34 | hash(insn, format) | |
35 | long insn; | |
36 | int format; | |
37 | { | |
38 | if (format & LONG_OPCODE) | |
39 | return ((insn & 0x3F000000) >> 24); | |
40 | else | |
41 | return((insn & 0x7E00) >> 9); | |
42 | } | |
43 | ||
44 | static struct hash_entry * | |
45 | lookup_hash (ins, size) | |
46 | uint32 ins; | |
47 | int size; | |
48 | { | |
49 | struct hash_entry *h; | |
50 | ||
51 | if (size) | |
52 | h = &hash_table[(ins & 0x3F000000) >> 24]; | |
53 | else | |
54 | h = &hash_table[(ins & 0x7E00) >> 9]; | |
55 | ||
56 | while ( (ins & h->mask) != h->opcode) | |
57 | { | |
58 | if (h->next == NULL) | |
59 | { | |
7eebfc62 | 60 | (*d10v_callback->printf_filtered) (d10v_callback, "ERROR looking up hash for %x at PC %x\n",ins, PC); |
2934d1c9 MH |
61 | exit(1); |
62 | } | |
63 | h = h->next; | |
64 | } | |
65 | return (h); | |
66 | } | |
67 | ||
2934d1c9 MH |
68 | static void |
69 | get_operands (struct simops *s, uint32 ins) | |
70 | { | |
71 | int i, shift, bits, flags; | |
72 | uint32 mask; | |
73 | for (i=0; i < s->numops; i++) | |
74 | { | |
75 | shift = s->operands[3*i]; | |
76 | bits = s->operands[3*i+1]; | |
77 | flags = s->operands[3*i+2]; | |
78 | mask = 0x7FFFFFFF >> (31 - bits); | |
79 | OP[i] = (ins >> shift) & mask; | |
80 | } | |
81 | } | |
82 | ||
83 | static void | |
84 | do_long (ins) | |
85 | uint32 ins; | |
86 | { | |
87 | struct hash_entry *h; | |
7eebfc62 MM |
88 | #ifdef DEBUG |
89 | if ((d10v_debug & DEBUG_INSTRUCTION) != 0) | |
90 | (*d10v_callback->printf_filtered) (d10v_callback, "do_long 0x%x\n", ins); | |
91 | #endif | |
2934d1c9 MH |
92 | h = lookup_hash (ins, 1); |
93 | get_operands (h->ops, ins); | |
87178dbd | 94 | State.ins_type = INS_LONG; |
7eebfc62 | 95 | ins_type_counters[ (int)State.ins_type ]++; |
2934d1c9 MH |
96 | (h->ops->func)(); |
97 | } | |
215ac953 | 98 | |
2934d1c9 | 99 | static void |
87178dbd | 100 | do_2_short (ins1, ins2, leftright) |
2934d1c9 | 101 | uint16 ins1, ins2; |
87178dbd | 102 | enum _leftright leftright; |
2934d1c9 MH |
103 | { |
104 | struct hash_entry *h; | |
215ac953 MM |
105 | reg_t orig_pc = PC; |
106 | ||
7eebfc62 MM |
107 | #ifdef DEBUG |
108 | if ((d10v_debug & DEBUG_INSTRUCTION) != 0) | |
109 | (*d10v_callback->printf_filtered) (d10v_callback, "do_2_short 0x%x (%s) -> 0x%x\n", | |
110 | ins1, (leftright) ? "left" : "right", ins2); | |
111 | #endif | |
2934d1c9 MH |
112 | /* printf ("do_2_short %x -> %x\n",ins1,ins2); */ |
113 | h = lookup_hash (ins1, 0); | |
114 | get_operands (h->ops, ins1); | |
87178dbd | 115 | State.ins_type = (leftright == LEFT_FIRST) ? INS_LEFT : INS_RIGHT; |
7eebfc62 | 116 | ins_type_counters[ (int)State.ins_type ]++; |
2934d1c9 | 117 | (h->ops->func)(); |
215ac953 MM |
118 | |
119 | /* If the PC has changed (ie, a jump), don't do the second instruction */ | |
57bc1a72 | 120 | if (orig_pc == PC && !State.exception) |
215ac953 MM |
121 | { |
122 | h = lookup_hash (ins2, 0); | |
123 | get_operands (h->ops, ins2); | |
124 | State.ins_type = (leftright == LEFT_FIRST) ? INS_RIGHT : INS_LEFT; | |
125 | ins_type_counters[ (int)State.ins_type ]++; | |
126 | (h->ops->func)(); | |
127 | } | |
2934d1c9 | 128 | } |
215ac953 | 129 | |
2934d1c9 MH |
130 | static void |
131 | do_parallel (ins1, ins2) | |
132 | uint16 ins1, ins2; | |
133 | { | |
134 | struct hash_entry *h1, *h2; | |
7eebfc62 MM |
135 | #ifdef DEBUG |
136 | if ((d10v_debug & DEBUG_INSTRUCTION) != 0) | |
137 | (*d10v_callback->printf_filtered) (d10v_callback, "do_parallel 0x%x || 0x%x\n", ins1, ins2); | |
138 | #endif | |
2934d1c9 | 139 | h1 = lookup_hash (ins1, 0); |
2934d1c9 | 140 | h2 = lookup_hash (ins2, 0); |
d70b4d42 | 141 | |
2934d1c9 MH |
142 | if (h1->ops->exec_type == PARONLY) |
143 | { | |
d70b4d42 | 144 | get_operands (h1->ops, ins1); |
87178dbd | 145 | State.ins_type = INS_LEFT; |
7eebfc62 | 146 | ins_type_counters[ (int)State.ins_type ]++; |
2934d1c9 MH |
147 | (h1->ops->func)(); |
148 | if (State.exe) | |
d70b4d42 MH |
149 | { |
150 | get_operands (h2->ops, ins2); | |
87178dbd | 151 | State.ins_type = INS_RIGHT; |
d70b4d42 MH |
152 | (h2->ops->func)(); |
153 | } | |
2934d1c9 MH |
154 | } |
155 | else if (h2->ops->exec_type == PARONLY) | |
156 | { | |
d70b4d42 | 157 | get_operands (h2->ops, ins2); |
87178dbd | 158 | State.ins_type = INS_RIGHT; |
7eebfc62 | 159 | ins_type_counters[ (int)State.ins_type ]++; |
2934d1c9 MH |
160 | (h2->ops->func)(); |
161 | if (State.exe) | |
d70b4d42 MH |
162 | { |
163 | get_operands (h1->ops, ins1); | |
87178dbd | 164 | State.ins_type = INS_LEFT; |
d70b4d42 MH |
165 | (h1->ops->func)(); |
166 | } | |
2934d1c9 MH |
167 | } |
168 | else | |
169 | { | |
d70b4d42 | 170 | get_operands (h1->ops, ins1); |
87178dbd | 171 | State.ins_type = INS_LEFT_PARALLEL; |
7eebfc62 | 172 | ins_type_counters[ (int)State.ins_type ]++; |
2934d1c9 | 173 | (h1->ops->func)(); |
57bc1a72 MM |
174 | if (!State.exception) |
175 | { | |
176 | get_operands (h2->ops, ins2); | |
177 | State.ins_type = INS_RIGHT_PARALLEL; | |
178 | ins_type_counters[ (int)State.ins_type ]++; | |
179 | (h2->ops->func)(); | |
180 | } | |
2934d1c9 MH |
181 | } |
182 | } | |
183 | ||
184 | ||
185 | void | |
186 | sim_size (power) | |
187 | int power; | |
188 | ||
189 | { | |
190 | if (State.imem) | |
191 | { | |
192 | free (State.imem); | |
193 | free (State.dmem); | |
194 | } | |
195 | ||
196 | State.imem = (uint8 *)calloc(1,1<<IMEM_SIZE); | |
197 | State.dmem = (uint8 *)calloc(1,1<<DMEM_SIZE); | |
198 | if (!State.imem || !State.dmem ) | |
199 | { | |
7eebfc62 | 200 | (*d10v_callback->printf_filtered) (d10v_callback, "Memory allocation failed.\n"); |
2934d1c9 MH |
201 | exit(1); |
202 | } | |
7eebfc62 | 203 | |
57bc1a72 MM |
204 | State.mem_min = 1<<IMEM_SIZE; |
205 | State.mem_max = 0; | |
206 | ||
7eebfc62 MM |
207 | #ifdef DEBUG |
208 | if ((d10v_debug & DEBUG_MEMSIZE) != 0) | |
209 | { | |
210 | (*d10v_callback->printf_filtered) (d10v_callback, "Allocated %d bytes instruction memory and\n",1<<IMEM_SIZE); | |
211 | (*d10v_callback->printf_filtered) (d10v_callback, " %d bytes data memory.\n", 1<<DMEM_SIZE); | |
212 | } | |
87178dbd | 213 | #endif |
2934d1c9 MH |
214 | } |
215 | ||
216 | static void | |
217 | init_system () | |
218 | { | |
219 | if (!State.imem) | |
220 | sim_size(1); | |
221 | } | |
222 | ||
223 | int | |
224 | sim_write (addr, buffer, size) | |
225 | SIM_ADDR addr; | |
226 | unsigned char *buffer; | |
227 | int size; | |
228 | { | |
2934d1c9 MH |
229 | init_system (); |
230 | ||
57bc1a72 MM |
231 | #ifdef DEBUG |
232 | if ((d10v_debug & DEBUG_INSTRUCTION) != 0) | |
233 | (*d10v_callback->printf_filtered) (d10v_callback, "sim_write %d bytes to 0x%x, min = 0x%x, max = 0x%x\n", | |
234 | size, addr, State.mem_min, State.mem_max); | |
235 | #endif | |
236 | ||
237 | if (State.mem_min > addr) | |
238 | State.mem_min = addr; | |
239 | ||
240 | if (State.mem_max < addr+size-1) | |
241 | State.mem_max = addr+size-1; | |
242 | ||
243 | memcpy (State.imem+addr, buffer, size); | |
2934d1c9 MH |
244 | return size; |
245 | } | |
246 | ||
247 | void | |
248 | sim_open (args) | |
249 | char *args; | |
250 | { | |
251 | struct simops *s; | |
252 | struct hash_entry *h, *prev; | |
1eaaf305 MM |
253 | static int init_p = 0; |
254 | ||
2934d1c9 | 255 | if (args != NULL) |
1eaaf305 MM |
256 | { |
257 | #ifdef DEBUG | |
258 | if (strcmp (args, "-t") == 0) | |
259 | d10v_debug = DEBUG; | |
260 | else | |
261 | #endif | |
262 | (*d10v_callback->printf_filtered) (d10v_callback, "ERROR: unsupported option(s): %s\n",args); | |
263 | } | |
2934d1c9 MH |
264 | |
265 | /* put all the opcodes in the hash table */ | |
1eaaf305 | 266 | if (!init_p++) |
2934d1c9 | 267 | { |
1eaaf305 | 268 | for (s = Simops; s->func; s++) |
2934d1c9 | 269 | { |
1eaaf305 MM |
270 | h = &hash_table[hash(s->opcode,s->format)]; |
271 | ||
272 | /* go to the last entry in the chain */ | |
273 | while (h->next) | |
274 | h = h->next; | |
275 | ||
276 | if (h->ops) | |
277 | { | |
278 | h->next = calloc(1,sizeof(struct hash_entry)); | |
279 | h = h->next; | |
280 | } | |
281 | h->ops = s; | |
282 | h->mask = s->mask; | |
283 | h->opcode = s->opcode; | |
2934d1c9 | 284 | } |
2934d1c9 MH |
285 | } |
286 | } | |
287 | ||
288 | ||
289 | void | |
290 | sim_close (quitting) | |
291 | int quitting; | |
292 | { | |
293 | /* nothing to do */ | |
294 | } | |
295 | ||
296 | void | |
297 | sim_set_profile (n) | |
298 | int n; | |
299 | { | |
7eebfc62 | 300 | (*d10v_callback->printf_filtered) (d10v_callback, "sim_set_profile %d\n",n); |
2934d1c9 MH |
301 | } |
302 | ||
303 | void | |
304 | sim_set_profile_size (n) | |
305 | int n; | |
306 | { | |
7eebfc62 | 307 | (*d10v_callback->printf_filtered) (d10v_callback, "sim_set_profile_size %d\n",n); |
2934d1c9 MH |
308 | } |
309 | ||
310 | void | |
311 | sim_resume (step, siggnal) | |
312 | int step, siggnal; | |
313 | { | |
314 | uint32 inst; | |
315 | int i; | |
316 | reg_t oldpc; | |
317 | ||
7eebfc62 | 318 | /* (*d10v_callback->printf_filtered) (d10v_callback, "sim_resume (%d,%d) PC=0x%x\n",step,siggnal,PC); */ |
2934d1c9 | 319 | |
d70b4d42 MH |
320 | if (step) |
321 | State.exception = SIGTRAP; | |
322 | else | |
323 | State.exception = 0; | |
324 | ||
325 | do | |
326 | { | |
57bc1a72 MM |
327 | uint32 byte_pc = ((uint32)PC) << 2; |
328 | if ((byte_pc < State.mem_min) || (byte_pc > State.mem_max)) | |
d70b4d42 | 329 | { |
57bc1a72 MM |
330 | (*d10v_callback->printf_filtered) (d10v_callback, |
331 | "PC (0x%lx) out of range, oldpc = 0x%lx, min = 0x%lx, max = 0x%lx\n", | |
332 | (long)byte_pc, (long)oldpc, (long)State.mem_min, (long)State.mem_max); | |
333 | State.exception = SIGILL; | |
d70b4d42 | 334 | } |
57bc1a72 | 335 | else |
d70b4d42 | 336 | { |
57bc1a72 MM |
337 | inst = RLW (byte_pc); |
338 | oldpc = PC; | |
339 | switch (inst & 0xC0000000) | |
340 | { | |
341 | case 0xC0000000: | |
342 | /* long instruction */ | |
343 | do_long (inst & 0x3FFFFFFF); | |
344 | break; | |
345 | case 0x80000000: | |
346 | /* R -> L */ | |
347 | do_2_short ( inst & 0x7FFF, (inst & 0x3FFF8000) >> 15, 0); | |
348 | break; | |
349 | case 0x40000000: | |
350 | /* L -> R */ | |
351 | do_2_short ((inst & 0x3FFF8000) >> 15, inst & 0x7FFF, 1); | |
352 | break; | |
353 | case 0: | |
354 | do_parallel ((inst & 0x3FFF8000) >> 15, inst & 0x7FFF); | |
355 | break; | |
356 | } | |
d70b4d42 | 357 | |
57bc1a72 MM |
358 | if (State.RP && PC == RPT_E) |
359 | { | |
360 | RPT_C -= 1; | |
361 | if (RPT_C == 0) | |
362 | State.RP = 0; | |
363 | else | |
364 | PC = RPT_S; | |
365 | } | |
366 | ||
367 | /* FIXME */ | |
368 | if (PC == oldpc) | |
369 | PC++; | |
370 | } | |
d70b4d42 MH |
371 | } |
372 | while (!State.exception); | |
2934d1c9 MH |
373 | } |
374 | ||
375 | int | |
376 | sim_trace () | |
377 | { | |
7eebfc62 MM |
378 | #ifdef DEBUG |
379 | d10v_debug = DEBUG; | |
380 | #endif | |
381 | sim_resume (0, 0); | |
382 | return 1; | |
2934d1c9 MH |
383 | } |
384 | ||
385 | void | |
386 | sim_info (verbose) | |
387 | int verbose; | |
388 | { | |
7eebfc62 MM |
389 | char buf[40]; |
390 | int size; | |
391 | long total = (ins_type_counters[ (int)INS_LONG ] | |
392 | + ins_type_counters[ (int)INS_LEFT ] | |
393 | + ins_type_counters[ (int)INS_LEFT_PARALLEL ] | |
394 | + ins_type_counters[ (int)INS_RIGHT ] | |
395 | + ins_type_counters[ (int)INS_RIGHT_PARALLEL ]); | |
396 | ||
397 | sprintf (buf, "%ld", total); | |
398 | size = strlen (buf); | |
399 | ||
400 | (*d10v_callback->printf_filtered) (d10v_callback, | |
401 | "executed %*ld instructions in the left container, %*ld parallel, %*ld nops\n", | |
402 | size, ins_type_counters[ (int)INS_LEFT ] + ins_type_counters[ (int)INS_LEFT_PARALLEL ], | |
403 | size, ins_type_counters[ (int)INS_LEFT_PARALLEL ], | |
404 | size, left_nops); | |
405 | ||
406 | (*d10v_callback->printf_filtered) (d10v_callback, | |
407 | "executed %*ld instructions in the right container, %*ld parallel, %*ld nops\n", | |
408 | size, ins_type_counters[ (int)INS_RIGHT ] + ins_type_counters[ (int)INS_RIGHT_PARALLEL ], | |
409 | size, ins_type_counters[ (int)INS_RIGHT_PARALLEL ], | |
410 | size, right_nops); | |
411 | ||
412 | (*d10v_callback->printf_filtered) (d10v_callback, | |
413 | "executed %*ld long instructions\n", | |
414 | size, ins_type_counters[ (int)INS_LONG ]); | |
415 | ||
416 | (*d10v_callback->printf_filtered) (d10v_callback, | |
417 | "executed %*ld total instructions\n", | |
418 | size, total); | |
2934d1c9 MH |
419 | } |
420 | ||
421 | void | |
422 | sim_create_inferior (start_address, argv, env) | |
423 | SIM_ADDR start_address; | |
424 | char **argv; | |
425 | char **env; | |
426 | { | |
57bc1a72 MM |
427 | uint8 *imem, *dmem; |
428 | uint32 mem_min, mem_max; | |
7eebfc62 MM |
429 | #ifdef DEBUG |
430 | if (d10v_debug) | |
431 | (*d10v_callback->printf_filtered) (d10v_callback, "sim_create_inferior: PC=0x%x\n", start_address); | |
432 | #endif | |
57bc1a72 MM |
433 | /* save memory pointers */ |
434 | imem = State.imem; | |
435 | dmem = State.dmem; | |
436 | mem_min = State.mem_min; | |
437 | mem_max = State.mem_max; | |
438 | /* reset all state information */ | |
439 | memset (&State, 0, sizeof(State)); | |
440 | /* restore memory pointers */ | |
441 | State.imem = imem; | |
442 | State.dmem = dmem; | |
443 | State.mem_min = mem_min; | |
444 | State.mem_max = mem_max; | |
445 | /* set PC */ | |
2934d1c9 MH |
446 | PC = start_address >> 2; |
447 | } | |
448 | ||
449 | ||
450 | void | |
451 | sim_kill () | |
452 | { | |
453 | /* nothing to do */ | |
454 | } | |
455 | ||
456 | void | |
457 | sim_set_callbacks(p) | |
458 | host_callback *p; | |
459 | { | |
87178dbd MM |
460 | /* printf ("sim_set_callbacks\n"); */ |
461 | d10v_callback = p; | |
2934d1c9 MH |
462 | } |
463 | ||
464 | void | |
465 | sim_stop_reason (reason, sigrc) | |
466 | enum sim_stop *reason; | |
467 | int *sigrc; | |
468 | { | |
7eebfc62 | 469 | /* (*d10v_callback->printf_filtered) (d10v_callback, "sim_stop_reason: PC=0x%x\n",PC<<2); */ |
d70b4d42 | 470 | |
a49a15ad | 471 | switch (State.exception) |
d70b4d42 | 472 | { |
a49a15ad | 473 | case SIG_D10V_STOP: /* stop instruction */ |
d70b4d42 | 474 | *reason = sim_exited; |
a49a15ad MM |
475 | *sigrc = 0; |
476 | break; | |
477 | ||
478 | case SIG_D10V_EXIT: /* exit trap */ | |
479 | *reason = sim_exited; | |
480 | *sigrc = State.regs[2]; | |
481 | break; | |
482 | ||
483 | default: /* some signal */ | |
d70b4d42 MH |
484 | *reason = sim_stopped; |
485 | *sigrc = State.exception; | |
a49a15ad | 486 | break; |
d70b4d42 MH |
487 | } |
488 | } | |
489 | ||
490 | void | |
491 | sim_fetch_register (rn, memory) | |
492 | int rn; | |
493 | unsigned char *memory; | |
494 | { | |
495 | if (rn > 31) | |
496 | { | |
497 | WRITE_64 (memory, State.a[rn-32]); | |
7eebfc62 | 498 | /* (*d10v_callback->printf_filtered) (d10v_callback, "sim_fetch_register %d 0x%llx\n",rn,State.a[rn-32]); */ |
d70b4d42 MH |
499 | } |
500 | else | |
501 | { | |
502 | WRITE_16 (memory, State.regs[rn]); | |
7eebfc62 | 503 | /* (*d10v_callback->printf_filtered) (d10v_callback, "sim_fetch_register %d 0x%x\n",rn,State.regs[rn]); */ |
d70b4d42 MH |
504 | } |
505 | } | |
506 | ||
507 | void | |
508 | sim_store_register (rn, memory) | |
509 | int rn; | |
510 | unsigned char *memory; | |
511 | { | |
512 | if (rn > 31) | |
513 | { | |
514 | State.a[rn-32] = READ_64 (memory) & MASK40; | |
7eebfc62 | 515 | /* (*d10v_callback->printf_filtered) (d10v_callback, "store: a%d=0x%llx\n",rn-32,State.a[rn-32]); */ |
d70b4d42 MH |
516 | } |
517 | else | |
518 | { | |
519 | State.regs[rn]= READ_16 (memory); | |
7eebfc62 | 520 | /* (*d10v_callback->printf_filtered) (d10v_callback, "store: r%d=0x%x\n",rn,State.regs[rn]); */ |
d70b4d42 | 521 | } |
2934d1c9 | 522 | } |
d70b4d42 MH |
523 | |
524 | sim_read (addr, buffer, size) | |
525 | SIM_ADDR addr; | |
526 | unsigned char *buffer; | |
527 | int size; | |
528 | { | |
529 | int i; | |
530 | for (i = 0; i < size; i++) | |
531 | { | |
532 | buffer[i] = State.imem[addr + i]; | |
533 | } | |
534 | return size; | |
535 | } | |
536 | ||
537 | void | |
538 | sim_do_command (cmd) | |
539 | char *cmd; | |
540 | { | |
7eebfc62 | 541 | (*d10v_callback->printf_filtered) (d10v_callback, "sim_do_command: %s\n",cmd); |
d70b4d42 MH |
542 | } |
543 | ||
544 | int | |
545 | sim_load (prog, from_tty) | |
546 | char *prog; | |
547 | int from_tty; | |
548 | { | |
549 | /* Return nonzero so GDB will handle it. */ | |
550 | return 1; | |
551 | } |