-/* Simulator for Motorolla's MCore processor
- Copyright (C) 1999 Free Software Foundation, Inc.
+/* Simulator for Motorola's MCore processor
+ Copyright (C) 1999, 2000, 2002, 2003, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <signal.h>
#include "sysdep.h"
#include <sys/param.h>
#include <netinet/in.h> /* for byte ordering macros */
#include "bfd.h"
-#include "callback.h"
+#include "gdb/callback.h"
#include "libiberty.h"
-#include "remote-sim.h"
+#include "gdb/remote-sim.h"
#ifndef NUM_ELEM
#define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0])
typedef long int word;
typedef unsigned long int uword;
+static int target_big_endian = 0;
static unsigned long heap_ptr = 0;
host_callback * callback;
-#define TARGET_BYTE_ORDER BIG_ENDIAN /* XXX */
-
unsigned long
mcore_extract_unsigned_integer (addr, len)
unsigned char * addr;
/* Start at the most significant end of the integer, and work towards
the least significant. */
retval = 0;
- for (p = startaddr; p < endaddr; ++p)
- retval = (retval << 8) | * p;
+
+ if (! target_big_endian)
+ {
+ for (p = endaddr; p > startaddr;)
+ retval = (retval << 8) | * -- p;
+ }
+ else
+ {
+ for (p = startaddr; p < endaddr;)
+ retval = (retval << 8) | * p ++;
+ }
return retval;
}
unsigned char * p;
unsigned char * startaddr = (unsigned char *)addr;
unsigned char * endaddr = startaddr + len;
-
- /* Start at the least significant end of the integer, and work towards
- the most significant. */
- for (p = endaddr - 1; p >= startaddr; --p)
+
+ if (! target_big_endian)
{
- * p = val & 0xff;
- val >>= 8;
+ for (p = startaddr; p < endaddr;)
+ {
+ * p ++ = val & 0xff;
+ val >>= 8;
+ }
+ }
+ else
+ {
+ for (p = endaddr; p > startaddr;)
+ {
+ * -- p = val & 0xff;
+ val >>= 8;
+ }
}
}
/* The machine state.
This state is maintained in host byte order. The
fetch/store register functions must translate between host
- byte order and the target processor byte order (for MCore this
- is big-endian). Since we know that the MCore is always big-endian,
- we cheat a bit and use the ntohl() and htonl() macros to
- achieve this end.
-
+ byte order and the target processor byte order.
Keeping this data in target byte order simplifies the register
read/write functions. Keeping this data in native order improves
the performance of the simulator. Simulation speed is deemed more
- important. */
+ important. */
/* The ordering of the mcore_regset structure is matched in the
gdb/config/mcore/tm-mcore.h file in the REGISTER_NAMES macro. */
word asints [1]; /* but accessed larger... */
} cpu;
-#define LAST_VALID_CREG 12 /* only 0..12 implemented */
-#define NUM_MCORE_REGS (16 + 16 + LAST_VALID_CREG)
+#define LAST_VALID_CREG 32 /* only 0..12 implemented */
+#define NUM_MCORE_REGS (16 + 16 + LAST_VALID_CREG + 1)
int memcycles = 1;
#define mem asregs.memory
/* maniuplate the carry bit */
-#define C_ON() (cpu.sr & 1)
+#define C_ON() (cpu.sr & 1)
#define C_VALUE() (cpu.sr & 1)
-#define C_OFF() ((cpu.sr & 1) == 0)
-#define SET_C() {cpu.sr |= 1;}
-#define CLR_C() {cpu.sr &= 0xfffffffe;}
-#define NEW_C(v){CLR_C(); cpu.sr |= ((v) & 1);}
+#define C_OFF() ((cpu.sr & 1) == 0)
+#define SET_C() {cpu.sr |= 1;}
+#define CLR_C() {cpu.sr &= 0xfffffffe;}
+#define NEW_C(v) {CLR_C(); cpu.sr |= ((v) & 1);}
#define SR_AF() ((cpu.sr >> 1) & 1)
cpu.asregs.exception = SIGBUS;
}
+ else if (! target_big_endian)
+ {
+ unsigned char * p = cpu.mem + x;
+ p[3] = v >> 24;
+ p[2] = v >> 16;
+ p[1] = v >> 8;
+ p[0] = v;
+ }
else
{
unsigned char * p = cpu.mem + x;
if ((x & 1) != 0)
{
if (issue_messages)
- fprintf (stderr, "short write to unaligned memory address: 0x%x\n", x);
+ fprintf (stderr, "short write to unaligned memory address: 0x%x\n",
+ x);
cpu.asregs.exception = SIGBUS;
}
+ else if (! target_big_endian)
+ {
+ unsigned char * p = cpu.mem + x;
+ p[1] = v >> 8;
+ p[0] = v;
+ }
else
{
unsigned char * p = cpu.mem + x;
}
}
-/* Read functions */
+/* Read functions. */
static int INLINE
rbat (x)
word x;
cpu.asregs.exception = SIGBUS;
return 0;
}
+ else if (! target_big_endian)
+ {
+ unsigned char * p = cpu.mem + x;
+ return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
+ }
else
{
unsigned char * p = cpu.mem + x;
cpu.asregs.exception = SIGBUS;
return 0;
}
+ else if (! target_big_endian)
+ {
+ unsigned char * p = cpu.mem + x;
+ return (p[1] << 8) | p[0];
+ }
else
{
unsigned char * p = cpu.mem + x;
{
}
-/* default to a 8 Mbyte (== 2^23) memory space */
+/* Default to a 8 Mbyte (== 2^23) memory space. */
static int sim_memory_size = 23;
#define MEM_SIZE_FLOOR 64
if (cpu.mem)
free (cpu.mem);
- /* watch out for the '0 count' problem. There's probably a better
- way.. e.g., why do we use 64 here? */
- if (cpu.asregs.msize < 64) /* ensure a boundary */
+ /* Watch out for the '0 count' problem. There's probably a better
+ way.. e.g., why do we use 64 here? */
+ if (cpu.asregs.msize < 64) /* Ensure a boundary. */
cpu.mem = (unsigned char *) calloc (64, (64 + cpu.asregs.msize) / 64);
else
cpu.mem = (unsigned char *) calloc (64, cpu.asregs.msize / 64);
{
if (issue_messages)
fprintf (stderr,
- "Not enough VM for simulation of %d bytes of RAM\n", cpu.asregs.msize);
+ "Not enough VM for simulation of %d bytes of RAM\n",
+ cpu.asregs.msize);
cpu.asregs.msize = 1;
cpu.mem = (unsigned char *) calloc (1, 1);
{
unsigned long a[3];
- switch ((unsigned long) (cpu.gr[TRAPCODE]))
+ switch ((unsigned long) (cpu.gr [TRAPCODE]))
{
case 3:
a[0] = (unsigned long) (cpu.gr[PARM1]);
break;
case 6:
- a[0] = (unsigned long) (cpu.gr[4]);
+ a[0] = (unsigned long) (cpu.gr[PARM1]);
/* Watch out for debugger's files. */
if (is_opened (a[0]))
{
default:
if (issue_messages)
- fprintf (stderr, "WARNING: sys call %d unimplemented\n", cpu.gr[TRAPCODE]);
+ fprintf (stderr, "WARNING: sys call %d unimplemented\n",
+ cpu.gr[TRAPCODE]);
break;
}
}
switch (what)
{
case 3: /* _read */
+ case 4: /* _write */
case 5: /* _open */
case 6: /* _close */
case 10: /* _unlink */
break;
case 0xFF:
- process_stub (what);
+ process_stub (cpu.gr[1]);
break;
default:
cpu.asregs.exception = step ? SIGTRAP: 0;
pc = cpu.asregs.pc;
- /* fetch the initial instructions that we'll decode */
+ /* Fetch the initial instructions that we'll decode. */
ibuf = rlat (pc & 0xFFFFFFFC);
needfetch = 0;
do
{
+ word oldpc;
+
insts ++;
if (pc & 02)
{
- inst = ibuf & 0xFFFF;
+ if (! target_big_endian)
+ inst = ibuf >> 16;
+ else
+ inst = ibuf & 0xFFFF;
needfetch = 1;
}
else
{
- inst = ibuf >> 16;
+ if (! target_big_endian)
+ inst = ibuf & 0xFFFF;
+ else
+ inst = ibuf >> 16;
}
#ifdef WATCHFUNCTIONS
WLendpc = 0;
}
- /* optimize with a hash to speed loop */
+ /* Optimize with a hash to speed loop. */
if (WLincyc == 0)
{
if ((WLhash == 0) || ((WLhash & pc) != 0))
if (tracing)
fprintf (stderr, "%.4x: inst = %.4x ", pc, inst);
-
+
+ oldpc = pc;
+
pc += 2;
switch (inst >> 8)
{
case 0x0: /* bkpt */
cpu.asregs.exception = SIGTRAP;
+ pc -= 2;
break;
case 0x1: /* sync */
cpu.sr = cpu.esr;
needfetch = 1;
- if (SR_AF())
+ if (SR_AF ())
cpu.asregs.active_gregs = & cpu.asregs.alt_gregs[0];
else
cpu.asregs.active_gregs = & cpu.asregs.gregs[0];
case 0x6: /* doze */
if (issue_messages)
- fprintf (stderr, "WARNING: oze unimplemented\n");
+ fprintf (stderr, "WARNING: doze unimplemented\n");
break;
case 0x7:
break;
case 0xC: /* jmp */
pc = cpu.gr[RD];
+ if (tracing && RD == 15)
+ fprintf (stderr, "Func return, r2 = %x, r3 = %x\n",
+ cpu.gr[2], cpu.gr[3]);
bonus_cycles++;
needfetch = 1;
break;
bonus_cycles += ticks;
}
bonus_cycles += 2; /* min. is 3, so add 2, plus ticks above */
+ if (tracing)
+ fprintf (stderr, " mult %x by %x to give %x",
+ cpu.gr[RD], cpu.gr[RS], cpu.gr[RD] * cpu.gr[RS]);
cpu.gr[RD] = cpu.gr[RD] * cpu.gr[RS];
break;
case 0x04: /* loopt */
unsigned long dst, src;
dst = cpu.gr[RD];
src = cpu.gr[RS];
- dst = dst >> src;
+ /* We must not rely solely upon the native shift operations, since they
+ may not match the M*Core's behaviour on boundary conditions. */
+ dst = src > 31 ? 0 : dst >> src;
cpu.gr[RD] = dst;
}
break;
case 0x12: /* mov */
cpu.gr[RD] = cpu.gr[RS];
+ if (tracing)
+ fprintf (stderr, "MOV %x into reg %d", cpu.gr[RD], RD);
break;
case 0x13: /* bgenr */
break;
case 0x1A: /* asr */
- cpu.gr[RD] = (long)cpu.gr[RD] >> cpu.gr[RS];
+ /* We must not rely solely upon the native shift operations, since they
+ may not match the M*Core's behaviour on boundary conditions. */
+ if (cpu.gr[RS] > 30)
+ cpu.gr[RD] = ((long) cpu.gr[RD]) < 0 ? -1 : 0;
+ else
+ cpu.gr[RD] = (long) cpu.gr[RD] >> cpu.gr[RS];
break;
case 0x1B: /* lsl */
- cpu.gr[RD] = cpu.gr[RD] << cpu.gr[RS];
+ /* We must not rely solely upon the native shift operations, since they
+ may not match the M*Core's behaviour on boundary conditions. */
+ cpu.gr[RD] = cpu.gr[RS] > 31 ? 0 : cpu.gr[RD] << cpu.gr[RS];
break;
case 0x1C: /* addu */
break;
case 0x7F: /* jsri */
cpu.gr[15] = pc;
+ if (tracing)
+ fprintf (stderr, "func call: r2 = %x r3 = %x r4 = %x r5 = %x r6 = %x r7 = %x\n",
+ cpu.gr[2], cpu.gr[3], cpu.gr[4], cpu.gr[5], cpu.gr[6], cpu.gr[7]);
case 0x70: /* jmpi */
pc = rlat ((pc + ((inst & 0xFF) << 2)) & 0xFFFFFFFC);
memops++;
if (tracing)
fprintf (stderr, "\n");
-
+
if (needfetch)
{
/* Do not let him fetch from a bad address! */
if (((uword)pc) >= cpu.asregs.msize)
{
if (issue_messages)
- fprintf (stderr, "PC outside of available memory! (%x)\n", pc);
+ fprintf (stderr, "PC loaded at 0x%x is outside of available memory! (0x%x)\n", oldpc, pc);
cpu.asregs.exception = SIGSEGV;
}
sim_write (sd, addr, buffer, size)
SIM_DESC sd;
SIM_ADDR addr;
- unsigned char * buffer;
+ const unsigned char * buffer;
int size;
{
int i;
{
if (length == 4)
{
- /* ival is in 'target' order, which we know to be big-endian.
- Let's convert it to natural order. */
long ival;
-
- ival = mcore_extract_unsigned_integer (memory, 4);/* misalignment safe */
+
+ /* misalignment safe */
+ ival = mcore_extract_unsigned_integer (memory, 4);
cpu.asints[rn] = ival;
}
{
if (length == 4)
{
- /* caller expects 'target order', which is big-endian. Convert
- * the native order we used [to speed up simulation] to the
- * byte order expected by the caller. */
long ival = cpu.asints[rn];
- mcore_store_unsigned_integer (memory, 4, ival);/* misalignment-safe */
+
+ /* misalignment-safe */
+ mcore_store_unsigned_integer (memory, 4, ival);
}
return 4;
#endif
double virttime = cpu.asregs.cycles / 36.0e6;
- callback->printf_filtered (callback, "\n\n# instructions executed %10d\n", cpu.asregs.insts);
- callback->printf_filtered (callback, "# cycles %10d\n", cpu.asregs.cycles);
- callback->printf_filtered (callback, "# pipeline stalls %10d\n", cpu.asregs.stalls);
- callback->printf_filtered (callback, "# virtual time taken %10.4f\n", virttime);
+ callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
+ cpu.asregs.insts);
+ callback->printf_filtered (callback, "# cycles %10d\n",
+ cpu.asregs.cycles);
+ callback->printf_filtered (callback, "# pipeline stalls %10d\n",
+ cpu.asregs.stalls);
+ callback->printf_filtered (callback, "# virtual time taken %10.4f\n",
+ virttime);
#ifdef WATCHFUNCTIONS
- callback->printf_filtered (callback, "\nNumber of watched functions: %d\n",ENDWL);
+ callback->printf_filtered (callback, "\nNumber of watched functions: %d\n",
+ ENDWL);
wcyc = 0;
for (w = 1; w <= ENDWL; w++)
{
callback->printf_filtered (callback, "WL = %s %8x\n",WLstr[w],WL[w]);
- callback->printf_filtered (callback, " calls = %d, cycles = %d\n", WLcnts[w],WLcyc[w]);
+ callback->printf_filtered (callback, " calls = %d, cycles = %d\n",
+ WLcnts[w],WLcyc[w]);
if (WLcnts[w] != 0)
- callback->printf_filtered (callback, " maxcpc = %d, mincpc = %d, avecpc = %d\n",WLmax[w],WLmin[w],WLcyc[w]/WLcnts[w]);
+ callback->printf_filtered (callback,
+ " maxcpc = %d, mincpc = %d, avecpc = %d\n",
+ WLmax[w],WLmin[w],WLcyc[w]/WLcnts[w]);
wcyc += WLcyc[w];
}
- callback->printf_filtered (callback, "Total cycles for watched functions: %d\n",wcyc);
+ callback->printf_filtered (callback,
+ "Total cycles for watched functions: %d\n",wcyc);
#endif
}
sim_open (kind, cb, abfd, argv)
SIM_OPEN_KIND kind;
host_callback * cb;
- struct _bfd * abfd;
+ struct bfd * abfd;
char ** argv;
{
int osize = sim_memory_size;
printf ("``%s'' is not appropriate object file.\n", prog);
return SIM_RC_FAIL;
}
-
+
/* Look for that bss section. */
s_bss = bfd_get_section_by_name (handle, ".bss");
/* figure the end of the bss section */
#if 0
printf ("bss section at 0x%08x for 0x%08x bytes\n",
- (unsigned long) s_bss->vma , (unsigned long) s_bss->_cooked_size);
+ (unsigned long) bfd_get_section_vma (handle, s_bss),
+ (unsigned long) bfd_section_size (handle, s_bss));
#endif
- heap_ptr = (unsigned long) s_bss->vma + (unsigned long) s_bss->_cooked_size;
+ heap_ptr = ((unsigned long) bfd_get_section_vma (handle, s_bss)
+ + (unsigned long) bfd_section_size (handle, s_bss));
/* Clean up after ourselves. */
bfd_close (handle);
if (prog_bfd == NULL)
return SIM_RC_FAIL;
+ target_big_endian = bfd_big_endian (prog_bfd);
+
if (abfd == NULL)
bfd_close (prog_bfd);
SIM_RC
sim_create_inferior (sd, prog_bfd, argv, env)
SIM_DESC sd;
- struct _bfd * prog_bfd;
+ struct bfd * prog_bfd;
char ** argv;
char ** env;
{