binutils-gdb/sim/moxie/interp.c
Mike Frysinger 034685f9ce sim: replace CIA_{GET,SET} with CPU_PC_{GET,SET}
The CIA_{GET,SET} macros serve the same function as CPU_PC_{GET,SET}
except the latter adds a layer of indirection via the sim state.  This
lets models set up different functions at runtime and doesn't reach so
directly into the arch-specific cpu state.

It also doesn't make sense to have two sets of macros that do exactly
the same thing, so lets standardize on the one that gets us more.
2015-04-17 02:44:30 -04:00

1325 lines
30 KiB
C

/* Simulator for the moxie processor
Copyright (C) 2008-2015 Free Software Foundation, Inc.
Contributed by Anthony Green
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 <fcntl.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 "libiberty.h"
#include "gdb/remote-sim.h"
#include "sim-main.h"
#include "sim-base.h"
#include "sim-options.h"
typedef int word;
typedef unsigned int uword;
/* Extract the signed 10-bit offset from a 16-bit branch
instruction. */
#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
#define EXTRACT_WORD(addr) \
((sim_core_read_aligned_1 (scpu, cia, read_map, addr) << 24) \
+ (sim_core_read_aligned_1 (scpu, cia, read_map, addr+1) << 16) \
+ (sim_core_read_aligned_1 (scpu, cia, read_map, addr+2) << 8) \
+ (sim_core_read_aligned_1 (scpu, cia, read_map, addr+3)))
#define EXTRACT_OFFSET(addr) \
(unsigned int) \
(((signed short) \
((sim_core_read_aligned_1 (scpu, cia, read_map, addr) << 8) \
+ (sim_core_read_aligned_1 (scpu, cia, read_map, addr+1))) << 16) >> 16)
static unsigned long
moxie_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;
for (p = endaddr; p > startaddr;)
retval = (retval << 8) | * -- p;
return retval;
}
static void
moxie_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;
for (p = endaddr; p > startaddr;)
{
* -- p = val & 0xff;
val >>= 8;
}
}
/* moxie register names. */
static const char *reg_names[16] =
{ "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5",
"$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" };
/* 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. 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. */
#define NUM_MOXIE_REGS 17 /* Including PC */
#define NUM_MOXIE_SREGS 256 /* The special registers */
#define PC_REGNO 16
/* The ordering of the moxie_regset structure is matched in the
gdb/config/moxie/tm-moxie.h file in the REGISTER_NAMES macro. */
/* TODO: This should be moved to sim-main.h:_sim_cpu. */
struct moxie_regset
{
word regs[NUM_MOXIE_REGS + 1]; /* primary registers */
word sregs[256]; /* special registers */
word cc; /* the condition code reg */
unsigned long long insts; /* instruction counter */
};
#define CC_GT 1<<0
#define CC_LT 1<<1
#define CC_EQ 1<<2
#define CC_GTU 1<<3
#define CC_LTU 1<<4
/* TODO: This should be moved to sim-main.h:_sim_cpu. */
union
{
struct moxie_regset asregs;
word asints [1]; /* but accessed larger... */
} cpu;
static void
set_initial_gprs (void)
{
int i;
long space;
/* Set up machine just out of reset. */
cpu.asregs.regs[PC_REGNO] = 0;
/* Clean out the register contents. */
for (i = 0; i < NUM_MOXIE_REGS; i++)
cpu.asregs.regs[i] = 0;
for (i = 0; i < NUM_MOXIE_SREGS; i++)
cpu.asregs.sregs[i] = 0;
}
/* Write a 1 byte value to memory. */
static INLINE void
wbat (sim_cpu *scpu, word pc, word x, word v)
{
address_word cia = CPU_PC_GET (scpu);
sim_core_write_aligned_1 (scpu, cia, write_map, x, v);
}
/* Write a 2 byte value to memory. */
static INLINE void
wsat (sim_cpu *scpu, word pc, word x, word v)
{
address_word cia = CPU_PC_GET (scpu);
sim_core_write_aligned_2 (scpu, cia, write_map, x, v);
}
/* Write a 4 byte value to memory. */
static INLINE void
wlat (sim_cpu *scpu, word pc, word x, word v)
{
address_word cia = CPU_PC_GET (scpu);
sim_core_write_aligned_4 (scpu, cia, write_map, x, v);
}
/* Read 2 bytes from memory. */
static INLINE int
rsat (sim_cpu *scpu, word pc, word x)
{
address_word cia = CPU_PC_GET (scpu);
return (sim_core_read_aligned_2 (scpu, cia, read_map, x));
}
/* Read 1 byte from memory. */
static INLINE int
rbat (sim_cpu *scpu, word pc, word x)
{
address_word cia = CPU_PC_GET (scpu);
return (sim_core_read_aligned_1 (scpu, cia, read_map, x));
}
/* Read 4 bytes from memory. */
static INLINE int
rlat (sim_cpu *scpu, word pc, word x)
{
address_word cia = CPU_PC_GET (scpu);
return (sim_core_read_aligned_4 (scpu, cia, read_map, x));
}
#define CHECK_FLAG(T,H) if (tflags & T) { hflags |= H; tflags ^= T; }
static unsigned int
convert_target_flags (unsigned int tflags)
{
unsigned int hflags = 0x0;
CHECK_FLAG(0x0001, O_WRONLY);
CHECK_FLAG(0x0002, O_RDWR);
CHECK_FLAG(0x0008, O_APPEND);
CHECK_FLAG(0x0200, O_CREAT);
CHECK_FLAG(0x0400, O_TRUNC);
CHECK_FLAG(0x0800, O_EXCL);
CHECK_FLAG(0x2000, O_SYNC);
if (tflags != 0x0)
fprintf (stderr,
"Simulator Error: problem converting target open flags for host. 0x%x\n",
tflags);
return hflags;
}
/* TODO: Move to sim-trace.h. */
static FILE *tracefile;
static const int tracing = 0;
#define TRACE(str) if (tracing) fprintf(tracefile,"0x%08x, %s, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", opc, str, cpu.asregs.regs[0], cpu.asregs.regs[1], cpu.asregs.regs[2], cpu.asregs.regs[3], cpu.asregs.regs[4], cpu.asregs.regs[5], cpu.asregs.regs[6], cpu.asregs.regs[7], cpu.asregs.regs[8], cpu.asregs.regs[9], cpu.asregs.regs[10], cpu.asregs.regs[11], cpu.asregs.regs[12], cpu.asregs.regs[13], cpu.asregs.regs[14], cpu.asregs.regs[15]);
void
sim_engine_run (SIM_DESC sd,
int next_cpu_nr, /* ignore */
int nr_cpus, /* ignore */
int siggnal) /* ignore */
{
word pc, opc;
unsigned short inst;
sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
address_word cia = CPU_PC_GET (scpu);
pc = cpu.asregs.regs[PC_REGNO];
/* Run instructions here. */
do
{
opc = pc;
/* Fetch the instruction at pc. */
inst = (sim_core_read_aligned_1 (scpu, cia, read_map, pc) << 8)
+ sim_core_read_aligned_1 (scpu, cia, read_map, pc+1);
/* Decode instruction. */
if (inst & (1 << 15))
{
if (inst & (1 << 14))
{
/* This is a Form 3 instruction. */
int opcode = (inst >> 10 & 0xf);
switch (opcode)
{
case 0x00: /* beq */
{
TRACE("beq");
if (cpu.asregs.cc & CC_EQ)
pc += INST2OFFSET(inst);
}
break;
case 0x01: /* bne */
{
TRACE("bne");
if (! (cpu.asregs.cc & CC_EQ))
pc += INST2OFFSET(inst);
}
break;
case 0x02: /* blt */
{
TRACE("blt");
if (cpu.asregs.cc & CC_LT)
pc += INST2OFFSET(inst);
} break;
case 0x03: /* bgt */
{
TRACE("bgt");
if (cpu.asregs.cc & CC_GT)
pc += INST2OFFSET(inst);
}
break;
case 0x04: /* bltu */
{
TRACE("bltu");
if (cpu.asregs.cc & CC_LTU)
pc += INST2OFFSET(inst);
}
break;
case 0x05: /* bgtu */
{
TRACE("bgtu");
if (cpu.asregs.cc & CC_GTU)
pc += INST2OFFSET(inst);
}
break;
case 0x06: /* bge */
{
TRACE("bge");
if (cpu.asregs.cc & (CC_GT | CC_EQ))
pc += INST2OFFSET(inst);
}
break;
case 0x07: /* ble */
{
TRACE("ble");
if (cpu.asregs.cc & (CC_LT | CC_EQ))
pc += INST2OFFSET(inst);
}
break;
case 0x08: /* bgeu */
{
TRACE("bgeu");
if (cpu.asregs.cc & (CC_GTU | CC_EQ))
pc += INST2OFFSET(inst);
}
break;
case 0x09: /* bleu */
{
TRACE("bleu");
if (cpu.asregs.cc & (CC_LTU | CC_EQ))
pc += INST2OFFSET(inst);
}
break;
default:
{
TRACE("SIGILL3");
sim_engine_halt (sd, NULL, NULL, pc, sim_stopped, SIM_SIGILL);
break;
}
}
}
else
{
/* This is a Form 2 instruction. */
int opcode = (inst >> 12 & 0x3);
switch (opcode)
{
case 0x00: /* inc */
{
int a = (inst >> 8) & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned v = (inst & 0xff);
TRACE("inc");
cpu.asregs.regs[a] = av + v;
}
break;
case 0x01: /* dec */
{
int a = (inst >> 8) & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned v = (inst & 0xff);
TRACE("dec");
cpu.asregs.regs[a] = av - v;
}
break;
case 0x02: /* gsr */
{
int a = (inst >> 8) & 0xf;
unsigned v = (inst & 0xff);
TRACE("gsr");
cpu.asregs.regs[a] = cpu.asregs.sregs[v];
}
break;
case 0x03: /* ssr */
{
int a = (inst >> 8) & 0xf;
unsigned v = (inst & 0xff);
TRACE("ssr");
cpu.asregs.sregs[v] = cpu.asregs.regs[a];
}
break;
default:
TRACE("SIGILL2");
sim_engine_halt (sd, NULL, NULL, pc, sim_stopped, SIM_SIGILL);
break;
}
}
}
else
{
/* This is a Form 1 instruction. */
int opcode = inst >> 8;
switch (opcode)
{
case 0x00: /* bad */
opc = opcode;
TRACE("SIGILL0");
sim_engine_halt (sd, NULL, NULL, pc, sim_stopped, SIM_SIGILL);
break;
case 0x01: /* ldi.l (immediate) */
{
int reg = (inst >> 4) & 0xf;
unsigned int val = EXTRACT_WORD(pc+2);
TRACE("ldi.l");
cpu.asregs.regs[reg] = val;
pc += 4;
}
break;
case 0x02: /* mov (register-to-register) */
{
int dest = (inst >> 4) & 0xf;
int src = (inst ) & 0xf;
TRACE("mov");
cpu.asregs.regs[dest] = cpu.asregs.regs[src];
}
break;
case 0x03: /* jsra */
{
unsigned int fn = EXTRACT_WORD(pc+2);
unsigned int sp = cpu.asregs.regs[1];
TRACE("jsra");
/* Save a slot for the static chain. */
sp -= 4;
/* Push the return address. */
sp -= 4;
wlat (scpu, opc, sp, pc + 6);
/* Push the current frame pointer. */
sp -= 4;
wlat (scpu, opc, sp, cpu.asregs.regs[0]);
/* Uncache the stack pointer and set the pc and $fp. */
cpu.asregs.regs[1] = sp;
cpu.asregs.regs[0] = sp;
pc = fn - 2;
}
break;
case 0x04: /* ret */
{
unsigned int sp = cpu.asregs.regs[0];
TRACE("ret");
/* Pop the frame pointer. */
cpu.asregs.regs[0] = rlat (scpu, opc, sp);
sp += 4;
/* Pop the return address. */
pc = rlat (scpu, opc, sp) - 2;
sp += 4;
/* Skip over the static chain slot. */
sp += 4;
/* Uncache the stack pointer. */
cpu.asregs.regs[1] = sp;
}
break;
case 0x05: /* add.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned bv = cpu.asregs.regs[b];
TRACE("add.l");
cpu.asregs.regs[a] = av + bv;
}
break;
case 0x06: /* push */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int sp = cpu.asregs.regs[a] - 4;
TRACE("push");
wlat (scpu, opc, sp, cpu.asregs.regs[b]);
cpu.asregs.regs[a] = sp;
}
break;
case 0x07: /* pop */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int sp = cpu.asregs.regs[a];
TRACE("pop");
cpu.asregs.regs[b] = rlat (scpu, opc, sp);
cpu.asregs.regs[a] = sp + 4;
}
break;
case 0x08: /* lda.l */
{
int reg = (inst >> 4) & 0xf;
unsigned int addr = EXTRACT_WORD(pc+2);
TRACE("lda.l");
cpu.asregs.regs[reg] = rlat (scpu, opc, addr);
pc += 4;
}
break;
case 0x09: /* sta.l */
{
int reg = (inst >> 4) & 0xf;
unsigned int addr = EXTRACT_WORD(pc+2);
TRACE("sta.l");
wlat (scpu, opc, addr, cpu.asregs.regs[reg]);
pc += 4;
}
break;
case 0x0a: /* ld.l (register indirect) */
{
int src = inst & 0xf;
int dest = (inst >> 4) & 0xf;
int xv;
TRACE("ld.l");
xv = cpu.asregs.regs[src];
cpu.asregs.regs[dest] = rlat (scpu, opc, xv);
}
break;
case 0x0b: /* st.l */
{
int dest = (inst >> 4) & 0xf;
int val = inst & 0xf;
TRACE("st.l");
wlat (scpu, opc, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
}
break;
case 0x0c: /* ldo.l */
{
unsigned int addr = EXTRACT_OFFSET(pc+2);
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
TRACE("ldo.l");
addr += cpu.asregs.regs[b];
cpu.asregs.regs[a] = rlat (scpu, opc, addr);
pc += 2;
}
break;
case 0x0d: /* sto.l */
{
unsigned int addr = EXTRACT_OFFSET(pc+2);
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
TRACE("sto.l");
addr += cpu.asregs.regs[a];
wlat (scpu, opc, addr, cpu.asregs.regs[b]);
pc += 2;
}
break;
case 0x0e: /* cmp */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int cc = 0;
int va = cpu.asregs.regs[a];
int vb = cpu.asregs.regs[b];
TRACE("cmp");
if (va == vb)
cc = CC_EQ;
else
{
cc |= (va < vb ? CC_LT : 0);
cc |= (va > vb ? CC_GT : 0);
cc |= ((unsigned int) va < (unsigned int) vb ? CC_LTU : 0);
cc |= ((unsigned int) va > (unsigned int) vb ? CC_GTU : 0);
}
cpu.asregs.cc = cc;
}
break;
case 0x0f: /* nop */
break;
case 0x10: /* sex.b */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
signed char bv = cpu.asregs.regs[b];
TRACE("sex.b");
cpu.asregs.regs[a] = (int) bv;
}
break;
case 0x11: /* sex.s */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
signed short bv = cpu.asregs.regs[b];
TRACE("sex.s");
cpu.asregs.regs[a] = (int) bv;
}
break;
case 0x12: /* zex.b */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
signed char bv = cpu.asregs.regs[b];
TRACE("zex.b");
cpu.asregs.regs[a] = (int) bv & 0xff;
}
break;
case 0x13: /* zex.s */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
signed short bv = cpu.asregs.regs[b];
TRACE("zex.s");
cpu.asregs.regs[a] = (int) bv & 0xffff;
}
break;
case 0x14: /* umul.x */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned bv = cpu.asregs.regs[b];
unsigned long long r =
(unsigned long long) av * (unsigned long long) bv;
TRACE("umul.x");
cpu.asregs.regs[a] = r >> 32;
}
break;
case 0x15: /* mul.x */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned bv = cpu.asregs.regs[b];
signed long long r =
(signed long long) av * (signed long long) bv;
TRACE("mul.x");
cpu.asregs.regs[a] = r >> 32;
}
break;
case 0x16: /* bad */
case 0x17: /* bad */
case 0x18: /* bad */
{
opc = opcode;
TRACE("SIGILL0");
sim_engine_halt (sd, NULL, NULL, pc, sim_stopped, SIM_SIGILL);
break;
}
case 0x19: /* jsr */
{
unsigned int fn = cpu.asregs.regs[(inst >> 4) & 0xf];
unsigned int sp = cpu.asregs.regs[1];
TRACE("jsr");
/* Save a slot for the static chain. */
sp -= 4;
/* Push the return address. */
sp -= 4;
wlat (scpu, opc, sp, pc + 2);
/* Push the current frame pointer. */
sp -= 4;
wlat (scpu, opc, sp, cpu.asregs.regs[0]);
/* Uncache the stack pointer and set the fp & pc. */
cpu.asregs.regs[1] = sp;
cpu.asregs.regs[0] = sp;
pc = fn - 2;
}
break;
case 0x1a: /* jmpa */
{
unsigned int tgt = EXTRACT_WORD(pc+2);
TRACE("jmpa");
pc = tgt - 2;
}
break;
case 0x1b: /* ldi.b (immediate) */
{
int reg = (inst >> 4) & 0xf;
unsigned int val = EXTRACT_WORD(pc+2);
TRACE("ldi.b");
cpu.asregs.regs[reg] = val;
pc += 4;
}
break;
case 0x1c: /* ld.b (register indirect) */
{
int src = inst & 0xf;
int dest = (inst >> 4) & 0xf;
int xv;
TRACE("ld.b");
xv = cpu.asregs.regs[src];
cpu.asregs.regs[dest] = rbat (scpu, opc, xv);
}
break;
case 0x1d: /* lda.b */
{
int reg = (inst >> 4) & 0xf;
unsigned int addr = EXTRACT_WORD(pc+2);
TRACE("lda.b");
cpu.asregs.regs[reg] = rbat (scpu, opc, addr);
pc += 4;
}
break;
case 0x1e: /* st.b */
{
int dest = (inst >> 4) & 0xf;
int val = inst & 0xf;
TRACE("st.b");
wbat (scpu, opc, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
}
break;
case 0x1f: /* sta.b */
{
int reg = (inst >> 4) & 0xf;
unsigned int addr = EXTRACT_WORD(pc+2);
TRACE("sta.b");
wbat (scpu, opc, addr, cpu.asregs.regs[reg]);
pc += 4;
}
break;
case 0x20: /* ldi.s (immediate) */
{
int reg = (inst >> 4) & 0xf;
unsigned int val = EXTRACT_WORD(pc+2);
TRACE("ldi.s");
cpu.asregs.regs[reg] = val;
pc += 4;
}
break;
case 0x21: /* ld.s (register indirect) */
{
int src = inst & 0xf;
int dest = (inst >> 4) & 0xf;
int xv;
TRACE("ld.s");
xv = cpu.asregs.regs[src];
cpu.asregs.regs[dest] = rsat (scpu, opc, xv);
}
break;
case 0x22: /* lda.s */
{
int reg = (inst >> 4) & 0xf;
unsigned int addr = EXTRACT_WORD(pc+2);
TRACE("lda.s");
cpu.asregs.regs[reg] = rsat (scpu, opc, addr);
pc += 4;
}
break;
case 0x23: /* st.s */
{
int dest = (inst >> 4) & 0xf;
int val = inst & 0xf;
TRACE("st.s");
wsat (scpu, opc, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
}
break;
case 0x24: /* sta.s */
{
int reg = (inst >> 4) & 0xf;
unsigned int addr = EXTRACT_WORD(pc+2);
TRACE("sta.s");
wsat (scpu, opc, addr, cpu.asregs.regs[reg]);
pc += 4;
}
break;
case 0x25: /* jmp */
{
int reg = (inst >> 4) & 0xf;
TRACE("jmp");
pc = cpu.asregs.regs[reg] - 2;
}
break;
case 0x26: /* and */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av, bv;
TRACE("and");
av = cpu.asregs.regs[a];
bv = cpu.asregs.regs[b];
cpu.asregs.regs[a] = av & bv;
}
break;
case 0x27: /* lshr */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av = cpu.asregs.regs[a];
int bv = cpu.asregs.regs[b];
TRACE("lshr");
cpu.asregs.regs[a] = (unsigned) ((unsigned) av >> bv);
}
break;
case 0x28: /* ashl */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av = cpu.asregs.regs[a];
int bv = cpu.asregs.regs[b];
TRACE("ashl");
cpu.asregs.regs[a] = av << bv;
}
break;
case 0x29: /* sub.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned bv = cpu.asregs.regs[b];
TRACE("sub.l");
cpu.asregs.regs[a] = av - bv;
}
break;
case 0x2a: /* neg */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int bv = cpu.asregs.regs[b];
TRACE("neg");
cpu.asregs.regs[a] = - bv;
}
break;
case 0x2b: /* or */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av, bv;
TRACE("or");
av = cpu.asregs.regs[a];
bv = cpu.asregs.regs[b];
cpu.asregs.regs[a] = av | bv;
}
break;
case 0x2c: /* not */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int bv = cpu.asregs.regs[b];
TRACE("not");
cpu.asregs.regs[a] = 0xffffffff ^ bv;
}
break;
case 0x2d: /* ashr */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av = cpu.asregs.regs[a];
int bv = cpu.asregs.regs[b];
TRACE("ashr");
cpu.asregs.regs[a] = av >> bv;
}
break;
case 0x2e: /* xor */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av, bv;
TRACE("xor");
av = cpu.asregs.regs[a];
bv = cpu.asregs.regs[b];
cpu.asregs.regs[a] = av ^ bv;
}
break;
case 0x2f: /* mul.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned av = cpu.asregs.regs[a];
unsigned bv = cpu.asregs.regs[b];
TRACE("mul.l");
cpu.asregs.regs[a] = av * bv;
}
break;
case 0x30: /* swi */
{
unsigned int inum = EXTRACT_WORD(pc+2);
TRACE("swi");
/* Set the special registers appropriately. */
cpu.asregs.sregs[2] = 3; /* MOXIE_EX_SWI */
cpu.asregs.sregs[3] = inum;
switch (inum)
{
case 0x1: /* SYS_exit */
{
sim_engine_halt (sd, NULL, NULL, pc, sim_exited,
cpu.asregs.regs[2]);
break;
}
case 0x2: /* SYS_open */
{
char fname[1024];
int mode = (int) convert_target_flags ((unsigned) cpu.asregs.regs[3]);
int perm = (int) cpu.asregs.regs[4];
int fd = open (fname, mode, perm);
sim_core_read_buffer (sd, scpu, read_map, fname,
cpu.asregs.regs[2], 1024);
/* FIXME - set errno */
cpu.asregs.regs[2] = fd;
break;
}
case 0x4: /* SYS_read */
{
int fd = cpu.asregs.regs[2];
unsigned len = (unsigned) cpu.asregs.regs[4];
char *buf = malloc (len);
cpu.asregs.regs[2] = read (fd, buf, len);
sim_core_write_buffer (sd, scpu, write_map, buf,
cpu.asregs.regs[3], len);
free (buf);
break;
}
case 0x5: /* SYS_write */
{
char *str;
/* String length is at 0x12($fp) */
unsigned count, len = (unsigned) cpu.asregs.regs[4];
str = malloc (len);
sim_core_read_buffer (sd, scpu, read_map, str,
cpu.asregs.regs[3], len);
count = write (cpu.asregs.regs[2], str, len);
free (str);
cpu.asregs.regs[2] = count;
break;
}
case 0xffffffff: /* Linux System Call */
{
unsigned int handler = cpu.asregs.sregs[1];
unsigned int sp = cpu.asregs.regs[1];
/* Save a slot for the static chain. */
sp -= 4;
/* Push the return address. */
sp -= 4;
wlat (scpu, opc, sp, pc + 6);
/* Push the current frame pointer. */
sp -= 4;
wlat (scpu, opc, sp, cpu.asregs.regs[0]);
/* Uncache the stack pointer and set the fp & pc. */
cpu.asregs.regs[1] = sp;
cpu.asregs.regs[0] = sp;
pc = handler - 6;
}
default:
break;
}
pc += 4;
}
break;
case 0x31: /* div.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av = cpu.asregs.regs[a];
int bv = cpu.asregs.regs[b];
TRACE("div.l");
cpu.asregs.regs[a] = av / bv;
}
break;
case 0x32: /* udiv.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned int av = cpu.asregs.regs[a];
unsigned int bv = cpu.asregs.regs[b];
TRACE("udiv.l");
cpu.asregs.regs[a] = (av / bv);
}
break;
case 0x33: /* mod.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
int av = cpu.asregs.regs[a];
int bv = cpu.asregs.regs[b];
TRACE("mod.l");
cpu.asregs.regs[a] = av % bv;
}
break;
case 0x34: /* umod.l */
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
unsigned int av = cpu.asregs.regs[a];
unsigned int bv = cpu.asregs.regs[b];
TRACE("umod.l");
cpu.asregs.regs[a] = (av % bv);
}
break;
case 0x35: /* brk */
TRACE("brk");
sim_engine_halt (sd, NULL, NULL, pc, sim_stopped, SIM_SIGTRAP);
pc -= 2; /* Adjust pc */
break;
case 0x36: /* ldo.b */
{
unsigned int addr = EXTRACT_OFFSET(pc+2);
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
TRACE("ldo.b");
addr += cpu.asregs.regs[b];
cpu.asregs.regs[a] = rbat (scpu, opc, addr);
pc += 2;
}
break;
case 0x37: /* sto.b */
{
unsigned int addr = EXTRACT_OFFSET(pc+2);
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
TRACE("sto.b");
addr += cpu.asregs.regs[a];
wbat (scpu, opc, addr, cpu.asregs.regs[b]);
pc += 2;
}
break;
case 0x38: /* ldo.s */
{
unsigned int addr = EXTRACT_OFFSET(pc+2);
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
TRACE("ldo.s");
addr += cpu.asregs.regs[b];
cpu.asregs.regs[a] = rsat (scpu, opc, addr);
pc += 2;
}
break;
case 0x39: /* sto.s */
{
unsigned int addr = EXTRACT_OFFSET(pc+2);
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
TRACE("sto.s");
addr += cpu.asregs.regs[a];
wsat (scpu, opc, addr, cpu.asregs.regs[b]);
pc += 2;
}
break;
default:
opc = opcode;
TRACE("SIGILL1");
sim_engine_halt (sd, NULL, NULL, pc, sim_stopped, SIM_SIGILL);
break;
}
}
cpu.asregs.insts++;
pc += 2;
cpu.asregs.regs[PC_REGNO] = pc;
} while (1);
}
int
sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
{
if (rn < NUM_MOXIE_REGS && rn >= 0)
{
if (length == 4)
{
long ival;
/* misalignment safe */
ival = moxie_extract_unsigned_integer (memory, 4);
cpu.asints[rn] = ival;
}
return 4;
}
else
return 0;
}
int
sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
{
if (rn < NUM_MOXIE_REGS && rn >= 0)
{
if (length == 4)
{
long ival = cpu.asints[rn];
/* misalignment-safe */
moxie_store_unsigned_integer (memory, 4, ival);
}
return 4;
}
else
return 0;
}
static sim_cia
moxie_pc_get (sim_cpu *cpu)
{
return cpu->registers[PCIDX];
}
static void
moxie_pc_set (sim_cpu *cpu, sim_cia pc)
{
cpu->registers[PCIDX] = pc;
}
static void
free_state (SIM_DESC sd)
{
if (STATE_MODULES (sd) != NULL)
sim_module_uninstall (sd);
sim_cpu_free_all (sd);
sim_state_free (sd);
}
SIM_DESC
sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
{
int i;
SIM_DESC sd = sim_state_alloc (kind, cb);
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
/* The cpu data is kept in a separately allocated chunk of memory. */
if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
STATE_WATCHPOINTS (sd)->pc = &cpu.asregs.regs[PC_REGNO];
STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (word);
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* getopt will print the error message so we just have to exit if this fails.
FIXME: Hmmm... in the case of gdb we need getopt to call
print_filtered. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
sim_do_command(sd," memory region 0x00000000,0x4000000") ;
sim_do_command(sd," memory region 0xE0000000,0x10000") ;
/* Check for/establish the a reference program image. */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL), abfd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Configure/verify the target byte order and other runtime
configuration options. */
if (sim_config (sd) != SIM_RC_OK)
{
sim_module_uninstall (sd);
return 0;
}
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
/* Uninstall the modules to avoid memory leaks,
file descriptor leaks, etc. */
sim_module_uninstall (sd);
return 0;
}
/* CPU specific initialization. */
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
CPU_PC_FETCH (cpu) = moxie_pc_get;
CPU_PC_STORE (cpu) = moxie_pc_set;
set_initial_gprs (); /* Reset the GPR registers. */
}
return sd;
}
void
sim_close (SIM_DESC sd, int quitting)
{
/* nothing to do */
}
/* Load the device tree blob. */
static void
load_dtb (SIM_DESC sd, const char *filename)
{
int size = 0;
FILE *f = fopen (filename, "rb");
char *buf;
sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
/* Don't warn as the sim works fine w/out a device tree. */
if (f == NULL)
return;
fseek (f, 0, SEEK_END);
size = ftell(f);
fseek (f, 0, SEEK_SET);
buf = alloca (size);
if (size != fread (buf, 1, size, f))
{
sim_io_eprintf (sd, "ERROR: error reading ``%s''.\n", filename);
return;
}
sim_core_write_buffer (sd, scpu, write_map, buf, 0xE0000000, size);
cpu.asregs.sregs[9] = 0xE0000000;
fclose (f);
}
SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
{
char ** avp;
int l, argc, i, tp;
sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
if (prog_bfd != NULL)
cpu.asregs.regs[PC_REGNO] = bfd_get_start_address (prog_bfd);
/* Copy args into target memory. */
avp = argv;
for (argc = 0; avp && *avp; avp++)
argc++;
/* Target memory looks like this:
0x00000000 zero word
0x00000004 argc word
0x00000008 start of argv
.
0x0000???? end of argv
0x0000???? zero word
0x0000???? start of data pointed to by argv */
wlat (scpu, 0, 0, 0);
wlat (scpu, 0, 4, argc);
/* tp is the offset of our first argv data. */
tp = 4 + 4 + argc * 4 + 4;
for (i = 0; i < argc; i++)
{
/* Set the argv value. */
wlat (scpu, 0, 4 + 4 + i * 4, tp);
/* Store the string. */
sim_core_write_buffer (sd, scpu, write_map, argv[i],
tp, strlen(argv[i])+1);
tp += strlen (argv[i]) + 1;
}
wlat (scpu, 0, 4 + 4 + i * 4, 0);
load_dtb (sd, DTB);
return SIM_RC_OK;
}