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