mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:54:41 +08:00
gdb/
2009-05-18 Jon Beniston <jon@beniston.com> * MAINTAINERS: Add lm32 target. * Makefile.in: Add lm32 dependencies. * NEWS: Indicate lm32 is a new target. * configure.tgt: Add lm32 targets. * lm32-tdep.c: New file. gdb/testsuite 2009-05-18 Jon Beniston <jon@beniston.com> * gdb.asm/asm-source.exp: Add lm32 target. include/gdb/ 2009-05-18 Jon Beniston <jon@beniston.com> * sim-lm32.h: New file. sim/ 2009-05-18 Jon Beniston <jon@beniston.com> * MAINTAINERS: Add Jon Beniston as maintainer of lm32 sim. * configure.ac: Add lm32 target. * lm32: New directory. sim/common 2009-05-18 Jon Beniston <jon@beniston.com> * gennltvals.sh: Add lm32 target. * nltvals.def: Add lm32 syscall definitions. sim/lm32/ 2009-05-18 Jon Beniston <jon@beniston.com> * Makefile.in: New file. * arch.c: New file. * arch.h: New file. * config.in: New file. * configure: New file. * configure.ac: New file. * cpu.c: New file. * cpu.h: New file. * cpuall.h: New file. * decode.c: New file. * decode.h: New file. * dv-lm32cpu.c: New file. * dv-lm32timer.c: New file. * dv-lm32uart.c: New file. * lm32.c: New file. * lm32-sim.h: New file. * mloop.in: New file. * model.c: New file. * sem.c: New file. * sem-switch.c: New file. * sim-if.c: New file. * sim-main.c: New file. * tconfig.in: New file. * traps.c: New file. * user.c: New file.
This commit is contained in:
parent
739fc47ac9
commit
c28c63d86b
@ -1,3 +1,11 @@
|
||||
2009-05-18 Jon Beniston <jon@beniston.com>
|
||||
|
||||
* MAINTAINERS: Add lm32 target.
|
||||
* Makefile.in: Add lm32 dependencies.
|
||||
* NEWS: Indicate lm32 is a new target.
|
||||
* configure.tgt: Add lm32 targets.
|
||||
* lm32-tdep.c: New file.
|
||||
|
||||
2009-05-18 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
* corelow.c (core_open): Flush the register cache before doing
|
||||
|
@ -270,6 +270,8 @@ the native maintainer when resolving ABI issues.
|
||||
ia64 --target=ia64-linux-gnu ,-Werror
|
||||
(--target=ia64-elf broken)
|
||||
|
||||
lm32 --target=lm32-elf ,-Werror
|
||||
|
||||
m32c --target=m32c-elf ,-Werror
|
||||
|
||||
m32r --target=m32r-elf ,-Werror
|
||||
|
@ -484,6 +484,7 @@ ALL_TARGET_OBS = \
|
||||
i386-dicos-tdep.o \
|
||||
iq2000-tdep.o \
|
||||
linux-tdep.o \
|
||||
lm32-tdep.o \
|
||||
m32c-tdep.o \
|
||||
m32r-linux-tdep.o m32r-tdep.o \
|
||||
m68hc11-tdep.o \
|
||||
@ -1314,6 +1315,7 @@ ALLDEPFILES = \
|
||||
linux-fork.c \
|
||||
linux-tdep.c \
|
||||
linux-record.c \
|
||||
lm32-tdep.c \
|
||||
m68hc11-tdep.c \
|
||||
m32r-tdep.c \
|
||||
m32r-linux-nat.c m32r-linux-tdep.c \
|
||||
|
1
gdb/NEWS
1
gdb/NEWS
@ -313,6 +313,7 @@ x86_64 MinGW x86_64-*-mingw*
|
||||
|
||||
* New targets
|
||||
|
||||
Lattice Mico32 lm32-*
|
||||
x86 DICOS i[34567]86-*-dicos*
|
||||
x86_64 DICOS x86_64-*-dicos*
|
||||
|
||||
|
@ -241,6 +241,11 @@ iq2000-*-*)
|
||||
gdb_sim=../sim/iq2000/libsim.a
|
||||
;;
|
||||
|
||||
lm32-*-*)
|
||||
gdb_target_obs="lm32-tdep.o"
|
||||
gdb_sim=../sim/lm32/libsim.a
|
||||
;;
|
||||
|
||||
m32c-*-*)
|
||||
# Target: Renesas M32C family
|
||||
gdb_target_obs="m32c-tdep.o prologue-value.o"
|
||||
|
585
gdb/lm32-tdep.c
Normal file
585
gdb/lm32-tdep.c
Normal file
@ -0,0 +1,585 @@
|
||||
/* Target-dependent code for Lattice Mico32 processor, for GDB.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "defs.h"
|
||||
#include "frame.h"
|
||||
#include "frame-unwind.h"
|
||||
#include "frame-base.h"
|
||||
#include "inferior.h"
|
||||
#include "dis-asm.h"
|
||||
#include "symfile.h"
|
||||
#include "remote.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdb/sim-lm32.h"
|
||||
#include "gdb/callback.h"
|
||||
#include "gdb/remote-sim.h"
|
||||
#include "sim-regno.h"
|
||||
#include "arch-utils.h"
|
||||
#include "regcache.h"
|
||||
#include "trad-frame.h"
|
||||
#include "reggroups.h"
|
||||
#include "opcodes/lm32-desc.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
/* Macros to extract fields from an instruction. */
|
||||
#define LM32_OPCODE(insn) ((insn >> 26) & 0x3f)
|
||||
#define LM32_REG0(insn) ((insn >> 21) & 0x1f)
|
||||
#define LM32_REG1(insn) ((insn >> 16) & 0x1f)
|
||||
#define LM32_REG2(insn) ((insn >> 11) & 0x1f)
|
||||
#define LM32_IMM16(insn) ((((long)insn & 0xffff) << 16) >> 16)
|
||||
|
||||
struct gdbarch_tdep
|
||||
{
|
||||
/* gdbarch target dependent data here. Currently unused for LM32. */
|
||||
};
|
||||
|
||||
struct lm32_frame_cache
|
||||
{
|
||||
/* The frame's base. Used when constructing a frame ID. */
|
||||
CORE_ADDR base;
|
||||
CORE_ADDR pc;
|
||||
/* Size of frame. */
|
||||
int size;
|
||||
/* Table indicating the location of each and every register. */
|
||||
struct trad_frame_saved_reg *saved_regs;
|
||||
};
|
||||
|
||||
/* Add the available register groups. */
|
||||
|
||||
static void
|
||||
lm32_add_reggroups (struct gdbarch *gdbarch)
|
||||
{
|
||||
reggroup_add (gdbarch, general_reggroup);
|
||||
reggroup_add (gdbarch, all_reggroup);
|
||||
reggroup_add (gdbarch, system_reggroup);
|
||||
}
|
||||
|
||||
/* Return whether a given register is in a given group. */
|
||||
|
||||
static int
|
||||
lm32_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
|
||||
struct reggroup *group)
|
||||
{
|
||||
if (group == general_reggroup)
|
||||
return ((regnum >= SIM_LM32_R0_REGNUM) && (regnum <= SIM_LM32_RA_REGNUM))
|
||||
|| (regnum == SIM_LM32_PC_REGNUM);
|
||||
else if (group == system_reggroup)
|
||||
return ((regnum >= SIM_LM32_EA_REGNUM) && (regnum <= SIM_LM32_BA_REGNUM))
|
||||
|| ((regnum >= SIM_LM32_EID_REGNUM) && (regnum <= SIM_LM32_IP_REGNUM));
|
||||
return default_register_reggroup_p (gdbarch, regnum, group);
|
||||
}
|
||||
|
||||
/* Return a name that corresponds to the given register number. */
|
||||
|
||||
static const char *
|
||||
lm32_register_name (struct gdbarch *gdbarch, int reg_nr)
|
||||
{
|
||||
static char *register_names[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "gp", "fp", "sp", "ra", "ea", "ba",
|
||||
"PC", "EID", "EBA", "DEBA", "IE", "IM", "IP"
|
||||
};
|
||||
|
||||
if ((reg_nr < 0) || (reg_nr >= ARRAY_SIZE (register_names)))
|
||||
return NULL;
|
||||
else
|
||||
return register_names[reg_nr];
|
||||
}
|
||||
|
||||
/* Return type of register. */
|
||||
|
||||
static struct type *
|
||||
lm32_register_type (struct gdbarch *gdbarch, int reg_nr)
|
||||
{
|
||||
return builtin_type_int32;
|
||||
}
|
||||
|
||||
/* Return non-zero if a register can't be written. */
|
||||
|
||||
static int
|
||||
lm32_cannot_store_register (struct gdbarch *gdbarch, int regno)
|
||||
{
|
||||
return (regno == SIM_LM32_R0_REGNUM) || (regno == SIM_LM32_EID_REGNUM);
|
||||
}
|
||||
|
||||
/* Analyze a function's prologue. */
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_analyze_prologue (CORE_ADDR pc, CORE_ADDR limit,
|
||||
struct lm32_frame_cache *info)
|
||||
{
|
||||
unsigned long instruction;
|
||||
|
||||
/* Keep reading though instructions, until we come across an instruction
|
||||
that isn't likely to be part of the prologue. */
|
||||
info->size = 0;
|
||||
for (; pc < limit; pc += 4)
|
||||
{
|
||||
|
||||
/* Read an instruction. */
|
||||
instruction = read_memory_integer (pc, 4);
|
||||
|
||||
if ((LM32_OPCODE (instruction) == OP_SW)
|
||||
&& (LM32_REG0 (instruction) == SIM_LM32_SP_REGNUM))
|
||||
{
|
||||
/* Any stack displaced store is likely part of the prologue.
|
||||
Record that the register is being saved, and the offset
|
||||
into the stack. */
|
||||
info->saved_regs[LM32_REG1 (instruction)].addr =
|
||||
LM32_IMM16 (instruction);
|
||||
}
|
||||
else if ((LM32_OPCODE (instruction) == OP_ADDI)
|
||||
&& (LM32_REG1 (instruction) == SIM_LM32_SP_REGNUM))
|
||||
{
|
||||
/* An add to the SP is likely to be part of the prologue.
|
||||
Adjust stack size by whatever the instruction adds to the sp. */
|
||||
info->size -= LM32_IMM16 (instruction);
|
||||
}
|
||||
else if ( /* add fp,fp,sp */
|
||||
((LM32_OPCODE (instruction) == OP_ADD)
|
||||
&& (LM32_REG2 (instruction) == SIM_LM32_FP_REGNUM)
|
||||
&& (LM32_REG0 (instruction) == SIM_LM32_FP_REGNUM)
|
||||
&& (LM32_REG1 (instruction) == SIM_LM32_SP_REGNUM))
|
||||
/* mv fp,imm */
|
||||
|| ((LM32_OPCODE (instruction) == OP_ADDI)
|
||||
&& (LM32_REG1 (instruction) == SIM_LM32_FP_REGNUM)
|
||||
&& (LM32_REG0 (instruction) == SIM_LM32_R0_REGNUM)))
|
||||
{
|
||||
/* Likely to be in the prologue for functions that require
|
||||
a frame pointer. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Any other instruction is likely not to be part of the prologue. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/* Return PC of first non prologue instruction, for the function at the
|
||||
specified address. */
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
{
|
||||
CORE_ADDR func_addr, limit_pc;
|
||||
struct symtab_and_line sal;
|
||||
struct lm32_frame_cache frame_info;
|
||||
struct trad_frame_saved_reg saved_regs[SIM_LM32_NUM_REGS];
|
||||
|
||||
/* See if we can determine the end of the prologue via the symbol table.
|
||||
If so, then return either PC, or the PC after the prologue, whichever
|
||||
is greater. */
|
||||
if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
|
||||
{
|
||||
CORE_ADDR post_prologue_pc = skip_prologue_using_sal (func_addr);
|
||||
if (post_prologue_pc != 0)
|
||||
return max (pc, post_prologue_pc);
|
||||
}
|
||||
|
||||
/* Can't determine prologue from the symbol table, need to examine
|
||||
instructions. */
|
||||
|
||||
/* Find an upper limit on the function prologue using the debug
|
||||
information. If the debug information could not be used to provide
|
||||
that bound, then use an arbitrary large number as the upper bound. */
|
||||
limit_pc = skip_prologue_using_sal (pc);
|
||||
if (limit_pc == 0)
|
||||
limit_pc = pc + 100; /* Magic. */
|
||||
|
||||
frame_info.saved_regs = saved_regs;
|
||||
return lm32_analyze_prologue (pc, limit_pc, &frame_info);
|
||||
}
|
||||
|
||||
/* Create a breakpoint instruction. */
|
||||
|
||||
static const gdb_byte *
|
||||
lm32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
|
||||
int *lenptr)
|
||||
{
|
||||
static const gdb_byte breakpoint[4] = { OP_RAISE << 2, 0, 0, 2 };
|
||||
|
||||
*lenptr = sizeof (breakpoint);
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
/* Setup registers and stack for faking a call to a function in the
|
||||
inferior. */
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
||||
struct regcache *regcache, CORE_ADDR bp_addr,
|
||||
int nargs, struct value **args, CORE_ADDR sp,
|
||||
int struct_return, CORE_ADDR struct_addr)
|
||||
{
|
||||
int first_arg_reg = SIM_LM32_R1_REGNUM;
|
||||
int num_arg_regs = 8;
|
||||
int i;
|
||||
|
||||
/* Set the return address. */
|
||||
regcache_cooked_write_signed (regcache, SIM_LM32_RA_REGNUM, bp_addr);
|
||||
|
||||
/* If we're returning a large struct, a pointer to the address to
|
||||
store it at is passed as a first hidden parameter. */
|
||||
if (struct_return)
|
||||
{
|
||||
regcache_cooked_write_unsigned (regcache, first_arg_reg, struct_addr);
|
||||
first_arg_reg++;
|
||||
num_arg_regs--;
|
||||
sp -= 4;
|
||||
}
|
||||
|
||||
/* Setup parameters. */
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
struct value *arg = args[i];
|
||||
struct type *arg_type = check_typedef (value_type (arg));
|
||||
gdb_byte *contents;
|
||||
int len;
|
||||
int j;
|
||||
int reg;
|
||||
ULONGEST val;
|
||||
|
||||
/* Promote small integer types to int. */
|
||||
switch (TYPE_CODE (arg_type))
|
||||
{
|
||||
case TYPE_CODE_INT:
|
||||
case TYPE_CODE_BOOL:
|
||||
case TYPE_CODE_CHAR:
|
||||
case TYPE_CODE_RANGE:
|
||||
case TYPE_CODE_ENUM:
|
||||
if (TYPE_LENGTH (arg_type) < 4)
|
||||
{
|
||||
arg_type = builtin_type_int32;
|
||||
arg = value_cast (arg_type, arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME: Handle structures. */
|
||||
|
||||
contents = (gdb_byte *) value_contents (arg);
|
||||
len = TYPE_LENGTH (arg_type);
|
||||
val = extract_unsigned_integer (contents, len);
|
||||
|
||||
/* First num_arg_regs parameters are passed by registers,
|
||||
and the rest are passed on the stack. */
|
||||
if (i < num_arg_regs)
|
||||
regcache_cooked_write_unsigned (regcache, first_arg_reg + i, val);
|
||||
else
|
||||
{
|
||||
write_memory (sp, (void *) &val, len);
|
||||
sp -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update stack pointer. */
|
||||
regcache_cooked_write_signed (regcache, SIM_LM32_SP_REGNUM, sp);
|
||||
|
||||
/* Return adjusted stack pointer. */
|
||||
return sp;
|
||||
}
|
||||
|
||||
/* Extract return value after calling a function in the inferior. */
|
||||
|
||||
static void
|
||||
lm32_extract_return_value (struct type *type, struct regcache *regcache,
|
||||
gdb_byte *valbuf)
|
||||
{
|
||||
int offset;
|
||||
ULONGEST l;
|
||||
CORE_ADDR return_buffer;
|
||||
|
||||
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|
||||
&& TYPE_CODE (type) != TYPE_CODE_UNION
|
||||
&& TYPE_CODE (type) != TYPE_CODE_ARRAY && TYPE_LENGTH (type) <= 4)
|
||||
{
|
||||
/* Return value is returned in a single register. */
|
||||
regcache_cooked_read_unsigned (regcache, SIM_LM32_R1_REGNUM, &l);
|
||||
store_unsigned_integer (valbuf, TYPE_LENGTH (type), l);
|
||||
}
|
||||
else if ((TYPE_CODE (type) == TYPE_CODE_INT) && (TYPE_LENGTH (type) == 8))
|
||||
{
|
||||
/* 64-bit values are returned in a register pair. */
|
||||
regcache_cooked_read_unsigned (regcache, SIM_LM32_R1_REGNUM, &l);
|
||||
memcpy (valbuf, &l, 4);
|
||||
regcache_cooked_read_unsigned (regcache, SIM_LM32_R2_REGNUM, &l);
|
||||
memcpy (valbuf + 4, &l, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Aggregate types greater than a single register are returned in memory.
|
||||
FIXME: Unless they are only 2 regs?. */
|
||||
regcache_cooked_read_unsigned (regcache, SIM_LM32_R1_REGNUM, &l);
|
||||
return_buffer = l;
|
||||
read_memory (return_buffer, valbuf, TYPE_LENGTH (type));
|
||||
}
|
||||
}
|
||||
|
||||
/* Write into appropriate registers a function return value of type
|
||||
TYPE, given in virtual format. */
|
||||
static void
|
||||
lm32_store_return_value (struct type *type, struct regcache *regcache,
|
||||
const gdb_byte *valbuf)
|
||||
{
|
||||
ULONGEST val;
|
||||
int len = TYPE_LENGTH (type);
|
||||
|
||||
if (len <= 4)
|
||||
{
|
||||
val = extract_unsigned_integer (valbuf, len);
|
||||
regcache_cooked_write_unsigned (regcache, SIM_LM32_R1_REGNUM, val);
|
||||
}
|
||||
else if (len <= 8)
|
||||
{
|
||||
val = extract_unsigned_integer (valbuf, 4);
|
||||
regcache_cooked_write_unsigned (regcache, SIM_LM32_R1_REGNUM, val);
|
||||
val = extract_unsigned_integer (valbuf + 4, len - 4);
|
||||
regcache_cooked_write_unsigned (regcache, SIM_LM32_R2_REGNUM, val);
|
||||
}
|
||||
else
|
||||
error (_("lm32_store_return_value: type length too large."));
|
||||
}
|
||||
|
||||
/* Determine whether a functions return value is in a register or memory. */
|
||||
static enum return_value_convention
|
||||
lm32_return_value (struct gdbarch *gdbarch, struct type *func_type,
|
||||
struct type *valtype, struct regcache *regcache,
|
||||
gdb_byte *readbuf, const gdb_byte *writebuf)
|
||||
{
|
||||
enum type_code code = TYPE_CODE (valtype);
|
||||
|
||||
if (code == TYPE_CODE_STRUCT
|
||||
|| code == TYPE_CODE_UNION
|
||||
|| code == TYPE_CODE_ARRAY || TYPE_LENGTH (valtype) > 8)
|
||||
return RETURN_VALUE_STRUCT_CONVENTION;
|
||||
|
||||
if (readbuf)
|
||||
lm32_extract_return_value (valtype, regcache, readbuf);
|
||||
if (writebuf)
|
||||
lm32_store_return_value (valtype, regcache, writebuf);
|
||||
|
||||
return RETURN_VALUE_REGISTER_CONVENTION;
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
|
||||
{
|
||||
return frame_unwind_register_unsigned (next_frame, SIM_LM32_PC_REGNUM);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
|
||||
{
|
||||
return frame_unwind_register_unsigned (next_frame, SIM_LM32_SP_REGNUM);
|
||||
}
|
||||
|
||||
static struct frame_id
|
||||
lm32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR sp = get_frame_register_unsigned (this_frame, SIM_LM32_SP_REGNUM);
|
||||
|
||||
return frame_id_build (sp, get_frame_pc (this_frame));
|
||||
}
|
||||
|
||||
/* Put here the code to store, into fi->saved_regs, the addresses of
|
||||
the saved registers of frame described by FRAME_INFO. This
|
||||
includes special registers such as pc and fp saved in special ways
|
||||
in the stack frame. sp is even more special: the address we return
|
||||
for it IS the sp for the next frame. */
|
||||
|
||||
static struct lm32_frame_cache *
|
||||
lm32_frame_cache (struct frame_info *this_frame, void **this_prologue_cache)
|
||||
{
|
||||
CORE_ADDR prologue_pc;
|
||||
CORE_ADDR current_pc;
|
||||
ULONGEST prev_sp;
|
||||
ULONGEST this_base;
|
||||
struct lm32_frame_cache *info;
|
||||
int prefixed;
|
||||
unsigned long instruction;
|
||||
int op;
|
||||
int offsets[32];
|
||||
int i;
|
||||
long immediate;
|
||||
|
||||
if ((*this_prologue_cache))
|
||||
return (*this_prologue_cache);
|
||||
|
||||
info = FRAME_OBSTACK_ZALLOC (struct lm32_frame_cache);
|
||||
(*this_prologue_cache) = info;
|
||||
info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
|
||||
|
||||
info->pc = get_frame_func (this_frame);
|
||||
current_pc = get_frame_pc (this_frame);
|
||||
lm32_analyze_prologue (info->pc, current_pc, info);
|
||||
|
||||
/* Compute the frame's base, and the previous frame's SP. */
|
||||
this_base = get_frame_register_unsigned (this_frame, SIM_LM32_SP_REGNUM);
|
||||
prev_sp = this_base + info->size;
|
||||
info->base = this_base;
|
||||
|
||||
/* Convert callee save offsets into addresses. */
|
||||
for (i = 0; i < gdbarch_num_regs (get_frame_arch (this_frame)) - 1; i++)
|
||||
{
|
||||
if (trad_frame_addr_p (info->saved_regs, i))
|
||||
info->saved_regs[i].addr = this_base + info->saved_regs[i].addr;
|
||||
}
|
||||
|
||||
/* The call instruction moves the caller's PC in the callee's RA register.
|
||||
Since this is an unwind, do the reverse. Copy the location of RA register
|
||||
into PC (the address / regnum) so that a request for PC will be
|
||||
converted into a request for the RA register. */
|
||||
info->saved_regs[SIM_LM32_PC_REGNUM] = info->saved_regs[SIM_LM32_RA_REGNUM];
|
||||
|
||||
/* The previous frame's SP needed to be computed. Save the computed value. */
|
||||
trad_frame_set_value (info->saved_regs, SIM_LM32_SP_REGNUM, prev_sp);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
lm32_frame_this_id (struct frame_info *this_frame, void **this_cache,
|
||||
struct frame_id *this_id)
|
||||
{
|
||||
struct lm32_frame_cache *cache = lm32_frame_cache (this_frame, this_cache);
|
||||
|
||||
/* This marks the outermost frame. */
|
||||
if (cache->base == 0)
|
||||
return;
|
||||
|
||||
(*this_id) = frame_id_build (cache->base, cache->pc);
|
||||
}
|
||||
|
||||
static struct value *
|
||||
lm32_frame_prev_register (struct frame_info *this_frame,
|
||||
void **this_prologue_cache, int regnum)
|
||||
{
|
||||
struct lm32_frame_cache *info;
|
||||
|
||||
info = lm32_frame_cache (this_frame, this_prologue_cache);
|
||||
return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
|
||||
}
|
||||
|
||||
static const struct frame_unwind lm32_frame_unwind = {
|
||||
NORMAL_FRAME,
|
||||
lm32_frame_this_id,
|
||||
lm32_frame_prev_register,
|
||||
NULL,
|
||||
default_frame_sniffer
|
||||
};
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_frame_base_address (struct frame_info *this_frame, void **this_cache)
|
||||
{
|
||||
struct lm32_frame_cache *info = lm32_frame_cache (this_frame, this_cache);
|
||||
|
||||
return info->base;
|
||||
}
|
||||
|
||||
static const struct frame_base lm32_frame_base = {
|
||||
&lm32_frame_unwind,
|
||||
lm32_frame_base_address,
|
||||
lm32_frame_base_address,
|
||||
lm32_frame_base_address
|
||||
};
|
||||
|
||||
static CORE_ADDR
|
||||
lm32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
|
||||
{
|
||||
/* Align to the size of an instruction (so that they can safely be
|
||||
pushed onto the stack. */
|
||||
return sp & ~3;
|
||||
}
|
||||
|
||||
static struct gdbarch *
|
||||
lm32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
||||
{
|
||||
struct gdbarch *gdbarch;
|
||||
struct gdbarch_tdep *tdep;
|
||||
|
||||
/* If there is already a candidate, use it. */
|
||||
arches = gdbarch_list_lookup_by_info (arches, &info);
|
||||
if (arches != NULL)
|
||||
return arches->gdbarch;
|
||||
|
||||
/* None found, create a new architecture from the information provided. */
|
||||
tdep = XMALLOC (struct gdbarch_tdep);
|
||||
gdbarch = gdbarch_alloc (&info, tdep);
|
||||
|
||||
/* Type sizes. */
|
||||
set_gdbarch_short_bit (gdbarch, 16);
|
||||
set_gdbarch_int_bit (gdbarch, 32);
|
||||
set_gdbarch_long_bit (gdbarch, 32);
|
||||
set_gdbarch_long_long_bit (gdbarch, 64);
|
||||
set_gdbarch_float_bit (gdbarch, 32);
|
||||
set_gdbarch_double_bit (gdbarch, 64);
|
||||
set_gdbarch_long_double_bit (gdbarch, 64);
|
||||
set_gdbarch_ptr_bit (gdbarch, 32);
|
||||
|
||||
/* Register info. */
|
||||
set_gdbarch_num_regs (gdbarch, SIM_LM32_NUM_REGS);
|
||||
set_gdbarch_sp_regnum (gdbarch, SIM_LM32_SP_REGNUM);
|
||||
set_gdbarch_pc_regnum (gdbarch, SIM_LM32_PC_REGNUM);
|
||||
set_gdbarch_register_name (gdbarch, lm32_register_name);
|
||||
set_gdbarch_register_type (gdbarch, lm32_register_type);
|
||||
set_gdbarch_cannot_store_register (gdbarch, lm32_cannot_store_register);
|
||||
|
||||
/* Frame info. */
|
||||
set_gdbarch_skip_prologue (gdbarch, lm32_skip_prologue);
|
||||
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
|
||||
set_gdbarch_decr_pc_after_break (gdbarch, 0);
|
||||
set_gdbarch_frame_args_skip (gdbarch, 0);
|
||||
|
||||
/* Frame unwinding. */
|
||||
set_gdbarch_frame_align (gdbarch, lm32_frame_align);
|
||||
frame_base_set_default (gdbarch, &lm32_frame_base);
|
||||
set_gdbarch_unwind_pc (gdbarch, lm32_unwind_pc);
|
||||
set_gdbarch_unwind_sp (gdbarch, lm32_unwind_sp);
|
||||
set_gdbarch_dummy_id (gdbarch, lm32_dummy_id);
|
||||
frame_unwind_append_unwinder (gdbarch, &lm32_frame_unwind);
|
||||
|
||||
/* Breakpoints. */
|
||||
set_gdbarch_breakpoint_from_pc (gdbarch, lm32_breakpoint_from_pc);
|
||||
set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
|
||||
|
||||
/* Calling functions in the inferior. */
|
||||
set_gdbarch_push_dummy_call (gdbarch, lm32_push_dummy_call);
|
||||
set_gdbarch_return_value (gdbarch, lm32_return_value);
|
||||
|
||||
/* Instruction disassembler. */
|
||||
set_gdbarch_print_insn (gdbarch, print_insn_lm32);
|
||||
|
||||
lm32_add_reggroups (gdbarch);
|
||||
set_gdbarch_register_reggroup_p (gdbarch, lm32_register_reggroup_p);
|
||||
|
||||
return gdbarch;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_lm32_tdep (void)
|
||||
{
|
||||
register_gdbarch_init (bfd_arch_lm32, lm32_gdbarch_init);
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
2009-05-18 Jon Beniston <jon@beniston.com>
|
||||
|
||||
* gdb.asm/asm-source.exp: Add lm32 target.
|
||||
|
||||
2009-05-17 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
* gdb.base/foll-fork.c: Include stdlib.h. Add markers for
|
||||
|
@ -64,6 +64,9 @@ switch -glob -- [istarget] {
|
||||
"i\[3456\]86-*-*" {
|
||||
set asm-arch i386
|
||||
}
|
||||
"lm32-*" {
|
||||
set asm-arch lm32
|
||||
}
|
||||
"m32r*-linux*" {
|
||||
set asm-arch m32r-linux
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
2009-05-18 Jon Beniston <jon@beniston.com>
|
||||
|
||||
* sim-lm32.h: New file.
|
||||
|
||||
2009-01-07 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
* callback.h (struct host_callback_struct): Mark member error as
|
||||
|
76
include/gdb/sim-lm32.h
Normal file
76
include/gdb/sim-lm32.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* This file defines the interface between the LM32 simulator and GDB.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#ifndef SIM_LM32_H
|
||||
#define SIM_LM32_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { // }
|
||||
#endif
|
||||
|
||||
enum sim_lm32_regs
|
||||
{
|
||||
SIM_LM32_R0_REGNUM,
|
||||
SIM_LM32_R1_REGNUM,
|
||||
SIM_LM32_R2_REGNUM,
|
||||
SIM_LM32_R3_REGNUM,
|
||||
SIM_LM32_R4_REGNUM,
|
||||
SIM_LM32_R5_REGNUM,
|
||||
SIM_LM32_R6_REGNUM,
|
||||
SIM_LM32_R7_REGNUM,
|
||||
SIM_LM32_R8_REGNUM,
|
||||
SIM_LM32_R9_REGNUM,
|
||||
SIM_LM32_R10_REGNUM,
|
||||
SIM_LM32_R11_REGNUM,
|
||||
SIM_LM32_R12_REGNUM,
|
||||
SIM_LM32_R13_REGNUM,
|
||||
SIM_LM32_R14_REGNUM,
|
||||
SIM_LM32_R15_REGNUM,
|
||||
SIM_LM32_R16_REGNUM,
|
||||
SIM_LM32_R17_REGNUM,
|
||||
SIM_LM32_R18_REGNUM,
|
||||
SIM_LM32_R19_REGNUM,
|
||||
SIM_LM32_R20_REGNUM,
|
||||
SIM_LM32_R21_REGNUM,
|
||||
SIM_LM32_R22_REGNUM,
|
||||
SIM_LM32_R23_REGNUM,
|
||||
SIM_LM32_R24_REGNUM,
|
||||
SIM_LM32_R25_REGNUM,
|
||||
SIM_LM32_GP_REGNUM,
|
||||
SIM_LM32_FP_REGNUM,
|
||||
SIM_LM32_SP_REGNUM,
|
||||
SIM_LM32_RA_REGNUM,
|
||||
SIM_LM32_BA_REGNUM,
|
||||
SIM_LM32_EA_REGNUM,
|
||||
SIM_LM32_PC_REGNUM,
|
||||
SIM_LM32_EID_REGNUM,
|
||||
SIM_LM32_EBA_REGNUM,
|
||||
SIM_LM32_DEBA_REGNUM,
|
||||
SIM_LM32_IE_REGNUM,
|
||||
SIM_LM32_IM_REGNUM,
|
||||
SIM_LM32_IP_REGNUM,
|
||||
SIM_LM32_NUM_REGS
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,3 +1,9 @@
|
||||
2009-05-18 Jon Beniston <jon@beniston.com>
|
||||
|
||||
* MAINTAINERS: Add Jon Beniston as maintainer of lm32 sim.
|
||||
* configure.ac: Add lm32 target.
|
||||
* lm32: New directory.
|
||||
|
||||
2009-05-11 Andrew Cagney <cagney@gnu.org>
|
||||
|
||||
* MAINTAINERS: Orphan ppc.
|
||||
|
@ -13,6 +13,7 @@ arm Nick Clifton <nickc@redhat.com>
|
||||
cr16 M R Swami Reddy <MR.Swami.Reddy@nsc.com>
|
||||
frv Dave Brolley <brolley@redhat.com>
|
||||
igen (igen simulators)
|
||||
lm32 Jon Beniston <jon@beniston.com>
|
||||
m68hc11 Stephane Carrez <stcarrez@nerim.fr>
|
||||
mips Thiemo Seufer <ths@networkno.de>
|
||||
moxie Anthony Green <green@moxielogic.com>
|
||||
|
@ -1,3 +1,8 @@
|
||||
2009-05-18 Jon Beniston <jon@beniston.com>
|
||||
|
||||
* gennltvals.sh: Add lm32 target.
|
||||
* nltvals.def: Add lm32 syscall definitions.
|
||||
|
||||
2009-03-19 J"orn Rennecke <joern.rennecke@arc.com> (tiny change)
|
||||
|
||||
Speed up simulator startup:
|
||||
|
@ -73,3 +73,6 @@ dir=libgloss/v850/sys target=v850
|
||||
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
|
||||
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
|
||||
|
||||
dir=libgloss target=lm32
|
||||
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
|
||||
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
|
||||
|
@ -454,3 +454,30 @@
|
||||
/* end cr16 sys target macros */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef NL_TARGET_lm32
|
||||
#ifdef sys_defs
|
||||
/* from syscall.h */
|
||||
/* begin lm32 sys target macros */
|
||||
{ "SYS_argv", 13 },
|
||||
{ "SYS_argvlen", 12 },
|
||||
{ "SYS_chdir", 14 },
|
||||
{ "SYS_chmod", 16 },
|
||||
{ "SYS_close", 3 },
|
||||
{ "SYS_exit", 1 },
|
||||
{ "SYS_fstat", 10 },
|
||||
{ "SYS_getpid", 8 },
|
||||
{ "SYS_gettimeofday", 19 },
|
||||
{ "SYS_kill", 9 },
|
||||
{ "SYS_link", 21 },
|
||||
{ "SYS_lseek", 6 },
|
||||
{ "SYS_open", 2 },
|
||||
{ "SYS_read", 4 },
|
||||
{ "SYS_stat", 15 },
|
||||
{ "SYS_time", 18 },
|
||||
{ "SYS_times", 20 },
|
||||
{ "SYS_unlink", 7 },
|
||||
{ "SYS_utime", 17 },
|
||||
{ "SYS_write", 5 },
|
||||
/* end lm32 sys target macros */
|
||||
#endif
|
||||
#endif
|
||||
|
8
sim/configure
vendored
8
sim/configure
vendored
@ -280,6 +280,7 @@ ac_subdirs_all="$ac_subdirs_all d10v"
|
||||
ac_subdirs_all="$ac_subdirs_all frv"
|
||||
ac_subdirs_all="$ac_subdirs_all h8300"
|
||||
ac_subdirs_all="$ac_subdirs_all iq2000"
|
||||
ac_subdirs_all="$ac_subdirs_all lm32"
|
||||
ac_subdirs_all="$ac_subdirs_all m32c"
|
||||
ac_subdirs_all="$ac_subdirs_all m32r"
|
||||
ac_subdirs_all="$ac_subdirs_all m68hc11"
|
||||
@ -3473,6 +3474,13 @@ subdirs="$subdirs iq2000"
|
||||
|
||||
testsuite=yes
|
||||
;;
|
||||
lm32-*-*)
|
||||
|
||||
|
||||
subdirs="$subdirs lm32"
|
||||
|
||||
testsuite=yes
|
||||
;;
|
||||
m32c-*-*)
|
||||
|
||||
|
||||
|
@ -77,6 +77,10 @@ if test "${enable_sim}" != no; then
|
||||
AC_CONFIG_SUBDIRS(iq2000)
|
||||
testsuite=yes
|
||||
;;
|
||||
lm32-*-*)
|
||||
AC_CONFIG_SUBDIRS(lm32)
|
||||
testsuite=yes
|
||||
;;
|
||||
m32c-*-*)
|
||||
AC_CONFIG_SUBDIRS(m32c)
|
||||
;;
|
||||
|
90
sim/lm32/Makefile.in
Normal file
90
sim/lm32/Makefile.in
Normal file
@ -0,0 +1,90 @@
|
||||
# Makefile for Lattice Mico32 simulator.
|
||||
# Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
## COMMON_PRE_CONFIG_FRAG
|
||||
|
||||
# List of object files, less common parts.
|
||||
SIM_OBJS = \
|
||||
$(SIM_NEW_COMMON_OBJS) \
|
||||
sim-cpu.o \
|
||||
sim-hload.o \
|
||||
sim-hrw.o \
|
||||
sim-model.o \
|
||||
sim-reg.o \
|
||||
sim-signal.o \
|
||||
cgen-utils.o cgen-trace.o cgen-scache.o \
|
||||
cgen-run.o sim-reason.o sim-engine.o sim-stop.o \
|
||||
sim-if.o arch.o \
|
||||
cpu.o decode.o sem.o model.o mloop.o \
|
||||
lm32.o traps.o user.o
|
||||
|
||||
# List of extra dependencies.
|
||||
# Generally this consists of simulator specific files included by sim-main.h.
|
||||
SIM_EXTRA_DEPS = $(CGEN_INCLUDE_DEPS) $(srcdir)/../../opcodes/lm32-desc.h
|
||||
|
||||
# List of flags to always pass to $(CC).
|
||||
#SIM_EXTRA_CFLAGS =
|
||||
|
||||
# List of main object files for `run'.
|
||||
SIM_RUN_OBJS = nrun.o
|
||||
|
||||
SIM_EXTRA_CLEAN = lm32-clean
|
||||
|
||||
# This selects the lm32 newlib/libgloss syscall definitions.
|
||||
NL_TARGET = -DNL_TARGET_lm32
|
||||
|
||||
## COMMON_POST_CONFIG_FRAG
|
||||
|
||||
arch = lm32
|
||||
|
||||
arch.o: arch.c $(SIM_MAIN_DEPS)
|
||||
|
||||
sim-if.o: sim-if.c $(SIM_MAIN_DEPS) $(srcdir)/../common/sim-core.h
|
||||
|
||||
LM32BF_INCLUDE_DEPS = \
|
||||
$(CGEN_MAIN_CPU_DEPS) \
|
||||
cpu.h decode.h eng.h
|
||||
|
||||
lm32.o: lm32.c $(LM32BF_INCLUDE_DEPS)
|
||||
|
||||
# FIXME: Use of `mono' is wip.
|
||||
mloop.c eng.h: stamp-mloop
|
||||
stamp-mloop: $(srcdir)/../common/genmloop.sh mloop.in Makefile
|
||||
$(SHELL) $(srccom)/genmloop.sh \
|
||||
-mono -fast -pbb -switch sem-switch.c \
|
||||
-cpu lm32bf -infile $(srcdir)/mloop.in
|
||||
$(SHELL) $(srcroot)/move-if-change eng.hin eng.h
|
||||
$(SHELL) $(srcroot)/move-if-change mloop.cin mloop.c
|
||||
touch stamp-mloop
|
||||
mloop.o: mloop.c sem-switch.c
|
||||
|
||||
cpu.o: cpu.c $(LM32BF_INCLUDE_DEPS)
|
||||
decode.o: decode.c $(LM32BF_INCLUDE_DEPS)
|
||||
sem.o: sem.c $(LM32BF_INCLUDE_DEPS)
|
||||
model.o: model.c $(LM32BF_INCLUDE_DEPS)
|
||||
|
||||
lm32-clean:
|
||||
rm -f mloop.c eng.h stamp-mloop
|
||||
rm -f stamp-arch stamp-cpu
|
||||
rm -f tmp-*
|
||||
|
||||
# cgen support, enable with --enable-cgen-maint
|
||||
CGEN_MAINT = ; @true
|
||||
# The following line is commented in or out depending upon --enable-cgen-maint.
|
||||
@CGEN_MAINT@CGEN_MAINT =
|
||||
|
||||
stamp-arch: $(CGEN_READ_SCM) $(CGEN_ARCH_SCM) $(CGEN_CPU_DIR)/lm32.cpu
|
||||
$(MAKE) cgen-arch $(CGEN_FLAGS_TO_PASS) mach=all \
|
||||
archfile=$(CGEN_CPU_DIR)/lm32.cpu \
|
||||
FLAGS="with-scache with-profile=fn"
|
||||
touch stamp-arch
|
||||
arch.h arch.c cpuall.h: $(CGEN_MAINT) stamp-arch
|
||||
|
||||
stamp-cpu: $(CGEN_READ_SCM) $(CGEN_CPU_SCM) $(CGEN_DECODE_SCM) $(CGEN_CPU_DIR)/lm32.cpu
|
||||
$(MAKE) cgen-cpu-decode $(CGEN_FLAGS_TO_PASS) \
|
||||
cpu=lm32bf mach=lm32 SUFFIX= \
|
||||
archfile=$(CGEN_CPU_DIR)/lm32.cpu \
|
||||
FLAGS="with-scache with-profile=fn" \
|
||||
EXTRAFILES="$(CGEN_CPU_SEM) $(CGEN_CPU_SEMSW)"
|
||||
touch stamp-cpu
|
||||
cpu.h sem.c sem-switch.c model.c decode.c decode.h: $(CGEN_MAINT) stamp-cpu
|
35
sim/lm32/arch.c
Normal file
35
sim/lm32/arch.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* Simulator support for lm32.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "sim-main.h"
|
||||
#include "bfd.h"
|
||||
|
||||
const MACH *sim_machs[] =
|
||||
{
|
||||
#ifdef HAVE_CPU_LM32BF
|
||||
& lm32_mach,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
44
sim/lm32/arch.h
Normal file
44
sim/lm32/arch.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* Simulator header for lm32.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LM32_ARCH_H
|
||||
#define LM32_ARCH_H
|
||||
|
||||
#define TARGET_BIG_ENDIAN 1
|
||||
|
||||
/* Enum declaration for model types. */
|
||||
typedef enum model_type {
|
||||
MODEL_LM32, MODEL_MAX
|
||||
} MODEL_TYPE;
|
||||
|
||||
#define MAX_MODELS ((int) MODEL_MAX)
|
||||
|
||||
/* Enum declaration for unit types. */
|
||||
typedef enum unit_type {
|
||||
UNIT_NONE, UNIT_LM32_U_EXEC, UNIT_MAX
|
||||
} UNIT_TYPE;
|
||||
|
||||
#define MAX_UNITS (1)
|
||||
|
||||
#endif /* LM32_ARCH_H */
|
116
sim/lm32/config.in
Normal file
116
sim/lm32/config.in
Normal file
@ -0,0 +1,116 @@
|
||||
/* config.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <fpu_control.h> header file. */
|
||||
#undef HAVE_FPU_CONTROL_H
|
||||
|
||||
/* Define to 1 if you have the `getrusage' function. */
|
||||
#undef HAVE_GETRUSAGE
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `time' function. */
|
||||
#undef HAVE_TIME
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#undef HAVE_ZLIB_H
|
||||
|
||||
/* Define to 1 if you have the `__setfpucw' function. */
|
||||
#undef HAVE___SETFPUCW
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Additional package description */
|
||||
#undef PKGVERSION
|
||||
|
||||
/* Bug reporting address */
|
||||
#undef REPORT_BUGS_TO
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
7508
sim/lm32/configure
vendored
Executable file
7508
sim/lm32/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
21
sim/lm32/configure.ac
Normal file
21
sim/lm32/configure.ac
Normal file
@ -0,0 +1,21 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.59)dnl
|
||||
AC_INIT(Makefile.in)
|
||||
AC_CONFIG_HEADER(config.h:config.in)
|
||||
|
||||
sinclude(../common/aclocal.m4)
|
||||
|
||||
# Bugs in autoconf 2.59 break the call to SIM_AC_COMMON, hack around
|
||||
# it by inlining the macro's contents.
|
||||
sinclude(../common/common.m4)
|
||||
|
||||
SIM_AC_OPTION_ENDIAN(BIG_ENDIAN)
|
||||
SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
|
||||
SIM_AC_OPTION_HOSTENDIAN
|
||||
SIM_AC_OPTION_SCACHE(16384)
|
||||
SIM_AC_OPTION_DEFAULT_MODEL(lm32)
|
||||
SIM_AC_OPTION_ENVIRONMENT
|
||||
SIM_AC_OPTION_CGEN_MAINT
|
||||
SIM_AC_OPTION_HARDWARE(yes,,lm32cpu lm32timer lm32uart)
|
||||
|
||||
SIM_AC_OUTPUT
|
85
sim/lm32/cpu.c
Normal file
85
sim/lm32/cpu.c
Normal file
@ -0,0 +1,85 @@
|
||||
/* Misc. support for CPU family lm32bf.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#define WANT_CPU lm32bf
|
||||
#define WANT_CPU_LM32BF
|
||||
|
||||
#include "sim-main.h"
|
||||
#include "cgen-ops.h"
|
||||
|
||||
/* Get the value of h-pc. */
|
||||
|
||||
USI
|
||||
lm32bf_h_pc_get (SIM_CPU *current_cpu)
|
||||
{
|
||||
return CPU (h_pc);
|
||||
}
|
||||
|
||||
/* Set a value for h-pc. */
|
||||
|
||||
void
|
||||
lm32bf_h_pc_set (SIM_CPU *current_cpu, USI newval)
|
||||
{
|
||||
CPU (h_pc) = newval;
|
||||
}
|
||||
|
||||
/* Get the value of h-gr. */
|
||||
|
||||
SI
|
||||
lm32bf_h_gr_get (SIM_CPU *current_cpu, UINT regno)
|
||||
{
|
||||
return CPU (h_gr[regno]);
|
||||
}
|
||||
|
||||
/* Set a value for h-gr. */
|
||||
|
||||
void
|
||||
lm32bf_h_gr_set (SIM_CPU *current_cpu, UINT regno, SI newval)
|
||||
{
|
||||
CPU (h_gr[regno]) = newval;
|
||||
}
|
||||
|
||||
/* Get the value of h-csr. */
|
||||
|
||||
SI
|
||||
lm32bf_h_csr_get (SIM_CPU *current_cpu, UINT regno)
|
||||
{
|
||||
return CPU (h_csr[regno]);
|
||||
}
|
||||
|
||||
/* Set a value for h-csr. */
|
||||
|
||||
void
|
||||
lm32bf_h_csr_set (SIM_CPU *current_cpu, UINT regno, SI newval)
|
||||
{
|
||||
CPU (h_csr[regno]) = newval;
|
||||
}
|
||||
|
||||
/* Record trace results for INSN. */
|
||||
|
||||
void
|
||||
lm32bf_record_trace_results (SIM_CPU *current_cpu, CGEN_INSN *insn,
|
||||
int *indices, TRACE_RECORD *tr)
|
||||
{
|
||||
}
|
349
sim/lm32/cpu.h
Normal file
349
sim/lm32/cpu.h
Normal file
@ -0,0 +1,349 @@
|
||||
/* CPU family header for lm32bf.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CPU_LM32BF_H
|
||||
#define CPU_LM32BF_H
|
||||
|
||||
/* Maximum number of instructions that are fetched at a time.
|
||||
This is for LIW type instructions sets (e.g. m32r). */
|
||||
#define MAX_LIW_INSNS 1
|
||||
|
||||
/* Maximum number of instructions that can be executed in parallel. */
|
||||
#define MAX_PARALLEL_INSNS 1
|
||||
|
||||
/* CPU state information. */
|
||||
typedef struct {
|
||||
/* Hardware elements. */
|
||||
struct {
|
||||
/* Program counter */
|
||||
USI h_pc;
|
||||
#define GET_H_PC() CPU (h_pc)
|
||||
#define SET_H_PC(x) (CPU (h_pc) = (x))
|
||||
/* General purpose registers */
|
||||
SI h_gr[32];
|
||||
#define GET_H_GR(a1) CPU (h_gr)[a1]
|
||||
#define SET_H_GR(a1, x) (CPU (h_gr)[a1] = (x))
|
||||
/* Control and status registers */
|
||||
SI h_csr[32];
|
||||
#define GET_H_CSR(a1) CPU (h_csr)[a1]
|
||||
#define SET_H_CSR(a1, x) (CPU (h_csr)[a1] = (x))
|
||||
} hardware;
|
||||
#define CPU_CGEN_HW(cpu) (& (cpu)->cpu_data.hardware)
|
||||
} LM32BF_CPU_DATA;
|
||||
|
||||
/* Cover fns for register access. */
|
||||
USI lm32bf_h_pc_get (SIM_CPU *);
|
||||
void lm32bf_h_pc_set (SIM_CPU *, USI);
|
||||
SI lm32bf_h_gr_get (SIM_CPU *, UINT);
|
||||
void lm32bf_h_gr_set (SIM_CPU *, UINT, SI);
|
||||
SI lm32bf_h_csr_get (SIM_CPU *, UINT);
|
||||
void lm32bf_h_csr_set (SIM_CPU *, UINT, SI);
|
||||
|
||||
/* These must be hand-written. */
|
||||
extern CPUREG_FETCH_FN lm32bf_fetch_register;
|
||||
extern CPUREG_STORE_FN lm32bf_store_register;
|
||||
|
||||
typedef struct {
|
||||
int empty;
|
||||
} MODEL_LM32_DATA;
|
||||
|
||||
/* Instruction argument buffer. */
|
||||
|
||||
union sem_fields {
|
||||
struct { /* no operands */
|
||||
int empty;
|
||||
} fmt_empty;
|
||||
struct { /* */
|
||||
IADDR i_call;
|
||||
} sfmt_bi;
|
||||
struct { /* */
|
||||
UINT f_csr;
|
||||
UINT f_r1;
|
||||
} sfmt_wcsr;
|
||||
struct { /* */
|
||||
UINT f_csr;
|
||||
UINT f_r2;
|
||||
} sfmt_rcsr;
|
||||
struct { /* */
|
||||
IADDR i_branch;
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
} sfmt_be;
|
||||
struct { /* */
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_uimm;
|
||||
} sfmt_andi;
|
||||
struct { /* */
|
||||
INT f_imm;
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
} sfmt_addi;
|
||||
struct { /* */
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_r2;
|
||||
UINT f_user;
|
||||
} sfmt_user;
|
||||
#if WITH_SCACHE_PBB
|
||||
/* Writeback handler. */
|
||||
struct {
|
||||
/* Pointer to argbuf entry for insn whose results need writing back. */
|
||||
const struct argbuf *abuf;
|
||||
} write;
|
||||
/* x-before handler */
|
||||
struct {
|
||||
/*const SCACHE *insns[MAX_PARALLEL_INSNS];*/
|
||||
int first_p;
|
||||
} before;
|
||||
/* x-after handler */
|
||||
struct {
|
||||
int empty;
|
||||
} after;
|
||||
/* This entry is used to terminate each pbb. */
|
||||
struct {
|
||||
/* Number of insns in pbb. */
|
||||
int insn_count;
|
||||
/* Next pbb to execute. */
|
||||
SCACHE *next;
|
||||
SCACHE *branch_target;
|
||||
} chain;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The ARGBUF struct. */
|
||||
struct argbuf {
|
||||
/* These are the baseclass definitions. */
|
||||
IADDR addr;
|
||||
const IDESC *idesc;
|
||||
char trace_p;
|
||||
char profile_p;
|
||||
/* ??? Temporary hack for skip insns. */
|
||||
char skip_count;
|
||||
char unused;
|
||||
/* cpu specific data follows */
|
||||
union sem semantic;
|
||||
int written;
|
||||
union sem_fields fields;
|
||||
};
|
||||
|
||||
/* A cached insn.
|
||||
|
||||
??? SCACHE used to contain more than just argbuf. We could delete the
|
||||
type entirely and always just use ARGBUF, but for future concerns and as
|
||||
a level of abstraction it is left in. */
|
||||
|
||||
struct scache {
|
||||
struct argbuf argbuf;
|
||||
};
|
||||
|
||||
/* Macros to simplify extraction, reading and semantic code.
|
||||
These define and assign the local vars that contain the insn's fields. */
|
||||
|
||||
#define EXTRACT_IFMT_EMPTY_VARS \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_EMPTY_CODE \
|
||||
length = 0; \
|
||||
|
||||
#define EXTRACT_IFMT_ADD_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_r2; \
|
||||
UINT f_resv0; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_ADD_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
|
||||
f_resv0 = EXTRACT_LSB0_UINT (insn, 32, 10, 11); \
|
||||
|
||||
#define EXTRACT_IFMT_ADDI_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
INT f_imm; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_ADDI_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16); \
|
||||
|
||||
#define EXTRACT_IFMT_ANDI_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_uimm; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_ANDI_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_uimm = EXTRACT_LSB0_UINT (insn, 32, 15, 16); \
|
||||
|
||||
#define EXTRACT_IFMT_ANDHII_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_uimm; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_ANDHII_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_uimm = EXTRACT_LSB0_UINT (insn, 32, 15, 16); \
|
||||
|
||||
#define EXTRACT_IFMT_B_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_r2; \
|
||||
UINT f_resv0; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_B_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
|
||||
f_resv0 = EXTRACT_LSB0_UINT (insn, 32, 10, 11); \
|
||||
|
||||
#define EXTRACT_IFMT_BI_VARS \
|
||||
UINT f_opcode; \
|
||||
SI f_call; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_BI_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_call = ((pc) + (((int) (((EXTRACT_LSB0_INT (insn, 32, 25, 26)) << (6))) >> (4)))); \
|
||||
|
||||
#define EXTRACT_IFMT_BE_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
SI f_branch; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_BE_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_branch = ((pc) + (((int) (((EXTRACT_LSB0_INT (insn, 32, 15, 16)) << (16))) >> (14)))); \
|
||||
|
||||
#define EXTRACT_IFMT_ORI_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_uimm; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_ORI_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_uimm = EXTRACT_LSB0_UINT (insn, 32, 15, 16); \
|
||||
|
||||
#define EXTRACT_IFMT_RCSR_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_csr; \
|
||||
UINT f_r1; \
|
||||
UINT f_r2; \
|
||||
UINT f_resv0; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_RCSR_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_csr = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
|
||||
f_resv0 = EXTRACT_LSB0_UINT (insn, 32, 10, 11); \
|
||||
|
||||
#define EXTRACT_IFMT_SEXTB_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_r2; \
|
||||
UINT f_resv0; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_SEXTB_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
|
||||
f_resv0 = EXTRACT_LSB0_UINT (insn, 32, 10, 11); \
|
||||
|
||||
#define EXTRACT_IFMT_USER_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_r0; \
|
||||
UINT f_r1; \
|
||||
UINT f_r2; \
|
||||
UINT f_user; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_USER_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
|
||||
f_user = EXTRACT_LSB0_UINT (insn, 32, 10, 11); \
|
||||
|
||||
#define EXTRACT_IFMT_WCSR_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_csr; \
|
||||
UINT f_r1; \
|
||||
UINT f_r2; \
|
||||
UINT f_resv0; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_WCSR_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_csr = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
|
||||
f_resv0 = EXTRACT_LSB0_UINT (insn, 32, 10, 11); \
|
||||
|
||||
#define EXTRACT_IFMT_BREAK_VARS \
|
||||
UINT f_opcode; \
|
||||
UINT f_exception; \
|
||||
unsigned int length;
|
||||
#define EXTRACT_IFMT_BREAK_CODE \
|
||||
length = 4; \
|
||||
f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
|
||||
f_exception = EXTRACT_LSB0_UINT (insn, 32, 25, 26); \
|
||||
|
||||
/* Collection of various things for the trace handler to use. */
|
||||
|
||||
typedef struct trace_record {
|
||||
IADDR pc;
|
||||
/* FIXME:wip */
|
||||
} TRACE_RECORD;
|
||||
|
||||
#endif /* CPU_LM32BF_H */
|
66
sim/lm32/cpuall.h
Normal file
66
sim/lm32/cpuall.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* Simulator CPU header for lm32.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LM32_CPUALL_H
|
||||
#define LM32_CPUALL_H
|
||||
|
||||
/* Include files for each cpu family. */
|
||||
|
||||
#ifdef WANT_CPU_LM32BF
|
||||
#include "eng.h"
|
||||
#include "cgen-engine.h"
|
||||
#include "cpu.h"
|
||||
#include "decode.h"
|
||||
#endif
|
||||
|
||||
extern const MACH lm32_mach;
|
||||
|
||||
#ifndef WANT_CPU
|
||||
/* The ARGBUF struct. */
|
||||
struct argbuf {
|
||||
/* These are the baseclass definitions. */
|
||||
IADDR addr;
|
||||
const IDESC *idesc;
|
||||
char trace_p;
|
||||
char profile_p;
|
||||
/* ??? Temporary hack for skip insns. */
|
||||
char skip_count;
|
||||
char unused;
|
||||
/* cpu specific data follows */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef WANT_CPU
|
||||
/* A cached insn.
|
||||
|
||||
??? SCACHE used to contain more than just argbuf. We could delete the
|
||||
type entirely and always just use ARGBUF, but for future concerns and as
|
||||
a level of abstraction it is left in. */
|
||||
|
||||
struct scache {
|
||||
struct argbuf argbuf;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* LM32_CPUALL_H */
|
955
sim/lm32/decode.c
Normal file
955
sim/lm32/decode.c
Normal file
@ -0,0 +1,955 @@
|
||||
/* Simulator instruction decoder for lm32bf.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#define WANT_CPU lm32bf
|
||||
#define WANT_CPU_LM32BF
|
||||
|
||||
#include "sim-main.h"
|
||||
#include "sim-assert.h"
|
||||
|
||||
/* The instruction descriptor array.
|
||||
This is computed at runtime. Space for it is not malloc'd to save a
|
||||
teensy bit of cpu in the decoder. Moving it to malloc space is trivial
|
||||
but won't be done until necessary (we don't currently support the runtime
|
||||
addition of instructions nor an SMP machine with different cpus). */
|
||||
static IDESC lm32bf_insn_data[LM32BF_INSN__MAX];
|
||||
|
||||
/* Commas between elements are contained in the macros.
|
||||
Some of these are conditionally compiled out. */
|
||||
|
||||
static const struct insn_sem lm32bf_insn_sem[] =
|
||||
{
|
||||
{ VIRTUAL_INSN_X_INVALID, LM32BF_INSN_X_INVALID, LM32BF_SFMT_EMPTY },
|
||||
{ VIRTUAL_INSN_X_AFTER, LM32BF_INSN_X_AFTER, LM32BF_SFMT_EMPTY },
|
||||
{ VIRTUAL_INSN_X_BEFORE, LM32BF_INSN_X_BEFORE, LM32BF_SFMT_EMPTY },
|
||||
{ VIRTUAL_INSN_X_CTI_CHAIN, LM32BF_INSN_X_CTI_CHAIN, LM32BF_SFMT_EMPTY },
|
||||
{ VIRTUAL_INSN_X_CHAIN, LM32BF_INSN_X_CHAIN, LM32BF_SFMT_EMPTY },
|
||||
{ VIRTUAL_INSN_X_BEGIN, LM32BF_INSN_X_BEGIN, LM32BF_SFMT_EMPTY },
|
||||
{ LM32_INSN_ADD, LM32BF_INSN_ADD, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_ADDI, LM32BF_INSN_ADDI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_AND, LM32BF_INSN_AND, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_ANDI, LM32BF_INSN_ANDI, LM32BF_SFMT_ANDI },
|
||||
{ LM32_INSN_ANDHII, LM32BF_INSN_ANDHII, LM32BF_SFMT_ANDHII },
|
||||
{ LM32_INSN_B, LM32BF_INSN_B, LM32BF_SFMT_B },
|
||||
{ LM32_INSN_BI, LM32BF_INSN_BI, LM32BF_SFMT_BI },
|
||||
{ LM32_INSN_BE, LM32BF_INSN_BE, LM32BF_SFMT_BE },
|
||||
{ LM32_INSN_BG, LM32BF_INSN_BG, LM32BF_SFMT_BE },
|
||||
{ LM32_INSN_BGE, LM32BF_INSN_BGE, LM32BF_SFMT_BE },
|
||||
{ LM32_INSN_BGEU, LM32BF_INSN_BGEU, LM32BF_SFMT_BE },
|
||||
{ LM32_INSN_BGU, LM32BF_INSN_BGU, LM32BF_SFMT_BE },
|
||||
{ LM32_INSN_BNE, LM32BF_INSN_BNE, LM32BF_SFMT_BE },
|
||||
{ LM32_INSN_CALL, LM32BF_INSN_CALL, LM32BF_SFMT_CALL },
|
||||
{ LM32_INSN_CALLI, LM32BF_INSN_CALLI, LM32BF_SFMT_CALLI },
|
||||
{ LM32_INSN_CMPE, LM32BF_INSN_CMPE, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_CMPEI, LM32BF_INSN_CMPEI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_CMPG, LM32BF_INSN_CMPG, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_CMPGI, LM32BF_INSN_CMPGI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_CMPGE, LM32BF_INSN_CMPGE, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_CMPGEI, LM32BF_INSN_CMPGEI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_CMPGEU, LM32BF_INSN_CMPGEU, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_CMPGEUI, LM32BF_INSN_CMPGEUI, LM32BF_SFMT_ANDI },
|
||||
{ LM32_INSN_CMPGU, LM32BF_INSN_CMPGU, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_CMPGUI, LM32BF_INSN_CMPGUI, LM32BF_SFMT_ANDI },
|
||||
{ LM32_INSN_CMPNE, LM32BF_INSN_CMPNE, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_CMPNEI, LM32BF_INSN_CMPNEI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_DIVU, LM32BF_INSN_DIVU, LM32BF_SFMT_DIVU },
|
||||
{ LM32_INSN_LB, LM32BF_INSN_LB, LM32BF_SFMT_LB },
|
||||
{ LM32_INSN_LBU, LM32BF_INSN_LBU, LM32BF_SFMT_LB },
|
||||
{ LM32_INSN_LH, LM32BF_INSN_LH, LM32BF_SFMT_LH },
|
||||
{ LM32_INSN_LHU, LM32BF_INSN_LHU, LM32BF_SFMT_LH },
|
||||
{ LM32_INSN_LW, LM32BF_INSN_LW, LM32BF_SFMT_LW },
|
||||
{ LM32_INSN_MODU, LM32BF_INSN_MODU, LM32BF_SFMT_DIVU },
|
||||
{ LM32_INSN_MUL, LM32BF_INSN_MUL, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_MULI, LM32BF_INSN_MULI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_NOR, LM32BF_INSN_NOR, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_NORI, LM32BF_INSN_NORI, LM32BF_SFMT_ANDI },
|
||||
{ LM32_INSN_OR, LM32BF_INSN_OR, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_ORI, LM32BF_INSN_ORI, LM32BF_SFMT_ORI },
|
||||
{ LM32_INSN_ORHII, LM32BF_INSN_ORHII, LM32BF_SFMT_ANDHII },
|
||||
{ LM32_INSN_RCSR, LM32BF_INSN_RCSR, LM32BF_SFMT_RCSR },
|
||||
{ LM32_INSN_SB, LM32BF_INSN_SB, LM32BF_SFMT_SB },
|
||||
{ LM32_INSN_SEXTB, LM32BF_INSN_SEXTB, LM32BF_SFMT_SEXTB },
|
||||
{ LM32_INSN_SEXTH, LM32BF_INSN_SEXTH, LM32BF_SFMT_SEXTB },
|
||||
{ LM32_INSN_SH, LM32BF_INSN_SH, LM32BF_SFMT_SH },
|
||||
{ LM32_INSN_SL, LM32BF_INSN_SL, LM32BF_SFMT_SL },
|
||||
{ LM32_INSN_SLI, LM32BF_INSN_SLI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_SR, LM32BF_INSN_SR, LM32BF_SFMT_SL },
|
||||
{ LM32_INSN_SRI, LM32BF_INSN_SRI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_SRU, LM32BF_INSN_SRU, LM32BF_SFMT_SL },
|
||||
{ LM32_INSN_SRUI, LM32BF_INSN_SRUI, LM32BF_SFMT_ADDI },
|
||||
{ LM32_INSN_SUB, LM32BF_INSN_SUB, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_SW, LM32BF_INSN_SW, LM32BF_SFMT_SW },
|
||||
{ LM32_INSN_USER, LM32BF_INSN_USER, LM32BF_SFMT_USER },
|
||||
{ LM32_INSN_WCSR, LM32BF_INSN_WCSR, LM32BF_SFMT_WCSR },
|
||||
{ LM32_INSN_XOR, LM32BF_INSN_XOR, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_XORI, LM32BF_INSN_XORI, LM32BF_SFMT_ANDI },
|
||||
{ LM32_INSN_XNOR, LM32BF_INSN_XNOR, LM32BF_SFMT_ADD },
|
||||
{ LM32_INSN_XNORI, LM32BF_INSN_XNORI, LM32BF_SFMT_ANDI },
|
||||
{ LM32_INSN_BREAK, LM32BF_INSN_BREAK, LM32BF_SFMT_BREAK },
|
||||
{ LM32_INSN_SCALL, LM32BF_INSN_SCALL, LM32BF_SFMT_BREAK },
|
||||
};
|
||||
|
||||
static const struct insn_sem lm32bf_insn_sem_invalid = {
|
||||
VIRTUAL_INSN_X_INVALID, LM32BF_INSN_X_INVALID, LM32BF_SFMT_EMPTY
|
||||
};
|
||||
|
||||
/* Initialize an IDESC from the compile-time computable parts. */
|
||||
|
||||
static INLINE void
|
||||
init_idesc (SIM_CPU *cpu, IDESC *id, const struct insn_sem *t)
|
||||
{
|
||||
const CGEN_INSN *insn_table = CGEN_CPU_INSN_TABLE (CPU_CPU_DESC (cpu))->init_entries;
|
||||
|
||||
id->num = t->index;
|
||||
id->sfmt = t->sfmt;
|
||||
if ((int) t->type <= 0)
|
||||
id->idata = & cgen_virtual_insn_table[- (int) t->type];
|
||||
else
|
||||
id->idata = & insn_table[t->type];
|
||||
id->attrs = CGEN_INSN_ATTRS (id->idata);
|
||||
/* Oh my god, a magic number. */
|
||||
id->length = CGEN_INSN_BITSIZE (id->idata) / 8;
|
||||
|
||||
#if WITH_PROFILE_MODEL_P
|
||||
id->timing = & MODEL_TIMING (CPU_MODEL (cpu)) [t->index];
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (cpu);
|
||||
SIM_ASSERT (t->index == id->timing->num);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Semantic pointers are initialized elsewhere. */
|
||||
}
|
||||
|
||||
/* Initialize the instruction descriptor table. */
|
||||
|
||||
void
|
||||
lm32bf_init_idesc_table (SIM_CPU *cpu)
|
||||
{
|
||||
IDESC *id,*tabend;
|
||||
const struct insn_sem *t,*tend;
|
||||
int tabsize = LM32BF_INSN__MAX;
|
||||
IDESC *table = lm32bf_insn_data;
|
||||
|
||||
memset (table, 0, tabsize * sizeof (IDESC));
|
||||
|
||||
/* First set all entries to the `invalid insn'. */
|
||||
t = & lm32bf_insn_sem_invalid;
|
||||
for (id = table, tabend = table + tabsize; id < tabend; ++id)
|
||||
init_idesc (cpu, id, t);
|
||||
|
||||
/* Now fill in the values for the chosen cpu. */
|
||||
for (t = lm32bf_insn_sem, tend = t + sizeof (lm32bf_insn_sem) / sizeof (*t);
|
||||
t != tend; ++t)
|
||||
{
|
||||
init_idesc (cpu, & table[t->index], t);
|
||||
}
|
||||
|
||||
/* Link the IDESC table into the cpu. */
|
||||
CPU_IDESC (cpu) = table;
|
||||
}
|
||||
|
||||
/* Given an instruction, return a pointer to its IDESC entry. */
|
||||
|
||||
const IDESC *
|
||||
lm32bf_decode (SIM_CPU *current_cpu, IADDR pc,
|
||||
CGEN_INSN_INT base_insn, CGEN_INSN_INT entire_insn,
|
||||
ARGBUF *abuf)
|
||||
{
|
||||
/* Result of decoder. */
|
||||
LM32BF_INSN_TYPE itype;
|
||||
|
||||
{
|
||||
CGEN_INSN_INT insn = base_insn;
|
||||
|
||||
{
|
||||
unsigned int val = (((insn >> 26) & (63 << 0)));
|
||||
switch (val)
|
||||
{
|
||||
case 0 :
|
||||
if ((entire_insn & 0xfc000000) == 0x0)
|
||||
{ itype = LM32BF_INSN_SRUI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 1 :
|
||||
if ((entire_insn & 0xfc000000) == 0x4000000)
|
||||
{ itype = LM32BF_INSN_NORI; goto extract_sfmt_andi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 2 :
|
||||
if ((entire_insn & 0xfc000000) == 0x8000000)
|
||||
{ itype = LM32BF_INSN_MULI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 3 :
|
||||
if ((entire_insn & 0xfc000000) == 0xc000000)
|
||||
{ itype = LM32BF_INSN_SH; goto extract_sfmt_sh; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 4 :
|
||||
if ((entire_insn & 0xfc000000) == 0x10000000)
|
||||
{ itype = LM32BF_INSN_LB; goto extract_sfmt_lb; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 5 :
|
||||
if ((entire_insn & 0xfc000000) == 0x14000000)
|
||||
{ itype = LM32BF_INSN_SRI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 6 :
|
||||
if ((entire_insn & 0xfc000000) == 0x18000000)
|
||||
{ itype = LM32BF_INSN_XORI; goto extract_sfmt_andi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 7 :
|
||||
if ((entire_insn & 0xfc000000) == 0x1c000000)
|
||||
{ itype = LM32BF_INSN_LH; goto extract_sfmt_lh; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 8 :
|
||||
if ((entire_insn & 0xfc000000) == 0x20000000)
|
||||
{ itype = LM32BF_INSN_ANDI; goto extract_sfmt_andi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 9 :
|
||||
if ((entire_insn & 0xfc000000) == 0x24000000)
|
||||
{ itype = LM32BF_INSN_XNORI; goto extract_sfmt_andi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 10 :
|
||||
if ((entire_insn & 0xfc000000) == 0x28000000)
|
||||
{ itype = LM32BF_INSN_LW; goto extract_sfmt_lw; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 11 :
|
||||
if ((entire_insn & 0xfc000000) == 0x2c000000)
|
||||
{ itype = LM32BF_INSN_LHU; goto extract_sfmt_lh; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 12 :
|
||||
if ((entire_insn & 0xfc000000) == 0x30000000)
|
||||
{ itype = LM32BF_INSN_SB; goto extract_sfmt_sb; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 13 :
|
||||
if ((entire_insn & 0xfc000000) == 0x34000000)
|
||||
{ itype = LM32BF_INSN_ADDI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 14 :
|
||||
if ((entire_insn & 0xfc000000) == 0x38000000)
|
||||
{ itype = LM32BF_INSN_ORI; goto extract_sfmt_ori; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 15 :
|
||||
if ((entire_insn & 0xfc000000) == 0x3c000000)
|
||||
{ itype = LM32BF_INSN_SLI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 16 :
|
||||
if ((entire_insn & 0xfc000000) == 0x40000000)
|
||||
{ itype = LM32BF_INSN_LBU; goto extract_sfmt_lb; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 17 :
|
||||
if ((entire_insn & 0xfc000000) == 0x44000000)
|
||||
{ itype = LM32BF_INSN_BE; goto extract_sfmt_be; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 18 :
|
||||
if ((entire_insn & 0xfc000000) == 0x48000000)
|
||||
{ itype = LM32BF_INSN_BG; goto extract_sfmt_be; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 19 :
|
||||
if ((entire_insn & 0xfc000000) == 0x4c000000)
|
||||
{ itype = LM32BF_INSN_BGE; goto extract_sfmt_be; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 20 :
|
||||
if ((entire_insn & 0xfc000000) == 0x50000000)
|
||||
{ itype = LM32BF_INSN_BGEU; goto extract_sfmt_be; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 21 :
|
||||
if ((entire_insn & 0xfc000000) == 0x54000000)
|
||||
{ itype = LM32BF_INSN_BGU; goto extract_sfmt_be; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 22 :
|
||||
if ((entire_insn & 0xfc000000) == 0x58000000)
|
||||
{ itype = LM32BF_INSN_SW; goto extract_sfmt_sw; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 23 :
|
||||
if ((entire_insn & 0xfc000000) == 0x5c000000)
|
||||
{ itype = LM32BF_INSN_BNE; goto extract_sfmt_be; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 24 :
|
||||
if ((entire_insn & 0xfc000000) == 0x60000000)
|
||||
{ itype = LM32BF_INSN_ANDHII; goto extract_sfmt_andhii; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 25 :
|
||||
if ((entire_insn & 0xfc000000) == 0x64000000)
|
||||
{ itype = LM32BF_INSN_CMPEI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 26 :
|
||||
if ((entire_insn & 0xfc000000) == 0x68000000)
|
||||
{ itype = LM32BF_INSN_CMPGI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 27 :
|
||||
if ((entire_insn & 0xfc000000) == 0x6c000000)
|
||||
{ itype = LM32BF_INSN_CMPGEI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 28 :
|
||||
if ((entire_insn & 0xfc000000) == 0x70000000)
|
||||
{ itype = LM32BF_INSN_CMPGEUI; goto extract_sfmt_andi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 29 :
|
||||
if ((entire_insn & 0xfc000000) == 0x74000000)
|
||||
{ itype = LM32BF_INSN_CMPGUI; goto extract_sfmt_andi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 30 :
|
||||
if ((entire_insn & 0xfc000000) == 0x78000000)
|
||||
{ itype = LM32BF_INSN_ORHII; goto extract_sfmt_andhii; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 31 :
|
||||
if ((entire_insn & 0xfc000000) == 0x7c000000)
|
||||
{ itype = LM32BF_INSN_CMPNEI; goto extract_sfmt_addi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 32 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0x80000000)
|
||||
{ itype = LM32BF_INSN_SRU; goto extract_sfmt_sl; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 33 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0x84000000)
|
||||
{ itype = LM32BF_INSN_NOR; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 34 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0x88000000)
|
||||
{ itype = LM32BF_INSN_MUL; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 35 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0x8c000000)
|
||||
{ itype = LM32BF_INSN_DIVU; goto extract_sfmt_divu; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 36 :
|
||||
if ((entire_insn & 0xfc1f07ff) == 0x90000000)
|
||||
{ itype = LM32BF_INSN_RCSR; goto extract_sfmt_rcsr; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 37 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0x94000000)
|
||||
{ itype = LM32BF_INSN_SR; goto extract_sfmt_sl; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 38 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0x98000000)
|
||||
{ itype = LM32BF_INSN_XOR; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 40 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xa0000000)
|
||||
{ itype = LM32BF_INSN_AND; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 41 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xa4000000)
|
||||
{ itype = LM32BF_INSN_XNOR; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 43 :
|
||||
{
|
||||
unsigned int val = (((insn >> 1) & (1 << 1)) | ((insn >> 0) & (1 << 0)));
|
||||
switch (val)
|
||||
{
|
||||
case 0 :
|
||||
if ((entire_insn & 0xffffffff) == 0xac000002)
|
||||
{ itype = LM32BF_INSN_BREAK; goto extract_sfmt_break; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 3 :
|
||||
if ((entire_insn & 0xffffffff) == 0xac000007)
|
||||
{ itype = LM32BF_INSN_SCALL; goto extract_sfmt_break; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
default : itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
}
|
||||
}
|
||||
case 44 :
|
||||
if ((entire_insn & 0xfc1f07ff) == 0xb0000000)
|
||||
{ itype = LM32BF_INSN_SEXTB; goto extract_sfmt_sextb; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 45 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xb4000000)
|
||||
{ itype = LM32BF_INSN_ADD; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 46 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xb8000000)
|
||||
{ itype = LM32BF_INSN_OR; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 47 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xbc000000)
|
||||
{ itype = LM32BF_INSN_SL; goto extract_sfmt_sl; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 48 :
|
||||
if ((entire_insn & 0xfc1fffff) == 0xc0000000)
|
||||
{ itype = LM32BF_INSN_B; goto extract_sfmt_b; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 49 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xc4000000)
|
||||
{ itype = LM32BF_INSN_MODU; goto extract_sfmt_divu; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 50 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xc8000000)
|
||||
{ itype = LM32BF_INSN_SUB; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 51 :
|
||||
if ((entire_insn & 0xfc000000) == 0xcc000000)
|
||||
{ itype = LM32BF_INSN_USER; goto extract_sfmt_user; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 52 :
|
||||
if ((entire_insn & 0xfc00ffff) == 0xd0000000)
|
||||
{ itype = LM32BF_INSN_WCSR; goto extract_sfmt_wcsr; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 54 :
|
||||
if ((entire_insn & 0xfc1fffff) == 0xd8000000)
|
||||
{ itype = LM32BF_INSN_CALL; goto extract_sfmt_call; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 55 :
|
||||
if ((entire_insn & 0xfc1f07ff) == 0xdc000000)
|
||||
{ itype = LM32BF_INSN_SEXTH; goto extract_sfmt_sextb; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 56 :
|
||||
if ((entire_insn & 0xfc000000) == 0xe0000000)
|
||||
{ itype = LM32BF_INSN_BI; goto extract_sfmt_bi; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 57 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xe4000000)
|
||||
{ itype = LM32BF_INSN_CMPE; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 58 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xe8000000)
|
||||
{ itype = LM32BF_INSN_CMPG; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 59 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xec000000)
|
||||
{ itype = LM32BF_INSN_CMPGE; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 60 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xf0000000)
|
||||
{ itype = LM32BF_INSN_CMPGEU; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 61 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xf4000000)
|
||||
{ itype = LM32BF_INSN_CMPGU; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 62 :
|
||||
if ((entire_insn & 0xfc000000) == 0xf8000000)
|
||||
{ itype = LM32BF_INSN_CALLI; goto extract_sfmt_calli; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
case 63 :
|
||||
if ((entire_insn & 0xfc0007ff) == 0xfc000000)
|
||||
{ itype = LM32BF_INSN_CMPNE; goto extract_sfmt_add; }
|
||||
itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
default : itype = LM32BF_INSN_X_INVALID; goto extract_sfmt_empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The instruction has been decoded, now extract the fields. */
|
||||
|
||||
extract_sfmt_empty:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
#define FLD(f) abuf->fields.fmt_empty.f
|
||||
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_empty", (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_add:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_user.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_r2;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
FLD (f_r2) = f_r2;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_add", "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, "f_r2 0x%x", 'x', f_r2, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_addi:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_addi", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_andi:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_andi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_uimm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_uimm = EXTRACT_LSB0_UINT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_uimm) = f_uimm;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_andi", "f_r0 0x%x", 'x', f_r0, "f_uimm 0x%x", 'x', f_uimm, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_andhii:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_andi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_uimm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_uimm = EXTRACT_LSB0_UINT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_uimm) = f_uimm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_andhii", "f_uimm 0x%x", 'x', f_uimm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_b:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_be.f
|
||||
UINT f_r0;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_b", "f_r0 0x%x", 'x', f_r0, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_bi:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_bi.f
|
||||
SI f_call;
|
||||
|
||||
f_call = ((pc) + (((int) (((EXTRACT_LSB0_INT (insn, 32, 25, 26)) << (6))) >> (4))));
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (i_call) = f_call;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_bi", "call 0x%x", 'x', f_call, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_be:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_be.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
SI f_branch;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_branch = ((pc) + (((int) (((EXTRACT_LSB0_INT (insn, 32, 15, 16)) << (16))) >> (14))));
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
FLD (i_branch) = f_branch;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_be", "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, "branch 0x%x", 'x', f_branch, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_call:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_be.f
|
||||
UINT f_r0;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_call", "f_r0 0x%x", 'x', f_r0, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_calli:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_bi.f
|
||||
SI f_call;
|
||||
|
||||
f_call = ((pc) + (((int) (((EXTRACT_LSB0_INT (insn, 32, 25, 26)) << (6))) >> (4))));
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (i_call) = f_call;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_calli", "call 0x%x", 'x', f_call, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_divu:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_user.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_r2;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
FLD (f_r2) = f_r2;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_divu", "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, "f_r2 0x%x", 'x', f_r2, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_lb:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_lb", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_lh:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_lh", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_lw:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_lw", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_ori:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_andi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_uimm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_uimm = EXTRACT_LSB0_UINT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_uimm) = f_uimm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_ori", "f_uimm 0x%x", 'x', f_uimm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_rcsr:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_rcsr.f
|
||||
UINT f_csr;
|
||||
UINT f_r2;
|
||||
|
||||
f_csr = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_csr) = f_csr;
|
||||
FLD (f_r2) = f_r2;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_rcsr", "f_csr 0x%x", 'x', f_csr, "f_r2 0x%x", 'x', f_r2, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_sb:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_sb", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_sextb:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_user.f
|
||||
UINT f_r0;
|
||||
UINT f_r2;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r2) = f_r2;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_sextb", "f_r0 0x%x", 'x', f_r0, "f_r2 0x%x", 'x', f_r2, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_sh:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_sh", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_sl:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_user.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_r2;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
FLD (f_r2) = f_r2;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_sl", "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, "f_r2 0x%x", 'x', f_r2, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_sw:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_addi.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
INT f_imm;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_imm = EXTRACT_LSB0_INT (insn, 32, 15, 16);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_imm) = f_imm;
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_sw", "f_imm 0x%x", 'x', f_imm, "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_user:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_user.f
|
||||
UINT f_r0;
|
||||
UINT f_r1;
|
||||
UINT f_r2;
|
||||
UINT f_user;
|
||||
|
||||
f_r0 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
f_r2 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
|
||||
f_user = EXTRACT_LSB0_UINT (insn, 32, 10, 11);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_r0) = f_r0;
|
||||
FLD (f_r1) = f_r1;
|
||||
FLD (f_user) = f_user;
|
||||
FLD (f_r2) = f_r2;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_user", "f_r0 0x%x", 'x', f_r0, "f_r1 0x%x", 'x', f_r1, "f_user 0x%x", 'x', f_user, "f_r2 0x%x", 'x', f_r2, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_wcsr:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
CGEN_INSN_INT insn = entire_insn;
|
||||
#define FLD(f) abuf->fields.sfmt_wcsr.f
|
||||
UINT f_csr;
|
||||
UINT f_r1;
|
||||
|
||||
f_csr = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
|
||||
f_r1 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
FLD (f_csr) = f_csr;
|
||||
FLD (f_r1) = f_r1;
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_wcsr", "f_csr 0x%x", 'x', f_csr, "f_r1 0x%x", 'x', f_r1, (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
extract_sfmt_break:
|
||||
{
|
||||
const IDESC *idesc = &lm32bf_insn_data[itype];
|
||||
#define FLD(f) abuf->fields.fmt_empty.f
|
||||
|
||||
|
||||
/* Record the fields for the semantic handler. */
|
||||
TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_break", (char *) 0));
|
||||
|
||||
#undef FLD
|
||||
return idesc;
|
||||
}
|
||||
|
||||
}
|
76
sim/lm32/decode.h
Normal file
76
sim/lm32/decode.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* Decode header for lm32bf.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU simulators.
|
||||
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LM32BF_DECODE_H
|
||||
#define LM32BF_DECODE_H
|
||||
|
||||
extern const IDESC *lm32bf_decode (SIM_CPU *, IADDR,
|
||||
CGEN_INSN_INT, CGEN_INSN_INT,
|
||||
ARGBUF *);
|
||||
extern void lm32bf_init_idesc_table (SIM_CPU *);
|
||||
extern void lm32bf_sem_init_idesc_table (SIM_CPU *);
|
||||
extern void lm32bf_semf_init_idesc_table (SIM_CPU *);
|
||||
|
||||
/* Enum declaration for instructions in cpu family lm32bf. */
|
||||
typedef enum lm32bf_insn_type {
|
||||
LM32BF_INSN_X_INVALID, LM32BF_INSN_X_AFTER, LM32BF_INSN_X_BEFORE, LM32BF_INSN_X_CTI_CHAIN
|
||||
, LM32BF_INSN_X_CHAIN, LM32BF_INSN_X_BEGIN, LM32BF_INSN_ADD, LM32BF_INSN_ADDI
|
||||
, LM32BF_INSN_AND, LM32BF_INSN_ANDI, LM32BF_INSN_ANDHII, LM32BF_INSN_B
|
||||
, LM32BF_INSN_BI, LM32BF_INSN_BE, LM32BF_INSN_BG, LM32BF_INSN_BGE
|
||||
, LM32BF_INSN_BGEU, LM32BF_INSN_BGU, LM32BF_INSN_BNE, LM32BF_INSN_CALL
|
||||
, LM32BF_INSN_CALLI, LM32BF_INSN_CMPE, LM32BF_INSN_CMPEI, LM32BF_INSN_CMPG
|
||||
, LM32BF_INSN_CMPGI, LM32BF_INSN_CMPGE, LM32BF_INSN_CMPGEI, LM32BF_INSN_CMPGEU
|
||||
, LM32BF_INSN_CMPGEUI, LM32BF_INSN_CMPGU, LM32BF_INSN_CMPGUI, LM32BF_INSN_CMPNE
|
||||
, LM32BF_INSN_CMPNEI, LM32BF_INSN_DIVU, LM32BF_INSN_LB, LM32BF_INSN_LBU
|
||||
, LM32BF_INSN_LH, LM32BF_INSN_LHU, LM32BF_INSN_LW, LM32BF_INSN_MODU
|
||||
, LM32BF_INSN_MUL, LM32BF_INSN_MULI, LM32BF_INSN_NOR, LM32BF_INSN_NORI
|
||||
, LM32BF_INSN_OR, LM32BF_INSN_ORI, LM32BF_INSN_ORHII, LM32BF_INSN_RCSR
|
||||
, LM32BF_INSN_SB, LM32BF_INSN_SEXTB, LM32BF_INSN_SEXTH, LM32BF_INSN_SH
|
||||
, LM32BF_INSN_SL, LM32BF_INSN_SLI, LM32BF_INSN_SR, LM32BF_INSN_SRI
|
||||
, LM32BF_INSN_SRU, LM32BF_INSN_SRUI, LM32BF_INSN_SUB, LM32BF_INSN_SW
|
||||
, LM32BF_INSN_USER, LM32BF_INSN_WCSR, LM32BF_INSN_XOR, LM32BF_INSN_XORI
|
||||
, LM32BF_INSN_XNOR, LM32BF_INSN_XNORI, LM32BF_INSN_BREAK, LM32BF_INSN_SCALL
|
||||
, LM32BF_INSN__MAX
|
||||
} LM32BF_INSN_TYPE;
|
||||
|
||||
/* Enum declaration for semantic formats in cpu family lm32bf. */
|
||||
typedef enum lm32bf_sfmt_type {
|
||||
LM32BF_SFMT_EMPTY, LM32BF_SFMT_ADD, LM32BF_SFMT_ADDI, LM32BF_SFMT_ANDI
|
||||
, LM32BF_SFMT_ANDHII, LM32BF_SFMT_B, LM32BF_SFMT_BI, LM32BF_SFMT_BE
|
||||
, LM32BF_SFMT_CALL, LM32BF_SFMT_CALLI, LM32BF_SFMT_DIVU, LM32BF_SFMT_LB
|
||||
, LM32BF_SFMT_LH, LM32BF_SFMT_LW, LM32BF_SFMT_ORI, LM32BF_SFMT_RCSR
|
||||
, LM32BF_SFMT_SB, LM32BF_SFMT_SEXTB, LM32BF_SFMT_SH, LM32BF_SFMT_SL
|
||||
, LM32BF_SFMT_SW, LM32BF_SFMT_USER, LM32BF_SFMT_WCSR, LM32BF_SFMT_BREAK
|
||||
} LM32BF_SFMT_TYPE;
|
||||
|
||||
/* Function unit handlers (user written). */
|
||||
|
||||
extern int lm32bf_model_lm32_u_exec (SIM_CPU *, const IDESC *, int /*unit_num*/, int /*referenced*/);
|
||||
|
||||
/* Profiling before/after handlers (user written) */
|
||||
|
||||
extern void lm32bf_model_insn_before (SIM_CPU *, int /*first_p*/);
|
||||
extern void lm32bf_model_insn_after (SIM_CPU *, int /*last_p*/, int /*cycles*/);
|
||||
|
||||
#endif /* LM32BF_DECODE_H */
|
247
sim/lm32/dv-lm32cpu.c
Normal file
247
sim/lm32/dv-lm32cpu.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* Lattice Mico32 CPU model.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "hw-main.h"
|
||||
#include "sim-main.h"
|
||||
|
||||
|
||||
struct lm32cpu
|
||||
{
|
||||
struct hw_event *event;
|
||||
};
|
||||
|
||||
/* input port ID's. */
|
||||
|
||||
enum
|
||||
{
|
||||
INT0_PORT,
|
||||
INT1_PORT,
|
||||
INT2_PORT,
|
||||
INT3_PORT,
|
||||
INT4_PORT,
|
||||
INT5_PORT,
|
||||
INT6_PORT,
|
||||
INT7_PORT,
|
||||
INT8_PORT,
|
||||
INT9_PORT,
|
||||
INT10_PORT,
|
||||
INT11_PORT,
|
||||
INT12_PORT,
|
||||
INT13_PORT,
|
||||
INT14_PORT,
|
||||
INT15_PORT,
|
||||
INT16_PORT,
|
||||
INT17_PORT,
|
||||
INT18_PORT,
|
||||
INT19_PORT,
|
||||
INT20_PORT,
|
||||
INT21_PORT,
|
||||
INT22_PORT,
|
||||
INT23_PORT,
|
||||
INT24_PORT,
|
||||
INT25_PORT,
|
||||
INT26_PORT,
|
||||
INT27_PORT,
|
||||
INT28_PORT,
|
||||
INT29_PORT,
|
||||
INT30_PORT,
|
||||
INT31_PORT,
|
||||
};
|
||||
|
||||
static const struct hw_port_descriptor lm32cpu_ports[] = {
|
||||
/* interrupt inputs. */
|
||||
{"int0", INT0_PORT, 0, input_port,},
|
||||
{"int1", INT1_PORT, 0, input_port,},
|
||||
{"int2", INT2_PORT, 0, input_port,},
|
||||
{"int3", INT3_PORT, 0, input_port,},
|
||||
{"int4", INT4_PORT, 0, input_port,},
|
||||
{"int5", INT5_PORT, 0, input_port,},
|
||||
{"int6", INT6_PORT, 0, input_port,},
|
||||
{"int7", INT7_PORT, 0, input_port,},
|
||||
{"int8", INT8_PORT, 0, input_port,},
|
||||
{"int9", INT9_PORT, 0, input_port,},
|
||||
{"int10", INT10_PORT, 0, input_port,},
|
||||
{"int11", INT11_PORT, 0, input_port,},
|
||||
{"int12", INT12_PORT, 0, input_port,},
|
||||
{"int13", INT13_PORT, 0, input_port,},
|
||||
{"int14", INT14_PORT, 0, input_port,},
|
||||
{"int15", INT15_PORT, 0, input_port,},
|
||||
{"int16", INT16_PORT, 0, input_port,},
|
||||
{"int17", INT17_PORT, 0, input_port,},
|
||||
{"int18", INT18_PORT, 0, input_port,},
|
||||
{"int19", INT19_PORT, 0, input_port,},
|
||||
{"int20", INT20_PORT, 0, input_port,},
|
||||
{"int21", INT21_PORT, 0, input_port,},
|
||||
{"int22", INT22_PORT, 0, input_port,},
|
||||
{"int23", INT23_PORT, 0, input_port,},
|
||||
{"int24", INT24_PORT, 0, input_port,},
|
||||
{"int25", INT25_PORT, 0, input_port,},
|
||||
{"int26", INT26_PORT, 0, input_port,},
|
||||
{"int27", INT27_PORT, 0, input_port,},
|
||||
{"int28", INT28_PORT, 0, input_port,},
|
||||
{"int29", INT29_PORT, 0, input_port,},
|
||||
{"int30", INT30_PORT, 0, input_port,},
|
||||
{"int31", INT31_PORT, 0, input_port,},
|
||||
{NULL,},
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Finish off the partially created hw device. Attach our local
|
||||
* callbacks. Wire up our port names etc.
|
||||
*/
|
||||
static hw_port_event_method lm32cpu_port_event;
|
||||
|
||||
|
||||
static void
|
||||
lm32cpu_finish (struct hw *me)
|
||||
{
|
||||
struct lm32cpu *controller;
|
||||
|
||||
controller = HW_ZALLOC (me, struct lm32cpu);
|
||||
set_hw_data (me, controller);
|
||||
set_hw_ports (me, lm32cpu_ports);
|
||||
set_hw_port_event (me, lm32cpu_port_event);
|
||||
|
||||
/* Initialize the pending interrupt flags. */
|
||||
controller->event = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* An event arrives on an interrupt port. */
|
||||
static unsigned int s_ui_ExtIntrs = 0;
|
||||
|
||||
|
||||
static void
|
||||
deliver_lm32cpu_interrupt (struct hw *me, void *data)
|
||||
{
|
||||
static unsigned int ip, im, im_and_ip_result;
|
||||
struct lm32cpu *controller = hw_data (me);
|
||||
SIM_DESC sd = hw_system (me);
|
||||
sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
|
||||
address_word cia = CIA_GET (cpu);
|
||||
int interrupt = (int) data;
|
||||
|
||||
|
||||
HW_TRACE ((me, "interrupt-check event"));
|
||||
|
||||
|
||||
/*
|
||||
* Determine if an external interrupt is active
|
||||
* and needs to cause an exception.
|
||||
*/
|
||||
im = lm32bf_h_csr_get (cpu, LM32_CSR_IM);
|
||||
ip = lm32bf_h_csr_get (cpu, LM32_CSR_IP);
|
||||
im_and_ip_result = im & ip;
|
||||
|
||||
|
||||
if ((lm32bf_h_csr_get (cpu, LM32_CSR_IE) & 1) && (im_and_ip_result != 0))
|
||||
{
|
||||
/* Save PC in exception address register. */
|
||||
lm32bf_h_gr_set (cpu, 30, lm32bf_h_pc_get (cpu));
|
||||
/* Restart at interrupt offset in handler exception table. */
|
||||
lm32bf_h_pc_set (cpu,
|
||||
lm32bf_h_csr_get (cpu,
|
||||
LM32_CSR_EBA) +
|
||||
LM32_EID_INTERRUPT * 32);
|
||||
/* Save interrupt enable and then clear. */
|
||||
lm32bf_h_csr_set (cpu, LM32_CSR_IE, 0x2);
|
||||
}
|
||||
|
||||
/* reschedule soon. */
|
||||
if (controller->event != NULL)
|
||||
hw_event_queue_deschedule (me, controller->event);
|
||||
controller->event = NULL;
|
||||
|
||||
|
||||
/* if there are external interrupts, schedule an interrupt-check again.
|
||||
* NOTE: THIS MAKES IT VERY INEFFICIENT. INSTEAD, TRIGGER THIS
|
||||
* CHECk_EVENT WHEN THE USER ENABLES IE OR USER MODIFIES IM REGISTERS.
|
||||
*/
|
||||
if (s_ui_ExtIntrs != 0)
|
||||
controller->event =
|
||||
hw_event_queue_schedule (me, 1, deliver_lm32cpu_interrupt, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Handle an event on one of the CPU's ports. */
|
||||
static void
|
||||
lm32cpu_port_event (struct hw *me,
|
||||
int my_port,
|
||||
struct hw *source, int source_port, int level)
|
||||
{
|
||||
struct lm32cpu *controller = hw_data (me);
|
||||
SIM_DESC sd = hw_system (me);
|
||||
sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
|
||||
address_word cia = CIA_GET (cpu);
|
||||
|
||||
|
||||
HW_TRACE ((me, "interrupt event on port %d, level %d", my_port, level));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Activate IP if the interrupt's activated; don't do anything if
|
||||
* the interrupt's deactivated.
|
||||
*/
|
||||
if (level == 1)
|
||||
{
|
||||
/*
|
||||
* save state of external interrupt.
|
||||
*/
|
||||
s_ui_ExtIntrs |= (1 << my_port);
|
||||
|
||||
/* interrupt-activated so set IP. */
|
||||
lm32bf_h_csr_set (cpu, LM32_CSR_IP,
|
||||
lm32bf_h_csr_get (cpu, LM32_CSR_IP) | (1 << my_port));
|
||||
|
||||
/*
|
||||
* Since interrupt is activated, queue an immediate event
|
||||
* to check if this interrupt is serviceable.
|
||||
*/
|
||||
if (controller->event != NULL)
|
||||
hw_event_queue_deschedule (me, controller->event);
|
||||
|
||||
|
||||
/*
|
||||
* Queue an immediate event to check if this interrupt must be serviced;
|
||||
* this will happen after the current instruction is complete.
|
||||
*/
|
||||
controller->event = hw_event_queue_schedule (me,
|
||||
0,
|
||||
deliver_lm32cpu_interrupt,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* save state of external interrupt.
|
||||
*/
|
||||
s_ui_ExtIntrs &= ~(1 << my_port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const struct hw_descriptor dv_lm32cpu_descriptor[] = {
|
||||
{"lm32cpu", lm32cpu_finish,},
|
||||
{NULL},
|
||||
};
|
220
sim/lm32/dv-lm32timer.c
Normal file
220
sim/lm32/dv-lm32timer.c
Normal file
@ -0,0 +1,220 @@
|
||||
/* Lattice Mico32 timer model.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "sim-main.h"
|
||||
#include "hw-main.h"
|
||||
#include "sim-assert.h"
|
||||
|
||||
struct lm32timer
|
||||
{
|
||||
unsigned base; /* Base address of this timer. */
|
||||
unsigned limit; /* Limit address of this timer. */
|
||||
unsigned int status;
|
||||
unsigned int control;
|
||||
unsigned int period;
|
||||
unsigned int snapshot;
|
||||
struct hw_event *event;
|
||||
};
|
||||
|
||||
/* Timer registers. */
|
||||
#define LM32_TIMER_STATUS 0x0
|
||||
#define LM32_TIMER_CONTROL 0x4
|
||||
#define LM32_TIMER_PERIOD 0x8
|
||||
#define LM32_TIMER_SNAPSHOT 0xc
|
||||
|
||||
/* Timer ports. */
|
||||
|
||||
enum
|
||||
{
|
||||
INT_PORT
|
||||
};
|
||||
|
||||
static const struct hw_port_descriptor lm32timer_ports[] = {
|
||||
{"int", INT_PORT, 0, output_port},
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
do_timer_event (struct hw *me, void *data)
|
||||
{
|
||||
struct lm32timer *timer = hw_data (me);
|
||||
|
||||
/* Is timer started? */
|
||||
if (timer->control & 0x4)
|
||||
{
|
||||
if (timer->snapshot)
|
||||
{
|
||||
/* Decrement timer. */
|
||||
timer->snapshot--;
|
||||
}
|
||||
else if (timer->control & 1)
|
||||
{
|
||||
/* Restart timer. */
|
||||
timer->snapshot = timer->period;
|
||||
}
|
||||
}
|
||||
/* Generate interrupt when timer is at 0, and interrupt enable is 1. */
|
||||
if ((timer->snapshot == 0) && (timer->control & 1))
|
||||
{
|
||||
/* Generate interrupt. */
|
||||
hw_port_event (me, INT_PORT, 1);
|
||||
}
|
||||
/* If timer is started, schedule another event to decrement the timer again. */
|
||||
if (timer->control & 4)
|
||||
hw_event_queue_schedule (me, 1, do_timer_event, 0);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
lm32timer_io_write_buffer (struct hw *me,
|
||||
const void *source,
|
||||
int space, unsigned_word base, unsigned nr_bytes)
|
||||
{
|
||||
struct lm32timer *timers = hw_data (me);
|
||||
int timer_reg;
|
||||
const unsigned char *source_bytes = source;
|
||||
int value = 0;
|
||||
|
||||
HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base,
|
||||
(int) nr_bytes, value));
|
||||
|
||||
if (nr_bytes == 4)
|
||||
value = (source_bytes[0] << 24)
|
||||
| (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]);
|
||||
else
|
||||
hw_abort (me, "write with invalid number of bytes: %d", nr_bytes);
|
||||
|
||||
timer_reg = base - timers->base;
|
||||
|
||||
switch (timer_reg)
|
||||
{
|
||||
case LM32_TIMER_STATUS:
|
||||
timers->status = value;
|
||||
break;
|
||||
case LM32_TIMER_CONTROL:
|
||||
timers->control = value;
|
||||
if (timers->control & 0x4)
|
||||
{
|
||||
/* Timer is started. */
|
||||
hw_event_queue_schedule (me, 1, do_timer_event, 0);
|
||||
}
|
||||
break;
|
||||
case LM32_TIMER_PERIOD:
|
||||
timers->period = value;
|
||||
break;
|
||||
default:
|
||||
hw_abort (me, "invalid register address: 0x%x.", timer_reg);
|
||||
}
|
||||
|
||||
return nr_bytes;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
lm32timer_io_read_buffer (struct hw *me,
|
||||
void *dest,
|
||||
int space, unsigned_word base, unsigned nr_bytes)
|
||||
{
|
||||
struct lm32timer *timers = hw_data (me);
|
||||
int timer_reg;
|
||||
int value;
|
||||
unsigned char *dest_bytes = dest;
|
||||
|
||||
HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes));
|
||||
|
||||
timer_reg = base - timers->base;
|
||||
|
||||
switch (timer_reg)
|
||||
{
|
||||
case LM32_TIMER_STATUS:
|
||||
value = timers->status;
|
||||
break;
|
||||
case LM32_TIMER_CONTROL:
|
||||
value = timers->control;
|
||||
break;
|
||||
case LM32_TIMER_PERIOD:
|
||||
value = timers->period;
|
||||
break;
|
||||
case LM32_TIMER_SNAPSHOT:
|
||||
value = timers->snapshot;
|
||||
break;
|
||||
default:
|
||||
hw_abort (me, "invalid register address: 0x%x.", timer_reg);
|
||||
}
|
||||
|
||||
if (nr_bytes == 4)
|
||||
{
|
||||
dest_bytes[0] = value >> 24;
|
||||
dest_bytes[1] = value >> 16;
|
||||
dest_bytes[2] = value >> 8;
|
||||
dest_bytes[3] = value;
|
||||
}
|
||||
else
|
||||
hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes);
|
||||
|
||||
return nr_bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
attach_lm32timer_regs (struct hw *me, struct lm32timer *timers)
|
||||
{
|
||||
unsigned_word attach_address;
|
||||
int attach_space;
|
||||
unsigned attach_size;
|
||||
reg_property_spec reg;
|
||||
|
||||
if (hw_find_property (me, "reg") == NULL)
|
||||
hw_abort (me, "Missing \"reg\" property");
|
||||
if (!hw_find_reg_array_property (me, "reg", 0, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
timers->base = attach_address;
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me);
|
||||
timers->limit = attach_address + (attach_size - 1);
|
||||
hw_attach_address (hw_parent (me),
|
||||
0, attach_space, attach_address, attach_size, me);
|
||||
}
|
||||
|
||||
static void
|
||||
lm32timer_finish (struct hw *me)
|
||||
{
|
||||
struct lm32timer *timers;
|
||||
int i;
|
||||
|
||||
timers = HW_ZALLOC (me, struct lm32timer);
|
||||
set_hw_data (me, timers);
|
||||
set_hw_io_read_buffer (me, lm32timer_io_read_buffer);
|
||||
set_hw_io_write_buffer (me, lm32timer_io_write_buffer);
|
||||
set_hw_ports (me, lm32timer_ports);
|
||||
|
||||
/* Attach ourself to our parent bus. */
|
||||
attach_lm32timer_regs (me, timers);
|
||||
|
||||
/* Initialize the timers. */
|
||||
timers->status = 0;
|
||||
timers->control = 0;
|
||||
timers->period = 0;
|
||||
timers->snapshot = 0;
|
||||
}
|
||||
|
||||
const struct hw_descriptor dv_lm32timer_descriptor[] = {
|
||||
{"lm32timer", lm32timer_finish,},
|
||||
{NULL},
|
||||
};
|
317
sim/lm32/dv-lm32uart.c
Normal file
317
sim/lm32/dv-lm32uart.c
Normal file
@ -0,0 +1,317 @@
|
||||
/* Lattice Mico32 UART model.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "sim-main.h"
|
||||
#include "hw-main.h"
|
||||
#include "sim-assert.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct lm32uart
|
||||
{
|
||||
unsigned base; /* Base address of this UART. */
|
||||
unsigned limit; /* Limit address of this UART. */
|
||||
unsigned char rbr;
|
||||
unsigned char thr;
|
||||
unsigned char ier;
|
||||
unsigned char iir;
|
||||
unsigned char lcr;
|
||||
unsigned char mcr;
|
||||
unsigned char lsr;
|
||||
unsigned char msr;
|
||||
unsigned char div;
|
||||
struct hw_event *event;
|
||||
};
|
||||
|
||||
/* UART registers. */
|
||||
|
||||
#define LM32_UART_RBR 0x0
|
||||
#define LM32_UART_THR 0x0
|
||||
#define LM32_UART_IER 0x4
|
||||
#define LM32_UART_IIR 0x8
|
||||
#define LM32_UART_LCR 0xc
|
||||
#define LM32_UART_MCR 0x10
|
||||
#define LM32_UART_LSR 0x14
|
||||
#define LM32_UART_MSR 0x18
|
||||
#define LM32_UART_DIV 0x1c
|
||||
|
||||
#define LM32_UART_IER_RX_INT 0x1
|
||||
#define LM32_UART_IER_TX_INT 0x2
|
||||
|
||||
#define MICOUART_IIR_TXRDY 0x2
|
||||
#define MICOUART_IIR_RXRDY 0x4
|
||||
|
||||
#define LM32_UART_LSR_RX_RDY 0x01
|
||||
#define LM32_UART_LSR_TX_RDY 0x20
|
||||
|
||||
#define LM32_UART_LCR_WLS_MASK 0x3
|
||||
#define LM32_UART_LCR_WLS_5 0x0
|
||||
#define LM32_UART_LCR_WLS_6 0x1
|
||||
#define LM32_UART_LCR_WLS_7 0x2
|
||||
#define LM32_UART_LCR_WLS_8 0x3
|
||||
|
||||
/* UART ports. */
|
||||
|
||||
enum
|
||||
{
|
||||
INT_PORT
|
||||
};
|
||||
|
||||
static const struct hw_port_descriptor lm32uart_ports[] = {
|
||||
{"int", INT_PORT, 0, output_port},
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
do_uart_tx_event (struct hw *me, void *data)
|
||||
{
|
||||
struct lm32uart *uart = hw_data (me);
|
||||
char c;
|
||||
|
||||
/* Generate interrupt when transmission is complete. */
|
||||
if (uart->ier & LM32_UART_IER_TX_INT)
|
||||
{
|
||||
/* Generate interrupt */
|
||||
hw_port_event (me, INT_PORT, 1);
|
||||
}
|
||||
|
||||
/* Indicate which interrupt has occured. */
|
||||
uart->iir = MICOUART_IIR_TXRDY;
|
||||
|
||||
/* Indicate THR is empty. */
|
||||
uart->lsr |= LM32_UART_LSR_TX_RDY;
|
||||
|
||||
/* Output the character in the THR. */
|
||||
c = (char) uart->thr;
|
||||
|
||||
/* WLS field in LCR register specifies the number of bits to output. */
|
||||
switch (uart->lcr & LM32_UART_LCR_WLS_MASK)
|
||||
{
|
||||
case LM32_UART_LCR_WLS_5:
|
||||
c &= 0x1f;
|
||||
break;
|
||||
case LM32_UART_LCR_WLS_6:
|
||||
c &= 0x3f;
|
||||
break;
|
||||
case LM32_UART_LCR_WLS_7:
|
||||
c &= 0x7f;
|
||||
break;
|
||||
}
|
||||
printf ("%c", c);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
lm32uart_io_write_buffer (struct hw *me,
|
||||
const void *source,
|
||||
int space, unsigned_word base, unsigned nr_bytes)
|
||||
{
|
||||
struct lm32uart *uart = hw_data (me);
|
||||
int uart_reg;
|
||||
const unsigned char *source_bytes = source;
|
||||
int value = 0;
|
||||
|
||||
HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base,
|
||||
(int) nr_bytes, value));
|
||||
|
||||
if (nr_bytes == 4)
|
||||
value = (source_bytes[0] << 24)
|
||||
| (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]);
|
||||
else
|
||||
hw_abort (me, "write of unsupported number of bytes: %d.", nr_bytes);
|
||||
|
||||
uart_reg = base - uart->base;
|
||||
|
||||
switch (uart_reg)
|
||||
{
|
||||
case LM32_UART_THR:
|
||||
/* Buffer the character to output. */
|
||||
uart->thr = value;
|
||||
|
||||
/* Indicate the THR is full. */
|
||||
uart->lsr &= ~LM32_UART_LSR_TX_RDY;
|
||||
|
||||
/* deassert interrupt when IER is loaded. */
|
||||
uart->iir &= ~MICOUART_IIR_TXRDY;
|
||||
|
||||
/* schedule an event to output the character. */
|
||||
hw_event_queue_schedule (me, 1, do_uart_tx_event, 0);
|
||||
|
||||
break;
|
||||
case LM32_UART_IER:
|
||||
uart->ier = value;
|
||||
if ((value & LM32_UART_IER_TX_INT)
|
||||
&& (uart->lsr & LM32_UART_LSR_TX_RDY))
|
||||
{
|
||||
/* hw_event_queue_schedule (me, 1, do_uart_tx_event, 0); */
|
||||
uart->lsr |= LM32_UART_LSR_TX_RDY;
|
||||
uart->iir |= MICOUART_IIR_TXRDY;
|
||||
hw_port_event (me, INT_PORT, 1);
|
||||
}
|
||||
else if ((value & LM32_UART_IER_TX_INT) == 0)
|
||||
{
|
||||
hw_port_event (me, INT_PORT, 0);
|
||||
}
|
||||
break;
|
||||
case LM32_UART_IIR:
|
||||
uart->iir = value;
|
||||
break;
|
||||
case LM32_UART_LCR:
|
||||
uart->lcr = value;
|
||||
break;
|
||||
case LM32_UART_MCR:
|
||||
uart->mcr = value;
|
||||
break;
|
||||
case LM32_UART_LSR:
|
||||
uart->lsr = value;
|
||||
break;
|
||||
case LM32_UART_MSR:
|
||||
uart->msr = value;
|
||||
break;
|
||||
case LM32_UART_DIV:
|
||||
uart->div = value;
|
||||
break;
|
||||
default:
|
||||
hw_abort (me, "write to invalid register address: 0x%x.", uart_reg);
|
||||
}
|
||||
|
||||
return nr_bytes;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
lm32uart_io_read_buffer (struct hw *me,
|
||||
void *dest,
|
||||
int space, unsigned_word base, unsigned nr_bytes)
|
||||
{
|
||||
struct lm32uart *uart = hw_data (me);
|
||||
int uart_reg;
|
||||
int value;
|
||||
unsigned char *dest_bytes = dest;
|
||||
fd_set fd;
|
||||
struct timeval tv;
|
||||
|
||||
HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes));
|
||||
|
||||
uart_reg = base - uart->base;
|
||||
|
||||
switch (uart_reg)
|
||||
{
|
||||
case LM32_UART_RBR:
|
||||
value = getchar ();
|
||||
uart->lsr &= ~LM32_UART_LSR_RX_RDY;
|
||||
break;
|
||||
case LM32_UART_IER:
|
||||
value = uart->ier;
|
||||
break;
|
||||
case LM32_UART_IIR:
|
||||
value = uart->iir;
|
||||
break;
|
||||
case LM32_UART_LCR:
|
||||
value = uart->lcr;
|
||||
break;
|
||||
case LM32_UART_MCR:
|
||||
value = uart->mcr;
|
||||
break;
|
||||
case LM32_UART_LSR:
|
||||
/* Check to see if any data waiting in stdin. */
|
||||
FD_ZERO (&fd);
|
||||
FD_SET (fileno (stdin), &fd);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
if (select (fileno (stdin) + 1, &fd, NULL, NULL, &tv))
|
||||
uart->lsr |= LM32_UART_LSR_RX_RDY;
|
||||
value = uart->lsr;
|
||||
break;
|
||||
case LM32_UART_MSR:
|
||||
value = uart->msr;
|
||||
break;
|
||||
case LM32_UART_DIV:
|
||||
value = uart->div;
|
||||
break;
|
||||
default:
|
||||
hw_abort (me, "read from invalid register address: 0x%x.", uart_reg);
|
||||
}
|
||||
|
||||
if (nr_bytes == 4)
|
||||
{
|
||||
dest_bytes[0] = value >> 24;
|
||||
dest_bytes[1] = value >> 16;
|
||||
dest_bytes[2] = value >> 8;
|
||||
dest_bytes[3] = value;
|
||||
}
|
||||
else
|
||||
hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes);
|
||||
|
||||
return nr_bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
attach_lm32uart_regs (struct hw *me, struct lm32uart *uart)
|
||||
{
|
||||
unsigned_word attach_address;
|
||||
int attach_space;
|
||||
unsigned attach_size;
|
||||
reg_property_spec reg;
|
||||
|
||||
if (hw_find_property (me, "reg") == NULL)
|
||||
hw_abort (me, "Missing \"reg\" property");
|
||||
if (!hw_find_reg_array_property (me, "reg", 0, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
uart->base = attach_address;
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me);
|
||||
uart->limit = attach_address + (attach_size - 1);
|
||||
hw_attach_address (hw_parent (me),
|
||||
0, attach_space, attach_address, attach_size, me);
|
||||
}
|
||||
|
||||
static void
|
||||
lm32uart_finish (struct hw *me)
|
||||
{
|
||||
struct lm32uart *uart;
|
||||
int i;
|
||||
|
||||
uart = HW_ZALLOC (me, struct lm32uart);
|
||||
set_hw_data (me, uart);
|
||||
set_hw_io_read_buffer (me, lm32uart_io_read_buffer);
|
||||
set_hw_io_write_buffer (me, lm32uart_io_write_buffer);
|
||||
set_hw_ports (me, lm32uart_ports);
|
||||
|
||||
/* Attach ourself to our parent bus. */
|
||||
attach_lm32uart_regs (me, uart);
|
||||
|
||||
/* Initialize the UART. */
|
||||
uart->rbr = 0;
|
||||
uart->thr = 0;
|
||||
uart->ier = 0;
|
||||
uart->iir = 0;
|
||||
uart->lcr = 0;
|
||||
uart->mcr = 0;
|
||||
uart->lsr = LM32_UART_LSR_TX_RDY;
|
||||
uart->msr = 0;
|
||||
uart->div = 0; /* By setting to zero, characters are output immediately. */
|
||||
}
|
||||
|
||||
const struct hw_descriptor dv_lm32uart_descriptor[] = {
|
||||
{"lm32uart", lm32uart_finish,},
|
||||
{NULL},
|
||||
};
|
57
sim/lm32/lm32-sim.h
Normal file
57
sim/lm32/lm32-sim.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#ifndef LM32_SIM_H
|
||||
#define LM32_SIM_H
|
||||
|
||||
#include "gdb/sim-lm32.h"
|
||||
|
||||
/* CSRs. */
|
||||
#define LM32_CSR_IE 0
|
||||
#define LM32_CSR_IM 1
|
||||
#define LM32_CSR_IP 2
|
||||
#define LM32_CSR_ICC 3
|
||||
#define LM32_CSR_DCC 4
|
||||
#define LM32_CSR_CC 5
|
||||
#define LM32_CSR_CFG 6
|
||||
#define LM32_CSR_EBA 7
|
||||
#define LM32_CSR_DC 8
|
||||
#define LM32_CSR_DEBA 9
|
||||
#define LM32_CSR_JTX 0xe
|
||||
#define LM32_CSR_JRX 0xf
|
||||
#define LM32_CSR_BP0 0x10
|
||||
#define LM32_CSR_BP1 0x11
|
||||
#define LM32_CSR_BP2 0x12
|
||||
#define LM32_CSR_BP3 0x13
|
||||
#define LM32_CSR_WP0 0x18
|
||||
#define LM32_CSR_WP1 0x19
|
||||
#define LM32_CSR_WP2 0x1a
|
||||
#define LM32_CSR_WP3 0x1b
|
||||
|
||||
/* Exception IDs. */
|
||||
#define LM32_EID_RESET 0
|
||||
#define LM32_EID_BREAKPOINT 1
|
||||
#define LM32_EID_INSTRUCTION_BUS_ERROR 2
|
||||
#define LM32_EID_WATCHPOINT 3
|
||||
#define LM32_EID_DATA_BUS_ERROR 4
|
||||
#define LM32_EID_DIVIDE_BY_ZERO 5
|
||||
#define LM32_EID_INTERRUPT 6
|
||||
#define LM32_EID_SYSTEM_CALL 7
|
||||
|
||||
#endif /* LM32_SIM_H */
|
100
sim/lm32/lm32.c
Normal file
100
sim/lm32/lm32.c
Normal file
@ -0,0 +1,100 @@
|
||||
/* Lattice Mico32 simulator support code.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#define WANT_CPU lm32bf
|
||||
#define WANT_CPU_LM32BF
|
||||
|
||||
#include "sim-main.h"
|
||||
#include "cgen-mem.h"
|
||||
#include "cgen-ops.h"
|
||||
|
||||
/* The contents of BUF are in target byte order. */
|
||||
|
||||
int
|
||||
lm32bf_fetch_register (SIM_CPU * current_cpu, int rn, unsigned char *buf,
|
||||
int len)
|
||||
{
|
||||
if (rn < 32)
|
||||
SETTSI (buf, lm32bf_h_gr_get (current_cpu, rn));
|
||||
else
|
||||
switch (rn)
|
||||
{
|
||||
case SIM_LM32_PC_REGNUM:
|
||||
SETTSI (buf, lm32bf_h_pc_get (current_cpu));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The contents of BUF are in target byte order. */
|
||||
|
||||
int
|
||||
lm32bf_store_register (SIM_CPU * current_cpu, int rn, unsigned char *buf,
|
||||
int len)
|
||||
{
|
||||
if (rn < 32)
|
||||
lm32bf_h_gr_set (current_cpu, rn, GETTSI (buf));
|
||||
else
|
||||
switch (rn)
|
||||
{
|
||||
case SIM_LM32_PC_REGNUM:
|
||||
lm32bf_h_pc_set (current_cpu, GETTSI (buf));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if WITH_PROFILE_MODEL_P
|
||||
|
||||
/* Initialize cycle counting for an insn.
|
||||
FIRST_P is non-zero if this is the first insn in a set of parallel
|
||||
insns. */
|
||||
|
||||
void
|
||||
lm32bf_model_insn_before (SIM_CPU * cpu, int first_p)
|
||||
{
|
||||
}
|
||||
|
||||
/* Record the cycles computed for an insn.
|
||||
LAST_P is non-zero if this is the last insn in a set of parallel insns,
|
||||
and we update the total cycle count.
|
||||
CYCLES is the cycle count of the insn. */
|
||||
|
||||
void
|
||||
lm32bf_model_insn_after (SIM_CPU * cpu, int last_p, int cycles)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lm32bf_model_lm32_u_exec (SIM_CPU * cpu, const IDESC * idesc,
|
||||
int unit_num, int referenced)
|
||||
{
|
||||
return idesc->timing->units[unit_num].done;
|
||||
}
|
||||
|
||||
#endif /* WITH_PROFILE_MODEL_P */
|
203
sim/lm32/mloop.in
Normal file
203
sim/lm32/mloop.in
Normal file
@ -0,0 +1,203 @@
|
||||
# Simulator main loop for lm32. -*- C -*-
|
||||
# Contributed by Jon Beniston <jon@beniston.com>
|
||||
#
|
||||
# This file is part of the GNU Simulators.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Syntax:
|
||||
# /bin/sh mainloop.in command
|
||||
#
|
||||
# Command is one of:
|
||||
#
|
||||
# init
|
||||
# support
|
||||
# extract-{simple,scache,pbb}
|
||||
# {full,fast}-exec-{simple,scache,pbb}
|
||||
#
|
||||
|
||||
case "x$1" in
|
||||
|
||||
xsupport)
|
||||
|
||||
cat <<EOF
|
||||
|
||||
static INLINE const IDESC *
|
||||
extract (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
|
||||
ARGBUF *abuf, int fast_p)
|
||||
{
|
||||
const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
|
||||
|
||||
@cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
|
||||
if (! fast_p)
|
||||
{
|
||||
int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
|
||||
int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
|
||||
@cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
static INLINE SEM_PC
|
||||
execute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p)
|
||||
{
|
||||
SEM_PC vpc;
|
||||
|
||||
if (fast_p)
|
||||
{
|
||||
#if ! WITH_SEM_SWITCH_FAST
|
||||
#if WITH_SCACHE
|
||||
vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc);
|
||||
#else
|
||||
vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, &sc->argbuf);
|
||||
#endif
|
||||
#else
|
||||
abort ();
|
||||
#endif /* WITH_SEM_SWITCH_FAST */
|
||||
}
|
||||
else
|
||||
{
|
||||
#if ! WITH_SEM_SWITCH_FULL
|
||||
ARGBUF *abuf = &sc->argbuf;
|
||||
const IDESC *idesc = abuf->idesc;
|
||||
const CGEN_INSN *idata = idesc->idata;
|
||||
#if WITH_SCACHE_PBB
|
||||
int virtual_p = CGEN_INSN_ATTR_VALUE (idata, CGEN_INSN_VIRTUAL);
|
||||
#else
|
||||
int virtual_p = 0;
|
||||
#endif
|
||||
if (! virtual_p)
|
||||
{
|
||||
/* FIXME: call x-before */
|
||||
if (ARGBUF_PROFILE_P (abuf))
|
||||
PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num);
|
||||
/* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
|
||||
if (PROFILE_MODEL_P (current_cpu)
|
||||
&& ARGBUF_PROFILE_P (abuf))
|
||||
@cpu@_model_insn_before (current_cpu, 1 /*first_p*/);
|
||||
TRACE_INSN_INIT (current_cpu, abuf, 1);
|
||||
TRACE_INSN (current_cpu, idata,
|
||||
(const struct argbuf *) abuf, abuf->addr);
|
||||
}
|
||||
#if WITH_SCACHE
|
||||
vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc);
|
||||
#else
|
||||
vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, abuf);
|
||||
#endif
|
||||
if (! virtual_p)
|
||||
{
|
||||
/* FIXME: call x-after */
|
||||
if (PROFILE_MODEL_P (current_cpu)
|
||||
&& ARGBUF_PROFILE_P (abuf))
|
||||
{
|
||||
int cycles;
|
||||
|
||||
cycles = (*idesc->timing->model_fn) (current_cpu, sc);
|
||||
@cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
|
||||
}
|
||||
TRACE_INSN_FINI (current_cpu, abuf, 1);
|
||||
}
|
||||
#else
|
||||
abort ();
|
||||
#endif /* WITH_SEM_SWITCH_FULL */
|
||||
}
|
||||
|
||||
return vpc;
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
;;
|
||||
|
||||
xinit)
|
||||
|
||||
# Nothing needed.
|
||||
|
||||
;;
|
||||
|
||||
xextract-simple | xextract-scache)
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
CGEN_INSN_INT insn = GETIMEMUSI (current_cpu, vpc);
|
||||
extract (current_cpu, vpc, insn, SEM_ARGBUF (sc), FAST_P);
|
||||
}
|
||||
EOF
|
||||
|
||||
;;
|
||||
|
||||
xextract-pbb)
|
||||
|
||||
# Inputs: current_cpu, pc, sc, max_insns, FAST_P
|
||||
# Outputs: sc, pc
|
||||
# sc must be left pointing past the last created entry.
|
||||
# pc must be left pointing past the last created entry.
|
||||
# If the pbb is terminated by a cti insn, SET_CTI_VPC(sc) must be called
|
||||
# to record the vpc of the cti insn.
|
||||
# SET_INSN_COUNT(n) must be called to record number of real insns.
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
const IDESC *idesc;
|
||||
int icount = 0;
|
||||
|
||||
while (max_insns > 0)
|
||||
{
|
||||
USI insn = GETIMEMUSI (current_cpu, pc);
|
||||
|
||||
idesc = extract (current_cpu, pc, insn, &sc->argbuf, FAST_P);
|
||||
++sc;
|
||||
--max_insns;
|
||||
++icount;
|
||||
pc += idesc->length;
|
||||
|
||||
if (IDESC_CTI_P (idesc))
|
||||
{
|
||||
SET_CTI_VPC (sc - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Finish:
|
||||
SET_INSN_COUNT (icount);
|
||||
}
|
||||
EOF
|
||||
|
||||
;;
|
||||
|
||||
xfull-exec-* | xfast-exec-*)
|
||||
|
||||
# Inputs: current_cpu, vpc, FAST_P
|
||||
# Outputs: vpc
|
||||
|
||||
cat <<EOF
|
||||
/* Update cycle counter */
|
||||
SET_H_CSR (LM32_CSR_CC, GET_H_CSR (LM32_CSR_CC) + 1);
|
||||
#if (! FAST_P && WITH_SEM_SWITCH_FULL) || (FAST_P && WITH_SEM_SWITCH_FAST)
|
||||
#define DEFINE_SWITCH
|
||||
#include "sem-switch.c"
|
||||
#else
|
||||
vpc = execute (current_cpu, vpc, FAST_P);
|
||||
#endif
|
||||
EOF
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Invalid argument to mainloop.in: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
1176
sim/lm32/model.c
Normal file
1176
sim/lm32/model.c
Normal file
File diff suppressed because it is too large
Load Diff
1554
sim/lm32/sem-switch.c
Normal file
1554
sim/lm32/sem-switch.c
Normal file
File diff suppressed because it is too large
Load Diff
1669
sim/lm32/sem.c
Normal file
1669
sim/lm32/sem.c
Normal file
File diff suppressed because it is too large
Load Diff
290
sim/lm32/sim-if.c
Normal file
290
sim/lm32/sim-if.c
Normal file
@ -0,0 +1,290 @@
|
||||
/* Main simulator entry points specific to Lattice Mico32.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "sim-main.h"
|
||||
#include "sim-options.h"
|
||||
#include "libiberty.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
static void free_state (SIM_DESC);
|
||||
static void print_lm32_misc_cpu (SIM_CPU * cpu, int verbose);
|
||||
static DECLARE_OPTION_HANDLER (lm32_option_handler);
|
||||
|
||||
enum
|
||||
{
|
||||
OPTION_ENDIAN = OPTION_START,
|
||||
};
|
||||
|
||||
/* GDB passes -E, even though it's fixed, so we have to handle it here. common code only handles it if SIM_HAVE_BIENDIAN is defined, which it isn't for lm32. */
|
||||
static const OPTION lm32_options[] = {
|
||||
{{"endian", required_argument, NULL, OPTION_ENDIAN},
|
||||
'E', "big", "Set endianness",
|
||||
lm32_option_handler},
|
||||
{{NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Records simulator descriptor so utilities like lm32_dump_regs can be
|
||||
called from gdb. */
|
||||
SIM_DESC current_state;
|
||||
|
||||
/* Cover function of sim_state_free to free the cpu buffers as well. */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Find memory range used by program. */
|
||||
|
||||
static unsigned long
|
||||
find_base (bfd *prog_bfd)
|
||||
{
|
||||
int found;
|
||||
unsigned long base = ~(0UL);
|
||||
asection *s;
|
||||
|
||||
found = 0;
|
||||
for (s = prog_bfd->sections; s; s = s->next)
|
||||
{
|
||||
if ((strcmp (bfd_get_section_name (prog_bfd, s), ".boot") == 0)
|
||||
|| (strcmp (bfd_get_section_name (prog_bfd, s), ".text") == 0)
|
||||
|| (strcmp (bfd_get_section_name (prog_bfd, s), ".data") == 0)
|
||||
|| (strcmp (bfd_get_section_name (prog_bfd, s), ".bss") == 0))
|
||||
{
|
||||
if (!found)
|
||||
{
|
||||
base = bfd_get_section_vma (prog_bfd, s);
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
base =
|
||||
bfd_get_section_vma (prog_bfd,
|
||||
s) < base ? bfd_get_section_vma (prog_bfd,
|
||||
s) : base;
|
||||
}
|
||||
}
|
||||
return base & ~(0xffffUL);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
find_limit (bfd *prog_bfd)
|
||||
{
|
||||
struct bfd_symbol **asymbols;
|
||||
long symsize;
|
||||
long symbol_count;
|
||||
long s;
|
||||
|
||||
symsize = bfd_get_symtab_upper_bound (prog_bfd);
|
||||
if (symsize < 0)
|
||||
return 0;
|
||||
asymbols = (asymbol **) xmalloc (symsize);
|
||||
symbol_count = bfd_canonicalize_symtab (prog_bfd, asymbols);
|
||||
if (symbol_count < 0)
|
||||
return 0;
|
||||
|
||||
for (s = 0; s < symbol_count; s++)
|
||||
{
|
||||
if (!strcmp (asymbols[s]->name, "_fstack"))
|
||||
return (asymbols[s]->value + 65536) & ~(0xffffUL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle lm32 specific options. */
|
||||
|
||||
static SIM_RC
|
||||
lm32_option_handler (sd, cpu, opt, arg, is_command)
|
||||
SIM_DESC sd;
|
||||
sim_cpu *cpu;
|
||||
int opt;
|
||||
char *arg;
|
||||
int is_command;
|
||||
{
|
||||
return SIM_RC_OK;
|
||||
}
|
||||
|
||||
/* Create an instance of the simulator. */
|
||||
|
||||
SIM_DESC
|
||||
sim_open (kind, callback, abfd, argv)
|
||||
SIM_OPEN_KIND kind;
|
||||
host_callback *callback;
|
||||
struct bfd *abfd;
|
||||
char **argv;
|
||||
{
|
||||
SIM_DESC sd = sim_state_alloc (kind, callback);
|
||||
char c;
|
||||
int i;
|
||||
unsigned long base, limit;
|
||||
|
||||
/* The cpu data is kept in a separately allocated chunk of memory. */
|
||||
if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK)
|
||||
{
|
||||
free_state (sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
|
||||
{
|
||||
free_state (sd);
|
||||
return 0;
|
||||
}
|
||||
sim_add_option_table (sd, NULL, lm32_options);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Allocate a handler for I/O devices
|
||||
if no memory for that range has been allocated by the user.
|
||||
All are allocated in one chunk to keep things from being
|
||||
unnecessarily complicated. */
|
||||
if (sim_core_read_buffer (sd, NULL, read_map, &c, LM32_DEVICE_ADDR, 1) == 0)
|
||||
sim_core_attach (sd, NULL, 0 /*level */ ,
|
||||
access_read_write, 0 /*space ??? */ ,
|
||||
LM32_DEVICE_ADDR, LM32_DEVICE_LEN /*nr_bytes */ ,
|
||||
0 /*modulo */ ,
|
||||
&lm32_devices, NULL /*buffer */ );
|
||||
#endif
|
||||
|
||||
/* check for/establish the 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;
|
||||
}
|
||||
|
||||
/* Check to see if memory exists at programs start address. */
|
||||
if (sim_core_read_buffer (sd, NULL, read_map, &c, STATE_START_ADDR (sd), 1)
|
||||
== 0)
|
||||
{
|
||||
if (STATE_PROG_BFD (sd) != NULL)
|
||||
{
|
||||
/* It doesn't, so we should try to allocate enough memory to hold program. */
|
||||
base = find_base (STATE_PROG_BFD (sd));
|
||||
limit = find_limit (STATE_PROG_BFD (sd));
|
||||
if (limit == 0)
|
||||
{
|
||||
sim_io_eprintf (sd,
|
||||
"Failed to find symbol _fstack in program. You must specify memory regions with --memory-region.\n");
|
||||
free_state (sd);
|
||||
return 0;
|
||||
}
|
||||
/*sim_io_printf (sd, "Allocating memory at 0x%x size 0x%x\n", base, limit); */
|
||||
sim_do_commandf (sd, "memory region 0x%x,0x%x", base, limit);
|
||||
}
|
||||
}
|
||||
|
||||
/* Establish any remaining configuration options. */
|
||||
if (sim_config (sd) != SIM_RC_OK)
|
||||
{
|
||||
free_state (sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sim_post_argv_init (sd) != SIM_RC_OK)
|
||||
{
|
||||
free_state (sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a copy of the cpu descriptor table. */
|
||||
{
|
||||
CGEN_CPU_DESC cd =
|
||||
lm32_cgen_cpu_open_1 (STATE_ARCHITECTURE (sd)->printable_name,
|
||||
CGEN_ENDIAN_BIG);
|
||||
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
|
||||
{
|
||||
SIM_CPU *cpu = STATE_CPU (sd, i);
|
||||
CPU_CPU_DESC (cpu) = cd;
|
||||
CPU_DISASSEMBLER (cpu) = sim_cgen_disassemble_insn;
|
||||
}
|
||||
lm32_cgen_init_dis (cd);
|
||||
}
|
||||
|
||||
/* Initialize various cgen things not done by common framework.
|
||||
Must be done after lm32_cgen_cpu_open. */
|
||||
cgen_init (sd);
|
||||
|
||||
/* Store in a global so things like lm32_dump_regs can be invoked
|
||||
from the gdb command line. */
|
||||
current_state = sd;
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
void
|
||||
sim_close (sd, quitting)
|
||||
SIM_DESC sd;
|
||||
int quitting;
|
||||
{
|
||||
lm32_cgen_cpu_close (CPU_CPU_DESC (STATE_CPU (sd, 0)));
|
||||
sim_module_uninstall (sd);
|
||||
}
|
||||
|
||||
SIM_RC
|
||||
sim_create_inferior (sd, abfd, argv, envp)
|
||||
SIM_DESC sd;
|
||||
struct bfd *abfd;
|
||||
char **argv;
|
||||
char **envp;
|
||||
{
|
||||
SIM_CPU *current_cpu = STATE_CPU (sd, 0);
|
||||
SIM_ADDR addr;
|
||||
|
||||
if (abfd != NULL)
|
||||
addr = bfd_get_start_address (abfd);
|
||||
else
|
||||
addr = 0;
|
||||
sim_pc_set (current_cpu, addr);
|
||||
|
||||
#if 0
|
||||
STATE_ARGV (sd) = sim_copy_argv (argv);
|
||||
STATE_ENVP (sd) = sim_copy_argv (envp);
|
||||
#endif
|
||||
|
||||
return SIM_RC_OK;
|
||||
}
|
||||
|
||||
void
|
||||
sim_do_command (sd, cmd)
|
||||
SIM_DESC sd;
|
||||
char *cmd;
|
||||
{
|
||||
if (sim_args_command (sd, cmd) != SIM_RC_OK)
|
||||
sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
|
||||
}
|
102
sim/lm32/sim-main.h
Normal file
102
sim/lm32/sim-main.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* Lattice Mico32 simulator support code
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
/* Main header for the LM32 simulator. */
|
||||
|
||||
#ifndef SIM_MAIN_H
|
||||
#define SIM_MAIN_H
|
||||
|
||||
#define USING_SIM_BASE_H /* FIXME: quick hack */
|
||||
|
||||
struct _sim_cpu; /* FIXME: should be in sim-basics.h */
|
||||
typedef struct _sim_cpu SIM_CPU;
|
||||
|
||||
#include "symcat.h"
|
||||
#include "sim-basics.h"
|
||||
#include "cgen-types.h"
|
||||
#include "lm32-desc.h"
|
||||
#include "lm32-opc.h"
|
||||
#include "arch.h"
|
||||
|
||||
/* These must be defined before sim-base.h. */
|
||||
typedef USI sim_cia;
|
||||
|
||||
#define CIA_GET(cpu) CPU_PC_GET (cpu)
|
||||
#define CIA_SET(cpu,val) CPU_PC_SET ((cpu), (val))
|
||||
|
||||
#define SIM_ENGINE_HALT_HOOK(sd, cpu, cia) \
|
||||
do { \
|
||||
if (cpu) /* null if ctrl-c */ \
|
||||
sim_pc_set ((cpu), (cia)); \
|
||||
} while (0)
|
||||
#define SIM_ENGINE_RESTART_HOOK(sd, cpu, cia) \
|
||||
do { \
|
||||
sim_pc_set ((cpu), (cia)); \
|
||||
} while (0)
|
||||
|
||||
#include "sim-base.h"
|
||||
#include "cgen-sim.h"
|
||||
#include "lm32-sim.h"
|
||||
#include "opcode/cgen.h"
|
||||
|
||||
/* The _sim_cpu struct. */
|
||||
|
||||
struct _sim_cpu
|
||||
{
|
||||
/* sim/common cpu base. */
|
||||
sim_cpu_base base;
|
||||
|
||||
/* Static parts of cgen. */
|
||||
CGEN_CPU cgen_cpu;
|
||||
|
||||
/* CPU specific parts go here.
|
||||
Note that in files that don't need to access these pieces WANT_CPU_FOO
|
||||
won't be defined and thus these parts won't appear. This is ok in the
|
||||
sense that things work. It is a source of bugs though.
|
||||
One has to of course be careful to not take the size of this
|
||||
struct and no structure members accessed in non-cpu specific files can
|
||||
go after here. Oh for a better language. */
|
||||
#if defined (WANT_CPU_LM32BF)
|
||||
LM32BF_CPU_DATA cpu_data;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* The sim_state struct. */
|
||||
|
||||
struct sim_state
|
||||
{
|
||||
sim_cpu *cpu;
|
||||
#define STATE_CPU(sd, n) (/*&*/ (sd)->cpu)
|
||||
|
||||
CGEN_STATE cgen_state;
|
||||
|
||||
sim_state_base base;
|
||||
};
|
||||
|
||||
/* Misc. */
|
||||
|
||||
/* Catch address exceptions. */
|
||||
extern SIM_CORE_SIGNAL_FN lm32_core_signal;
|
||||
#define SIM_CORE_SIGNAL(SD,CPU,CIA,MAP,NR_BYTES,ADDR,TRANSFER,ERROR) \
|
||||
lm32_core_signal ((SD), (CPU), (CIA), (MAP), (NR_BYTES), (ADDR), \
|
||||
(TRANSFER), (ERROR))
|
||||
|
||||
#endif /* SIM_MAIN_H */
|
27
sim/lm32/tconfig.in
Normal file
27
sim/lm32/tconfig.in
Normal file
@ -0,0 +1,27 @@
|
||||
/* Lattice Mico32 simulator configuration.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#ifndef LM32_TCONFIG_H
|
||||
#define LM32_TCONFIG_H
|
||||
|
||||
/* See sim-hload.c. We properly handle LMA. */
|
||||
#define SIM_HANDLES_LMA 1
|
||||
|
||||
#define WITH_SCACHE_PBB 1
|
||||
|
||||
#endif /* LM32_TCONFIG_H */
|
268
sim/lm32/traps.c
Normal file
268
sim/lm32/traps.c
Normal file
@ -0,0 +1,268 @@
|
||||
/* Lattice Mico32 exception and system call support.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#define WANT_CPU lm32bf
|
||||
#define WANT_CPU_LM32BF
|
||||
|
||||
#include "sim-main.h"
|
||||
#include "lm32-sim.h"
|
||||
#include "targ-vals.h"
|
||||
|
||||
/* Read memory function for system call interface. */
|
||||
|
||||
static int
|
||||
syscall_read_mem (host_callback * cb, struct cb_syscall *sc,
|
||||
unsigned long taddr, char *buf, int bytes)
|
||||
{
|
||||
SIM_DESC sd = (SIM_DESC) sc->p1;
|
||||
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
|
||||
|
||||
return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
|
||||
}
|
||||
|
||||
/* Write memory function for system call interface. */
|
||||
|
||||
static int
|
||||
syscall_write_mem (host_callback * cb, struct cb_syscall *sc,
|
||||
unsigned long taddr, const char *buf, int bytes)
|
||||
{
|
||||
SIM_DESC sd = (SIM_DESC) sc->p1;
|
||||
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
|
||||
|
||||
return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
|
||||
}
|
||||
|
||||
/* Handle invalid instructions. */
|
||||
|
||||
SEM_PC
|
||||
sim_engine_invalid_insn (SIM_CPU * current_cpu, IADDR cia, SEM_PC pc)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
|
||||
sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/* Handle divide instructions. */
|
||||
|
||||
USI
|
||||
lm32bf_divu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
host_callback *cb = STATE_CALLBACK (sd);
|
||||
|
||||
/* Check for divide by zero */
|
||||
if (GET_H_GR (r1) == 0)
|
||||
{
|
||||
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
|
||||
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE);
|
||||
else
|
||||
{
|
||||
/* Save PC in exception address register. */
|
||||
SET_H_GR (30, pc);
|
||||
/* Save and clear interrupt enable. */
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
|
||||
/* Branch to divide by zero exception handler. */
|
||||
return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_H_GR (r2, (USI) GET_H_GR (r0) / (USI) GET_H_GR (r1));
|
||||
return pc + 4;
|
||||
}
|
||||
}
|
||||
|
||||
USI
|
||||
lm32bf_modu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
host_callback *cb = STATE_CALLBACK (sd);
|
||||
|
||||
/* Check for divide by zero. */
|
||||
if (GET_H_GR (r1) == 0)
|
||||
{
|
||||
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
|
||||
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE);
|
||||
else
|
||||
{
|
||||
/* Save PC in exception address register. */
|
||||
SET_H_GR (30, pc);
|
||||
/* Save and clear interrupt enable. */
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
|
||||
/* Branch to divide by zero exception handler. */
|
||||
return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_H_GR (r2, (USI) GET_H_GR (r0) % (USI) GET_H_GR (r1));
|
||||
return pc + 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle break instructions. */
|
||||
|
||||
USI
|
||||
lm32bf_break_insn (SIM_CPU * current_cpu, IADDR pc)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
host_callback *cb = STATE_CALLBACK (sd);
|
||||
/* Breakpoint. */
|
||||
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
|
||||
{
|
||||
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
|
||||
return pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Save PC in breakpoint address register. */
|
||||
SET_H_GR (31, pc);
|
||||
/* Save and clear interrupt enable. */
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 2);
|
||||
/* Branch to breakpoint exception handler. */
|
||||
return GET_H_CSR (LM32_CSR_DEBA) + LM32_EID_BREAKPOINT * 32;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle scall instructions. */
|
||||
|
||||
USI
|
||||
lm32bf_scall_insn (SIM_CPU * current_cpu, IADDR pc)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
host_callback *cb = STATE_CALLBACK (sd);
|
||||
|
||||
if ((STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
|
||||
|| (GET_H_GR (8) == TARGET_SYS_exit))
|
||||
{
|
||||
/* Delegate system call to host O/S. */
|
||||
CB_SYSCALL s;
|
||||
CB_SYSCALL_INIT (&s);
|
||||
s.p1 = (PTR) sd;
|
||||
s.p2 = (PTR) current_cpu;
|
||||
s.read_mem = syscall_read_mem;
|
||||
s.write_mem = syscall_write_mem;
|
||||
/* Extract parameters. */
|
||||
s.func = GET_H_GR (8);
|
||||
s.arg1 = GET_H_GR (1);
|
||||
s.arg2 = GET_H_GR (2);
|
||||
s.arg3 = GET_H_GR (3);
|
||||
/* Halt the simulator if the requested system call is _exit. */
|
||||
if (s.func == TARGET_SYS_exit)
|
||||
sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
|
||||
/* Perform the system call. */
|
||||
cb_syscall (cb, &s);
|
||||
/* Store the return value in the CPU's registers. */
|
||||
SET_H_GR (1, s.result);
|
||||
SET_H_GR (2, s.result2);
|
||||
SET_H_GR (3, s.errcode);
|
||||
/* Skip over scall instruction. */
|
||||
return pc + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Save PC in exception address register. */
|
||||
SET_H_GR (30, pc);
|
||||
/* Save and clear interrupt enable */
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
|
||||
/* Branch to system call exception handler. */
|
||||
return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_SYSTEM_CALL * 32;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle b instructions. */
|
||||
|
||||
USI
|
||||
lm32bf_b_insn (SIM_CPU * current_cpu, USI r0, USI f_r0)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
host_callback *cb = STATE_CALLBACK (sd);
|
||||
|
||||
/* Restore interrupt enable. */
|
||||
if (f_r0 == 30)
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 2) >> 1);
|
||||
else if (f_r0 == 31)
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 4) >> 2);
|
||||
return r0;
|
||||
}
|
||||
|
||||
/* Handle wcsr instructions. */
|
||||
|
||||
void
|
||||
lm32bf_wcsr_insn (SIM_CPU * current_cpu, USI f_csr, USI r1)
|
||||
{
|
||||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||||
host_callback *cb = STATE_CALLBACK (sd);
|
||||
|
||||
/* Writing a 1 to IP CSR clears a bit, writing 0 has no effect. */
|
||||
if (f_csr == LM32_CSR_IP)
|
||||
SET_H_CSR (f_csr, GET_H_CSR (f_csr) & ~r1);
|
||||
else
|
||||
SET_H_CSR (f_csr, r1);
|
||||
}
|
||||
|
||||
/* Handle signals. */
|
||||
|
||||
void
|
||||
lm32_core_signal (SIM_DESC sd,
|
||||
sim_cpu * cpu,
|
||||
sim_cia cia,
|
||||
unsigned map,
|
||||
int nr_bytes,
|
||||
address_word addr,
|
||||
transfer_type transfer, sim_core_signals sig)
|
||||
{
|
||||
const char *copy = (transfer == read_transfer ? "read" : "write");
|
||||
address_word ip = CIA_ADDR (cia);
|
||||
SIM_CPU *current_cpu = cpu;
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case sim_core_unmapped_signal:
|
||||
sim_io_eprintf (sd,
|
||||
"core: %d byte %s to unmapped address 0x%lx at 0x%lx\n",
|
||||
nr_bytes, copy, (unsigned long) addr,
|
||||
(unsigned long) ip);
|
||||
SET_H_GR (30, ip);
|
||||
/* Save and clear interrupt enable. */
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
|
||||
CIA_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32);
|
||||
sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32,
|
||||
sim_stopped, SIM_SIGSEGV);
|
||||
break;
|
||||
case sim_core_unaligned_signal:
|
||||
sim_io_eprintf (sd,
|
||||
"core: %d byte misaligned %s to address 0x%lx at 0x%lx\n",
|
||||
nr_bytes, copy, (unsigned long) addr,
|
||||
(unsigned long) ip);
|
||||
SET_H_GR (30, ip);
|
||||
/* Save and clear interrupt enable. */
|
||||
SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
|
||||
CIA_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32);
|
||||
sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32,
|
||||
sim_stopped, SIM_SIGBUS);
|
||||
break;
|
||||
default:
|
||||
sim_engine_abort (sd, cpu, cia,
|
||||
"sim_core_signal - internal error - bad switch");
|
||||
}
|
||||
}
|
30
sim/lm32/user.c
Normal file
30
sim/lm32/user.c
Normal file
@ -0,0 +1,30 @@
|
||||
/* Semantics for user defined instructions on the Lattice Mico32.
|
||||
Contributed by Jon Beniston <jon@beniston.com>
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "sim-main.h"
|
||||
|
||||
/* Handle user defined instructions. */
|
||||
|
||||
UINT
|
||||
lm32bf_user_insn (SIM_CPU * current_cpu, INT r0, INT r1, UINT imm)
|
||||
{
|
||||
/* FIXME: Should probably call code in a user supplied library. */
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user