191ec03314
Since the sim doesn't have any debug support in it, we can only exit cleanly. But this is still better than nothing. Change the default microblaze sim to not dump the debug load output when running. No other does this, and it breaks the testsuite.
945 lines
19 KiB
C
945 lines
19 KiB
C
/* Simulator for Xilinx MicroBlaze processor
|
|
Copyright 2009-2015 Free Software Foundation, Inc.
|
|
|
|
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 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, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/times.h>
|
|
#include <sys/param.h>
|
|
#include <unistd.h>
|
|
#include "bfd.h"
|
|
#include "gdb/callback.h"
|
|
#include "libiberty.h"
|
|
#include "gdb/remote-sim.h"
|
|
#include "run-sim.h"
|
|
#include "sim-main.h"
|
|
#include "sim-utils.h"
|
|
#include "microblaze-dis.h"
|
|
|
|
|
|
#ifndef NUM_ELEM
|
|
#define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0])
|
|
#endif
|
|
|
|
static int target_big_endian = 1;
|
|
static unsigned long heap_ptr = 0;
|
|
static unsigned long stack_ptr = 0;
|
|
host_callback *callback;
|
|
|
|
static unsigned long
|
|
microblaze_extract_unsigned_integer (unsigned char *addr, int len)
|
|
{
|
|
unsigned long retval;
|
|
unsigned char *p;
|
|
unsigned char *startaddr = (unsigned char *)addr;
|
|
unsigned char *endaddr = startaddr + len;
|
|
|
|
if (len > (int) sizeof (unsigned long))
|
|
printf ("That operation is not available on integers of more than "
|
|
"%zu bytes.", sizeof (unsigned long));
|
|
|
|
/* Start at the most significant end of the integer, and work towards
|
|
the least significant. */
|
|
retval = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
static void
|
|
microblaze_store_unsigned_integer (unsigned char *addr, int len,
|
|
unsigned long val)
|
|
{
|
|
unsigned char *p;
|
|
unsigned char *startaddr = (unsigned char *)addr;
|
|
unsigned char *endaddr = startaddr + len;
|
|
|
|
if (!target_big_endian)
|
|
{
|
|
for (p = startaddr; p < endaddr;)
|
|
{
|
|
*p++ = val & 0xff;
|
|
val >>= 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (p = endaddr; p > startaddr;)
|
|
{
|
|
*--p = val & 0xff;
|
|
val >>= 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct sim_state microblaze_state;
|
|
|
|
int memcycles = 1;
|
|
|
|
static SIM_OPEN_KIND sim_kind;
|
|
static char *myname;
|
|
|
|
static int issue_messages = 0;
|
|
|
|
static void /* INLINE */
|
|
wbat (word x, word v)
|
|
{
|
|
if (((uword)x) >= CPU.msize)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "byte write to 0x%x outside memory range\n", x);
|
|
|
|
CPU.exception = SIGSEGV;
|
|
}
|
|
else
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
p[0] = v;
|
|
}
|
|
}
|
|
|
|
static void /* INLINE */
|
|
wlat (word x, word v)
|
|
{
|
|
if (((uword)x) >= CPU.msize)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "word write to 0x%x outside memory range\n", x);
|
|
|
|
CPU.exception = SIGSEGV;
|
|
}
|
|
else
|
|
{
|
|
if ((x & 3) != 0)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "word write to unaligned memory address: 0x%x\n", x);
|
|
|
|
CPU.exception = SIGBUS;
|
|
}
|
|
else if (!target_big_endian)
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
p[3] = v >> 24;
|
|
p[2] = v >> 16;
|
|
p[1] = v >> 8;
|
|
p[0] = v;
|
|
}
|
|
else
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
p[0] = v >> 24;
|
|
p[1] = v >> 16;
|
|
p[2] = v >> 8;
|
|
p[3] = v;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void /* INLINE */
|
|
what (word x, word v)
|
|
{
|
|
if (((uword)x) >= CPU.msize)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "short write to 0x%x outside memory range\n", x);
|
|
|
|
CPU.exception = SIGSEGV;
|
|
}
|
|
else
|
|
{
|
|
if ((x & 1) != 0)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "short write to unaligned memory address: 0x%x\n",
|
|
x);
|
|
|
|
CPU.exception = SIGBUS;
|
|
}
|
|
else if (!target_big_endian)
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
p[1] = v >> 8;
|
|
p[0] = v;
|
|
}
|
|
else
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
p[0] = v >> 8;
|
|
p[1] = v;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Read functions. */
|
|
static int /* INLINE */
|
|
rbat (word x)
|
|
{
|
|
if (((uword)x) >= CPU.msize)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "byte read from 0x%x outside memory range\n", x);
|
|
|
|
CPU.exception = SIGSEGV;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
return p[0];
|
|
}
|
|
}
|
|
|
|
static int /* INLINE */
|
|
rlat (word x)
|
|
{
|
|
if (((uword) x) >= CPU.msize)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "word read from 0x%x outside memory range\n", x);
|
|
|
|
CPU.exception = SIGSEGV;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ((x & 3) != 0)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "word read from unaligned address: 0x%x\n", x);
|
|
|
|
CPU.exception = SIGBUS;
|
|
return 0;
|
|
}
|
|
else if (! target_big_endian)
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
|
|
}
|
|
else
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
|
}
|
|
}
|
|
}
|
|
|
|
static int /* INLINE */
|
|
rhat (word x)
|
|
{
|
|
if (((uword)x) >= CPU.msize)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "short read from 0x%x outside memory range\n", x);
|
|
|
|
CPU.exception = SIGSEGV;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ((x & 1) != 0)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "short read from unaligned address: 0x%x\n", x);
|
|
|
|
CPU.exception = SIGBUS;
|
|
return 0;
|
|
}
|
|
else if (!target_big_endian)
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
return (p[1] << 8) | p[0];
|
|
}
|
|
else
|
|
{
|
|
unsigned char *p = CPU.memory + x;
|
|
return (p[0] << 8) | p[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Default to a 8 Mbyte (== 2^23) memory space. */
|
|
static int sim_memory_size = 1 << 23;
|
|
|
|
#define MEM_SIZE_FLOOR 64
|
|
void
|
|
sim_size (int size)
|
|
{
|
|
sim_memory_size = size;
|
|
CPU.msize = sim_memory_size;
|
|
|
|
if (CPU.memory)
|
|
free (CPU.memory);
|
|
|
|
CPU.memory = (unsigned char *) calloc (1, CPU.msize);
|
|
|
|
if (!CPU.memory)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr,
|
|
"Not enough VM for simulation of %ld bytes of RAM\n",
|
|
CPU.msize);
|
|
|
|
CPU.msize = 1;
|
|
CPU.memory = (unsigned char *) calloc (1, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_pointers (void)
|
|
{
|
|
if (CPU.msize != (sim_memory_size))
|
|
sim_size (sim_memory_size);
|
|
}
|
|
|
|
static void
|
|
set_initial_gprs (void)
|
|
{
|
|
int i;
|
|
long space;
|
|
unsigned long memsize;
|
|
|
|
init_pointers ();
|
|
|
|
/* Set up machine just out of reset. */
|
|
PC = 0;
|
|
MSR = 0;
|
|
|
|
memsize = CPU.msize / (1024 * 1024);
|
|
|
|
if (issue_messages > 1)
|
|
fprintf (stderr, "Simulated memory of %ld Mbytes (0x0 .. 0x%08lx)\n",
|
|
memsize, CPU.msize - 1);
|
|
|
|
/* Clean out the GPRs */
|
|
for (i = 0; i < 32; i++)
|
|
CPU.regs[i] = 0;
|
|
CPU.insts = 0;
|
|
CPU.cycles = 0;
|
|
CPU.imm_enable = 0;
|
|
}
|
|
|
|
#define WATCHFUNCTIONS 1
|
|
#ifdef WATCHFUNCTIONS
|
|
|
|
#define MAXWL 80
|
|
word WL[MAXWL];
|
|
char *WLstr[MAXWL];
|
|
|
|
int ENDWL=0;
|
|
int WLincyc;
|
|
int WLcyc[MAXWL];
|
|
int WLcnts[MAXWL];
|
|
int WLmax[MAXWL];
|
|
int WLmin[MAXWL];
|
|
word WLendpc;
|
|
int WLbcyc;
|
|
int WLW;
|
|
#endif
|
|
|
|
static int tracing = 0;
|
|
|
|
void
|
|
sim_resume (SIM_DESC sd, int step, int siggnal)
|
|
{
|
|
int needfetch;
|
|
word inst;
|
|
enum microblaze_instr op;
|
|
int memops;
|
|
int bonus_cycles;
|
|
int insts;
|
|
int w;
|
|
int cycs;
|
|
word WLhash;
|
|
ubyte carry;
|
|
int imm_unsigned;
|
|
short ra, rb, rd;
|
|
long immword;
|
|
uword oldpc, newpc;
|
|
short delay_slot_enable;
|
|
short branch_taken;
|
|
short num_delay_slot; /* UNUSED except as reqd parameter */
|
|
enum microblaze_instr_type insn_type;
|
|
|
|
CPU.exception = step ? SIGTRAP : 0;
|
|
|
|
memops = 0;
|
|
bonus_cycles = 0;
|
|
insts = 0;
|
|
|
|
do
|
|
{
|
|
/* Fetch the initial instructions that we'll decode. */
|
|
inst = rlat (PC & 0xFFFFFFFC);
|
|
|
|
op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
|
|
&num_delay_slot);
|
|
|
|
if (op == invalid_inst)
|
|
fprintf (stderr, "Unknown instruction 0x%04x", inst);
|
|
|
|
if (tracing)
|
|
fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
|
|
|
|
rd = GET_RD;
|
|
rb = GET_RB;
|
|
ra = GET_RA;
|
|
/* immword = IMM_W; */
|
|
|
|
oldpc = PC;
|
|
delay_slot_enable = 0;
|
|
branch_taken = 0;
|
|
if (op == microblaze_brk)
|
|
CPU.exception = SIGTRAP;
|
|
else if (inst == MICROBLAZE_HALT_INST)
|
|
{
|
|
CPU.exception = SIGQUIT;
|
|
insts += 1;
|
|
bonus_cycles++;
|
|
}
|
|
else
|
|
{
|
|
switch(op)
|
|
{
|
|
#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
|
|
case NAME: \
|
|
ACTION; \
|
|
break;
|
|
#include "microblaze.isa"
|
|
#undef INSTRUCTION
|
|
|
|
default:
|
|
CPU.exception = SIGILL;
|
|
fprintf (stderr, "ERROR: Unknown opcode\n");
|
|
}
|
|
/* Make R0 consistent */
|
|
CPU.regs[0] = 0;
|
|
|
|
/* Check for imm instr */
|
|
if (op == imm)
|
|
IMM_ENABLE = 1;
|
|
else
|
|
IMM_ENABLE = 0;
|
|
|
|
/* Update cycle counts */
|
|
insts ++;
|
|
if (insn_type == memory_store_inst || insn_type == memory_load_inst)
|
|
memops++;
|
|
if (insn_type == mult_inst)
|
|
bonus_cycles++;
|
|
if (insn_type == barrel_shift_inst)
|
|
bonus_cycles++;
|
|
if (insn_type == anyware_inst)
|
|
bonus_cycles++;
|
|
if (insn_type == div_inst)
|
|
bonus_cycles += 33;
|
|
|
|
if ((insn_type == branch_inst || insn_type == return_inst)
|
|
&& branch_taken)
|
|
{
|
|
/* Add an extra cycle for taken branches */
|
|
bonus_cycles++;
|
|
/* For branch instructions handle the instruction in the delay slot */
|
|
if (delay_slot_enable)
|
|
{
|
|
newpc = PC;
|
|
PC = oldpc + INST_SIZE;
|
|
inst = rlat (PC & 0xFFFFFFFC);
|
|
op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
|
|
&num_delay_slot);
|
|
if (op == invalid_inst)
|
|
fprintf (stderr, "Unknown instruction 0x%04x", inst);
|
|
if (tracing)
|
|
fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
|
|
rd = GET_RD;
|
|
rb = GET_RB;
|
|
ra = GET_RA;
|
|
/* immword = IMM_W; */
|
|
if (op == microblaze_brk)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "Breakpoint set in delay slot "
|
|
"(at address 0x%x) will not be honored\n", PC);
|
|
/* ignore the breakpoint */
|
|
}
|
|
else if (insn_type == branch_inst || insn_type == return_inst)
|
|
{
|
|
if (issue_messages)
|
|
fprintf (stderr, "Cannot have branch or return instructions "
|
|
"in delay slot (at address 0x%x)\n", PC);
|
|
CPU.exception = SIGILL;
|
|
}
|
|
else
|
|
{
|
|
switch(op)
|
|
{
|
|
#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
|
|
case NAME: \
|
|
ACTION; \
|
|
break;
|
|
#include "microblaze.isa"
|
|
#undef INSTRUCTION
|
|
|
|
default:
|
|
CPU.exception = SIGILL;
|
|
fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
|
|
}
|
|
/* Update cycle counts */
|
|
insts++;
|
|
if (insn_type == memory_store_inst
|
|
|| insn_type == memory_load_inst)
|
|
memops++;
|
|
if (insn_type == mult_inst)
|
|
bonus_cycles++;
|
|
if (insn_type == barrel_shift_inst)
|
|
bonus_cycles++;
|
|
if (insn_type == anyware_inst)
|
|
bonus_cycles++;
|
|
if (insn_type == div_inst)
|
|
bonus_cycles += 33;
|
|
}
|
|
/* Restore the PC */
|
|
PC = newpc;
|
|
/* Make R0 consistent */
|
|
CPU.regs[0] = 0;
|
|
/* Check for imm instr */
|
|
if (op == imm)
|
|
IMM_ENABLE = 1;
|
|
else
|
|
IMM_ENABLE = 0;
|
|
}
|
|
else
|
|
/* no delay slot: increment cycle count */
|
|
bonus_cycles++;
|
|
}
|
|
}
|
|
|
|
if (tracing)
|
|
fprintf (stderr, "\n");
|
|
}
|
|
while (!CPU.exception);
|
|
|
|
/* Hide away the things we've cached while executing. */
|
|
/* CPU.pc = pc; */
|
|
CPU.insts += insts; /* instructions done ... */
|
|
CPU.cycles += insts; /* and each takes a cycle */
|
|
CPU.cycles += bonus_cycles; /* and extra cycles for branches */
|
|
CPU.cycles += memops; /* and memop cycle delays */
|
|
}
|
|
|
|
|
|
int
|
|
sim_write (SIM_DESC sd, SIM_ADDR addr, const unsigned char *buffer, int size)
|
|
{
|
|
int i;
|
|
init_pointers ();
|
|
|
|
memcpy (&CPU.memory[addr], buffer, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
int
|
|
sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
|
|
{
|
|
int i;
|
|
init_pointers ();
|
|
|
|
memcpy (buffer, &CPU.memory[addr], size);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
int
|
|
sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
|
|
{
|
|
init_pointers ();
|
|
|
|
if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
|
|
{
|
|
if (length == 4)
|
|
{
|
|
/* misalignment safe */
|
|
long ival = microblaze_extract_unsigned_integer (memory, 4);
|
|
if (rn < NUM_REGS)
|
|
CPU.regs[rn] = ival;
|
|
else
|
|
CPU.spregs[rn-NUM_REGS] = ival;
|
|
return 4;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
|
|
{
|
|
long ival;
|
|
init_pointers ();
|
|
|
|
if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
|
|
{
|
|
if (length == 4)
|
|
{
|
|
if (rn < NUM_REGS)
|
|
ival = CPU.regs[rn];
|
|
else
|
|
ival = CPU.spregs[rn-NUM_REGS];
|
|
|
|
/* misalignment-safe */
|
|
microblaze_store_unsigned_integer (memory, 4, ival);
|
|
return 4;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
sim_trace (SIM_DESC sd)
|
|
{
|
|
tracing = 1;
|
|
|
|
sim_resume (sd, 0, 0);
|
|
|
|
tracing = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc)
|
|
{
|
|
if (CPU.exception == SIGQUIT)
|
|
{
|
|
*reason = sim_exited;
|
|
*sigrc = RETREG;
|
|
}
|
|
else
|
|
{
|
|
*reason = sim_stopped;
|
|
*sigrc = CPU.exception;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
sim_stop (SIM_DESC sd)
|
|
{
|
|
CPU.exception = SIGINT;
|
|
return 1;
|
|
}
|
|
|
|
|
|
void
|
|
sim_info (SIM_DESC sd, int verbose)
|
|
{
|
|
#ifdef WATCHFUNCTIONS
|
|
int w, wcyc;
|
|
#endif
|
|
|
|
callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
|
|
CPU.insts);
|
|
callback->printf_filtered (callback, "# cycles %10d\n",
|
|
(CPU.cycles) ? CPU.cycles+2 : 0);
|
|
|
|
#ifdef WATCHFUNCTIONS
|
|
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]);
|
|
|
|
if (WLcnts[w] != 0)
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
struct aout
|
|
{
|
|
unsigned char sa_machtype[2];
|
|
unsigned char sa_magic[2];
|
|
unsigned char sa_tsize[4];
|
|
unsigned char sa_dsize[4];
|
|
unsigned char sa_bsize[4];
|
|
unsigned char sa_syms[4];
|
|
unsigned char sa_entry[4];
|
|
unsigned char sa_trelo[4];
|
|
unsigned char sa_drelo[4];
|
|
} aout;
|
|
|
|
#define LONG(x) (((x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
|
|
#define SHORT(x) (((x)[0]<<8)|(x)[1])
|
|
|
|
SIM_DESC
|
|
sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
|
|
{
|
|
/* SIM_DESC sd = sim_state_alloc(kind, alloc);*/
|
|
|
|
int osize = sim_memory_size;
|
|
myname = argv[0];
|
|
callback = cb;
|
|
|
|
if (kind == SIM_OPEN_STANDALONE)
|
|
issue_messages = 1;
|
|
|
|
/* Discard and reacquire memory -- start with a clean slate. */
|
|
sim_size (1); /* small */
|
|
sim_size (osize); /* and back again */
|
|
|
|
set_initial_gprs (); /* Reset the GPR registers. */
|
|
|
|
return ((SIM_DESC) 1);
|
|
}
|
|
|
|
void
|
|
sim_close (SIM_DESC sd, int quitting)
|
|
{
|
|
if (CPU.memory)
|
|
{
|
|
free(CPU.memory);
|
|
CPU.memory = NULL;
|
|
CPU.msize = 0;
|
|
}
|
|
}
|
|
|
|
SIM_RC
|
|
sim_load (SIM_DESC sd, const char *prog, bfd *abfd, int from_tty)
|
|
{
|
|
/* Do the right thing for ELF executables; this turns out to be
|
|
just about the right thing for any object format that:
|
|
- we crack using BFD routines
|
|
- follows the traditional UNIX text/data/bss layout
|
|
- calls the bss section ".bss". */
|
|
|
|
extern bfd *sim_load_file (); /* ??? Don't know where this should live. */
|
|
bfd *prog_bfd;
|
|
|
|
{
|
|
bfd *handle;
|
|
asection *s;
|
|
int found_loadable_section = 0;
|
|
bfd_vma max_addr = 0;
|
|
handle = bfd_openr (prog, 0);
|
|
|
|
if (!handle)
|
|
{
|
|
printf("``%s'' could not be opened.\n", prog);
|
|
return SIM_RC_FAIL;
|
|
}
|
|
|
|
/* Makes sure that we have an object file, also cleans gets the
|
|
section headers in place. */
|
|
if (!bfd_check_format (handle, bfd_object))
|
|
{
|
|
/* wasn't an object file */
|
|
bfd_close (handle);
|
|
printf ("``%s'' is not appropriate object file.\n", prog);
|
|
return SIM_RC_FAIL;
|
|
}
|
|
|
|
for (s = handle->sections; s; s = s->next)
|
|
{
|
|
if (s->flags & SEC_ALLOC)
|
|
{
|
|
bfd_vma vma = 0;
|
|
int size = bfd_get_section_size (s);
|
|
if (size > 0)
|
|
{
|
|
vma = bfd_section_vma (handle, s);
|
|
if (vma >= max_addr)
|
|
{
|
|
max_addr = vma + size;
|
|
}
|
|
}
|
|
if (s->flags & SEC_LOAD)
|
|
found_loadable_section = 1;
|
|
}
|
|
}
|
|
|
|
if (!found_loadable_section)
|
|
{
|
|
/* No loadable sections */
|
|
bfd_close(handle);
|
|
printf("No loadable sections in file %s\n", prog);
|
|
return SIM_RC_FAIL;
|
|
}
|
|
|
|
sim_memory_size = (unsigned long) max_addr;
|
|
|
|
/* Clean up after ourselves. */
|
|
bfd_close (handle);
|
|
|
|
}
|
|
|
|
/* from sh -- dac */
|
|
prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
|
|
/* sim_kind == SIM_OPEN_DEBUG, */
|
|
0,
|
|
0, sim_write);
|
|
if (prog_bfd == NULL)
|
|
return SIM_RC_FAIL;
|
|
|
|
target_big_endian = bfd_big_endian (prog_bfd);
|
|
PC = bfd_get_start_address (prog_bfd);
|
|
|
|
if (abfd == NULL)
|
|
bfd_close (prog_bfd);
|
|
|
|
return SIM_RC_OK;
|
|
}
|
|
|
|
SIM_RC
|
|
sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
|
|
{
|
|
char **avp;
|
|
int nargs = 0;
|
|
int nenv = 0;
|
|
int s_length;
|
|
int l;
|
|
unsigned long strings;
|
|
unsigned long pointers;
|
|
unsigned long hi_stack;
|
|
|
|
|
|
/* Set the initial register set. */
|
|
l = issue_messages;
|
|
issue_messages = 0;
|
|
set_initial_gprs ();
|
|
issue_messages = l;
|
|
|
|
hi_stack = CPU.msize - 4;
|
|
PC = bfd_get_start_address (prog_bfd);
|
|
|
|
/* For now ignore all parameters to the program */
|
|
|
|
return SIM_RC_OK;
|
|
}
|
|
|
|
void
|
|
sim_do_command (SIM_DESC sd, const char *cmd)
|
|
{
|
|
/* Nothing there yet; it's all an error. */
|
|
|
|
if (cmd != NULL)
|
|
{
|
|
char ** simargv = buildargv (cmd);
|
|
|
|
if (strcmp (simargv[0], "watch") == 0)
|
|
{
|
|
if ((simargv[1] == NULL) || (simargv[2] == NULL))
|
|
{
|
|
fprintf (stderr, "Error: missing argument to watch cmd.\n");
|
|
freeargv (simargv);
|
|
return;
|
|
}
|
|
|
|
ENDWL++;
|
|
|
|
WL[ENDWL] = strtol (simargv[2], NULL, 0);
|
|
WLstr[ENDWL] = strdup (simargv[1]);
|
|
fprintf (stderr, "Added %s (%x) to watchlist, #%d\n",WLstr[ENDWL],
|
|
WL[ENDWL], ENDWL);
|
|
|
|
}
|
|
else if (strcmp (simargv[0], "dumpmem") == 0)
|
|
{
|
|
unsigned char * p;
|
|
FILE * dumpfile;
|
|
|
|
if (simargv[1] == NULL)
|
|
fprintf (stderr, "Error: missing argument to dumpmem cmd.\n");
|
|
|
|
fprintf (stderr, "Writing dumpfile %s...",simargv[1]);
|
|
|
|
dumpfile = fopen (simargv[1], "w");
|
|
p = CPU.memory;
|
|
fwrite (p, CPU.msize-1, 1, dumpfile);
|
|
fclose (dumpfile);
|
|
|
|
fprintf (stderr, "done.\n");
|
|
}
|
|
else if (strcmp (simargv[0], "clearstats") == 0)
|
|
{
|
|
CPU.cycles = 0;
|
|
CPU.insts = 0;
|
|
ENDWL = 0;
|
|
}
|
|
else if (strcmp (simargv[0], "verbose") == 0)
|
|
{
|
|
issue_messages = 2;
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr,"Error: \"%s\" is not a valid M.CORE simulator command.\n",
|
|
cmd);
|
|
}
|
|
|
|
freeargv (simargv);
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, "M.CORE sim commands: \n");
|
|
fprintf (stderr, " watch <funcname> <addr>\n");
|
|
fprintf (stderr, " dumpmem <filename>\n");
|
|
fprintf (stderr, " clearstats\n");
|
|
fprintf (stderr, " verbose\n");
|
|
}
|
|
}
|
|
|
|
void
|
|
sim_set_callbacks (host_callback *ptr)
|
|
{
|
|
callback = ptr;
|
|
}
|
|
|
|
char **
|
|
sim_complete_command (SIM_DESC sd, const char *text, const char *word)
|
|
{
|
|
return NULL;
|
|
}
|