xref: /netbsd-src/external/gpl3/gdb/dist/sim/microblaze/interp.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* Simulator for Xilinx MicroBlaze processor
2    Copyright 2009-2014 Free Software Foundation, Inc.
3 
4    This file is part of GDB, the GNU debugger.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "config.h"
20 #include <signal.h>
21 #include "sysdep.h"
22 #include <sys/times.h>
23 #include <sys/param.h>
24 #include <netinet/in.h>	/* for byte ordering macros */
25 #include "bfd.h"
26 #include "gdb/callback.h"
27 #include "libiberty.h"
28 #include "gdb/remote-sim.h"
29 #include "sim-main.h"
30 #include "sim-utils.h"
31 #include "microblaze-dis.h"
32 
33 
34 #ifndef NUM_ELEM
35 #define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0])
36 #endif
37 
38 static int target_big_endian = 1;
39 static unsigned long heap_ptr = 0;
40 static unsigned long stack_ptr = 0;
41 host_callback *callback;
42 
43 unsigned long
44 microblaze_extract_unsigned_integer (unsigned char *addr, int len)
45 {
46   unsigned long retval;
47   unsigned char *p;
48   unsigned char *startaddr = (unsigned char *)addr;
49   unsigned char *endaddr = startaddr + len;
50 
51   if (len > (int) sizeof (unsigned long))
52     printf ("That operation is not available on integers of more than "
53 	    "%d bytes.", sizeof (unsigned long));
54 
55   /* Start at the most significant end of the integer, and work towards
56      the least significant.  */
57   retval = 0;
58 
59   if (!target_big_endian)
60     {
61       for (p = endaddr; p > startaddr;)
62 	retval = (retval << 8) | * -- p;
63     }
64   else
65     {
66       for (p = startaddr; p < endaddr;)
67 	retval = (retval << 8) | * p ++;
68     }
69 
70   return retval;
71 }
72 
73 void
74 microblaze_store_unsigned_integer (unsigned char *addr, int len,
75 				   unsigned long val)
76 {
77   unsigned char *p;
78   unsigned char *startaddr = (unsigned char *)addr;
79   unsigned char *endaddr = startaddr + len;
80 
81   if (!target_big_endian)
82     {
83       for (p = startaddr; p < endaddr;)
84 	{
85 	  *p++ = val & 0xff;
86 	  val >>= 8;
87 	}
88     }
89   else
90     {
91       for (p = endaddr; p > startaddr;)
92 	{
93 	  *--p = val & 0xff;
94 	  val >>= 8;
95 	}
96     }
97 }
98 
99 struct sim_state microblaze_state;
100 
101 int memcycles = 1;
102 
103 static SIM_OPEN_KIND sim_kind;
104 static char *myname;
105 
106 static int issue_messages = 0;
107 
108 long
109 int_sbrk (int inc_bytes)
110 {
111   long addr;
112 
113   addr = heap_ptr;
114 
115   heap_ptr += inc_bytes;
116 
117   if (issue_messages && heap_ptr > SP)
118     fprintf (stderr, "Warning: heap_ptr overlaps stack!\n");
119 
120   return addr;
121 }
122 
123 static void /* INLINE */
124 wbat (word x, word v)
125 {
126   if (((uword)x) >= CPU.msize)
127     {
128       if (issue_messages)
129 	fprintf (stderr, "byte write to 0x%x outside memory range\n", x);
130 
131       CPU.exception = SIGSEGV;
132     }
133   else
134     {
135       unsigned char *p = CPU.memory + x;
136       p[0] = v;
137     }
138 }
139 
140 static void /* INLINE */
141 wlat (word x, word v)
142 {
143   if (((uword)x) >= CPU.msize)
144     {
145       if (issue_messages)
146 	fprintf (stderr, "word write to 0x%x outside memory range\n", x);
147 
148       CPU.exception = SIGSEGV;
149     }
150   else
151     {
152       if ((x & 3) != 0)
153 	{
154 	  if (issue_messages)
155 	    fprintf (stderr, "word write to unaligned memory address: 0x%x\n", x);
156 
157 	  CPU.exception = SIGBUS;
158 	}
159       else if (!target_big_endian)
160 	{
161 	  unsigned char *p = CPU.memory + x;
162 	  p[3] = v >> 24;
163 	  p[2] = v >> 16;
164 	  p[1] = v >> 8;
165 	  p[0] = v;
166 	}
167       else
168 	{
169 	  unsigned char *p = CPU.memory + x;
170 	  p[0] = v >> 24;
171 	  p[1] = v >> 16;
172 	  p[2] = v >> 8;
173 	  p[3] = v;
174 	}
175     }
176 }
177 
178 static void /* INLINE */
179 what (word x, word v)
180 {
181   if (((uword)x) >= CPU.msize)
182     {
183       if (issue_messages)
184 	fprintf (stderr, "short write to 0x%x outside memory range\n", x);
185 
186       CPU.exception = SIGSEGV;
187     }
188   else
189     {
190       if ((x & 1) != 0)
191 	{
192 	  if (issue_messages)
193 	    fprintf (stderr, "short write to unaligned memory address: 0x%x\n",
194 		     x);
195 
196 	  CPU.exception = SIGBUS;
197 	}
198       else if (!target_big_endian)
199 	{
200 	  unsigned char *p = CPU.memory + x;
201 	  p[1] = v >> 8;
202 	  p[0] = v;
203 	}
204       else
205 	{
206 	  unsigned char *p = CPU.memory + x;
207 	  p[0] = v >> 8;
208 	  p[1] = v;
209 	}
210     }
211 }
212 
213 /* Read functions.  */
214 static int /* INLINE */
215 rbat (word x)
216 {
217   if (((uword)x) >= CPU.msize)
218     {
219       if (issue_messages)
220 	fprintf (stderr, "byte read from 0x%x outside memory range\n", x);
221 
222       CPU.exception = SIGSEGV;
223       return 0;
224     }
225   else
226     {
227       unsigned char *p = CPU.memory + x;
228       return p[0];
229     }
230 }
231 
232 static int /* INLINE */
233 rlat (word x)
234 {
235   if (((uword) x) >= CPU.msize)
236     {
237       if (issue_messages)
238 	fprintf (stderr, "word read from 0x%x outside memory range\n", x);
239 
240       CPU.exception = SIGSEGV;
241       return 0;
242     }
243   else
244     {
245       if ((x & 3) != 0)
246 	{
247 	  if (issue_messages)
248 	    fprintf (stderr, "word read from unaligned address: 0x%x\n", x);
249 
250 	  CPU.exception = SIGBUS;
251 	  return 0;
252 	}
253       else if (! target_big_endian)
254 	{
255 	  unsigned char *p = CPU.memory + x;
256 	  return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
257 	}
258       else
259 	{
260 	  unsigned char *p = CPU.memory + x;
261 	  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
262 	}
263     }
264 }
265 
266 static int /* INLINE */
267 rhat (word x)
268 {
269   if (((uword)x) >= CPU.msize)
270     {
271       if (issue_messages)
272 	fprintf (stderr, "short read from 0x%x outside memory range\n", x);
273 
274       CPU.exception = SIGSEGV;
275       return 0;
276     }
277   else
278     {
279       if ((x & 1) != 0)
280 	{
281 	  if (issue_messages)
282 	    fprintf (stderr, "short read from unaligned address: 0x%x\n", x);
283 
284 	  CPU.exception = SIGBUS;
285 	  return 0;
286 	}
287       else if (!target_big_endian)
288 	{
289 	  unsigned char *p = CPU.memory + x;
290 	  return (p[1] << 8) | p[0];
291 	}
292       else
293 	{
294 	  unsigned char *p = CPU.memory + x;
295 	  return (p[0] << 8) | p[1];
296 	}
297     }
298 }
299 
300 
301 #define SEXTB(x) (((x & 0xff) ^ (~ 0x7f)) + 0x80)
302 #define SEXTW(y) ((int)((short)y))
303 
304 static int
305 IOMEM (int addr, int write, int value)
306 {
307 }
308 
309 /* Default to a 8 Mbyte (== 2^23) memory space.  */
310 static int sim_memory_size = 1 << 23;
311 
312 #define	MEM_SIZE_FLOOR	64
313 void
314 sim_size (int size)
315 {
316   sim_memory_size = size;
317   CPU.msize = sim_memory_size;
318 
319   if (CPU.memory)
320     free (CPU.memory);
321 
322   CPU.memory = (unsigned char *) calloc (1, CPU.msize);
323 
324   if (!CPU.memory)
325     {
326       if (issue_messages)
327 	fprintf (stderr,
328 		 "Not enough VM for simulation of %d bytes of RAM\n",
329 		 CPU.msize);
330 
331       CPU.msize = 1;
332       CPU.memory = (unsigned char *) calloc (1, 1);
333     }
334 }
335 
336 static void
337 init_pointers ()
338 {
339   if (CPU.msize != (sim_memory_size))
340     sim_size (sim_memory_size);
341 }
342 
343 static void
344 set_initial_gprs ()
345 {
346   int i;
347   long space;
348   unsigned long memsize;
349 
350   init_pointers ();
351 
352   /* Set up machine just out of reset.  */
353   PC = 0;
354   MSR = 0;
355 
356   memsize = CPU.msize / (1024 * 1024);
357 
358   if (issue_messages > 1)
359     fprintf (stderr, "Simulated memory of %d Mbytes (0x0 .. 0x%08x)\n",
360 	     memsize, CPU.msize - 1);
361 
362   /* Clean out the GPRs */
363   for (i = 0; i < 32; i++)
364     CPU.regs[i] = 0;
365   CPU.insts = 0;
366   CPU.cycles = 0;
367   CPU.imm_enable = 0;
368 
369 }
370 
371 static void
372 interrupt ()
373 {
374   CPU.exception = SIGINT;
375 }
376 
377 /* Functions so that trapped open/close don't interfere with the
378    parent's functions.  We say that we can't close the descriptors
379    that we didn't open.  exit() and cleanup() get in trouble here,
380    to some extent.  That's the price of emulation.  */
381 
382 unsigned char opened[100];
383 
384 static void
385 log_open (int fd)
386 {
387   if (fd < 0 || fd > NUM_ELEM (opened))
388     return;
389 
390   opened[fd] = 1;
391 }
392 
393 static void
394 log_close (int fd)
395 {
396   if (fd < 0 || fd > NUM_ELEM (opened))
397     return;
398 
399   opened[fd] = 0;
400 }
401 
402 static int
403 is_opened (int fd)
404 {
405   if (fd < 0 || fd > NUM_ELEM (opened))
406     return 0;
407 
408   return opened[fd];
409 }
410 
411 static void
412 handle_trap1 ()
413 {
414 }
415 
416 static void
417 process_stub (int what)
418 {
419   /* These values should match those in libgloss/microblaze/syscalls.s.  */
420   switch (what)
421     {
422     case 3:  /* _read */
423     case 4:  /* _write */
424     case 5:  /* _open */
425     case 6:  /* _close */
426     case 10: /* _unlink */
427     case 19: /* _lseek */
428     case 43: /* _times */
429       handle_trap1 ();
430       break;
431 
432     default:
433       if (issue_messages)
434 	fprintf (stderr, "Unhandled stub opcode: %d\n", what);
435       break;
436     }
437 }
438 
439 static void
440 util (unsigned what)
441 {
442   switch (what)
443     {
444     case 0:	/* exit */
445       CPU.exception = SIGQUIT;
446       break;
447 
448     case 1:	/* printf */
449       {
450 	unsigned long a[6];
451 	unsigned char *s;
452 	int i;
453 
454 	for (s = (unsigned char *)a[0], i = 1 ; *s && i < 6 ; s++)
455 	  if (*s == '%')
456 	    i++;
457       }
458       break;
459 
460     case 2:	/* scanf */
461       if (issue_messages)
462 	fprintf (stderr, "WARNING: scanf unimplemented\n");
463       break;
464 
465     case 3:	/* utime */
466       break;
467 
468     case 0xFF:
469       process_stub (CPU.regs[1]);
470       break;
471 
472     default:
473       if (issue_messages)
474 	fprintf (stderr, "Unhandled util code: %x\n", what);
475       break;
476     }
477 }
478 
479 /* For figuring out whether we carried; addc/subc use this. */
480 static int
481 iu_carry (unsigned long a, unsigned long b, int cin)
482 {
483   unsigned long	x;
484 
485   x = (a & 0xffff) + (b & 0xffff) + cin;
486   x = (x >> 16) + (a >> 16) + (b >> 16);
487   x >>= 16;
488 
489   return (x != 0);
490 }
491 
492 #define WATCHFUNCTIONS 1
493 #ifdef WATCHFUNCTIONS
494 
495 #define MAXWL 80
496 word WL[MAXWL];
497 char *WLstr[MAXWL];
498 
499 int ENDWL=0;
500 int WLincyc;
501 int WLcyc[MAXWL];
502 int WLcnts[MAXWL];
503 int WLmax[MAXWL];
504 int WLmin[MAXWL];
505 word WLendpc;
506 int WLbcyc;
507 int WLW;
508 #endif
509 
510 static int tracing = 0;
511 
512 void
513 sim_resume (SIM_DESC sd, int step, int siggnal)
514 {
515   int needfetch;
516   word inst;
517   enum microblaze_instr op;
518   void (*sigsave)();
519   int memops;
520   int bonus_cycles;
521   int insts;
522   int w;
523   int cycs;
524   word WLhash;
525   ubyte carry;
526   int imm_unsigned;
527   short ra, rb, rd;
528   long immword;
529   uword oldpc, newpc;
530   short delay_slot_enable;
531   short branch_taken;
532   short num_delay_slot; /* UNUSED except as reqd parameter */
533   enum microblaze_instr_type insn_type;
534 
535   sigsave = signal (SIGINT, interrupt);
536   CPU.exception = step ? SIGTRAP : 0;
537 
538   memops = 0;
539   bonus_cycles = 0;
540   insts = 0;
541 
542   do
543     {
544       /* Fetch the initial instructions that we'll decode. */
545       inst = rlat (PC & 0xFFFFFFFC);
546 
547       op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
548 				&num_delay_slot);
549 
550       if (op == invalid_inst)
551 	fprintf (stderr, "Unknown instruction 0x%04x", inst);
552 
553       if (tracing)
554 	fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
555 
556       rd = GET_RD;
557       rb = GET_RB;
558       ra = GET_RA;
559       /*      immword = IMM_W; */
560 
561       oldpc = PC;
562       delay_slot_enable = 0;
563       branch_taken = 0;
564       if (op == microblaze_brk)
565 	CPU.exception = SIGTRAP;
566       else if (inst == MICROBLAZE_HALT_INST)
567 	{
568 	  CPU.exception = SIGQUIT;
569 	  insts += 1;
570 	  bonus_cycles++;
571 	}
572       else
573 	{
574 	  switch(op)
575 	    {
576 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION)		\
577 	    case NAME:					\
578 	      ACTION;					\
579 	      break;
580 #include "microblaze.isa"
581 #undef INSTRUCTION
582 
583 	    default:
584 	      CPU.exception = SIGILL;
585 	      fprintf (stderr, "ERROR: Unknown opcode\n");
586 	    }
587 	  /* Make R0 consistent */
588 	  CPU.regs[0] = 0;
589 
590 	  /* Check for imm instr */
591 	  if (op == imm)
592 	    IMM_ENABLE = 1;
593 	  else
594 	    IMM_ENABLE = 0;
595 
596 	  /* Update cycle counts */
597 	  insts ++;
598 	  if (insn_type == memory_store_inst || insn_type == memory_load_inst)
599 	    memops++;
600 	  if (insn_type == mult_inst)
601 	    bonus_cycles++;
602 	  if (insn_type == barrel_shift_inst)
603 	    bonus_cycles++;
604 	  if (insn_type == anyware_inst)
605 	    bonus_cycles++;
606 	  if (insn_type == div_inst)
607 	    bonus_cycles += 33;
608 
609 	  if ((insn_type == branch_inst || insn_type == return_inst)
610 	      && branch_taken)
611 	    {
612 	      /* Add an extra cycle for taken branches */
613 	      bonus_cycles++;
614 	      /* For branch instructions handle the instruction in the delay slot */
615 	      if (delay_slot_enable)
616 	        {
617 	          newpc = PC;
618 	          PC = oldpc + INST_SIZE;
619 	          inst = rlat (PC & 0xFFFFFFFC);
620 	          op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
621 					    &num_delay_slot);
622 	          if (op == invalid_inst)
623 		    fprintf (stderr, "Unknown instruction 0x%04x", inst);
624 	          if (tracing)
625 		    fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
626 	          rd = GET_RD;
627 	          rb = GET_RB;
628 	          ra = GET_RA;
629 	          /*	      immword = IMM_W; */
630 	          if (op == microblaze_brk)
631 		    {
632 		      if (issue_messages)
633 		        fprintf (stderr, "Breakpoint set in delay slot "
634 			         "(at address 0x%x) will not be honored\n", PC);
635 		      /* ignore the breakpoint */
636 		    }
637 	          else if (insn_type == branch_inst || insn_type == return_inst)
638 		    {
639 		      if (issue_messages)
640 		        fprintf (stderr, "Cannot have branch or return instructions "
641 			         "in delay slot (at address 0x%x)\n", PC);
642 		      CPU.exception = SIGILL;
643 		    }
644 	          else
645 		    {
646 		      switch(op)
647 		        {
648 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION)		\
649 		        case NAME:			\
650 			  ACTION;			\
651 			  break;
652 #include "microblaze.isa"
653 #undef INSTRUCTION
654 
655 		        default:
656 		          CPU.exception = SIGILL;
657 		          fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
658 		        }
659 		      /* Update cycle counts */
660 		      insts++;
661 		      if (insn_type == memory_store_inst
662 		          || insn_type == memory_load_inst)
663 		        memops++;
664 		      if (insn_type == mult_inst)
665 		        bonus_cycles++;
666 		      if (insn_type == barrel_shift_inst)
667 		        bonus_cycles++;
668 		      if (insn_type == anyware_inst)
669 		        bonus_cycles++;
670 		      if (insn_type == div_inst)
671 		        bonus_cycles += 33;
672 		    }
673 	          /* Restore the PC */
674 	          PC = newpc;
675 	          /* Make R0 consistent */
676 	          CPU.regs[0] = 0;
677 	          /* Check for imm instr */
678 	          if (op == imm)
679 		    IMM_ENABLE = 1;
680 	          else
681 		    IMM_ENABLE = 0;
682 	        }
683 	      else
684 		/* no delay slot: increment cycle count */
685 		bonus_cycles++;
686 	    }
687 	}
688 
689       if (tracing)
690 	fprintf (stderr, "\n");
691     }
692   while (!CPU.exception);
693 
694   /* Hide away the things we've cached while executing.  */
695   /*  CPU.pc = pc; */
696   CPU.insts += insts;		/* instructions done ... */
697   CPU.cycles += insts;		/* and each takes a cycle */
698   CPU.cycles += bonus_cycles;	/* and extra cycles for branches */
699   CPU.cycles += memops; 	/* and memop cycle delays */
700 
701   signal (SIGINT, sigsave);
702 }
703 
704 
705 int
706 sim_write (SIM_DESC sd, SIM_ADDR addr, const unsigned char *buffer, int size)
707 {
708   int i;
709   init_pointers ();
710 
711   memcpy (&CPU.memory[addr], buffer, size);
712 
713   return size;
714 }
715 
716 int
717 sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
718 {
719   int i;
720   init_pointers ();
721 
722   memcpy (buffer, &CPU.memory[addr], size);
723 
724   return size;
725 }
726 
727 
728 int
729 sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
730 {
731   init_pointers ();
732 
733   if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
734     {
735       if (length == 4)
736 	{
737 	  /* misalignment safe */
738 	  long ival = microblaze_extract_unsigned_integer (memory, 4);
739 	  if (rn < NUM_REGS)
740 	    CPU.regs[rn] = ival;
741 	  else
742 	    CPU.spregs[rn-NUM_REGS] = ival;
743 	  return 4;
744 	}
745       else
746 	return 0;
747     }
748   else
749     return 0;
750 }
751 
752 int
753 sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
754 {
755   long ival;
756   init_pointers ();
757 
758   if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
759     {
760       if (length == 4)
761 	{
762 	  if (rn < NUM_REGS)
763 	    ival = CPU.regs[rn];
764 	  else
765 	    ival = CPU.spregs[rn-NUM_REGS];
766 
767 	  /* misalignment-safe */
768 	  microblaze_store_unsigned_integer (memory, 4, ival);
769 	  return 4;
770 	}
771       else
772 	return 0;
773     }
774   else
775     return 0;
776 }
777 
778 
779 int
780 sim_trace (SIM_DESC sd)
781 {
782   tracing = 1;
783 
784   sim_resume (sd, 0, 0);
785 
786   tracing = 0;
787 
788   return 1;
789 }
790 
791 void
792 sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc)
793 {
794   if (CPU.exception == SIGQUIT)
795     {
796       *reason = sim_exited;
797       *sigrc = RETREG;
798     }
799   else
800     {
801       *reason = sim_stopped;
802       *sigrc = CPU.exception;
803     }
804 }
805 
806 
807 int
808 sim_stop (SIM_DESC sd)
809 {
810   CPU.exception = SIGINT;
811   return 1;
812 }
813 
814 
815 void
816 sim_info (SIM_DESC sd, int verbose)
817 {
818 #ifdef WATCHFUNCTIONS
819   int w, wcyc;
820 #endif
821 
822   callback->printf_filtered (callback, "\n\n# instructions executed  %10d\n",
823 			     CPU.insts);
824   callback->printf_filtered (callback, "# cycles                 %10d\n",
825 			     (CPU.cycles) ? CPU.cycles+2 : 0);
826 
827 #ifdef WATCHFUNCTIONS
828   callback->printf_filtered (callback, "\nNumber of watched functions: %d\n",
829 			     ENDWL);
830 
831   wcyc = 0;
832 
833   for (w = 1; w <= ENDWL; w++)
834     {
835       callback->printf_filtered (callback, "WL = %s %8x\n",WLstr[w],WL[w]);
836       callback->printf_filtered (callback, "  calls = %d, cycles = %d\n",
837 				 WLcnts[w],WLcyc[w]);
838 
839       if (WLcnts[w] != 0)
840 	callback->printf_filtered (callback,
841 				   "  maxcpc = %d, mincpc = %d, avecpc = %d\n",
842 				   WLmax[w],WLmin[w],WLcyc[w]/WLcnts[w]);
843       wcyc += WLcyc[w];
844     }
845 
846   callback->printf_filtered (callback,
847 			     "Total cycles for watched functions: %d\n",wcyc);
848 #endif
849 }
850 
851 struct	aout
852 {
853   unsigned char  sa_machtype[2];
854   unsigned char  sa_magic[2];
855   unsigned char  sa_tsize[4];
856   unsigned char  sa_dsize[4];
857   unsigned char  sa_bsize[4];
858   unsigned char  sa_syms[4];
859   unsigned char  sa_entry[4];
860   unsigned char  sa_trelo[4];
861   unsigned char  sa_drelo[4];
862 } aout;
863 
864 #define	LONG(x)		(((x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
865 #define	SHORT(x)	(((x)[0]<<8)|(x)[1])
866 
867 SIM_DESC
868 sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
869 {
870   /*  SIM_DESC sd = sim_state_alloc(kind, alloc);*/
871 
872   int osize = sim_memory_size;
873   myname = argv[0];
874   callback = cb;
875 
876   if (kind == SIM_OPEN_STANDALONE)
877     issue_messages = 1;
878 
879   /* Discard and reacquire memory -- start with a clean slate.  */
880   sim_size (1);		/* small */
881   sim_size (osize);	/* and back again */
882 
883   set_initial_gprs ();	/* Reset the GPR registers.  */
884 
885   return ((SIM_DESC) 1);
886 }
887 
888 void
889 sim_close (SIM_DESC sd, int quitting)
890 {
891   if (CPU.memory)
892     {
893       free(CPU.memory);
894       CPU.memory = NULL;
895       CPU.msize = 0;
896     }
897 }
898 
899 SIM_RC
900 sim_load (SIM_DESC sd, char *prog, bfd *abfd, int from_tty)
901 {
902   /* Do the right thing for ELF executables; this turns out to be
903      just about the right thing for any object format that:
904        - we crack using BFD routines
905        - follows the traditional UNIX text/data/bss layout
906        - calls the bss section ".bss".   */
907 
908   extern bfd *sim_load_file (); /* ??? Don't know where this should live.  */
909   bfd *prog_bfd;
910 
911   {
912     bfd *handle;
913     asection *s;
914     int found_loadable_section = 0;
915     bfd_vma max_addr = 0;
916     handle = bfd_openr (prog, 0);
917 
918     if (!handle)
919       {
920 	printf("``%s'' could not be opened.\n", prog);
921 	return SIM_RC_FAIL;
922       }
923 
924     /* Makes sure that we have an object file, also cleans gets the
925        section headers in place.  */
926     if (!bfd_check_format (handle, bfd_object))
927       {
928 	/* wasn't an object file */
929 	bfd_close (handle);
930 	printf ("``%s'' is not appropriate object file.\n", prog);
931 	return SIM_RC_FAIL;
932       }
933 
934     for (s = handle->sections; s; s = s->next)
935       {
936 	if (s->flags & SEC_ALLOC)
937 	  {
938 	    bfd_vma vma = 0;
939 	    int size = bfd_get_section_size (s);
940 	    if (size > 0)
941 	      {
942 		vma = bfd_section_vma (handle, s);
943 		if (vma >= max_addr)
944 		  {
945 		    max_addr = vma + size;
946 		  }
947 	      }
948 	    if (s->flags & SEC_LOAD)
949 	      found_loadable_section = 1;
950 	  }
951       }
952 
953     if (!found_loadable_section)
954       {
955 	/* No loadable sections */
956 	bfd_close(handle);
957 	printf("No loadable sections in file %s\n", prog);
958 	return SIM_RC_FAIL;
959       }
960 
961     sim_memory_size = (unsigned long) max_addr;
962 
963     /* Clean up after ourselves.  */
964     bfd_close (handle);
965 
966   }
967 
968   /* from sh -- dac */
969   prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
970 			    /* sim_kind == SIM_OPEN_DEBUG, */
971 			    1,
972 			    0, sim_write);
973   if (prog_bfd == NULL)
974     return SIM_RC_FAIL;
975 
976   target_big_endian = bfd_big_endian (prog_bfd);
977   PC = bfd_get_start_address (prog_bfd);
978 
979   if (abfd == NULL)
980     bfd_close (prog_bfd);
981 
982   return SIM_RC_OK;
983 }
984 
985 SIM_RC
986 sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
987 {
988   char **avp;
989   int nargs = 0;
990   int nenv = 0;
991   int s_length;
992   int l;
993   unsigned long strings;
994   unsigned long pointers;
995   unsigned long hi_stack;
996 
997 
998   /* Set the initial register set.  */
999   l = issue_messages;
1000   issue_messages = 0;
1001   set_initial_gprs ();
1002   issue_messages = l;
1003 
1004   hi_stack = CPU.msize - 4;
1005   PC = bfd_get_start_address (prog_bfd);
1006 
1007   /* For now ignore all parameters to the program */
1008 
1009   return SIM_RC_OK;
1010 }
1011 
1012 void
1013 sim_kill (SIM_DESC sd)
1014 {
1015   /* nothing to do */
1016 }
1017 
1018 void
1019 sim_do_command (SIM_DESC sd, char * cmd)
1020 {
1021   /* Nothing there yet; it's all an error.  */
1022 
1023   if (cmd != NULL)
1024     {
1025       char ** simargv = buildargv (cmd);
1026 
1027       if (strcmp (simargv[0], "watch") == 0)
1028 	{
1029 	  if ((simargv[1] == NULL) || (simargv[2] == NULL))
1030 	    {
1031 	      fprintf (stderr, "Error: missing argument to watch cmd.\n");
1032 	      return;
1033 	    }
1034 
1035 	  ENDWL++;
1036 
1037 	  WL[ENDWL] = strtol (simargv[2], NULL, 0);
1038 	  WLstr[ENDWL] = strdup (simargv[1]);
1039 	  fprintf (stderr, "Added %s (%x) to watchlist, #%d\n",WLstr[ENDWL],
1040 		   WL[ENDWL], ENDWL);
1041 
1042 	}
1043       else if (strcmp (simargv[0], "dumpmem") == 0)
1044 	{
1045 	  unsigned char * p;
1046 	  FILE * dumpfile;
1047 
1048 	  if (simargv[1] == NULL)
1049 	    fprintf (stderr, "Error: missing argument to dumpmem cmd.\n");
1050 
1051 	  fprintf (stderr, "Writing dumpfile %s...",simargv[1]);
1052 
1053 	  dumpfile = fopen (simargv[1], "w");
1054 	  p = CPU.memory;
1055 	  fwrite (p, CPU.msize-1, 1, dumpfile);
1056 	  fclose (dumpfile);
1057 
1058 	  fprintf (stderr, "done.\n");
1059 	}
1060       else if (strcmp (simargv[0], "clearstats") == 0)
1061 	{
1062 	  CPU.cycles = 0;
1063 	  CPU.insts = 0;
1064 	  ENDWL = 0;
1065 	}
1066       else if (strcmp (simargv[0], "verbose") == 0)
1067 	{
1068 	  issue_messages = 2;
1069 	}
1070       else
1071 	{
1072 	  fprintf (stderr,"Error: \"%s\" is not a valid M.CORE simulator command.\n",
1073 		   cmd);
1074 	}
1075     }
1076   else
1077     {
1078       fprintf (stderr, "M.CORE sim commands: \n");
1079       fprintf (stderr, "  watch <funcname> <addr>\n");
1080       fprintf (stderr, "  dumpmem <filename>\n");
1081       fprintf (stderr, "  clearstats\n");
1082       fprintf (stderr, "  verbose\n");
1083     }
1084 }
1085 
1086 void
1087 sim_set_callbacks (host_callback *ptr)
1088 {
1089   callback = ptr;
1090 }
1091 
1092 char **
1093 sim_complete_command (SIM_DESC sd, const char *text, const char *word)
1094 {
1095   return NULL;
1096 }
1097