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