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:
Jon Beniston 2009-05-18 13:25:35 +00:00
parent 739fc47ac9
commit c28c63d86b
42 changed files with 16349 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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*

View File

@ -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
View 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);
}

View File

@ -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

View File

@ -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
}

View File

@ -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
View 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

View File

@ -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.

View File

@ -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>

View File

@ -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:

View File

@ -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}"

View File

@ -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
View File

@ -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-*-*)

View File

@ -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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

21
sim/lm32/configure.ac Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
timers->base = attach_address;
hw_unit_size_to_attach_size (hw_parent (me), &reg.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
View 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, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
uart->base = attach_address;
hw_unit_size_to_attach_size (hw_parent (me), &reg.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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

290
sim/lm32/sim-if.c Normal file
View 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
View 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
View 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
View 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
View 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;
}