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