Better error messages when a program stops due to signal; support d10v getpid/kill
[platform/upstream/binutils.git] / sim / d10v / interp.c
1 #include <signal.h>
2 #include "sysdep.h"
3 #include "bfd.h"
4 #include "remote-sim.h"
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
11 enum _leftright { LEFT_FIRST, RIGHT_FIRST };
12
13 int d10v_debug;
14 host_callback *d10v_callback;
15 long ins_type_counters[ (int)INS_MAX ];
16 long left_nops, right_nops;
17
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         {
60           (*d10v_callback->printf_filtered) (d10v_callback, "ERROR looking up hash for %x at PC %x\n",ins, PC);
61           exit(1);
62         }
63       h = h->next;
64     }
65   return (h);
66 }
67
68 uint32
69 get_longword (x)
70       uint8 *x;
71 {
72   uint8 *a = x;
73   return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + (a[3]);
74 }
75
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
85 uint16
86 get_word (x)
87       uint8 *x;
88 {
89   uint8 *a = x;
90   return ((uint16)a[0]<<8) + a[1];
91 }
92
93
94 void
95 write_word (addr, data)
96      uint8 *addr;
97      uint16 data;
98 {
99   uint8 *a = addr;
100   a[0] = data >> 8;
101   a[1] = data & 0xff;
102 }
103
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
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
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;
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
155   h = lookup_hash (ins, 1);
156   get_operands (h->ops, ins);
157   State.ins_type = INS_LONG;
158   ins_type_counters[ (int)State.ins_type ]++;
159   (h->ops->func)();
160 }
161
162 static void
163 do_2_short (ins1, ins2, leftright)
164      uint16 ins1, ins2;
165      enum _leftright leftright;
166 {
167   struct hash_entry *h;
168   reg_t orig_pc = PC;
169
170 #ifdef DEBUG
171   if ((d10v_debug & DEBUG_INSTRUCTION) != 0)
172     (*d10v_callback->printf_filtered) (d10v_callback, "do_2_short 0x%x (%s) -> 0x%x\n",
173                                        ins1, (leftright) ? "left" : "right", ins2);
174 #endif
175   /*  printf ("do_2_short %x -> %x\n",ins1,ins2); */
176   h = lookup_hash (ins1, 0);
177   get_operands (h->ops, ins1);
178   State.ins_type = (leftright == LEFT_FIRST) ? INS_LEFT : INS_RIGHT;
179   ins_type_counters[ (int)State.ins_type ]++;
180   (h->ops->func)();
181
182   /* If the PC has changed (ie, a jump), don't do the second instruction */
183   if (orig_pc == PC && !State.exception)
184     {
185       h = lookup_hash (ins2, 0);
186       get_operands (h->ops, ins2);
187       State.ins_type = (leftright == LEFT_FIRST) ? INS_RIGHT : INS_LEFT;
188       ins_type_counters[ (int)State.ins_type ]++;
189       (h->ops->func)();
190     }
191 }
192
193 static void
194 do_parallel (ins1, ins2)
195      uint16 ins1, ins2;
196 {
197   struct hash_entry *h1, *h2;
198 #ifdef DEBUG
199   if ((d10v_debug & DEBUG_INSTRUCTION) != 0)
200     (*d10v_callback->printf_filtered) (d10v_callback, "do_parallel 0x%x || 0x%x\n", ins1, ins2);
201 #endif
202   h1 = lookup_hash (ins1, 0);
203   h2 = lookup_hash (ins2, 0);
204
205   if (h1->ops->exec_type == PARONLY)
206     {
207       get_operands (h1->ops, ins1);
208       State.ins_type = INS_LEFT;
209       ins_type_counters[ (int)State.ins_type ]++;
210       (h1->ops->func)();
211       if (State.exe)
212         {
213           get_operands (h2->ops, ins2);
214           State.ins_type = INS_RIGHT;
215           (h2->ops->func)();
216         }
217     }
218   else if (h2->ops->exec_type == PARONLY)
219     {
220       get_operands (h2->ops, ins2);
221       State.ins_type = INS_RIGHT;
222       ins_type_counters[ (int)State.ins_type ]++;
223       (h2->ops->func)();
224       if (State.exe)
225         {
226           get_operands (h1->ops, ins1);
227           State.ins_type = INS_LEFT;
228           (h1->ops->func)();
229         }
230     }
231   else
232     {
233       get_operands (h1->ops, ins1);
234       State.ins_type = INS_LEFT_PARALLEL;
235       ins_type_counters[ (int)State.ins_type ]++;
236       (h1->ops->func)();
237       if (!State.exception)
238         {
239           get_operands (h2->ops, ins2);
240           State.ins_type = INS_RIGHT_PARALLEL;
241           ins_type_counters[ (int)State.ins_type ]++;
242           (h2->ops->func)();
243         }
244     }
245 }
246  
247
248 void
249 sim_size (power)
250      int power;
251
252 {
253   if (State.imem)
254     {
255       free (State.imem);
256       free (State.dmem);
257     }
258
259   State.imem = (uint8 *)calloc(1,1<<IMEM_SIZE);
260   State.dmem = (uint8 *)calloc(1,1<<DMEM_SIZE);
261   if (!State.imem || !State.dmem )
262     {
263       (*d10v_callback->printf_filtered) (d10v_callback, "Memory allocation failed.\n");
264       exit(1);
265     }
266
267   State.mem_min = 1<<IMEM_SIZE;
268   State.mem_max = 0;
269
270 #ifdef DEBUG
271   if ((d10v_debug & DEBUG_MEMSIZE) != 0)
272     {
273       (*d10v_callback->printf_filtered) (d10v_callback, "Allocated %d bytes instruction memory and\n",1<<IMEM_SIZE);
274       (*d10v_callback->printf_filtered) (d10v_callback, "          %d bytes data memory.\n",          1<<DMEM_SIZE);
275     }
276 #endif
277 }
278
279 static void
280 init_system ()
281 {
282   if (!State.imem)
283     sim_size(1);
284 }
285
286 int
287 sim_write (addr, buffer, size)
288      SIM_ADDR addr;
289      unsigned char *buffer;
290      int size;
291 {
292   init_system ();
293
294 #ifdef DEBUG
295   if ((d10v_debug & DEBUG_INSTRUCTION) != 0)
296     (*d10v_callback->printf_filtered) (d10v_callback, "sim_write %d bytes to 0x%x, min = 0x%x, max = 0x%x\n",
297                                        size, addr, State.mem_min, State.mem_max);
298 #endif
299
300   if (State.mem_min > addr)
301     State.mem_min = addr;
302
303   if (State.mem_max < addr+size-1)
304     State.mem_max = addr+size-1;
305
306   memcpy (State.imem+addr, buffer, size);
307   return size;
308 }
309
310 void
311 sim_open (args)
312      char *args;
313 {
314   struct simops *s;
315   struct hash_entry *h, *prev;
316   static int init_p = 0;
317
318   if (args != NULL)
319     {
320 #ifdef DEBUG
321       if (strcmp (args, "-t") == 0)
322         d10v_debug = DEBUG;
323       else
324 #endif
325         (*d10v_callback->printf_filtered) (d10v_callback, "ERROR: unsupported option(s): %s\n",args);
326     }
327
328   /* put all the opcodes in the hash table */
329   if (!init_p++)
330     {
331       for (s = Simops; s->func; s++)
332         {
333           h = &hash_table[hash(s->opcode,s->format)];
334       
335           /* go to the last entry in the chain */
336           while (h->next)
337             h = h->next;
338
339           if (h->ops)
340             {
341               h->next = calloc(1,sizeof(struct hash_entry));
342               h = h->next;
343             }
344           h->ops = s;
345           h->mask = s->mask;
346           h->opcode = s->opcode;
347         }
348     }
349 }
350
351
352 void
353 sim_close (quitting)
354      int quitting;
355 {
356   /* nothing to do */
357 }
358
359 void
360 sim_set_profile (n)
361      int n;
362 {
363   (*d10v_callback->printf_filtered) (d10v_callback, "sim_set_profile %d\n",n);
364 }
365
366 void
367 sim_set_profile_size (n)
368      int n;
369 {
370   (*d10v_callback->printf_filtered) (d10v_callback, "sim_set_profile_size %d\n",n);
371 }
372
373 void
374 sim_resume (step, siggnal)
375      int step, siggnal;
376 {
377   uint32 inst;
378   int i;
379   reg_t oldpc;
380
381 /*   (*d10v_callback->printf_filtered) (d10v_callback, "sim_resume (%d,%d)  PC=0x%x\n",step,siggnal,PC); */
382
383  if (step)
384    State.exception = SIGTRAP;
385  else
386    State.exception = 0;
387  
388  do
389    {
390      uint32 byte_pc = ((uint32)PC) << 2;
391      if ((byte_pc < State.mem_min) || (byte_pc > State.mem_max))
392        {
393          (*d10v_callback->printf_filtered) (d10v_callback,
394                                             "PC (0x%lx) out of range, oldpc = 0x%lx, min = 0x%lx, max = 0x%lx\n",
395                                             (long)byte_pc, (long)oldpc, (long)State.mem_min, (long)State.mem_max);
396          State.exception = SIGILL;
397        }
398      else
399        {
400          inst = RLW (byte_pc); 
401          oldpc = PC;
402          switch (inst & 0xC0000000)
403            {
404            case 0xC0000000:
405              /* long instruction */
406              do_long (inst & 0x3FFFFFFF);
407              break;
408            case 0x80000000:
409              /* R -> L */
410              do_2_short ( inst & 0x7FFF, (inst & 0x3FFF8000) >> 15, 0);
411              break;
412            case 0x40000000:
413              /* L -> R */
414              do_2_short ((inst & 0x3FFF8000) >> 15, inst & 0x7FFF, 1);
415              break;
416            case 0:
417              do_parallel ((inst & 0x3FFF8000) >> 15, inst & 0x7FFF);
418              break;
419            }
420      
421          if (State.RP && PC == RPT_E)
422            {
423              RPT_C -= 1;
424              if (RPT_C == 0)
425                State.RP = 0;
426              else
427                PC = RPT_S;
428            }
429
430          /* FIXME */
431          if (PC == oldpc)
432            PC++;
433        }
434    } 
435  while (!State.exception);
436 }
437
438 int
439 sim_trace ()
440 {
441 #ifdef DEBUG
442   d10v_debug = DEBUG;
443 #endif
444   sim_resume (0, 0);
445   return 1;
446 }
447
448 void
449 sim_info (verbose)
450      int verbose;
451 {
452   char buf[40];
453   int size;
454   long total = (ins_type_counters[ (int)INS_LONG ]
455                 + ins_type_counters[ (int)INS_LEFT ]
456                 + ins_type_counters[ (int)INS_LEFT_PARALLEL ]
457                 + ins_type_counters[ (int)INS_RIGHT ]
458                 + ins_type_counters[ (int)INS_RIGHT_PARALLEL ]);
459
460   sprintf (buf, "%ld", total);
461   size = strlen (buf);
462
463   (*d10v_callback->printf_filtered) (d10v_callback,
464                                      "executed %*ld instructions in the left  container, %*ld parallel, %*ld nops\n",
465                                      size, ins_type_counters[ (int)INS_LEFT ] + ins_type_counters[ (int)INS_LEFT_PARALLEL ],
466                                      size, ins_type_counters[ (int)INS_LEFT_PARALLEL ],
467                                      size, left_nops);
468
469   (*d10v_callback->printf_filtered) (d10v_callback,
470                                      "executed %*ld instructions in the right container, %*ld parallel, %*ld nops\n",
471                                      size, ins_type_counters[ (int)INS_RIGHT ] + ins_type_counters[ (int)INS_RIGHT_PARALLEL ],
472                                      size, ins_type_counters[ (int)INS_RIGHT_PARALLEL ],
473                                      size, right_nops);
474
475   (*d10v_callback->printf_filtered) (d10v_callback,
476                                      "executed %*ld long instructions\n",
477                                      size, ins_type_counters[ (int)INS_LONG ]);
478
479   (*d10v_callback->printf_filtered) (d10v_callback,
480                                      "executed %*ld total instructions\n",
481                                      size, total);
482 }
483
484 void
485 sim_create_inferior (start_address, argv, env)
486      SIM_ADDR start_address;
487      char **argv;
488      char **env;
489 {
490   uint8 *imem, *dmem;
491   uint32 mem_min, mem_max;
492 #ifdef DEBUG
493   if (d10v_debug)
494     (*d10v_callback->printf_filtered) (d10v_callback, "sim_create_inferior:  PC=0x%x\n", start_address);
495 #endif
496   /* save memory pointers */
497   imem = State.imem;
498   dmem = State.dmem;
499   mem_min = State.mem_min;
500   mem_max = State.mem_max;
501   /* reset all state information */
502   memset (&State, 0, sizeof(State));
503   /* restore memory pointers */
504   State.imem = imem;
505   State.dmem = dmem;
506   State.mem_min = mem_min;
507   State.mem_max = mem_max;
508   /* set PC */
509   PC = start_address >> 2;
510 }
511
512
513 void
514 sim_kill ()
515 {
516   /* nothing to do */
517 }
518
519 void
520 sim_set_callbacks(p)
521      host_callback *p;
522 {
523 /*  printf ("sim_set_callbacks\n"); */
524   d10v_callback = p;
525 }
526
527 void
528 sim_stop_reason (reason, sigrc)
529      enum sim_stop *reason;
530      int *sigrc;
531 {
532 /*   (*d10v_callback->printf_filtered) (d10v_callback, "sim_stop_reason:  PC=0x%x\n",PC<<2); */
533
534   switch (State.exception)
535     {
536     case SIG_D10V_STOP:                 /* stop instruction */
537       *reason = sim_exited;
538       *sigrc = 0;
539       break;
540
541     case SIG_D10V_EXIT:                 /* exit trap */
542       *reason = sim_exited;
543       *sigrc = State.regs[2];
544       break;
545
546     default:                            /* some signal */
547       *reason = sim_stopped;
548       *sigrc = State.exception;
549       break;
550     } 
551 }
552
553 void
554 sim_fetch_register (rn, memory)
555      int rn;
556      unsigned char *memory;
557 {
558   if (rn > 31)
559     {
560       WRITE_64 (memory, State.a[rn-32]);
561       /* (*d10v_callback->printf_filtered) (d10v_callback, "sim_fetch_register %d 0x%llx\n",rn,State.a[rn-32]); */
562     }
563   else
564     {
565       WRITE_16 (memory, State.regs[rn]);
566       /* (*d10v_callback->printf_filtered) (d10v_callback, "sim_fetch_register %d 0x%x\n",rn,State.regs[rn]); */
567     }
568 }
569  
570 void
571 sim_store_register (rn, memory)
572      int rn;
573      unsigned char *memory;
574 {
575   if (rn > 31)
576     {
577       State.a[rn-32] =  READ_64 (memory) & MASK40;
578       /* (*d10v_callback->printf_filtered) (d10v_callback, "store: a%d=0x%llx\n",rn-32,State.a[rn-32]); */
579     }
580   else
581     {
582       State.regs[rn]= READ_16 (memory);
583       /* (*d10v_callback->printf_filtered) (d10v_callback, "store: r%d=0x%x\n",rn,State.regs[rn]); */
584     }
585 }
586
587 sim_read (addr, buffer, size)
588      SIM_ADDR addr;
589      unsigned char *buffer;
590      int size;
591 {
592   int i;
593   for (i = 0; i < size; i++)
594     {
595       buffer[i] = State.imem[addr + i];
596     }
597   return size;
598
599
600 void
601 sim_do_command (cmd)
602      char *cmd;
603
604   (*d10v_callback->printf_filtered) (d10v_callback, "sim_do_command: %s\n",cmd);
605 }
606
607 int
608 sim_load (prog, from_tty)
609      char *prog;
610      int from_tty;
611 {
612   /* Return nonzero so GDB will handle it.  */
613   return 1;
614