sim: bfin: new port

This can boot Das U-Boot and a Linux kernel.  It also supports Linux
userspace FLAT and FDPIC (dynamic and static) ELFs.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
Mike Frysinger 2011-03-06 00:20:21 +00:00
parent 7dcf22fd41
commit ef016f835f
110 changed files with 30357 additions and 0 deletions

View File

@ -1,3 +1,7 @@
2011-03-05 Mike Frysinger <vapier@gentoo.org>
* sim-bfin.h: New file.
2011-01-11 Andrew Burgess <aburgess@broadcom.com>
* remote-sim.h (sim_store_register): Update the API

82
include/gdb/sim-bfin.h Normal file
View File

@ -0,0 +1,82 @@
/* This file defines the interface between the Blackfin simulator and GDB.
Copyright (C) 2005-2011 Free Software Foundation, Inc.
Contributed by Analog Devices.
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/>. */
enum sim_bfin_regnum {
SIM_BFIN_R0_REGNUM = 0,
SIM_BFIN_R1_REGNUM,
SIM_BFIN_R2_REGNUM,
SIM_BFIN_R3_REGNUM,
SIM_BFIN_R4_REGNUM,
SIM_BFIN_R5_REGNUM,
SIM_BFIN_R6_REGNUM,
SIM_BFIN_R7_REGNUM,
SIM_BFIN_P0_REGNUM,
SIM_BFIN_P1_REGNUM,
SIM_BFIN_P2_REGNUM,
SIM_BFIN_P3_REGNUM,
SIM_BFIN_P4_REGNUM,
SIM_BFIN_P5_REGNUM,
SIM_BFIN_SP_REGNUM,
SIM_BFIN_FP_REGNUM,
SIM_BFIN_I0_REGNUM,
SIM_BFIN_I1_REGNUM,
SIM_BFIN_I2_REGNUM,
SIM_BFIN_I3_REGNUM,
SIM_BFIN_M0_REGNUM,
SIM_BFIN_M1_REGNUM,
SIM_BFIN_M2_REGNUM,
SIM_BFIN_M3_REGNUM,
SIM_BFIN_B0_REGNUM,
SIM_BFIN_B1_REGNUM,
SIM_BFIN_B2_REGNUM,
SIM_BFIN_B3_REGNUM,
SIM_BFIN_L0_REGNUM,
SIM_BFIN_L1_REGNUM,
SIM_BFIN_L2_REGNUM,
SIM_BFIN_L3_REGNUM,
SIM_BFIN_A0_DOT_X_REGNUM,
SIM_BFIN_A0_DOT_W_REGNUM,
SIM_BFIN_A1_DOT_X_REGNUM,
SIM_BFIN_A1_DOT_W_REGNUM,
SIM_BFIN_ASTAT_REGNUM,
SIM_BFIN_RETS_REGNUM,
SIM_BFIN_LC0_REGNUM,
SIM_BFIN_LT0_REGNUM,
SIM_BFIN_LB0_REGNUM,
SIM_BFIN_LC1_REGNUM,
SIM_BFIN_LT1_REGNUM,
SIM_BFIN_LB1_REGNUM,
SIM_BFIN_CYCLES_REGNUM,
SIM_BFIN_CYCLES2_REGNUM,
SIM_BFIN_USP_REGNUM,
SIM_BFIN_SEQSTAT_REGNUM,
SIM_BFIN_SYSCFG_REGNUM,
SIM_BFIN_RETI_REGNUM,
SIM_BFIN_RETX_REGNUM,
SIM_BFIN_RETN_REGNUM,
SIM_BFIN_RETE_REGNUM,
SIM_BFIN_PC_REGNUM,
SIM_BFIN_CC_REGNUM,
SIM_BFIN_TEXT_ADDR,
SIM_BFIN_TEXT_END_ADDR,
SIM_BFIN_DATA_ADDR,
SIM_BFIN_IPEND_REGNUM
};

View File

@ -1,3 +1,9 @@
2011-03-05 Mike Frysinger <vapier@gentoo.org>
* MAINTAINERS: Add bfin entry.
* configure.tgt (bfin-*-*): Handle bfin targets.
* configure: Regenerate.
2011-01-05 Mike Frysinger <vapier@gentoo.org>
* .gitignore: Add /*/hw-config.h.

View File

@ -10,6 +10,7 @@ gdb-patches@sources.redhat.com
Maintainers for particular sims:
arm Nick Clifton <nickc@redhat.com>
bfin Mike Frysinger <vapier@gentoo.org>
cr16 M R Swami Reddy <MR.Swami.Reddy@nsc.com>
frv Dave Brolley <brolley@redhat.com>
igen (igen simulators)

97
sim/bfin/Makefile.in Normal file
View File

@ -0,0 +1,97 @@
# Makefile template for Configure for the Blackfin simulator.
# Copyright (C) 2005-2011 Free Software Foundation, Inc.
# Written by Analog Devices, Inc.
#
# 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/>.
# This selects the bfin newlib/libgloss syscall definitions.
NL_TARGET = -DNL_TARGET_bfin
## COMMON_PRE_CONFIG_FRAG
# List of main object files for `run'.
SIM_RUN_OBJS = nrun.o
SIM_OBJS = \
$(SIM_NEW_COMMON_OBJS) \
bfin-sim.o \
devices.o \
gui.o \
interp.o \
machs.o \
sim-cpu.o \
sim-engine.o \
sim-hload.o \
sim-hrw.o \
sim-model.o \
sim-reason.o \
sim-reg.o \
sim-resume.o \
sim-stop.o \
@BFIN_SIM_EXTRA_OBJS@ \
$(SIM_EXTRA_OBJS)
INCLUDE = bfin-sim.h
SIM_EXTRA_CFLAGS = @SDL_CFLAGS@
SIM_EXTRA_LIBS = @SDL_LIBS@ -lm
## COMMON_POST_CONFIG_FRAG
$(srcdir)/linux-fixed-code.h: $(srcdir)/linux-fixed-code.s Makefile.in
$(AS_FOR_TARGET) $< -o linux-fixed-code.o
( set -e; \
echo "/* DO NOT EDIT: Autogenerated from linux-fixed-code.s. */"; \
echo "static const unsigned char bfin_linux_fixed_code[] = {"; \
$(OBJDUMP_FOR_TARGET) -d -z linux-fixed-code.o > $@.dis; \
sed -n $@.dis \
-e 's:^[^ ]* :0x:' \
-e '/^0x/{s: .*::;s: *$$:,:;s: :, 0x:g;p}'; \
rm -f $@.dis; \
echo "};" \
) > $@.tmp
rm -f linux-fixed-code.o
mv $@.tmp $@
interp.o: interp.c targ-vals.h linux-targ-map.h linux-fixed-code.h devices.h $(INCLUDE)
bfin-sim.o: bfin-sim.c $(INCLUDE)
gui.o: gui.c $(INCLUDE)
machs.o: machs.c $(INCLUDE)
dv-bfin_cec.o: dv-bfin_cec.c devices.h $(INCLUDE)
dv-bfin_ctimer.o: dv-bfin_ctimer.c devices.h $(INCLUDE)
dv-bfin_dma.o: dv-bfin_dma.c devices.h $(INCLUDE)
dv-bfin_dma_pmap.o: dv-bfin_dma_pmap.c devices.h $(INCLUDE)
dv-bfin_ebiu_amc.o: dv-bfin_ebiu_amc.c devices.h $(INCLUDE)
dv-bfin_ebiu_ddrc.o: dv-bfin_ebiu_ddrc.c devices.h $(INCLUDE)
dv-bfin_ebiu_sdc.o: dv-bfin_ebiu_sdc.c devices.h $(INCLUDE)
dv-bfin_emac.o: dv-bfin_emac.c devices.h $(INCLUDE)
dv-bfin_eppi.o: dv-bfin_eppi.c devices.h $(INCLUDE)
dv-bfin_evt.o: dv-bfin_evt.c devices.h $(INCLUDE)
dv-bfin_gptimer.o: dv-bfin_gptimer.c devices.h $(INCLUDE)
dv-bfin_jtag.o: dv-bfin_jtag.c devices.h $(INCLUDE)
dv-bfin_mmu.o: dv-bfin_mmu.c devices.h $(INCLUDE)
dv-bfin_nfc.o: dv-bfin_nfc.c devices.h $(INCLUDE)
dv-bfin_otp.o: dv-bfin_otp.c devices.h $(INCLUDE)
dv-bfin_pll.o: dv-bfin_pll.c devices.h $(INCLUDE)
dv-bfin_ppi.o: dv-bfin_ppi.c devices.h $(INCLUDE)
dv-bfin_rtc.o: dv-bfin_rtc.c devices.h $(INCLUDE)
dv-bfin_sic.o: dv-bfin_sic.c devices.h $(INCLUDE)
dv-bfin_spi.o: dv-bfin_spi.c devices.h $(INCLUDE)
dv-bfin_trace.o: dv-bfin_trace.c devices.h $(INCLUDE)
dv-bfin_twi.o: dv-bfin_twi.c devices.h $(INCLUDE)
dv-bfin_uart.o: dv-bfin_uart.c devices.h $(INCLUDE)
dv-bfin_uart2.o: dv-bfin_uart2.c devices.h $(INCLUDE)
dv-bfin_wdog.o: dv-bfin_wdog.c devices.h $(INCLUDE)
dv-bfin_wp.o: dv-bfin_wp.c devices.h $(INCLUDE)
dv-eth_phy.o: devices.h $(INCLUDE)

28
sim/bfin/TODO Normal file
View File

@ -0,0 +1,28 @@
need to review ASTAT write behavior
how to model RETE and IVG0 bit in IPEND ...
model the loop buffer ? this means no ifetches because they're cached.
see page 4-26 in Blackfin PRM under hardware loops.
handle DSPID at 0xffe05000
CEC should handle multiple exceptions at same address. would need
exception processing to be delayed ? at least needs a stack for
the CEC to pop things off.
R0 = [SP++]; gets traced as R0 = [P6++];
merge dv-bfin_evt with dv-bfin_cec since the EVT regs are part of the CEC
fix single stepping over debug assert instructions in hardware
exception in IVG5 causes double fault ?
add a "file" option to the async banks to back it
tests:
- check AN bits with Dreg subtraction
R0 = R1 - R2;
- check astat bits with vector add/sub +|+
- check acc with VIT_MAX and similiar insns

171
sim/bfin/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,171 @@
# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# 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 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
fi
if test -n "$PKG_CONFIG"; then
_pkg_min_version=m4_default([$1], [0.9.0])
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
PKG_CONFIG=""
fi
fi[]dnl
])# PKG_PROG_PKG_CONFIG
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
m4_default([$2], [:])
m4_ifvaln([$3], [else
$3])dnl
fi])
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
elif test -n "$PKG_CONFIG"; then
PKG_CHECK_EXISTS([$3],
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
[pkg_failed=yes])
else
pkg_failed=untried
fi[]dnl
])# _PKG_CONFIG
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi[]dnl
])# _PKG_SHORT_ERRORS_SUPPORTED
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
_PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
$3
fi[]dnl
])# PKG_CHECK_MODULES

6099
sim/bfin/bfin-sim.c Normal file

File diff suppressed because it is too large Load Diff

350
sim/bfin/bfin-sim.h Normal file
View File

@ -0,0 +1,350 @@
/* Simulator for Analog Devices Blackfin processors.
Copyright (C) 2005-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 _BFIN_SIM_H_
#define _BFIN_SIM_H_
#include <stdbool.h>
#include <stdint.h>
typedef uint8_t bu8;
typedef uint16_t bu16;
typedef uint32_t bu32;
typedef uint64_t bu40;
typedef uint64_t bu64;
typedef int8_t bs8;
typedef int16_t bs16;
typedef int32_t bs32;
typedef int64_t bs40;
typedef int64_t bs64;
/* For dealing with parallel instructions, we must avoid changing our register
file until all parallel insns have been simulated. This queue of stores
can be used to delay a modification.
XXX: Should go and convert all 32 bit insns to use this. */
struct store {
bu32 *addr;
bu32 val;
};
/* The KSP/USP handling wrt SP may not follow the hardware exactly (the hw
looks at current mode and uses either SP or USP based on that. We instead
always operate on SP and mirror things in KSP and USP. During a CEC
transition, we take care of syncing the values. This lowers the simulation
complexity and speeds things up a bit. */
struct bfin_cpu_state
{
bu32 dpregs[16], iregs[4], mregs[4], bregs[4], lregs[4], cycles[3];
bu32 ax[2], aw[2];
bu32 lt[2], lc[2], lb[2];
bu32 ksp, usp, seqstat, syscfg, rets, reti, retx, retn, rete;
bu32 pc, emudat[2];
/* These ASTAT flags need not be bu32, but it makes pointers easier. */
bu32 ac0, ac0_copy, ac1, an, aq;
union { struct { bu32 av0; bu32 av1; }; bu32 av [2]; };
union { struct { bu32 av0s; bu32 av1s; }; bu32 avs[2]; };
bu32 az, cc, v, v_copy, vs;
bu32 rnd_mod;
bu32 v_internal;
bu32 astat_reserved;
/* Set by an instruction emulation function if we performed a jump. We
cannot compare oldpc to newpc as this ignores the "jump 0;" case. */
bool did_jump;
/* Used by the CEC to figure out where to return to. */
bu32 insn_len;
/* How many cycles did this insn take to complete ? */
bu32 cycle_delay;
/* The pc currently being interpreted in parallel insns. */
bu32 multi_pc;
/* Needed for supporting the DISALGNEXCPT instruction */
int dis_algn_expt;
/* See notes above for struct store. */
struct store stores[20];
int n_stores;
#if (WITH_HW)
/* Cache heavily used CPU-specific device pointers. */
void *cec_cache;
void *evt_cache;
void *mmu_cache;
void *trace_cache;
#endif
};
#define REG_H_L(h, l) (((h) & 0xffff0000) | ((l) & 0x0000ffff))
#define DREG(x) (BFIN_CPU_STATE.dpregs[x])
#define PREG(x) (BFIN_CPU_STATE.dpregs[x + 8])
#define SPREG PREG (6)
#define FPREG PREG (7)
#define IREG(x) (BFIN_CPU_STATE.iregs[x])
#define MREG(x) (BFIN_CPU_STATE.mregs[x])
#define BREG(x) (BFIN_CPU_STATE.bregs[x])
#define LREG(x) (BFIN_CPU_STATE.lregs[x])
#define AXREG(x) (BFIN_CPU_STATE.ax[x])
#define AWREG(x) (BFIN_CPU_STATE.aw[x])
#define CCREG (BFIN_CPU_STATE.cc)
#define LCREG(x) (BFIN_CPU_STATE.lc[x])
#define LTREG(x) (BFIN_CPU_STATE.lt[x])
#define LBREG(x) (BFIN_CPU_STATE.lb[x])
#define CYCLESREG (BFIN_CPU_STATE.cycles[0])
#define CYCLES2REG (BFIN_CPU_STATE.cycles[1])
#define CYCLES2SHDREG (BFIN_CPU_STATE.cycles[2])
#define KSPREG (BFIN_CPU_STATE.ksp)
#define USPREG (BFIN_CPU_STATE.usp)
#define SEQSTATREG (BFIN_CPU_STATE.seqstat)
#define SYSCFGREG (BFIN_CPU_STATE.syscfg)
#define RETSREG (BFIN_CPU_STATE.rets)
#define RETIREG (BFIN_CPU_STATE.reti)
#define RETXREG (BFIN_CPU_STATE.retx)
#define RETNREG (BFIN_CPU_STATE.retn)
#define RETEREG (BFIN_CPU_STATE.rete)
#define PCREG (BFIN_CPU_STATE.pc)
#define EMUDAT_INREG (BFIN_CPU_STATE.emudat[0])
#define EMUDAT_OUTREG (BFIN_CPU_STATE.emudat[1])
#define INSN_LEN (BFIN_CPU_STATE.insn_len)
#define CYCLE_DELAY (BFIN_CPU_STATE.cycle_delay)
#define DIS_ALGN_EXPT (BFIN_CPU_STATE.dis_algn_expt)
#define EXCAUSE_SHIFT 0
#define EXCAUSE_MASK (0x3f << EXCAUSE_SHIFT)
#define EXCAUSE ((SEQSTATREG & EXCAUSE_MASK) >> EXCAUSE_SHIFT)
#define HWERRCAUSE_SHIFT 14
#define HWERRCAUSE_MASK (0x1f << HWERRCAUSE_SHIFT)
#define HWERRCAUSE ((SEQSTATREG & HWERRCAUSE_MASK) >> HWERRCAUSE_SHIFT)
#define _SET_CORE32REG_IDX(reg, p, x, val) \
do { \
bu32 __v = (val); \
TRACE_REGISTER (cpu, "wrote "#p"%i = %#x", x, __v); \
reg = __v; \
} while (0)
#define SET_DREG(x, val) _SET_CORE32REG_IDX (DREG (x), R, x, val)
#define SET_PREG(x, val) _SET_CORE32REG_IDX (PREG (x), P, x, val)
#define SET_IREG(x, val) _SET_CORE32REG_IDX (IREG (x), I, x, val)
#define SET_MREG(x, val) _SET_CORE32REG_IDX (MREG (x), M, x, val)
#define SET_BREG(x, val) _SET_CORE32REG_IDX (BREG (x), B, x, val)
#define SET_LREG(x, val) _SET_CORE32REG_IDX (LREG (x), L, x, val)
#define SET_LCREG(x, val) _SET_CORE32REG_IDX (LCREG (x), LC, x, val)
#define SET_LTREG(x, val) _SET_CORE32REG_IDX (LTREG (x), LT, x, val)
#define SET_LBREG(x, val) _SET_CORE32REG_IDX (LBREG (x), LB, x, val)
#define SET_DREG_L_H(x, l, h) SET_DREG (x, REG_H_L (h, l))
#define SET_DREG_L(x, l) SET_DREG (x, REG_H_L (DREG (x), l))
#define SET_DREG_H(x, h) SET_DREG (x, REG_H_L (h, DREG (x)))
#define _SET_CORE32REG_ALU(reg, p, x, val) \
do { \
bu32 __v = (val); \
TRACE_REGISTER (cpu, "wrote A%i"#p" = %#x", x, __v); \
reg = __v; \
} while (0)
#define SET_AXREG(x, val) _SET_CORE32REG_ALU (AXREG (x), X, x, val)
#define SET_AWREG(x, val) _SET_CORE32REG_ALU (AWREG (x), W, x, val)
#define SET_AREG(x, val) \
do { \
bu40 __a = (val); \
SET_AXREG (x, (__a >> 32) & 0xff); \
SET_AWREG (x, __a); \
} while (0)
#define SET_AREG32(x, val) \
do { \
SET_AWREG (x, val); \
SET_AXREG (x, -(AWREG (x) >> 31)); \
} while (0)
#define _SET_CORE32REG(reg, val) \
do { \
bu32 __v = (val); \
TRACE_REGISTER (cpu, "wrote "#reg" = %#x", __v); \
reg##REG = __v; \
} while (0)
#define SET_FPREG(val) _SET_CORE32REG (FP, val)
#define SET_SPREG(val) _SET_CORE32REG (SP, val)
#define SET_CYCLESREG(val) _SET_CORE32REG (CYCLES, val)
#define SET_CYCLES2REG(val) _SET_CORE32REG (CYCLES2, val)
#define SET_CYCLES2SHDREG(val) _SET_CORE32REG (CYCLES2SHD, val)
#define SET_KSPREG(val) _SET_CORE32REG (KSP, val)
#define SET_USPREG(val) _SET_CORE32REG (USP, val)
#define SET_SYSCFGREG(val) _SET_CORE32REG (SYSCFG, val)
#define SET_RETSREG(val) _SET_CORE32REG (RETS, val)
#define SET_RETIREG(val) _SET_CORE32REG (RETI, val)
#define SET_RETXREG(val) _SET_CORE32REG (RETX, val)
#define SET_RETNREG(val) _SET_CORE32REG (RETN, val)
#define SET_RETEREG(val) _SET_CORE32REG (RETE, val)
#define SET_PCREG(val) _SET_CORE32REG (PC, val)
#define _SET_CORE32REGFIELD(reg, field, val, mask, shift) \
do { \
bu32 __f = (val); \
bu32 __v = ((reg##REG) & ~(mask)) | (__f << (shift)); \
TRACE_REGISTER (cpu, "wrote "#field" = %#x ("#reg" = %#x)", __f, __v); \
reg##REG = __v; \
} while (0)
#define SET_SEQSTATREG(val) _SET_CORE32REG (SEQSTAT, val)
#define SET_EXCAUSE(excp) _SET_CORE32REGFIELD (SEQSTAT, EXCAUSE, excp, EXCAUSE_MASK, EXCAUSE_SHIFT)
#define SET_HWERRCAUSE(hwerr) _SET_CORE32REGFIELD (SEQSTAT, HWERRCAUSE, hwerr, HWERRCAUSE_MASK, HWERRCAUSE_SHIFT)
#define AZ_BIT 0
#define AN_BIT 1
#define AC0_COPY_BIT 2
#define V_COPY_BIT 3
#define CC_BIT 5
#define AQ_BIT 6
#define RND_MOD_BIT 8
#define AC0_BIT 12
#define AC1_BIT 13
#define AV0_BIT 16
#define AV0S_BIT 17
#define AV1_BIT 18
#define AV1S_BIT 19
#define V_BIT 24
#define VS_BIT 25
#define ASTAT_DEFINED_BITS \
((1 << AZ_BIT) | (1 << AN_BIT) | (1 << AC0_COPY_BIT) | (1 << V_COPY_BIT) \
|(1 << CC_BIT) | (1 << AQ_BIT) \
|(1 << RND_MOD_BIT) \
|(1 << AC0_BIT) | (1 << AC1_BIT) \
|(1 << AV0_BIT) | (1 << AV0S_BIT) | (1 << AV1_BIT) | (1 << AV1S_BIT) \
|(1 << V_BIT) | (1 << VS_BIT))
#define ASTATREG(field) (BFIN_CPU_STATE.field)
#define ASTAT_DEPOSIT(field, bit) (ASTATREG(field) << (bit))
#define ASTAT \
(ASTAT_DEPOSIT(az, AZ_BIT) \
|ASTAT_DEPOSIT(an, AN_BIT) \
|ASTAT_DEPOSIT(ac0_copy, AC0_COPY_BIT) \
|ASTAT_DEPOSIT(v_copy, V_COPY_BIT) \
|ASTAT_DEPOSIT(cc, CC_BIT) \
|ASTAT_DEPOSIT(aq, AQ_BIT) \
|ASTAT_DEPOSIT(rnd_mod, RND_MOD_BIT) \
|ASTAT_DEPOSIT(ac0, AC0_BIT) \
|ASTAT_DEPOSIT(ac1, AC1_BIT) \
|ASTAT_DEPOSIT(av0, AV0_BIT) \
|ASTAT_DEPOSIT(av0s, AV0S_BIT) \
|ASTAT_DEPOSIT(av1, AV1_BIT) \
|ASTAT_DEPOSIT(av1s, AV1S_BIT) \
|ASTAT_DEPOSIT(v, V_BIT) \
|ASTAT_DEPOSIT(vs, VS_BIT) \
|ASTATREG(astat_reserved))
#define ASTAT_EXTRACT(a, bit) (((a) >> bit) & 1)
#define _SET_ASTAT(a, field, bit) (ASTATREG(field) = ASTAT_EXTRACT(a, bit))
#define SET_ASTAT(a) \
do { \
TRACE_REGISTER (cpu, "wrote ASTAT = %#x", a); \
_SET_ASTAT(a, az, AZ_BIT); \
_SET_ASTAT(a, an, AN_BIT); \
_SET_ASTAT(a, ac0_copy, AC0_COPY_BIT); \
_SET_ASTAT(a, v_copy, V_COPY_BIT); \
_SET_ASTAT(a, cc, CC_BIT); \
_SET_ASTAT(a, aq, AQ_BIT); \
_SET_ASTAT(a, rnd_mod, RND_MOD_BIT); \
_SET_ASTAT(a, ac0, AC0_BIT); \
_SET_ASTAT(a, ac1, AC1_BIT); \
_SET_ASTAT(a, av0, AV0_BIT); \
_SET_ASTAT(a, av0s, AV0S_BIT); \
_SET_ASTAT(a, av1, AV1_BIT); \
_SET_ASTAT(a, av1s, AV1S_BIT); \
_SET_ASTAT(a, v, V_BIT); \
_SET_ASTAT(a, vs, VS_BIT); \
ASTATREG(astat_reserved) = (a) & ~ASTAT_DEFINED_BITS; \
} while (0)
#define SET_ASTATREG(field, val) \
do { \
int __v = !!(val); \
TRACE_REGISTER (cpu, "wrote ASTAT["#field"] = %i", __v); \
ASTATREG (field) = __v; \
if (&ASTATREG (field) == &ASTATREG (ac0)) \
{ \
TRACE_REGISTER (cpu, "wrote ASTAT["#field"_copy] = %i", __v); \
ASTATREG (ac0_copy) = __v; \
} \
else if (&ASTATREG (field) == &ASTATREG (v)) \
{ \
TRACE_REGISTER (cpu, "wrote ASTAT["#field"_copy] = %i", __v); \
ASTATREG (v_copy) = __v; \
} \
} while (0)
#define SET_CCREG(val) SET_ASTATREG (cc, val)
#define SYSCFG_SSSTEP (1 << 0)
#define SYSCFG_CCEN (1 << 1)
#define SYSCFG_SNEN (1 << 2)
#define __PUT_MEM(taddr, v, size) \
do { \
bu##size __v = (v); \
bu32 __taddr = (taddr); \
int __cnt, __bytes = size / 8; \
mmu_check_addr (cpu, __taddr, true, false, __bytes); \
__cnt = sim_core_write_buffer (CPU_STATE(cpu), cpu, write_map, \
(void *)&__v, __taddr, __bytes); \
if (__cnt != __bytes) \
mmu_process_fault (cpu, __taddr, true, false, false, true); \
TRACE_CORE (cpu, __taddr, __bytes, write_map, __v); \
} while (0)
#define PUT_BYTE(taddr, v) __PUT_MEM(taddr, v, 8)
#define PUT_WORD(taddr, v) __PUT_MEM(taddr, v, 16)
#define PUT_LONG(taddr, v) __PUT_MEM(taddr, v, 32)
#define __GET_MEM(taddr, size, inst, map) \
({ \
bu##size __ret; \
bu32 __taddr = (taddr); \
int __cnt, __bytes = size / 8; \
mmu_check_addr (cpu, __taddr, false, inst, __bytes); \
__cnt = sim_core_read_buffer (CPU_STATE(cpu), cpu, map, \
(void *)&__ret, __taddr, __bytes); \
if (__cnt != __bytes) \
mmu_process_fault (cpu, __taddr, false, inst, false, true); \
TRACE_CORE (cpu, __taddr, __bytes, map, __ret); \
__ret; \
})
#define _GET_MEM(taddr, size) __GET_MEM(taddr, size, false, read_map)
#define GET_BYTE(taddr) _GET_MEM(taddr, 8)
#define GET_WORD(taddr) _GET_MEM(taddr, 16)
#define GET_LONG(taddr) _GET_MEM(taddr, 32)
#define IFETCH(taddr) __GET_MEM(taddr, 16, true, exec_map)
#define IFETCH_CHECK(taddr) mmu_check_addr (cpu, taddr, false, true, 2)
extern void bfin_syscall (SIM_CPU *);
extern bu32 interp_insn_bfin (SIM_CPU *, bu32);
extern bu32 hwloop_get_next_pc (SIM_CPU *, bu32, bu32);
/* Defines for Blackfin memory layouts. */
#define BFIN_ASYNC_BASE 0x20000000
#define BFIN_SYSTEM_MMR_BASE 0xFFC00000
#define BFIN_CORE_MMR_BASE 0xFFE00000
#define BFIN_L1_SRAM_SCRATCH 0xFFB00000
#define BFIN_L1_SRAM_SCRATCH_SIZE 0x1000
#define BFIN_L1_SRAM_SCRATCH_END (BFIN_L1_SRAM_SCRATCH + BFIN_L1_SRAM_SCRATCH_SIZE)
#define BFIN_L1_CACHE_BYTES 32
#endif

43
sim/bfin/bfroms/all.h Normal file
View File

@ -0,0 +1,43 @@
#include "bf50x-0.0.h"
#include "bf51x-0.0.h"
#include "bf51x-0.1.h"
#include "bf51x-0.2.h"
#include "bf526-0.0.h"
#include "bf526-0.1.h"
#include "bf527-0.0.h"
#include "bf527-0.1.h"
#include "bf527-0.2.h"
#include "bf533-0.1.h"
#include "bf533-0.2.h"
#include "bf533-0.3.h"
#define bfrom_bf533_0_4 bfrom_bf533_0_3
#define bfrom_bf533_0_5 bfrom_bf533_0_3
#define bfrom_bf533_0_6 bfrom_bf533_0_3
#include "bf537-0.0.h"
#include "bf537-0.1.h"
#define bfrom_bf537_0_2 bfrom_bf537_0_1
#include "bf537-0.3.h"
#include "bf538-0.0.h"
#define bfrom_bf538_0_1 bfrom_bf538_0_0
#define bfrom_bf538_0_2 bfrom_bf538_0_0
#define bfrom_bf538_0_3 bfrom_bf538_0_0
#define bfrom_bf538_0_4 bfrom_bf538_0_0
#define bfrom_bf538_0_5 bfrom_bf538_0_0
#include "bf54x-0.0.h"
#include "bf54x-0.1.h"
#include "bf54x-0.2.h"
#include "bf54x_l1-0.0.h"
#include "bf54x_l1-0.1.h"
#include "bf54x_l1-0.2.h"
#include "bf561-0.5.h"
#include "bf59x-0.0.h"
#define bfrom_bf59x_0_1 bfrom_bf59x_0_0
#include "bf59x_l1-0.1.h"

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf50x_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf51x_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf51x_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf51x_0_2[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf526_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf526_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf527_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf527_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf527_0_2[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf533_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf533_0_2[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf533_0_3[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf537_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf537_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf537_0_3[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf538_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf54x_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf54x_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf54x_0_2[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf54x_l1_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf54x_l1_0_1[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf54x_l1_0_2[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf561_0_5[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf59x_0_0[] = {
};

View File

@ -0,0 +1,3 @@
/* DO NOT EDIT: Autogenerated. */
static const char bfrom_bf59x_l1_0_1[] = {
};

176
sim/bfin/config.in Normal file
View File

@ -0,0 +1,176 @@
/* config.in. Generated from configure.ac by autoheader. */
/* Define to 1 if NLS is requested. */
#undef ENABLE_NLS
/* Define as 1 if you have catgets and don't want to use GNU gettext. */
#undef HAVE_CATGETS
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
#undef HAVE_GETTEXT
/* Define as 1 if you have the stpcpy function. */
#undef HAVE_STPCPY
/* Define if your locale.h file contains LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
/* 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 if dv-sockser is usable. */
#undef HAVE_DV_SOCKSER
/* 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 `getegid' function. */
#undef HAVE_GETEGID
/* Define to 1 if you have the `geteuid' function. */
#undef HAVE_GETEUID
/* Define to 1 if you have the `getgid' function. */
#undef HAVE_GETGID
/* Define to 1 if you have the `getrusage' function. */
#undef HAVE_GETRUSAGE
/* Define to 1 if you have the `getuid' function. */
#undef HAVE_GETUID
/* 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 <linux/if_tun.h> header file. */
#undef HAVE_LINUX_IF_TUN_H
/* Define to 1 if you have the <linux/mii.h> header file. */
#undef HAVE_LINUX_MII_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mmap' function. */
#undef HAVE_MMAP
/* Define to 1 if you have the `munmap' function. */
#undef HAVE_MUNMAP
/* Define to 1 if you have the <net/if.h> header file. */
#undef HAVE_NET_IF_H
/* Define to 1 if you have the `setgid' function. */
#undef HAVE_SETGID
/* Define to 1 if you have the `setuid' function. */
#undef HAVE_SETUID
/* 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/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_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 home page for this package. */
#undef PACKAGE_URL
/* 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

6779
sim/bfin/configure vendored Executable file

File diff suppressed because it is too large Load Diff

75
sim/bfin/configure.ac Normal file
View File

@ -0,0 +1,75 @@
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(LITTLE_ENDIAN)
SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
SIM_AC_OPTION_HOSTENDIAN
SIM_AC_OPTION_DEFAULT_MODEL(bf537)
SIM_AC_OPTION_ENVIRONMENT
SIM_AC_OPTION_INLINE
SIM_AC_OPTION_WARNINGS
SIM_AC_OPTION_HARDWARE(yes,,\
bfin_cec \
bfin_ctimer \
bfin_dma \
bfin_dmac \
bfin_ebiu_amc \
bfin_ebiu_ddrc \
bfin_ebiu_sdc \
bfin_emac \
bfin_eppi \
bfin_evt \
bfin_gptimer \
bfin_jtag \
bfin_mmu \
bfin_nfc \
bfin_otp \
bfin_pll \
bfin_ppi \
bfin_rtc \
bfin_sic \
bfin_spi \
bfin_trace \
bfin_twi \
bfin_uart \
bfin_uart2 \
bfin_wdog \
bfin_wp \
eth_phy \
)
AC_CHECK_FUNCS([getuid getgid geteuid getegid setuid setgid mmap munmap])
AC_CHECK_HEADERS([sys/ioctl.h sys/mman.h net/if.h linux/if_tun.h linux/mii.h])
BFIN_SIM_EXTRA_OBJS=
dnl make sure the dv-sockser code can be supported (i.e. windows)
case ${host} in
*mingw32*) ;;
*)
AC_DEFINE_UNQUOTED([HAVE_DV_SOCKSER], 1, [Define if dv-sockser is usable.])
BFIN_SIM_EXTRA_OBJS="${BFIN_SIM_EXTRA_OBJS} dv-sockser.o"
;;
esac
AC_SUBST([BFIN_SIM_EXTRA_OBJS], ${BFIN_SIM_EXTRA_OBJS})
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES(SDL, sdl, [
AC_CHECK_LIB(dl, dlopen, [
SDL_CFLAGS="${SDL_CFLAGS} -DHAVE_SDL"
SDL_LIBS="-ldl"
], [SDL_CFLAGS= SDL_LIBS=])
], [:])
AC_SUBST(SDL_CFLAGS)
AC_SUBST(SDL_LIBS)
SIM_AC_OUTPUT

163
sim/bfin/devices.c Normal file
View File

@ -0,0 +1,163 @@
/* Blackfin device support.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "sim-hw.h"
#include "hw-device.h"
#include "dv-bfin_cec.h"
#include "dv-bfin_mmu.h"
static void
bfin_mmr_invalid (struct hw *me, SIM_CPU *cpu, address_word addr,
unsigned nr_bytes, bool write)
{
if (!cpu)
cpu = hw_system_cpu (me);
/* Only throw a fit if the cpu is doing the access. DMA/GDB simply
go unnoticed. Not exactly hardware behavior, but close enough. */
if (!cpu)
{
sim_io_eprintf (hw_system (me), "%s: invalid MMR access @ %#x\n",
hw_path (me), addr);
return;
}
HW_TRACE ((me, "invalid MMR %s to 0x%08lx length %u",
write ? "write" : "read", (unsigned long) addr, nr_bytes));
/* XXX: is this what hardware does ? */
if (addr >= BFIN_CORE_MMR_BASE)
/* XXX: This should be setting up CPLB fault addrs ? */
mmu_process_fault (cpu, addr, write, false, false, true);
else
/* XXX: Newer parts set up an interrupt from EBIU and program
EBIU_ERRADDR with the address. */
cec_hwerr (cpu, HWERR_SYSTEM_MMR);
}
void
dv_bfin_mmr_invalid (struct hw *me, address_word addr, unsigned nr_bytes,
bool write)
{
bfin_mmr_invalid (me, NULL, addr, nr_bytes, write);
}
void
dv_bfin_mmr_require (struct hw *me, address_word addr, unsigned nr_bytes,
unsigned size, bool write)
{
if (nr_bytes != size)
dv_bfin_mmr_invalid (me, addr, nr_bytes, write);
}
static bool
bfin_mmr_check (struct hw *me, SIM_CPU *cpu, address_word addr,
unsigned nr_bytes, bool write)
{
if (addr >= BFIN_CORE_MMR_BASE)
{
/* All Core MMRs are aligned 32bits. */
if ((addr & 3) == 0 && nr_bytes == 4)
return true;
}
else if (addr >= BFIN_SYSTEM_MMR_BASE)
{
/* All System MMRs are 32bit aligned, but can be 16bits or 32bits. */
if ((addr & 0x3) == 0 && (nr_bytes == 2 || nr_bytes == 4))
return true;
}
else
return true;
/* Still here ? Must be crap. */
bfin_mmr_invalid (me, cpu, addr, nr_bytes, write);
return false;
}
bool
dv_bfin_mmr_check (struct hw *me, address_word addr, unsigned nr_bytes,
bool write)
{
return bfin_mmr_check (me, NULL, addr, nr_bytes, write);
}
int
device_io_read_buffer (device *me, void *source, int space,
address_word addr, unsigned nr_bytes,
SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
{
struct hw *dv_me = (struct hw *) me;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
return nr_bytes;
if (bfin_mmr_check (dv_me, cpu, addr, nr_bytes, false))
if (cpu)
{
sim_cpu_hw_io_read_buffer (cpu, cia, dv_me, source, space,
addr, nr_bytes);
return nr_bytes;
}
else
return sim_hw_io_read_buffer (sd, dv_me, source, space, addr, nr_bytes);
else
return 0;
}
int
device_io_write_buffer (device *me, const void *source, int space,
address_word addr, unsigned nr_bytes,
SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
{
struct hw *dv_me = (struct hw *) me;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
return nr_bytes;
if (bfin_mmr_check (dv_me, cpu, addr, nr_bytes, true))
if (cpu)
{
sim_cpu_hw_io_write_buffer (cpu, cia, dv_me, source, space,
addr, nr_bytes);
return nr_bytes;
}
else
return sim_hw_io_write_buffer (sd, dv_me, source, space, addr, nr_bytes);
else
return 0;
}
void device_error (device *me, const char *message, ...)
{
/* Don't bother doing anything here -- any place in common code that
calls device_error() follows it with sim_hw_abort(). Since the
device isn't bound to the system yet, we can't call any common
hardware error funcs on it or we'll hit a NULL pointer. */
}
unsigned int dv_get_bus_num (struct hw *me)
{
const hw_unit *unit = hw_unit_address (me);
return unit->cells[unit->nr_cells - 1];
}

156
sim/bfin/devices.h Normal file
View File

@ -0,0 +1,156 @@
/* Common Blackfin device stuff.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DEVICES_H
#define DEVICES_H
#include "hw-base.h"
#include "hw-main.h"
#include "hw-device.h"
#include "hw-tree.h"
/* We keep the same inital structure layout with DMA enabled devices. */
struct dv_bfin {
bu32 base;
struct hw *dma_master;
bool acked;
};
#define BFIN_MMR_16(mmr) mmr, __pad_##mmr
/* Most peripherals have either one interrupt or these three. */
#define DV_PORT_TX 0
#define DV_PORT_RX 1
#define DV_PORT_STAT 2
unsigned int dv_get_bus_num (struct hw *);
static inline bu8 dv_load_1 (const void *ptr)
{
const unsigned char *c = ptr;
return c[0];
}
static inline void dv_store_1 (void *ptr, bu8 val)
{
unsigned char *c = ptr;
c[0] = val;
}
static inline bu16 dv_load_2 (const void *ptr)
{
const unsigned char *c = ptr;
return (c[1] << 8) | dv_load_1 (ptr);
}
static inline void dv_store_2 (void *ptr, bu16 val)
{
unsigned char *c = ptr;
c[1] = val >> 8;
dv_store_1 (ptr, val);
}
static inline bu32 dv_load_4 (const void *ptr)
{
const unsigned char *c = ptr;
return (c[3] << 24) | (c[2] << 16) | dv_load_2 (ptr);
}
static inline void dv_store_4 (void *ptr, bu32 val)
{
unsigned char *c = ptr;
c[3] = val >> 24;
c[2] = val >> 16;
dv_store_2 (ptr, val);
}
/* Helpers for MMRs where all bits are W1C except for the specified
bits -- those ones are RO. */
#define dv_w1c(ptr, val, bits) (*(ptr) &= ~((val) & (bits)))
static inline void dv_w1c_2 (bu16 *ptr, bu16 val, bu16 bits)
{
dv_w1c (ptr, val, bits);
}
static inline void dv_w1c_4 (bu32 *ptr, bu32 val, bu32 bits)
{
dv_w1c (ptr, val, bits);
}
/* Helpers for MMRs where all bits are RW except for the specified
bits -- those ones are W1C. */
#define dv_w1c_partial(ptr, val, bits) \
(*(ptr) = ((val) | (*(ptr) & (bits))) & ~((val) & (bits)))
static inline void dv_w1c_2_partial (bu16 *ptr, bu16 val, bu16 bits)
{
dv_w1c_partial (ptr, val, bits);
}
static inline void dv_w1c_4_partial (bu32 *ptr, bu32 val, bu32 bits)
{
dv_w1c_partial (ptr, val, bits);
}
/* XXX: Grubbing around in device internals is probably wrong, but
until someone shows me what's right ... */
static inline struct hw *
dv_get_device (SIM_CPU *cpu, const char *device_name)
{
SIM_DESC sd = CPU_STATE (cpu);
void *root = STATE_HW (sd);
return hw_tree_find_device (root, device_name);
}
static inline void *
dv_get_state (SIM_CPU *cpu, const char *device_name)
{
return hw_data (dv_get_device (cpu, device_name));
}
#define DV_STATE(cpu, dv) dv_get_state (cpu, "/core/bfin_"#dv)
#define DV_STATE_CACHED(cpu, dv) \
({ \
struct bfin_##dv *__##dv = BFIN_CPU_STATE.dv##_cache; \
if (!__##dv) \
BFIN_CPU_STATE.dv##_cache = __##dv = dv_get_state (cpu, "/core/bfin_"#dv); \
__##dv; \
})
void dv_bfin_mmr_invalid (struct hw *, address_word, unsigned nr_bytes, bool write);
void dv_bfin_mmr_require (struct hw *, address_word, unsigned nr_bytes, unsigned size, bool write);
bool dv_bfin_mmr_check (struct hw *, address_word, unsigned nr_bytes, bool write);
#define dv_bfin_mmr_require_16(hw, addr, nr_bytes, write) dv_bfin_mmr_require (hw, addr, nr_bytes, 2, write)
#define dv_bfin_mmr_require_32(hw, addr, nr_bytes, write) dv_bfin_mmr_require (hw, addr, nr_bytes, 4, write)
#define HW_TRACE_WRITE() \
HW_TRACE ((me, "write 0x%08lx (%s) length %u with 0x%x", \
(unsigned long) addr, mmr_name (mmr_off), nr_bytes, value))
#define HW_TRACE_READ() \
HW_TRACE ((me, "read 0x%08lx (%s) length %u", \
(unsigned long) addr, mmr_name (mmr_off), nr_bytes))
#define HW_TRACE_DMA_WRITE() \
HW_TRACE ((me, "dma write 0x%08lx length %u", \
(unsigned long) addr, nr_bytes))
#define HW_TRACE_DMA_READ() \
HW_TRACE ((me, "dma read 0x%08lx length %u", \
(unsigned long) addr, nr_bytes))
#endif

807
sim/bfin/dv-bfin_cec.c Normal file
View File

@ -0,0 +1,807 @@
/* Blackfin Core Event Controller (CEC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_cec.h"
#include "dv-bfin_evt.h"
#include "dv-bfin_mmu.h"
struct bfin_cec
{
bu32 base;
SIM_CPU *cpu;
struct hw *me;
struct hw_event *pending;
/* Order after here is important -- matches hardware MMR layout. */
bu32 evt_override, imask, ipend, ilat, iprio;
};
#define mmr_base() offsetof(struct bfin_cec, evt_override)
#define mmr_offset(mmr) (offsetof(struct bfin_cec, mmr) - mmr_base())
static const char * const mmr_names[] = {
"EVT_OVERRIDE", "IMASK", "IPEND", "ILAT", "IPRIO",
};
#define mmr_name(off) mmr_names[(off) / 4]
static void _cec_raise (SIM_CPU *, struct bfin_cec *, int);
static void
bfin_cec_hw_event_callback (struct hw *me, void *data)
{
struct bfin_cec *cec = data;
hw_event_queue_deschedule (me, cec->pending);
_cec_raise (cec->cpu, cec, -1);
cec->pending = NULL;
}
static void
bfin_cec_check_pending (struct hw *me, struct bfin_cec *cec)
{
if (cec->pending)
return;
cec->pending = hw_event_queue_schedule (me, 0, bfin_cec_hw_event_callback, cec);
}
static void
_cec_check_pending (SIM_CPU *cpu, struct bfin_cec *cec)
{
bfin_cec_check_pending (cec->me, cec);
}
static void
_cec_imask_write (struct bfin_cec *cec, bu32 value)
{
cec->imask = (value & IVG_MASKABLE_B) | (cec->imask & IVG_UNMASKABLE_B);
}
static unsigned
bfin_cec_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_cec *cec = hw_data (me);
bu32 mmr_off;
bu32 value;
value = dv_load_4 (source);
mmr_off = addr - cec->base;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(evt_override):
cec->evt_override = value;
break;
case mmr_offset(imask):
_cec_imask_write (cec, value);
bfin_cec_check_pending (me, cec);
break;
case mmr_offset(ipend):
/* Read-only register. */
break;
case mmr_offset(ilat):
dv_w1c_4 (&cec->ilat, value, 0);
break;
case mmr_offset(iprio):
cec->iprio = (value & IVG_UNMASKABLE_B);
break;
}
return nr_bytes;
}
static unsigned
bfin_cec_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_cec *cec = hw_data (me);
bu32 mmr_off;
bu32 *valuep;
mmr_off = addr - cec->base;
valuep = (void *)((unsigned long)cec + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_store_4 (dest, *valuep);
return nr_bytes;
}
static const struct hw_port_descriptor bfin_cec_ports[] = {
{ "emu", IVG_EMU, 0, input_port, },
{ "rst", IVG_RST, 0, input_port, },
{ "nmi", IVG_NMI, 0, input_port, },
{ "evx", IVG_EVX, 0, input_port, },
{ "ivhw", IVG_IVHW, 0, input_port, },
{ "ivtmr", IVG_IVTMR, 0, input_port, },
{ "ivg7", IVG7, 0, input_port, },
{ "ivg8", IVG8, 0, input_port, },
{ "ivg9", IVG9, 0, input_port, },
{ "ivg10", IVG10, 0, input_port, },
{ "ivg11", IVG11, 0, input_port, },
{ "ivg12", IVG12, 0, input_port, },
{ "ivg13", IVG13, 0, input_port, },
{ "ivg14", IVG14, 0, input_port, },
{ "ivg15", IVG15, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static void
bfin_cec_port_event (struct hw *me, int my_port, struct hw *source,
int source_port, int level)
{
struct bfin_cec *cec = hw_data (me);
_cec_raise (cec->cpu, cec, my_port);
}
static void
attach_bfin_cec_regs (struct hw *me, struct bfin_cec *cec)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_CEC_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_CEC_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
cec->base = attach_address;
/* XXX: should take from the device tree. */
cec->cpu = STATE_CPU (hw_system (me), 0);
cec->me = me;
}
static void
bfin_cec_finish (struct hw *me)
{
struct bfin_cec *cec;
cec = HW_ZALLOC (me, struct bfin_cec);
set_hw_data (me, cec);
set_hw_io_read_buffer (me, bfin_cec_io_read_buffer);
set_hw_io_write_buffer (me, bfin_cec_io_write_buffer);
set_hw_ports (me, bfin_cec_ports);
set_hw_port_event (me, bfin_cec_port_event);
attach_bfin_cec_regs (me, cec);
/* Initialize the CEC. */
cec->imask = IVG_UNMASKABLE_B;
cec->ipend = IVG_RST_B | IVG_IRPTEN_B;
}
const struct hw_descriptor dv_bfin_cec_descriptor[] = {
{"bfin_cec", bfin_cec_finish,},
{NULL, NULL},
};
static const char * const excp_decoded[] = {
[VEC_SYS ] = "Custom exception 0 (system call)",
[VEC_EXCPT01 ] = "Custom exception 1 (software breakpoint)",
[VEC_EXCPT02 ] = "Custom exception 2 (KGDB hook)",
[VEC_EXCPT03 ] = "Custom exception 3 (userspace stack overflow)",
[VEC_EXCPT04 ] = "Custom exception 4 (dump trace buffer)",
[VEC_EXCPT05 ] = "Custom exception 5",
[VEC_EXCPT06 ] = "Custom exception 6",
[VEC_EXCPT07 ] = "Custom exception 7",
[VEC_EXCPT08 ] = "Custom exception 8",
[VEC_EXCPT09 ] = "Custom exception 9",
[VEC_EXCPT10 ] = "Custom exception 10",
[VEC_EXCPT11 ] = "Custom exception 11",
[VEC_EXCPT12 ] = "Custom exception 12",
[VEC_EXCPT13 ] = "Custom exception 13",
[VEC_EXCPT14 ] = "Custom exception 14",
[VEC_EXCPT15 ] = "Custom exception 15",
[VEC_STEP ] = "Hardware single step",
[VEC_OVFLOW ] = "Trace buffer overflow",
[VEC_UNDEF_I ] = "Undefined instruction",
[VEC_ILGAL_I ] = "Illegal instruction combo (multi-issue)",
[VEC_CPLB_VL ] = "DCPLB protection violation",
[VEC_MISALI_D ] = "Unaligned data access",
[VEC_UNCOV ] = "Unrecoverable event (double fault)",
[VEC_CPLB_M ] = "DCPLB miss",
[VEC_CPLB_MHIT ] = "Multiple DCPLB hit",
[VEC_WATCH ] = "Watchpoint match",
[VEC_ISTRU_VL ] = "ADSP-BF535 only",
[VEC_MISALI_I ] = "Unaligned instruction access",
[VEC_CPLB_I_VL ] = "ICPLB protection violation",
[VEC_CPLB_I_M ] = "ICPLB miss",
[VEC_CPLB_I_MHIT] = "Multiple ICPLB hit",
[VEC_ILL_RES ] = "Illegal supervisor resource",
};
#define CEC_STATE(cpu) DV_STATE_CACHED (cpu, cec)
#define __cec_get_ivg(val) (ffs ((val) & ~IVG_IRPTEN_B) - 1)
#define _cec_get_ivg(cec) __cec_get_ivg ((cec)->ipend & ~IVG_EMU_B)
int
cec_get_ivg (SIM_CPU *cpu)
{
switch (STATE_ENVIRONMENT (CPU_STATE (cpu)))
{
case OPERATING_ENVIRONMENT:
return _cec_get_ivg (CEC_STATE (cpu));
default:
return IVG_USER;
}
}
static bool
_cec_is_supervisor_mode (struct bfin_cec *cec)
{
return (cec->ipend & ~(IVG_EMU_B | IVG_IRPTEN_B));
}
bool
cec_is_supervisor_mode (SIM_CPU *cpu)
{
switch (STATE_ENVIRONMENT (CPU_STATE (cpu)))
{
case OPERATING_ENVIRONMENT:
return _cec_is_supervisor_mode (CEC_STATE (cpu));
case USER_ENVIRONMENT:
return false;
default:
return true;
}
}
static bool
_cec_is_user_mode (struct bfin_cec *cec)
{
return !_cec_is_supervisor_mode (cec);
}
bool
cec_is_user_mode (SIM_CPU *cpu)
{
return !cec_is_supervisor_mode (cpu);
}
static void
_cec_require_supervisor (SIM_CPU *cpu, struct bfin_cec *cec)
{
if (_cec_is_user_mode (cec))
cec_exception (cpu, VEC_ILL_RES);
}
void
cec_require_supervisor (SIM_CPU *cpu)
{
/* Do not call _cec_require_supervisor() to avoid CEC_STATE()
as that macro requires OS operating mode. */
if (cec_is_user_mode (cpu))
cec_exception (cpu, VEC_ILL_RES);
}
#define excp_to_sim_halt(reason, sigrc) \
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, PCREG, reason, sigrc)
void
cec_exception (SIM_CPU *cpu, int excp)
{
SIM_DESC sd = CPU_STATE (cpu);
int sigrc = -1;
TRACE_EVENTS (cpu, "processing exception %#x in EVT%i", excp,
cec_get_ivg (cpu));
/* Ideally what would happen here for real hardware exceptions (not
fake sim ones) is that:
- For service exceptions (excp <= 0x11):
RETX is the _next_ PC which can be tricky with jumps/hardware loops/...
- For error exceptions (excp > 0x11):
RETX is the _current_ PC (i.e. the one causing the exception)
- PC is loaded with EVT3 MMR
- ILAT/IPEND in CEC is updated depending on current IVG level
- the fault address MMRs get updated with data/instruction info
- Execution continues on in the EVT3 handler */
/* Handle simulator exceptions first. */
switch (excp)
{
case VEC_SIM_HLT:
excp_to_sim_halt (sim_exited, 0);
return;
case VEC_SIM_ABORT:
excp_to_sim_halt (sim_exited, 1);
return;
case VEC_SIM_TRAP:
/* GDB expects us to step over EMUEXCPT. */
/* XXX: What about hwloops and EMUEXCPT at the end?
Pretty sure gdb doesn't handle this already... */
SET_PCREG (PCREG + 2);
/* Only trap when we are running in gdb. */
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
excp_to_sim_halt (sim_stopped, SIM_SIGTRAP);
return;
case VEC_SIM_DBGA:
/* If running in gdb, simply trap. */
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
excp_to_sim_halt (sim_stopped, SIM_SIGTRAP);
else
excp_to_sim_halt (sim_exited, 2);
}
if (excp <= 0x3f)
{
SET_EXCAUSE (excp);
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
{
/* ICPLB regs always get updated. */
/* XXX: Should optimize this call path ... */
if (excp != VEC_MISALI_I && excp != VEC_MISALI_D
&& excp != VEC_CPLB_I_M && excp != VEC_CPLB_M
&& excp != VEC_CPLB_I_VL && excp != VEC_CPLB_VL
&& excp != VEC_CPLB_I_MHIT && excp != VEC_CPLB_MHIT)
mmu_log_ifault (cpu);
_cec_raise (cpu, CEC_STATE (cpu), IVG_EVX);
/* We need to restart the engine so that we don't return
and continue processing this bad insn. */
if (EXCAUSE >= 0x20)
sim_engine_restart (sd, cpu, NULL, PCREG);
return;
}
}
TRACE_EVENTS (cpu, "running virtual exception handler");
switch (excp)
{
case VEC_SYS:
bfin_syscall (cpu);
break;
case VEC_EXCPT01: /* Userspace gdb breakpoint. */
sigrc = SIM_SIGTRAP;
break;
case VEC_UNDEF_I: /* Undefined instruction. */
sigrc = SIM_SIGILL;
break;
case VEC_ILL_RES: /* Illegal supervisor resource. */
case VEC_MISALI_I: /* Misaligned instruction. */
sigrc = SIM_SIGBUS;
break;
case VEC_CPLB_M:
case VEC_CPLB_I_M:
sigrc = SIM_SIGSEGV;
break;
default:
sim_io_eprintf (sd, "Unhandled exception %#x at 0x%08x (%s)\n",
excp, PCREG, excp_decoded[excp]);
sigrc = SIM_SIGILL;
break;
}
if (sigrc != -1)
excp_to_sim_halt (sim_stopped, sigrc);
}
bu32 cec_cli (SIM_CPU *cpu)
{
struct bfin_cec *cec;
bu32 old_mask;
if (STATE_ENVIRONMENT (CPU_STATE (cpu)) != OPERATING_ENVIRONMENT)
return 0;
cec = CEC_STATE (cpu);
_cec_require_supervisor (cpu, cec);
/* XXX: what about IPEND[4] ? */
old_mask = cec->imask;
_cec_imask_write (cec, 0);
TRACE_EVENTS (cpu, "CLI changed IMASK from %#x to %#x", old_mask, cec->imask);
return old_mask;
}
void cec_sti (SIM_CPU *cpu, bu32 ints)
{
struct bfin_cec *cec;
bu32 old_mask;
if (STATE_ENVIRONMENT (CPU_STATE (cpu)) != OPERATING_ENVIRONMENT)
return;
cec = CEC_STATE (cpu);
_cec_require_supervisor (cpu, cec);
/* XXX: what about IPEND[4] ? */
old_mask = cec->imask;
_cec_imask_write (cec, ints);
TRACE_EVENTS (cpu, "STI changed IMASK from %#x to %#x", old_mask, cec->imask);
/* Check for pending interrupts that are now enabled. */
_cec_check_pending (cpu, cec);
}
static void
cec_irpten_enable (SIM_CPU *cpu, struct bfin_cec *cec)
{
/* Globally mask interrupts. */
TRACE_EVENTS (cpu, "setting IPEND[4] to globally mask interrupts");
cec->ipend |= IVG_IRPTEN_B;
}
static void
cec_irpten_disable (SIM_CPU *cpu, struct bfin_cec *cec)
{
/* Clear global interrupt mask. */
TRACE_EVENTS (cpu, "clearing IPEND[4] to not globally mask interrupts");
cec->ipend &= ~IVG_IRPTEN_B;
}
static void
_cec_raise (SIM_CPU *cpu, struct bfin_cec *cec, int ivg)
{
SIM_DESC sd = CPU_STATE (cpu);
int curr_ivg = _cec_get_ivg (cec);
bool snen;
bool irpten;
TRACE_EVENTS (cpu, "processing request for EVT%i while at EVT%i",
ivg, curr_ivg);
irpten = (cec->ipend & IVG_IRPTEN_B);
snen = (SYSCFGREG & SYSCFG_SNEN);
if (curr_ivg == -1)
curr_ivg = IVG_USER;
/* Just check for higher latched interrupts. */
if (ivg == -1)
{
if (irpten)
goto done; /* All interrupts are masked anyways. */
ivg = __cec_get_ivg (cec->ilat & cec->imask);
if (ivg < 0)
goto done; /* Nothing latched. */
if (ivg > curr_ivg)
goto done; /* Nothing higher latched. */
if (!snen && ivg == curr_ivg)
goto done; /* Self nesting disabled. */
/* Still here, so fall through to raise to higher pending. */
}
cec->ilat |= (1 << ivg);
if (ivg <= IVG_EVX)
{
/* These two are always processed. */
if (ivg == IVG_EMU || ivg == IVG_RST)
goto process_int;
/* Anything lower might trigger a double fault. */
if (curr_ivg <= ivg)
{
/* Double fault ! :( */
SET_EXCAUSE (VEC_UNCOV);
/* XXX: SET_RETXREG (...); */
sim_io_error (sd, "%s: double fault at 0x%08x ! :(", __func__, PCREG);
excp_to_sim_halt (sim_stopped, SIM_SIGABRT);
}
/* No double fault -> always process. */
goto process_int;
}
else if (irpten && curr_ivg != IVG_USER)
{
/* Interrupts are globally masked. */
}
else if (!(cec->imask & (1 << ivg)))
{
/* This interrupt is masked. */
}
else if (ivg < curr_ivg || (snen && ivg == curr_ivg))
{
/* Do transition! */
bu32 oldpc;
process_int:
cec->ipend |= (1 << ivg);
cec->ilat &= ~(1 << ivg);
/* Interrupts are processed in between insns which means the return
point is the insn-to-be-executed (which is the current PC). But
exceptions are handled while executing an insn, so we may have to
advance the PC ourselves when setting RETX.
XXX: Advancing the PC should only be for "service" exceptions, and
handling them after executing the insn should be OK, which
means we might be able to use the event interface for it. */
oldpc = PCREG;
switch (ivg)
{
case IVG_EMU:
/* Signal the JTAG ICE. */
/* XXX: what happens with 'raise 0' ? */
SET_RETEREG (oldpc);
excp_to_sim_halt (sim_stopped, SIM_SIGTRAP);
/* XXX: Need an easy way for gdb to signal it isnt here. */
cec->ipend &= ~IVG_EMU_B;
break;
case IVG_RST:
/* Have the core reset simply exit (i.e. "shutdown"). */
excp_to_sim_halt (sim_exited, 0);
break;
case IVG_NMI:
/* XXX: Should check this. */
SET_RETNREG (oldpc);
break;
case IVG_EVX:
/* Non-service exceptions point to the excepting instruction. */
if (EXCAUSE >= 0x20)
SET_RETXREG (oldpc);
else
{
bu32 nextpc = hwloop_get_next_pc (cpu, oldpc, INSN_LEN);
SET_RETXREG (nextpc);
}
break;
case IVG_IRPTEN:
/* XXX: what happens with 'raise 4' ? */
sim_io_error (sd, "%s: what to do with 'raise 4' ?", __func__);
break;
default:
SET_RETIREG (oldpc | (ivg == curr_ivg ? 1 : 0));
break;
}
/* If EVT_OVERRIDE is in effect (IVG7+), use the reset address. */
if ((cec->evt_override & 0xff80) & (1 << ivg))
SET_PCREG (cec_get_reset_evt (cpu));
else
SET_PCREG (cec_get_evt (cpu, ivg));
TRACE_BRANCH (cpu, oldpc, PCREG, -1, "CEC changed PC (to EVT%i):", ivg);
BFIN_CPU_STATE.did_jump = true;
/* Enable the global interrupt mask upon interrupt entry. */
if (ivg >= IVG_IVHW)
cec_irpten_enable (cpu, cec);
}
/* When moving between states, don't let internal states bleed through. */
DIS_ALGN_EXPT &= ~1;
/* When going from user to super, we set LSB in LB regs to avoid
misbehavior and/or malicious code.
Also need to load SP alias with KSP. */
if (curr_ivg == IVG_USER)
{
int i;
for (i = 0; i < 2; ++i)
if (!(LBREG (i) & 1))
SET_LBREG (i, LBREG (i) | 1);
SET_USPREG (SPREG);
SET_SPREG (KSPREG);
}
done:
TRACE_EVENTS (cpu, "now at EVT%i", _cec_get_ivg (cec));
}
static bu32
cec_read_ret_reg (SIM_CPU *cpu, int ivg)
{
switch (ivg)
{
case IVG_EMU: return RETEREG;
case IVG_NMI: return RETNREG;
case IVG_EVX: return RETXREG;
default: return RETIREG;
}
}
void
cec_latch (SIM_CPU *cpu, int ivg)
{
struct bfin_cec *cec;
if (STATE_ENVIRONMENT (CPU_STATE (cpu)) != OPERATING_ENVIRONMENT)
{
bu32 oldpc = PCREG;
SET_PCREG (cec_read_ret_reg (cpu, ivg));
TRACE_BRANCH (cpu, oldpc, PCREG, -1, "CEC changed PC");
return;
}
cec = CEC_STATE (cpu);
cec->ilat |= (1 << ivg);
_cec_check_pending (cpu, cec);
}
void
cec_hwerr (SIM_CPU *cpu, int hwerr)
{
SET_HWERRCAUSE (hwerr);
cec_latch (cpu, IVG_IVHW);
}
void
cec_return (SIM_CPU *cpu, int ivg)
{
SIM_DESC sd = CPU_STATE (cpu);
struct bfin_cec *cec;
bool snen;
int curr_ivg;
bu32 oldpc, newpc;
oldpc = PCREG;
BFIN_CPU_STATE.did_jump = true;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
{
SET_PCREG (cec_read_ret_reg (cpu, ivg));
TRACE_BRANCH (cpu, oldpc, PCREG, -1, "CEC changed PC");
return;
}
cec = CEC_STATE (cpu);
/* XXX: This isn't entirely correct ... */
cec->ipend &= ~IVG_EMU_B;
curr_ivg = _cec_get_ivg (cec);
if (curr_ivg == -1)
curr_ivg = IVG_USER;
if (ivg == -1)
ivg = curr_ivg;
TRACE_EVENTS (cpu, "returning from EVT%i (should be EVT%i)", curr_ivg, ivg);
/* Not allowed to return from usermode. */
if (curr_ivg == IVG_USER)
cec_exception (cpu, VEC_ILL_RES);
if (ivg > IVG15 || ivg < 0)
sim_io_error (sd, "%s: ivg %i out of range !", __func__, ivg);
_cec_require_supervisor (cpu, cec);
switch (ivg)
{
case IVG_EMU:
/* RTE -- only valid in emulation mode. */
/* XXX: What does the hardware do ? */
if (curr_ivg != IVG_EMU)
cec_exception (cpu, VEC_ILL_RES);
break;
case IVG_NMI:
/* RTN -- only valid in NMI. */
/* XXX: What does the hardware do ? */
if (curr_ivg != IVG_NMI)
cec_exception (cpu, VEC_ILL_RES);
break;
case IVG_EVX:
/* RTX -- only valid in exception. */
/* XXX: What does the hardware do ? */
if (curr_ivg != IVG_EVX)
cec_exception (cpu, VEC_ILL_RES);
break;
default:
/* RTI -- not valid in emulation, nmi, exception, or user. */
/* XXX: What does the hardware do ? */
if (curr_ivg == IVG_EMU || curr_ivg == IVG_NMI
|| curr_ivg == IVG_EVX || curr_ivg == IVG_USER)
cec_exception (cpu, VEC_ILL_RES);
break;
case IVG_IRPTEN:
/* XXX: Is this even possible ? */
excp_to_sim_halt (sim_stopped, SIM_SIGABRT);
break;
}
newpc = cec_read_ret_reg (cpu, ivg);
/* XXX: Does this nested trick work on EMU/NMI/EVX ? */
snen = (newpc & 1);
/* XXX: Delayed clear shows bad PCREG register trace above ? */
SET_PCREG (newpc & ~1);
TRACE_BRANCH (cpu, oldpc, PCREG, -1, "CEC changed PC (from EVT%i)", ivg);
/* Update ipend after the TRACE_BRANCH so dv-bfin_trace
knows current CEC state wrt overflow. */
if (!snen)
cec->ipend &= ~(1 << ivg);
/* Disable global interrupt mask to let any interrupt take over, but
only when we were already in a RTI level. Only way we could have
raised at that point is if it was cleared in the first place. */
if (ivg >= IVG_IVHW || ivg == IVG_RST)
cec_irpten_disable (cpu, cec);
/* When going from super to user, we clear LSB in LB regs in case
it was set on the transition up.
Also need to load SP alias with USP. */
if (_cec_get_ivg (cec) == -1)
{
int i;
for (i = 0; i < 2; ++i)
if (LBREG (i) & 1)
SET_LBREG (i, LBREG (i) & ~1);
SET_KSPREG (SPREG);
SET_SPREG (USPREG);
}
/* Check for pending interrupts before we return to usermode. */
_cec_check_pending (cpu, cec);
}
void
cec_push_reti (SIM_CPU *cpu)
{
/* XXX: Need to check hardware with popped RETI value
and bit 1 is set (when handling nested interrupts).
Also need to check behavior wrt SNEN in SYSCFG. */
struct bfin_cec *cec;
if (STATE_ENVIRONMENT (CPU_STATE (cpu)) != OPERATING_ENVIRONMENT)
return;
TRACE_EVENTS (cpu, "pushing RETI");
cec = CEC_STATE (cpu);
cec_irpten_disable (cpu, cec);
/* Check for pending interrupts. */
_cec_check_pending (cpu, cec);
}
void
cec_pop_reti (SIM_CPU *cpu)
{
/* XXX: Need to check hardware with popped RETI value
and bit 1 is set (when handling nested interrupts).
Also need to check behavior wrt SNEN in SYSCFG. */
struct bfin_cec *cec;
if (STATE_ENVIRONMENT (CPU_STATE (cpu)) != OPERATING_ENVIRONMENT)
return;
TRACE_EVENTS (cpu, "popping RETI");
cec = CEC_STATE (cpu);
cec_irpten_enable (cpu, cec);
}

139
sim/bfin/dv-bfin_cec.h Normal file
View File

@ -0,0 +1,139 @@
/* Blackfin Core Event Controller (CEC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_CEC_H
#define DV_BFIN_CEC_H
#include "sim-main.h"
#define BFIN_COREMMR_CEC_BASE 0xFFE02100
#define BFIN_COREMMR_CEC_SIZE (4 * 5)
/* 0xFFE02100 ... 0xFFE02110 */
#define BFIN_COREMMR_EVT_OVERRIDE (BFIN_COREMMR_CEC_BASE + (4 * 0))
#define BFIN_COREMMR_IMASK (BFIN_COREMMR_CEC_BASE + (4 * 1))
#define BFIN_COREMMR_IPEND (BFIN_COREMMR_CEC_BASE + (4 * 2))
#define BFIN_COREMMR_ILAT (BFIN_COREMMR_CEC_BASE + (4 * 3))
#define BFIN_COREMMR_IPRIO (BFIN_COREMMR_CEC_BASE + (4 * 4))
#define IVG_EMU 0
#define IVG_RST 1
#define IVG_NMI 2
#define IVG_EVX 3
#define IVG_IRPTEN 4 /* Global is Reserved */
#define IVG_IVHW 5
#define IVG_IVTMR 6
#define IVG7 7
#define IVG8 8
#define IVG9 9
#define IVG10 10
#define IVG11 11
#define IVG12 12
#define IVG13 13
#define IVG14 14
#define IVG15 15
#define IVG_USER 16 /* Not real; for internal use */
#define IVG_EMU_B (1 << IVG_EMU)
#define IVG_RST_B (1 << IVG_RST)
#define IVG_NMI_B (1 << IVG_NMI)
#define IVG_EVX_B (1 << IVG_EVX)
#define IVG_IRPTEN_B (1 << IVG_IRPTEN)
#define IVG_IVHW_B (1 << IVG_IVHW)
#define IVG_IVTMR_B (1 << IVG_IVTMR)
#define IVG7_B (1 << IVG7)
#define IVG8_B (1 << IVG8)
#define IVG9_B (1 << IVG9)
#define IVG10_B (1 << IVG10)
#define IVG11_B (1 << IVG11)
#define IVG12_B (1 << IVG12)
#define IVG13_B (1 << IVG13)
#define IVG14_B (1 << IVG14)
#define IVG15_B (1 << IVG15)
#define IVG_UNMASKABLE_B \
(IVG_EMU_B | IVG_RST_B | IVG_NMI_B | IVG_EVX_B | IVG_IRPTEN_B)
#define IVG_MASKABLE_B \
(IVG_IVHW_B | IVG_IVTMR_B | IVG7_B | IVG8_B | IVG9_B | \
IVG10_B | IVG11_B | IVG12_B | IVG13_B | IVG14_B | IVG15_B)
#define VEC_SYS 0x0
#define VEC_EXCPT01 0x1
#define VEC_EXCPT02 0x2
#define VEC_EXCPT03 0x3
#define VEC_EXCPT04 0x4
#define VEC_EXCPT05 0x5
#define VEC_EXCPT06 0x6
#define VEC_EXCPT07 0x7
#define VEC_EXCPT08 0x8
#define VEC_EXCPT09 0x9
#define VEC_EXCPT10 0xa
#define VEC_EXCPT11 0xb
#define VEC_EXCPT12 0xc
#define VEC_EXCPT13 0xd
#define VEC_EXCPT14 0xe
#define VEC_EXCPT15 0xf
#define VEC_STEP 0x10 /* single step */
#define VEC_OVFLOW 0x11 /* trace buffer overflow */
#define VEC_UNDEF_I 0x21 /* undefined instruction */
#define VEC_ILGAL_I 0x22 /* illegal instruction combo (multi-issue) */
#define VEC_CPLB_VL 0x23 /* DCPLB protection violation */
#define VEC_MISALI_D 0x24 /* unaligned data access */
#define VEC_UNCOV 0x25 /* unrecoverable event (double fault) */
#define VEC_CPLB_M 0x26 /* DCPLB miss */
#define VEC_CPLB_MHIT 0x27 /* multiple DCPLB hit */
#define VEC_WATCH 0x28 /* watchpoint match */
#define VEC_ISTRU_VL 0x29 /* ADSP-BF535 only */
#define VEC_MISALI_I 0x2a /* unaligned instruction access */
#define VEC_CPLB_I_VL 0x2b /* ICPLB protection violation */
#define VEC_CPLB_I_M 0x2c /* ICPLB miss */
#define VEC_CPLB_I_MHIT 0x2d /* multiple ICPLB hit */
#define VEC_ILL_RES 0x2e /* illegal supervisor resource */
/*
* The hardware reserves 63+ for future use - we use it to tell our
* normal exception handling code we have a hardware error
*/
#define VEC_HWERR 63
#define VEC_SIM_BASE 64
#define VEC_SIM_HLT (VEC_SIM_BASE + 1)
#define VEC_SIM_ABORT (VEC_SIM_BASE + 2)
#define VEC_SIM_TRAP (VEC_SIM_BASE + 3)
#define VEC_SIM_DBGA (VEC_SIM_BASE + 4)
extern void cec_exception (SIM_CPU *, int vec_excp);
#define HWERR_SYSTEM_MMR 0x02
#define HWERR_EXTERN_ADDR 0x03
#define HWERR_PERF_FLOW 0x12
#define HWERR_RAISE_5 0x18
extern void cec_hwerr (SIM_CPU *, int hwerr);
extern void cec_latch (SIM_CPU *, int ivg);
extern void cec_return (SIM_CPU *, int ivg);
extern int cec_get_ivg (SIM_CPU *);
extern bool cec_is_supervisor_mode (SIM_CPU *);
extern bool cec_is_user_mode (SIM_CPU *);
extern void cec_require_supervisor (SIM_CPU *);
extern bu32 cec_cli (SIM_CPU *);
extern void cec_sti (SIM_CPU *, bu32 ints);
extern void cec_push_reti (SIM_CPU *);
extern void cec_pop_reti (SIM_CPU *);
#endif

267
sim/bfin/dv-bfin_ctimer.c Normal file
View File

@ -0,0 +1,267 @@
/* Blackfin Core Timer model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_cec.h"
#include "dv-bfin_ctimer.h"
struct bfin_ctimer
{
bu32 base;
struct hw_event *handler;
signed64 timeout;
/* Order after here is important -- matches hardware MMR layout. */
bu32 tcntl, tperiod, tscale, tcount;
};
#define mmr_base() offsetof(struct bfin_ctimer, tcntl)
#define mmr_offset(mmr) (offsetof(struct bfin_ctimer, mmr) - mmr_base())
static const char * const mmr_names[] = {
"TCNTL", "TPERIOD", "TSCALE", "TCOUNT",
};
#define mmr_name(off) mmr_names[(off) / 4]
static bool
bfin_ctimer_enabled (struct bfin_ctimer *ctimer)
{
return (ctimer->tcntl & TMPWR) && (ctimer->tcntl & TMREN);
}
static bu32
bfin_ctimer_scale (struct bfin_ctimer *ctimer)
{
/* Only low 8 bits are actually checked. */
return (ctimer->tscale & 0xff) + 1;
}
static void
bfin_ctimer_schedule (struct hw *me, struct bfin_ctimer *ctimer);
static void
bfin_ctimer_expire (struct hw *me, void *data)
{
struct bfin_ctimer *ctimer = data;
ctimer->tcntl |= TINT;
if (ctimer->tcntl & TAUTORLD)
{
ctimer->tcount = ctimer->tperiod;
bfin_ctimer_schedule (me, ctimer);
}
else
{
ctimer->tcount = 0;
ctimer->handler = NULL;
}
hw_port_event (me, IVG_IVTMR, 1);
}
static void
bfin_ctimer_update_count (struct hw *me, struct bfin_ctimer *ctimer)
{
bu32 scale, ticks;
signed64 timeout;
/* If the timer was enabled w/out autoreload and has expired, then
there's nothing to calculate here. */
if (ctimer->handler == NULL)
return;
scale = bfin_ctimer_scale (ctimer);
timeout = hw_event_remain_time (me, ctimer->handler);
ticks = ctimer->timeout - timeout;
ctimer->tcount -= (scale * ticks);
ctimer->timeout = timeout;
}
static void
bfin_ctimer_deschedule (struct hw *me, struct bfin_ctimer *ctimer)
{
if (ctimer->handler)
{
hw_event_queue_deschedule (me, ctimer->handler);
ctimer->handler = NULL;
}
}
static void
bfin_ctimer_schedule (struct hw *me, struct bfin_ctimer *ctimer)
{
bu32 scale = bfin_ctimer_scale (ctimer);
ctimer->timeout = (ctimer->tcount / scale) + !!(ctimer->tcount % scale);
ctimer->handler = hw_event_queue_schedule (me, ctimer->timeout,
bfin_ctimer_expire,
ctimer);
}
static unsigned
bfin_ctimer_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_ctimer *ctimer = hw_data (me);
bool curr_enabled;
bu32 mmr_off;
bu32 value;
bu32 *valuep;
value = dv_load_4 (source);
mmr_off = addr - ctimer->base;
valuep = (void *)((unsigned long)ctimer + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
curr_enabled = bfin_ctimer_enabled (ctimer);
switch (mmr_off)
{
case mmr_offset(tcntl):
/* HRM describes TINT as sticky, but it isn't W1C. */
*valuep = value;
if (bfin_ctimer_enabled (ctimer) == curr_enabled)
{
/* Do nothing. */
}
else if (curr_enabled)
{
bfin_ctimer_update_count (me, ctimer);
bfin_ctimer_deschedule (me, ctimer);
}
else
bfin_ctimer_schedule (me, ctimer);
break;
case mmr_offset(tcount):
/* HRM says writes are discarded when enabled. */
/* XXX: But hardware seems to be writeable all the time ? */
/* if (!curr_enabled) */
*valuep = value;
break;
case mmr_offset(tperiod):
/* HRM says writes are discarded when enabled. */
/* XXX: But hardware seems to be writeable all the time ? */
/* if (!curr_enabled) */
{
/* Writes are mirrored into TCOUNT. */
ctimer->tcount = value;
*valuep = value;
}
break;
case mmr_offset(tscale):
if (curr_enabled)
{
bfin_ctimer_update_count (me, ctimer);
bfin_ctimer_deschedule (me, ctimer);
}
*valuep = value;
if (curr_enabled)
bfin_ctimer_schedule (me, ctimer);
break;
}
return nr_bytes;
}
static unsigned
bfin_ctimer_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_ctimer *ctimer = hw_data (me);
bu32 mmr_off;
bu32 *valuep;
mmr_off = addr - ctimer->base;
valuep = (void *)((unsigned long)ctimer + mmr_base() + mmr_off);
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(tcount):
/* Since we're optimizing events here, we need to calculate
the new tcount value. */
if (bfin_ctimer_enabled (ctimer))
bfin_ctimer_update_count (me, ctimer);
break;
}
dv_store_4 (dest, *valuep);
return nr_bytes;
}
static const struct hw_port_descriptor bfin_ctimer_ports[] = {
{ "ivtmr", IVG_IVTMR, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_ctimer_regs (struct hw *me, struct bfin_ctimer *ctimer)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_CTIMER_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_CTIMER_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
ctimer->base = attach_address;
}
static void
bfin_ctimer_finish (struct hw *me)
{
struct bfin_ctimer *ctimer;
ctimer = HW_ZALLOC (me, struct bfin_ctimer);
set_hw_data (me, ctimer);
set_hw_io_read_buffer (me, bfin_ctimer_io_read_buffer);
set_hw_io_write_buffer (me, bfin_ctimer_io_write_buffer);
set_hw_ports (me, bfin_ctimer_ports);
attach_bfin_ctimer_regs (me, ctimer);
/* Initialize the Core Timer. */
}
const struct hw_descriptor dv_bfin_ctimer_descriptor[] = {
{"bfin_ctimer", bfin_ctimer_finish,},
{NULL, NULL},
};

33
sim/bfin/dv-bfin_ctimer.h Normal file
View File

@ -0,0 +1,33 @@
/* Blackfin Core Timer model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_CTIMER_H
#define DV_BFIN_CTIMER_H
#define BFIN_COREMMR_CTIMER_BASE 0xFFE03000
#define BFIN_COREMMR_CTIMER_SIZE (4 * 4)
/* TCNTL Masks */
#define TMPWR (1 << 0)
#define TMREN (1 << 1)
#define TAUTORLD (1 << 2)
#define TINT (1 << 3)
#endif

553
sim/bfin/dv-bfin_dma.c Normal file
View File

@ -0,0 +1,553 @@
/* Blackfin Direct Memory Access (DMA) Channel model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "hw-device.h"
#include "dv-bfin_dma.h"
#include "dv-bfin_dmac.h"
/* Note: This DMA implementation requires the producer to be the master when
the peer is MDMA. The source is always a slave. This way we don't
have the two DMA devices thrashing each other with one trying to
write and the other trying to read. */
struct bfin_dma
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
unsigned ele_size;
struct hw *hw_peer;
/* Order after here is important -- matches hardware MMR layout. */
union {
struct { bu16 ndpl, ndph; };
bu32 next_desc_ptr;
};
union {
struct { bu16 sal, sah; };
bu32 start_addr;
};
bu16 BFIN_MMR_16 (config);
bu32 _pad0;
bu16 BFIN_MMR_16 (x_count);
bs16 BFIN_MMR_16 (x_modify);
bu16 BFIN_MMR_16 (y_count);
bs16 BFIN_MMR_16 (y_modify);
bu32 curr_desc_ptr, curr_addr;
bu16 BFIN_MMR_16 (irq_status);
bu16 BFIN_MMR_16 (peripheral_map);
bu16 BFIN_MMR_16 (curr_x_count);
bu32 _pad1;
bu16 BFIN_MMR_16 (curr_y_count);
bu32 _pad2;
};
#define mmr_base() offsetof(struct bfin_dma, next_desc_ptr)
#define mmr_offset(mmr) (offsetof(struct bfin_dma, mmr) - mmr_base())
static const char * const mmr_names[] = {
"NEXT_DESC_PTR", "START_ADDR", "CONFIG", "<INV>", "X_COUNT", "X_MODIFY",
"Y_COUNT", "Y_MODIFY", "CURR_DESC_PTR", "CURR_ADDR", "IRQ_STATUS",
"PERIPHERAL_MAP", "CURR_X_COUNT", "<INV>", "CURR_Y_COUNT", "<INV>",
};
#define mmr_name(off) mmr_names[(off) / 4]
static bool
bfin_dma_enabled (struct bfin_dma *dma)
{
return (dma->config & DMAEN);
}
static bool
bfin_dma_running (struct bfin_dma *dma)
{
return (dma->irq_status & DMA_RUN);
}
static struct hw *
bfin_dma_get_peer (struct hw *me, struct bfin_dma *dma)
{
if (dma->hw_peer)
return dma->hw_peer;
return dma->hw_peer = bfin_dmac_get_peer (me, dma->peripheral_map);
}
static void
bfin_dma_process_desc (struct hw *me, struct bfin_dma *dma)
{
bu8 ndsize = (dma->config & NDSIZE) >> NDSIZE_SHIFT;
bu16 _flows[9], *flows = _flows;
HW_TRACE ((me, "dma starting up %#x", dma->config));
switch (dma->config & WDSIZE)
{
case WDSIZE_32:
dma->ele_size = 4;
break;
case WDSIZE_16:
dma->ele_size = 2;
break;
default:
dma->ele_size = 1;
break;
}
/* Address has to be mutiple of transfer size. */
if (dma->start_addr & (dma->ele_size - 1))
dma->irq_status |= DMA_ERR;
if (dma->ele_size != (unsigned) abs (dma->x_modify))
hw_abort (me, "DMA config (striding) %#x not supported (x_modify: %d)",
dma->config, dma->x_modify);
switch (dma->config & DMAFLOW)
{
case DMAFLOW_AUTO:
case DMAFLOW_STOP:
if (ndsize)
hw_abort (me, "DMA config error: DMAFLOW_{AUTO,STOP} requires NDSIZE_0");
break;
case DMAFLOW_ARRAY:
if (ndsize == 0 || ndsize > 7)
hw_abort (me, "DMA config error: DMAFLOW_ARRAY requires NDSIZE 1...7");
sim_read (hw_system (me), dma->curr_desc_ptr, (void *)flows, ndsize * 2);
break;
case DMAFLOW_SMALL:
if (ndsize == 0 || ndsize > 8)
hw_abort (me, "DMA config error: DMAFLOW_SMALL requires NDSIZE 1...8");
sim_read (hw_system (me), dma->next_desc_ptr, (void *)flows, ndsize * 2);
break;
case DMAFLOW_LARGE:
if (ndsize == 0 || ndsize > 9)
hw_abort (me, "DMA config error: DMAFLOW_LARGE requires NDSIZE 1...9");
sim_read (hw_system (me), dma->next_desc_ptr, (void *)flows, ndsize * 2);
break;
default:
hw_abort (me, "DMA config error: invalid DMAFLOW %#x", dma->config);
}
if (ndsize)
{
bu8 idx;
bu16 *stores[] = {
&dma->sal,
&dma->sah,
&dma->config,
&dma->x_count,
(void *) &dma->x_modify,
&dma->y_count,
(void *) &dma->y_modify,
};
switch (dma->config & DMAFLOW)
{
case DMAFLOW_LARGE:
dma->ndph = _flows[1];
--ndsize;
++flows;
case DMAFLOW_SMALL:
dma->ndpl = _flows[0];
--ndsize;
++flows;
break;
}
for (idx = 0; idx < ndsize; ++idx)
*stores[idx] = flows[idx];
}
dma->curr_desc_ptr = dma->next_desc_ptr;
dma->curr_addr = dma->start_addr;
dma->curr_x_count = dma->x_count ? : 0xffff;
dma->curr_y_count = dma->y_count ? : 0xffff;
}
static int
bfin_dma_finish_x (struct hw *me, struct bfin_dma *dma)
{
/* XXX: This would be the time to process the next descriptor. */
/* XXX: Should this toggle Enable in dma->config ? */
if (dma->config & DI_EN)
hw_port_event (me, 0, 1);
if ((dma->config & DMA2D) && dma->curr_y_count > 1)
{
dma->curr_y_count -= 1;
dma->curr_x_count = dma->x_count;
/* With 2D, last X transfer does not modify curr_addr. */
dma->curr_addr = dma->curr_addr - dma->x_modify + dma->y_modify;
return 1;
}
switch (dma->config & DMAFLOW)
{
case DMAFLOW_STOP:
HW_TRACE ((me, "dma is complete"));
dma->irq_status = (dma->irq_status & ~DMA_RUN) | DMA_DONE;
return 0;
default:
bfin_dma_process_desc (me, dma);
return 1;
}
}
static void bfin_dma_hw_event_callback (struct hw *, void *);
static void
bfin_dma_reschedule (struct hw *me, unsigned delay)
{
struct bfin_dma *dma = hw_data (me);
if (dma->handler)
{
hw_event_queue_deschedule (me, dma->handler);
dma->handler = NULL;
}
if (!delay)
return;
HW_TRACE ((me, "scheduling next process in %u", delay));
dma->handler = hw_event_queue_schedule (me, delay,
bfin_dma_hw_event_callback, dma);
}
/* Chew through the DMA over and over. */
static void
bfin_dma_hw_event_callback (struct hw *me, void *data)
{
struct bfin_dma *dma = data;
struct hw *peer;
struct dv_bfin *bfin_peer;
bu8 buf[4096];
unsigned ret, nr_bytes, ele_count;
dma->handler = NULL;
peer = bfin_dma_get_peer (me, dma);
bfin_peer = hw_data (peer);
ret = 0;
if (dma->x_modify < 0)
/* XXX: This sucks performance wise. */
nr_bytes = dma->ele_size;
else
nr_bytes = MIN (sizeof (buf), dma->curr_x_count * dma->ele_size);
/* Pumping a chunk! */
bfin_peer->dma_master = me;
bfin_peer->acked = false;
if (dma->config & WNR)
{
HW_TRACE ((me, "dma transfer to 0x%08lx length %u",
(unsigned long) dma->curr_addr, nr_bytes));
ret = hw_dma_read_buffer (peer, buf, 0, dma->curr_addr, nr_bytes);
/* Has the DMA stalled ? abort for now. */
if (ret == 0)
goto reschedule;
/* XXX: How to handle partial DMA transfers ? */
if (ret % dma->ele_size)
goto error;
ret = sim_write (hw_system (me), dma->curr_addr, buf, ret);
}
else
{
HW_TRACE ((me, "dma transfer from 0x%08lx length %u",
(unsigned long) dma->curr_addr, nr_bytes));
ret = sim_read (hw_system (me), dma->curr_addr, buf, nr_bytes);
if (ret == 0)
goto reschedule;
/* XXX: How to handle partial DMA transfers ? */
if (ret % dma->ele_size)
goto error;
ret = hw_dma_write_buffer (peer, buf, 0, dma->curr_addr, ret, 0);
if (ret == 0)
goto reschedule;
}
/* Ignore partial writes. */
ele_count = ret / dma->ele_size;
dma->curr_addr += ele_count * dma->x_modify;
dma->curr_x_count -= ele_count;
if ((!dma->acked && dma->curr_x_count) || bfin_dma_finish_x (me, dma))
/* Still got work to do, so schedule again. */
reschedule:
bfin_dma_reschedule (me, ret ? 1 : 5000);
return;
error:
/* Don't reschedule on errors ... */
dma->irq_status |= DMA_ERR;
}
static unsigned
bfin_dma_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_dma *dma = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr % dma->base;
valuep = (void *)((unsigned long)dma + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
/* XXX: All registers are RO when DMA is enabled (except IRQ_STATUS).
But does the HW discard writes or send up IVGHW ? The sim
simply discards atm ... */
switch (mmr_off)
{
case mmr_offset(next_desc_ptr):
case mmr_offset(start_addr):
case mmr_offset(curr_desc_ptr):
case mmr_offset(curr_addr):
/* Don't require 32bit access as all DMA MMRs can be used as 16bit. */
if (!bfin_dma_running (dma))
{
if (nr_bytes == 4)
*value32p = value;
else
*value16p = value;
}
else
HW_TRACE ((me, "discarding write while dma running"));
break;
case mmr_offset(x_count):
case mmr_offset(x_modify):
case mmr_offset(y_count):
case mmr_offset(y_modify):
if (!bfin_dma_running (dma))
*value16p = value;
break;
case mmr_offset(peripheral_map):
if (!bfin_dma_running (dma))
{
*value16p = (*value16p & CTYPE) | (value & ~CTYPE);
/* Clear peripheral peer so it gets looked up again. */
dma->hw_peer = NULL;
}
else
HW_TRACE ((me, "discarding write while dma running"));
break;
case mmr_offset(config):
/* XXX: How to handle updating CONFIG of a running channel ? */
if (nr_bytes == 4)
*value32p = value;
else
*value16p = value;
if (bfin_dma_enabled (dma))
{
dma->irq_status |= DMA_RUN;
bfin_dma_process_desc (me, dma);
/* The writer is the master. */
if (!(dma->peripheral_map & CTYPE) || (dma->config & WNR))
bfin_dma_reschedule (me, 1);
}
else
{
dma->irq_status &= ~DMA_RUN;
bfin_dma_reschedule (me, 0);
}
break;
case mmr_offset(irq_status):
dv_w1c_2 (value16p, value, DMA_DONE | DMA_ERR);
break;
case mmr_offset(curr_x_count):
case mmr_offset(curr_y_count):
if (!bfin_dma_running (dma))
*value16p = value;
else
HW_TRACE ((me, "discarding write while dma running"));
break;
default:
/* XXX: The HW lets the pad regions be read/written ... */
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_dma_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_dma *dma = hw_data (me);
bu32 mmr_off;
bu16 *value16p;
bu32 *value32p;
void *valuep;
mmr_off = addr % dma->base;
valuep = (void *)((unsigned long)dma + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
/* Hardware lets you read all MMRs as 16 or 32 bits, even reserved. */
if (nr_bytes == 4)
dv_store_4 (dest, *value32p);
else
dv_store_2 (dest, *value16p);
return nr_bytes;
}
static unsigned
bfin_dma_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
struct bfin_dma *dma = hw_data (me);
unsigned ret, ele_count;
HW_TRACE_DMA_READ ();
/* If someone is trying to read from me, I have to be enabled. */
if (!bfin_dma_enabled (dma) && !bfin_dma_running (dma))
return 0;
/* XXX: handle x_modify ... */
ret = sim_read (hw_system (me), dma->curr_addr, dest, nr_bytes);
/* Ignore partial writes. */
ele_count = ret / dma->ele_size;
/* Has the DMA stalled ? abort for now. */
if (!ele_count)
return 0;
dma->curr_addr += ele_count * dma->x_modify;
dma->curr_x_count -= ele_count;
if (dma->curr_x_count == 0)
bfin_dma_finish_x (me, dma);
return ret;
}
static unsigned
bfin_dma_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
struct bfin_dma *dma = hw_data (me);
unsigned ret, ele_count;
HW_TRACE_DMA_WRITE ();
/* If someone is trying to write to me, I have to be enabled. */
if (!bfin_dma_enabled (dma) && !bfin_dma_running (dma))
return 0;
/* XXX: handle x_modify ... */
ret = sim_write (hw_system (me), dma->curr_addr, source, nr_bytes);
/* Ignore partial writes. */
ele_count = ret / dma->ele_size;
/* Has the DMA stalled ? abort for now. */
if (!ele_count)
return 0;
dma->curr_addr += ele_count * dma->x_modify;
dma->curr_x_count -= ele_count;
if (dma->curr_x_count == 0)
bfin_dma_finish_x (me, dma);
return ret;
}
static const struct hw_port_descriptor bfin_dma_ports[] = {
{ "di", 0, 0, output_port, }, /* DMA Interrupt */
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_dma_regs (struct hw *me, struct bfin_dma *dma)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_DMA_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_DMA_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
dma->base = attach_address;
}
static void
bfin_dma_finish (struct hw *me)
{
struct bfin_dma *dma;
dma = HW_ZALLOC (me, struct bfin_dma);
set_hw_data (me, dma);
set_hw_io_read_buffer (me, bfin_dma_io_read_buffer);
set_hw_io_write_buffer (me, bfin_dma_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_dma_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_dma_dma_write_buffer);
set_hw_ports (me, bfin_dma_ports);
attach_bfin_dma_regs (me, dma);
/* Initialize the DMA Channel. */
dma->peripheral_map = bfin_dmac_default_pmap (me);
}
const struct hw_descriptor dv_bfin_dma_descriptor[] = {
{"bfin_dma", bfin_dma_finish,},
{NULL, NULL},
};

65
sim/bfin/dv-bfin_dma.h Normal file
View File

@ -0,0 +1,65 @@
/* Blackfin Direct Memory Access (DMA) Channel model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_DMA_H
#define DV_BFIN_DMA_H
#define BFIN_MMR_DMA_SIZE (4 * 16)
/* DMA_CONFIG Masks */
#define DMAEN 0x0001 /* DMA Channel Enable */
#define WNR 0x0002 /* Channel Direction (W/R*) */
#define WDSIZE_8 0x0000 /* Transfer Word Size = 8 */
#define WDSIZE_16 0x0004 /* Transfer Word Size = 16 */
#define WDSIZE_32 0x0008 /* Transfer Word Size = 32 */
#define WDSIZE 0x000c /* Transfer Word Size */
#define DMA2D 0x0010 /* DMA Mode (2D/1D*) */
#define RESTART 0x0020 /* DMA Buffer Clear */
#define DI_SEL 0x0040 /* Data Interrupt Timing Select */
#define DI_EN 0x0080 /* Data Interrupt Enable */
#define NDSIZE_0 0x0000 /* Next Descriptor Size = 0 (Stop/Autobuffer) */
#define NDSIZE_1 0x0100 /* Next Descriptor Size = 1 */
#define NDSIZE_2 0x0200 /* Next Descriptor Size = 2 */
#define NDSIZE_3 0x0300 /* Next Descriptor Size = 3 */
#define NDSIZE_4 0x0400 /* Next Descriptor Size = 4 */
#define NDSIZE_5 0x0500 /* Next Descriptor Size = 5 */
#define NDSIZE_6 0x0600 /* Next Descriptor Size = 6 */
#define NDSIZE_7 0x0700 /* Next Descriptor Size = 7 */
#define NDSIZE_8 0x0800 /* Next Descriptor Size = 8 */
#define NDSIZE_9 0x0900 /* Next Descriptor Size = 9 */
#define NDSIZE 0x0f00 /* Next Descriptor Size */
#define NDSIZE_SHIFT 8
#define DMAFLOW 0x7000 /* Flow Control */
#define DMAFLOW_STOP 0x0000 /* Stop Mode */
#define DMAFLOW_AUTO 0x1000 /* Autobuffer Mode */
#define DMAFLOW_ARRAY 0x4000 /* Descriptor Array Mode */
#define DMAFLOW_SMALL 0x6000 /* Small Model Descriptor List Mode */
#define DMAFLOW_LARGE 0x7000 /* Large Model Descriptor List Mode */
/* DMA_IRQ_STATUS Masks */
#define DMA_DONE 0x0001 /* DMA Completion Interrupt Status */
#define DMA_ERR 0x0002 /* DMA Error Interrupt Status */
#define DFETCH 0x0004 /* DMA Descriptor Fetch Indicator */
#define DMA_RUN 0x0008 /* DMA Channel Running Indicator */
/* DMA_PERIPHERAL_MAP Masks */
#define CTYPE (1 << 6)
#endif

469
sim/bfin/dv-bfin_dmac.c Normal file
View File

@ -0,0 +1,469 @@
/* Blackfin Direct Memory Access (DMA) Controller model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "sim-hw.h"
#include "devices.h"
#include "hw-device.h"
#include "dv-bfin_dma.h"
#include "dv-bfin_dmac.h"
struct bfin_dmac
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
const char **pmap;
unsigned int pmap_count;
};
struct hw *
bfin_dmac_get_peer (struct hw *dma, bu16 pmap)
{
struct hw *ret, *me;
struct bfin_dmac *dmac;
char peer[100];
me = hw_parent (dma);
dmac = hw_data (me);
if (pmap & CTYPE)
{
/* MDMA channel. */
unsigned int chan_num = dv_get_bus_num (dma);
if (chan_num & 1)
chan_num &= ~1;
else
chan_num |= 1;
sprintf (peer, "%s/bfin_dma@%u", hw_path (me), chan_num);
}
else
{
unsigned int idx = pmap >> 12;
if (idx >= dmac->pmap_count)
hw_abort (me, "Invalid DMA peripheral_map %#x", pmap);
else
sprintf (peer, "/core/bfin_%s", dmac->pmap[idx]);
}
ret = hw_tree_find_device (me, peer);
if (!ret)
hw_abort (me, "Unable to locate peer for %s (pmap:%#x %s)",
hw_name (dma), pmap, peer);
return ret;
}
bu16
bfin_dmac_default_pmap (struct hw *dma)
{
unsigned int chan_num = dv_get_bus_num (dma);
if (chan_num < BFIN_DMAC_MDMA_BASE)
return (chan_num % 12) << 12;
else
return CTYPE; /* MDMA */
}
static const char *bfin_dmac_50x_pmap[] = {
"ppi@0", "rsi", "sport@0", "sport@0", "sport@1", "sport@1",
"spi@0", "spi@1", "uart2@0", "uart2@0", "uart2@1", "uart2@1",
};
/* XXX: Need to figure out how to handle portmuxed DMA channels. */
static const struct hw_port_descriptor bfin_dmac_50x_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "rsi", 1, 0, input_port, },
{ "sport@0_rx", 2, 0, input_port, },
{ "sport@0_tx", 3, 0, input_port, },
{ "sport@1_tx", 4, 0, input_port, },
{ "sport@1_rx", 5, 0, input_port, },
{ "spi@0", 6, 0, input_port, },
{ "spi@1", 7, 0, input_port, },
{ "uart2@0_rx", 8, 0, input_port, },
{ "uart2@0_tx", 9, 0, input_port, },
{ "uart2@1_rx", 10, 0, input_port, },
{ "uart2@1_tx", 11, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac_51x_pmap[] = {
"ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1",
"sport@1", "spi@0", "uart@0", "uart@0", "uart@1", "uart@1",
};
/* XXX: Need to figure out how to handle portmuxed DMA channels. */
static const struct hw_port_descriptor bfin_dmac_51x_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "emac_rx", 1, 0, input_port, },
{ "emac_tx", 2, 0, input_port, },
{ "sport@0_rx", 3, 0, input_port, },
{ "sport@0_tx", 4, 0, input_port, },
/*{ "rsi", 4, 0, input_port, },*/
{ "sport@1_tx", 5, 0, input_port, },
/*{ "spi@1", 5, 0, input_port, },*/
{ "sport@1_rx", 6, 0, input_port, },
{ "spi@0", 7, 0, input_port, },
{ "uart@0_rx", 8, 0, input_port, },
{ "uart@0_tx", 9, 0, input_port, },
{ "uart@1_rx", 10, 0, input_port, },
{ "uart@1_tx", 11, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac_52x_pmap[] = {
"ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1",
"sport@1", "spi", "uart@0", "uart@0", "uart@1", "uart@1",
};
/* XXX: Need to figure out how to handle portmuxed DMA channels
like PPI/NFC here which share DMA0. */
static const struct hw_port_descriptor bfin_dmac_52x_ports[] = {
{ "ppi@0", 0, 0, input_port, },
/*{ "nfc", 0, 0, input_port, },*/
{ "emac_rx", 1, 0, input_port, },
/*{ "hostdp", 1, 0, input_port, },*/
{ "emac_tx", 2, 0, input_port, },
/*{ "nfc", 2, 0, input_port, },*/
{ "sport@0_tx", 3, 0, input_port, },
{ "sport@0_rx", 4, 0, input_port, },
{ "sport@1_tx", 5, 0, input_port, },
{ "sport@1_rx", 6, 0, input_port, },
{ "spi", 7, 0, input_port, },
{ "uart@0_tx", 8, 0, input_port, },
{ "uart@0_rx", 9, 0, input_port, },
{ "uart@1_tx", 10, 0, input_port, },
{ "uart@1_rx", 11, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac_533_pmap[] = {
"ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi",
"uart@0", "uart@0",
};
static const struct hw_port_descriptor bfin_dmac_533_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "sport@0_tx", 1, 0, input_port, },
{ "sport@0_rx", 2, 0, input_port, },
{ "sport@1_tx", 3, 0, input_port, },
{ "sport@1_rx", 4, 0, input_port, },
{ "spi", 5, 0, input_port, },
{ "uart@0_tx", 6, 0, input_port, },
{ "uart@0_rx", 7, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac_537_pmap[] = {
"ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1",
"sport@1", "spi", "uart@0", "uart@0", "uart@1", "uart@1",
};
static const struct hw_port_descriptor bfin_dmac_537_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "emac_rx", 1, 0, input_port, },
{ "emac_tx", 2, 0, input_port, },
{ "sport@0_tx", 3, 0, input_port, },
{ "sport@0_rx", 4, 0, input_port, },
{ "sport@1_tx", 5, 0, input_port, },
{ "sport@1_rx", 6, 0, input_port, },
{ "spi", 7, 0, input_port, },
{ "uart@0_tx", 8, 0, input_port, },
{ "uart@0_rx", 9, 0, input_port, },
{ "uart@1_tx", 10, 0, input_port, },
{ "uart@1_rx", 11, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac0_538_pmap[] = {
"ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi@0",
"uart@0", "uart@0",
};
static const struct hw_port_descriptor bfin_dmac0_538_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "sport@0_rx", 1, 0, input_port, },
{ "sport@0_tx", 2, 0, input_port, },
{ "sport@1_rx", 3, 0, input_port, },
{ "sport@1_tx", 4, 0, input_port, },
{ "spi@0", 5, 0, input_port, },
{ "uart@0_rx", 6, 0, input_port, },
{ "uart@0_tx", 7, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac1_538_pmap[] = {
"sport@2", "sport@2", "sport@3", "sport@3", NULL, NULL,
"spi@1", "spi@2", "uart@1", "uart@1", "uart@2", "uart@2",
};
static const struct hw_port_descriptor bfin_dmac1_538_ports[] = {
{ "sport@2_rx", 0, 0, input_port, },
{ "sport@2_tx", 1, 0, input_port, },
{ "sport@3_rx", 2, 0, input_port, },
{ "sport@3_tx", 3, 0, input_port, },
{ "spi@1", 6, 0, input_port, },
{ "spi@2", 7, 0, input_port, },
{ "uart@1_rx", 8, 0, input_port, },
{ "uart@1_tx", 9, 0, input_port, },
{ "uart@2_rx", 10, 0, input_port, },
{ "uart@2_tx", 11, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac0_54x_pmap[] = {
"sport@0", "sport@0", "sport@1", "sport@1", "spi@0", "spi@1",
"uart2@0", "uart2@0", "uart2@1", "uart2@1", "atapi", "atapi",
};
static const struct hw_port_descriptor bfin_dmac0_54x_ports[] = {
{ "sport@0_rx", 0, 0, input_port, },
{ "sport@0_tx", 1, 0, input_port, },
{ "sport@1_rx", 2, 0, input_port, },
{ "sport@1_tx", 3, 0, input_port, },
{ "spi@0", 4, 0, input_port, },
{ "spi@1", 5, 0, input_port, },
{ "uart2@0_rx", 6, 0, input_port, },
{ "uart2@0_tx", 7, 0, input_port, },
{ "uart2@1_rx", 8, 0, input_port, },
{ "uart2@1_tx", 9, 0, input_port, },
{ "atapi", 10, 0, input_port, },
{ "atapi", 11, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac1_54x_pmap[] = {
"eppi@0", "eppi@1", "eppi@2", "pixc", "pixc", "pixc",
"sport@2", "sport@2", "sport@3", "sport@3", "sdh",
"spi@2", "uart2@2", "uart2@2", "uart2@3", "uart2@3",
};
static const struct hw_port_descriptor bfin_dmac1_54x_ports[] = {
{ "eppi@0", 0, 0, input_port, },
{ "eppi@1", 1, 0, input_port, },
{ "eppi@2", 2, 0, input_port, },
{ "pixc", 3, 0, input_port, },
{ "pixc", 4, 0, input_port, },
{ "pixc", 5, 0, input_port, },
{ "sport@2_rx", 6, 0, input_port, },
{ "sport@2_tx", 7, 0, input_port, },
{ "sport@3_rx", 8, 0, input_port, },
{ "sport@3_tx", 9, 0, input_port, },
{ "sdh", 10, 0, input_port, },
/*{ "nfc", 10, 0, input_port, },*/
{ "spi@2", 11, 0, input_port, },
{ "uart2@2_rx", 12, 0, input_port, },
{ "uart2@2_tx", 13, 0, input_port, },
{ "uart2@3_rx", 14, 0, input_port, },
{ "uart2@3_tx", 15, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac0_561_pmap[] = {
"sport@0", "sport@0", "sport@1", "sport@1", "spi", "uart@0", "uart@0",
};
static const struct hw_port_descriptor bfin_dmac0_561_ports[] = {
{ "sport@0_rx", 0, 0, input_port, },
{ "sport@0_tx", 1, 0, input_port, },
{ "sport@1_rx", 2, 0, input_port, },
{ "sport@1_tx", 3, 0, input_port, },
{ "spi@0", 4, 0, input_port, },
{ "uart@0_rx", 5, 0, input_port, },
{ "uart@0_tx", 6, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac1_561_pmap[] = {
"ppi@0", "ppi@1",
};
static const struct hw_port_descriptor bfin_dmac1_561_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "ppi@1", 1, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static const char *bfin_dmac_59x_pmap[] = {
"ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi@0",
"spi@1", "uart@0", "uart@0",
};
static const struct hw_port_descriptor bfin_dmac_59x_ports[] = {
{ "ppi@0", 0, 0, input_port, },
{ "sport@0_tx", 1, 0, input_port, },
{ "sport@0_rx", 2, 0, input_port, },
{ "sport@1_tx", 3, 0, input_port, },
{ "sport@1_rx", 4, 0, input_port, },
{ "spi@0", 5, 0, input_port, },
{ "spi@1", 6, 0, input_port, },
{ "uart@0_rx", 7, 0, input_port, },
{ "uart@0_tx", 8, 0, input_port, },
{ NULL, 0, 0, 0, },
};
static void
bfin_dmac_port_event (struct hw *me, int my_port, struct hw *source,
int source_port, int level)
{
SIM_DESC sd = hw_system (me);
struct bfin_dmac *dmac = hw_data (me);
struct hw *dma = hw_child (me);
while (dma)
{
bu16 pmap;
sim_hw_io_read_buffer (sd, dma, &pmap, 0, 0x2c, sizeof (pmap));
pmap >>= 12;
if (pmap == my_port)
break;
dma = hw_sibling (dma);
}
if (!dma)
hw_abort (me, "no valid dma mapping found for %s", dmac->pmap[my_port]);
/* Have the DMA channel raise its interrupt to the SIC. */
hw_port_event (dma, 0, 1);
}
static void
bfin_dmac_finish (struct hw *me)
{
struct bfin_dmac *dmac;
unsigned int dmac_num = dv_get_bus_num (me);
dmac = HW_ZALLOC (me, struct bfin_dmac);
set_hw_data (me, dmac);
set_hw_port_event (me, bfin_dmac_port_event);
/* Initialize the DMA Controller. */
if (hw_find_property (me, "type") == NULL)
hw_abort (me, "Missing \"type\" property");
switch (hw_find_integer_property (me, "type"))
{
case 500 ... 509:
if (dmac_num != 0)
hw_abort (me, "this Blackfin only has a DMAC0");
dmac->pmap = bfin_dmac_50x_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac_50x_pmap);
set_hw_ports (me, bfin_dmac_50x_ports);
break;
case 510 ... 519:
if (dmac_num != 0)
hw_abort (me, "this Blackfin only has a DMAC0");
dmac->pmap = bfin_dmac_51x_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac_51x_pmap);
set_hw_ports (me, bfin_dmac_51x_ports);
break;
case 522 ... 527:
if (dmac_num != 0)
hw_abort (me, "this Blackfin only has a DMAC0");
dmac->pmap = bfin_dmac_52x_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac_52x_pmap);
set_hw_ports (me, bfin_dmac_52x_ports);
break;
case 531 ... 533:
if (dmac_num != 0)
hw_abort (me, "this Blackfin only has a DMAC0");
dmac->pmap = bfin_dmac_533_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac_533_pmap);
set_hw_ports (me, bfin_dmac_533_ports);
break;
case 534:
case 536:
case 537:
if (dmac_num != 0)
hw_abort (me, "this Blackfin only has a DMAC0");
dmac->pmap = bfin_dmac_537_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac_537_pmap);
set_hw_ports (me, bfin_dmac_537_ports);
break;
case 538 ... 539:
switch (dmac_num)
{
case 0:
dmac->pmap = bfin_dmac0_538_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_538_pmap);
set_hw_ports (me, bfin_dmac0_538_ports);
break;
case 1:
dmac->pmap = bfin_dmac1_538_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_538_pmap);
set_hw_ports (me, bfin_dmac1_538_ports);
break;
default:
hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1");
}
break;
case 540 ... 549:
switch (dmac_num)
{
case 0:
dmac->pmap = bfin_dmac0_54x_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_54x_pmap);
set_hw_ports (me, bfin_dmac0_54x_ports);
break;
case 1:
dmac->pmap = bfin_dmac1_54x_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_54x_pmap);
set_hw_ports (me, bfin_dmac1_54x_ports);
break;
default:
hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1");
}
break;
case 561:
switch (dmac_num)
{
case 0:
dmac->pmap = bfin_dmac0_561_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_561_pmap);
set_hw_ports (me, bfin_dmac0_561_ports);
break;
case 1:
dmac->pmap = bfin_dmac1_561_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_561_pmap);
set_hw_ports (me, bfin_dmac1_561_ports);
break;
default:
hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1");
}
break;
case 590 ... 599:
if (dmac_num != 0)
hw_abort (me, "this Blackfin only has a DMAC0");
dmac->pmap = bfin_dmac_59x_pmap;
dmac->pmap_count = ARRAY_SIZE (bfin_dmac_59x_pmap);
set_hw_ports (me, bfin_dmac_59x_ports);
break;
default:
hw_abort (me, "no support for DMAC on this Blackfin model yet");
}
}
const struct hw_descriptor dv_bfin_dmac_descriptor[] = {
{"bfin_dmac", bfin_dmac_finish,},
{NULL, NULL},
};

32
sim/bfin/dv-bfin_dmac.h Normal file
View File

@ -0,0 +1,32 @@
/* Blackfin Direct Memory Access (DMA) Controller model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_DMAC_H
#define DV_BFIN_DMAC_H
#define BFIN_MMR_DMAC0_BASE 0xFFC00C00
#define BFIN_MMR_DMAC1_BASE 0xFFC01C00
#define BFIN_DMAC_MDMA_BASE 0x100
struct hw *bfin_dmac_get_peer (struct hw *dma, bu16 pmap);
bu16 bfin_dmac_default_pmap (struct hw *dma);
#endif

456
sim/bfin/dv-bfin_ebiu_amc.c Normal file
View File

@ -0,0 +1,456 @@
/* Blackfin External Bus Interface Unit (EBIU) Asynchronous Memory Controller
(AMC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_ebiu_amc.h"
struct bfin_ebiu_amc
{
bu32 base;
int type;
bu32 bank_size;
unsigned (*io_write) (struct hw *, const void *, int, address_word,
unsigned, struct bfin_ebiu_amc *, bu32, bu32);
unsigned (*io_read) (struct hw *, void *, int, address_word, unsigned,
struct bfin_ebiu_amc *, bu32, void *, bu16 *, bu32 *);
struct hw *slaves[4];
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(amgctl);
union {
struct {
bu32 ambctl0, ambctl1;
bu32 _pad0[5];
bu16 BFIN_MMR_16(mode);
bu16 BFIN_MMR_16(fctl);
} bf50x;
struct {
bu32 ambctl0, ambctl1;
} bf53x;
struct {
bu32 ambctl0, ambctl1;
bu32 mbsctl, arbstat, mode, fctl;
} bf54x;
};
};
#define mmr_base() offsetof(struct bfin_ebiu_amc, amgctl)
#define mmr_offset(mmr) (offsetof(struct bfin_ebiu_amc, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const bf50x_mmr_names[] = {
"EBIU_AMGCTL", "EBIU_AMBCTL0", "EBIU_AMBCTL1",
[mmr_idx (bf50x.mode)] = "EBIU_MODE", "EBIU_FCTL",
};
static const char * const bf53x_mmr_names[] = {
"EBIU_AMGCTL", "EBIU_AMBCTL0", "EBIU_AMBCTL1",
};
static const char * const bf54x_mmr_names[] = {
"EBIU_AMGCTL", "EBIU_AMBCTL0", "EBIU_AMBCTL1",
"EBIU_MSBCTL", "EBIU_ARBSTAT", "EBIU_MODE", "EBIU_FCTL",
};
static const char * const *mmr_names;
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static void
bfin_ebiu_amc_write_amgctl (struct hw *me, struct bfin_ebiu_amc *amc,
bu16 amgctl)
{
bu32 amben_old, amben, addr, i;
amben_old = MIN ((amc->amgctl >> 1) & 0x7, 4);
amben = MIN ((amgctl >> 1) & 0x7, 4);
HW_TRACE ((me, "reattaching banks: AMGCTL 0x%04x[%u] -> 0x%04x[%u]",
amc->amgctl, amben_old, amgctl, amben));
for (i = 0; i < 4; ++i)
{
addr = BFIN_EBIU_AMC_BASE + i * amc->bank_size;
if (i < amben_old)
{
HW_TRACE ((me, "detaching bank %u (%#x base)", i, addr));
sim_core_detach (hw_system (me), NULL, 0, 0, addr);
}
if (i < amben)
{
struct hw *slave = amc->slaves[i];
HW_TRACE ((me, "attaching bank %u (%#x base) to %s", i, addr,
slave ? hw_path (slave) : "<floating pins>"));
sim_core_attach (hw_system (me), NULL, 0, access_read_write_exec,
0, addr, amc->bank_size, 0, slave, NULL);
}
}
amc->amgctl = amgctl;
}
static unsigned
bf50x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes,
struct bfin_ebiu_amc *amc, bu32 mmr_off,
bu32 value)
{
switch (mmr_off)
{
case mmr_offset(amgctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
bfin_ebiu_amc_write_amgctl (me, amc, value);
break;
case mmr_offset(bf50x.ambctl0):
amc->bf50x.ambctl0 = value;
break;
case mmr_offset(bf50x.ambctl1):
amc->bf50x.ambctl1 = value;
break;
case mmr_offset(bf50x.mode):
/* XXX: implement this. */
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
break;
case mmr_offset(bf50x.fctl):
/* XXX: implement this. */
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bf53x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes,
struct bfin_ebiu_amc *amc, bu32 mmr_off,
bu32 value)
{
switch (mmr_off)
{
case mmr_offset(amgctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
bfin_ebiu_amc_write_amgctl (me, amc, value);
break;
case mmr_offset(bf53x.ambctl0):
amc->bf53x.ambctl0 = value;
break;
case mmr_offset(bf53x.ambctl1):
amc->bf53x.ambctl1 = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bf54x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes,
struct bfin_ebiu_amc *amc, bu32 mmr_off,
bu32 value)
{
switch (mmr_off)
{
case mmr_offset(amgctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
bfin_ebiu_amc_write_amgctl (me, amc, value);
break;
case mmr_offset(bf54x.ambctl0):
amc->bf54x.ambctl0 = value;
break;
case mmr_offset(bf54x.ambctl1):
amc->bf54x.ambctl1 = value;
break;
case mmr_offset(bf54x.mbsctl):
/* XXX: implement this. */
break;
case mmr_offset(bf54x.arbstat):
/* XXX: implement this. */
break;
case mmr_offset(bf54x.mode):
/* XXX: implement this. */
break;
case mmr_offset(bf54x.fctl):
/* XXX: implement this. */
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_ebiu_amc *amc = hw_data (me);
bu32 mmr_off;
bu32 value;
value = dv_load_4 (source);
mmr_off = addr - amc->base;
HW_TRACE_WRITE ();
return amc->io_write (me, source, space, addr, nr_bytes,
amc, mmr_off, value);
}
static unsigned
bf50x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes,
struct bfin_ebiu_amc *amc, bu32 mmr_off,
void *valuep, bu16 *value16, bu32 *value32)
{
switch (mmr_off)
{
case mmr_offset(amgctl):
case mmr_offset(bf50x.fctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16);
break;
case mmr_offset(bf50x.ambctl0):
case mmr_offset(bf50x.ambctl1):
case mmr_offset(bf50x.mode):
dv_store_4 (dest, *value32);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bf53x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes,
struct bfin_ebiu_amc *amc, bu32 mmr_off,
void *valuep, bu16 *value16, bu32 *value32)
{
switch (mmr_off)
{
case mmr_offset(amgctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16);
break;
case mmr_offset(bf53x.ambctl0):
case mmr_offset(bf53x.ambctl1):
dv_store_4 (dest, *value32);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bf54x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes,
struct bfin_ebiu_amc *amc, bu32 mmr_off,
void *valuep, bu16 *value16, bu32 *value32)
{
switch (mmr_off)
{
case mmr_offset(amgctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16);
break;
case mmr_offset(bf54x.ambctl0):
case mmr_offset(bf54x.ambctl1):
case mmr_offset(bf54x.mbsctl):
case mmr_offset(bf54x.arbstat):
case mmr_offset(bf54x.mode):
case mmr_offset(bf54x.fctl):
dv_store_4 (dest, *value32);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bfin_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_ebiu_amc *amc = hw_data (me);
bu32 mmr_off;
void *valuep;
mmr_off = addr - amc->base;
valuep = (void *)((unsigned long)amc + mmr_base() + mmr_off);
HW_TRACE_READ ();
return amc->io_read (me, dest, space, addr, nr_bytes, amc,
mmr_off, valuep, valuep, valuep);
}
static void
bfin_ebiu_amc_attach_address_callback (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client)
{
struct bfin_ebiu_amc *amc = hw_data (me);
HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
if (addr + nr_bytes > 4)
hw_abort (me, "ebiu amc attaches are done in terms of banks");
while (nr_bytes--)
amc->slaves[addr + nr_bytes] = client;
bfin_ebiu_amc_write_amgctl (me, amc, amc->amgctl);
}
static void
attach_bfin_ebiu_amc_regs (struct hw *me, struct bfin_ebiu_amc *amc,
unsigned reg_size)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
if (hw_find_property (me, "type") == NULL)
hw_abort (me, "Missing \"type\" property");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != reg_size)
hw_abort (me, "\"reg\" size must be %#x", reg_size);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
amc->base = attach_address;
}
static void
bfin_ebiu_amc_finish (struct hw *me)
{
struct bfin_ebiu_amc *amc;
bu32 amgctl;
unsigned reg_size;
amc = HW_ZALLOC (me, struct bfin_ebiu_amc);
set_hw_data (me, amc);
set_hw_io_read_buffer (me, bfin_ebiu_amc_io_read_buffer);
set_hw_io_write_buffer (me, bfin_ebiu_amc_io_write_buffer);
set_hw_attach_address (me, bfin_ebiu_amc_attach_address_callback);
amc->type = hw_find_integer_property (me, "type");
switch (amc->type)
{
case 500 ... 509:
amc->io_write = bf50x_ebiu_amc_io_write_buffer;
amc->io_read = bf50x_ebiu_amc_io_read_buffer;
mmr_names = bf50x_mmr_names;
reg_size = sizeof (amc->bf50x) + 4;
/* Initialize the AMC. */
amc->bank_size = 1 * 1024 * 1024;
amgctl = 0x00F3;
amc->bf50x.ambctl0 = 0x0000FFC2;
amc->bf50x.ambctl1 = 0x0000FFC2;
amc->bf50x.mode = 0x0001;
amc->bf50x.fctl = 0x0002;
break;
case 540 ... 549:
amc->io_write = bf54x_ebiu_amc_io_write_buffer;
amc->io_read = bf54x_ebiu_amc_io_read_buffer;
mmr_names = bf54x_mmr_names;
reg_size = sizeof (amc->bf54x) + 4;
/* Initialize the AMC. */
amc->bank_size = 64 * 1024 * 1024;
amgctl = 0x0002;
amc->bf54x.ambctl0 = 0xFFC2FFC2;
amc->bf54x.ambctl1 = 0xFFC2FFC2;
amc->bf54x.fctl = 0x0006;
break;
case 510 ... 519:
case 522 ... 527:
case 531 ... 533:
case 534:
case 536:
case 537:
case 538 ... 539:
case 561:
amc->io_write = bf53x_ebiu_amc_io_write_buffer;
amc->io_read = bf53x_ebiu_amc_io_read_buffer;
mmr_names = bf53x_mmr_names;
reg_size = sizeof (amc->bf53x) + 4;
/* Initialize the AMC. */
if (amc->type == 561)
amc->bank_size = 64 * 1024 * 1024;
else
amc->bank_size = 1 * 1024 * 1024;
amgctl = 0x00F2;
amc->bf53x.ambctl0 = 0xFFC2FFC2;
amc->bf53x.ambctl1 = 0xFFC2FFC2;
break;
case 590 ... 599: /* BF59x has no AMC. */
default:
hw_abort (me, "no support for EBIU AMC on this Blackfin model yet");
}
attach_bfin_ebiu_amc_regs (me, amc, reg_size);
bfin_ebiu_amc_write_amgctl (me, amc, amgctl);
}
const struct hw_descriptor dv_bfin_ebiu_amc_descriptor[] = {
{"bfin_ebiu_amc", bfin_ebiu_amc_finish,},
{NULL, NULL},
};

View File

@ -0,0 +1,31 @@
/* Blackfin External Bus Interface Unit (EBIU) Asynchronous Memory Controller
(AMC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_EBIU_AMC_H
#define DV_BFIN_EBIU_AMC_H
#define BFIN_MMR_EBIU_AMC_SIZE (4 * 3)
#define BF50X_MMR_EBIU_AMC_SIZE 0x28
#define BF54X_MMR_EBIU_AMC_SIZE (4 * 7)
#define BFIN_EBIU_AMC_BASE 0x20000000
#endif

View File

@ -0,0 +1,184 @@
/* Blackfin External Bus Interface Unit (EBIU) DDR Controller (DDRC) Model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_ebiu_ddrc.h"
struct bfin_ebiu_ddrc
{
bu32 base, reg_size, bank_size;
/* Order after here is important -- matches hardware MMR layout. */
union {
struct { bu32 ddrctl0, ddrctl1, ddrctl2, ddrctl3; };
bu32 ddrctl[4];
};
bu32 ddrque, erradd;
bu16 BFIN_MMR_16(errmst);
bu16 BFIN_MMR_16(rstctl);
bu32 ddrbrc[8], ddrbwc[8];
bu32 ddracct, ddrtact, ddrarct;
bu32 ddrgc[4];
bu32 ddrmcen, ddrmccl;
};
#define mmr_base() offsetof(struct bfin_ebiu_ddrc, ddrctl0)
#define mmr_offset(mmr) (offsetof(struct bfin_ebiu_ddrc, mmr) - mmr_base())
static const char * const mmr_names[] = {
"EBIU_DDRCTL0", "EBIU_DDRCTL1", "EBIU_DDRCTL2", "EBIU_DDRCTL3", "EBIU_DDRQUE",
"EBIU_ERRADD", "EBIU_ERRMST", "EBIU_RSTCTL", "EBIU_DDRBRC0", "EBIU_DDRBRC1",
"EBIU_DDRBRC2", "EBIU_DDRBRC3", "EBIU_DDRBRC4", "EBIU_DDRBRC5",
"EBIU_DDRBRC6", "EBIU_DDRBRC7", "EBIU_DDRBWC0", "EBIU_DDRBWC1"
"EBIU_DDRBWC2", "EBIU_DDRBWC3", "EBIU_DDRBWC4", "EBIU_DDRBWC5",
"EBIU_DDRBWC6", "EBIU_DDRBWC7", "EBIU_DDRACCT", "EBIU_DDRTACT",
"EBIU_ARCT", "EBIU_DDRGC0", "EBIU_DDRGC1", "EBIU_DDRGC2", "EBIU_DDRGC3",
"EBIU_DDRMCEN", "EBIU_DDRMCCL",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_ebiu_ddrc_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_ebiu_ddrc *ddrc = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - ddrc->base;
valuep = (void *)((unsigned long)ddrc + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(errmst):
case mmr_offset(rstctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
*value16p = value;
break;
default:
dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
*value32p = value;
break;
}
return nr_bytes;
}
static unsigned
bfin_ebiu_ddrc_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_ebiu_ddrc *ddrc = hw_data (me);
bu32 mmr_off;
bu32 *value32p;
bu16 *value16p;
void *valuep;
mmr_off = addr - ddrc->base;
valuep = (void *)((unsigned long)ddrc + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(errmst):
case mmr_offset(rstctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
default:
dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
dv_store_4 (dest, *value32p);
break;
}
return nr_bytes;
}
static void
attach_bfin_ebiu_ddrc_regs (struct hw *me, struct bfin_ebiu_ddrc *ddrc)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_EBIU_DDRC_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EBIU_DDRC_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
ddrc->base = attach_address;
}
static void
bfin_ebiu_ddrc_finish (struct hw *me)
{
struct bfin_ebiu_ddrc *ddrc;
ddrc = HW_ZALLOC (me, struct bfin_ebiu_ddrc);
set_hw_data (me, ddrc);
set_hw_io_read_buffer (me, bfin_ebiu_ddrc_io_read_buffer);
set_hw_io_write_buffer (me, bfin_ebiu_ddrc_io_write_buffer);
attach_bfin_ebiu_ddrc_regs (me, ddrc);
/* Initialize the DDRC. */
ddrc->ddrctl0 = 0x098E8411;
ddrc->ddrctl1 = 0x10026223;
ddrc->ddrctl2 = 0x00000021;
ddrc->ddrctl3 = 0x00000003; /* XXX: MDDR is 0x20 ... */
ddrc->ddrque = 0x00001115;
ddrc->rstctl = 0x0002;
}
const struct hw_descriptor dv_bfin_ebiu_ddrc_descriptor[] = {
{"bfin_ebiu_ddrc", bfin_ebiu_ddrc_finish,},
{NULL, NULL},
};

View File

@ -0,0 +1,26 @@
/* Blackfin External Bus Interface Unit (EBIU) DDR Controller (DDRC) Model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_EBIU_DDRC_H
#define DV_BFIN_EBIU_DDRC_H
#define BFIN_MMR_EBIU_DDRC_SIZE 0xb0
#endif

201
sim/bfin/dv-bfin_ebiu_sdc.c Normal file
View File

@ -0,0 +1,201 @@
/* Blackfin External Bus Interface Unit (EBIU) SDRAM Controller (SDC) Model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_ebiu_sdc.h"
struct bfin_ebiu_sdc
{
bu32 base;
int type;
bu32 reg_size, bank_size;
/* Order after here is important -- matches hardware MMR layout. */
bu32 sdgctl;
bu32 sdbctl; /* 16bit on most parts ... */
bu16 BFIN_MMR_16(sdrrc);
bu16 BFIN_MMR_16(sdstat);
};
#define mmr_base() offsetof(struct bfin_ebiu_sdc, sdgctl)
#define mmr_offset(mmr) (offsetof(struct bfin_ebiu_sdc, mmr) - mmr_base())
static const char * const mmr_names[] = {
"EBIU_SDGCTL", "EBIU_SDBCTL", "EBIU_SDRRC", "EBIU_SDSTAT",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_ebiu_sdc_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_ebiu_sdc *sdc = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - sdc->base;
valuep = (void *)((unsigned long)sdc + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(sdgctl):
/* XXX: SRFS should make external mem unreadable. */
*value32p = value;
break;
case mmr_offset(sdbctl):
if (sdc->type == 561)
{
dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
*value32p = value;
}
else
{
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
*value16p = value;
}
break;
case mmr_offset(sdrrc):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
*value16p = value;
break;
case mmr_offset(sdstat):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
/* XXX: Some bits are W1C ... */
break;
}
return nr_bytes;
}
static unsigned
bfin_ebiu_sdc_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_ebiu_sdc *sdc = hw_data (me);
bu32 mmr_off;
bu32 *value32p;
bu16 *value16p;
void *valuep;
mmr_off = addr - sdc->base;
valuep = (void *)((unsigned long)sdc + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(sdgctl):
dv_store_4 (dest, *value32p);
break;
case mmr_offset(sdbctl):
if (sdc->type == 561)
{
dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
dv_store_4 (dest, *value32p);
}
else
{
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
}
break;
case mmr_offset(sdrrc):
case mmr_offset(sdstat):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
}
return nr_bytes;
}
static void
attach_bfin_ebiu_sdc_regs (struct hw *me, struct bfin_ebiu_sdc *sdc)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_EBIU_SDC_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EBIU_SDC_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
sdc->base = attach_address;
}
static void
bfin_ebiu_sdc_finish (struct hw *me)
{
struct bfin_ebiu_sdc *sdc;
sdc = HW_ZALLOC (me, struct bfin_ebiu_sdc);
set_hw_data (me, sdc);
set_hw_io_read_buffer (me, bfin_ebiu_sdc_io_read_buffer);
set_hw_io_write_buffer (me, bfin_ebiu_sdc_io_write_buffer);
attach_bfin_ebiu_sdc_regs (me, sdc);
sdc->type = hw_find_integer_property (me, "type");
/* Initialize the SDC. */
sdc->sdgctl = 0xE0088849;
sdc->sdbctl = 0x00000000;
sdc->sdrrc = 0x081A;
sdc->sdstat = 0x0008;
/* XXX: We boot with 64M external memory by default ... */
sdc->sdbctl |= EBE | EBSZ_64 | EBCAW_10;
}
const struct hw_descriptor dv_bfin_ebiu_sdc_descriptor[] = {
{"bfin_ebiu_sdc", bfin_ebiu_sdc_finish,},
{NULL, NULL},
};

View File

@ -0,0 +1,39 @@
/* Blackfin External Bus Interface Unit (EBIU) SDRAM Controller (SDC) Model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_EBIU_SDC_H
#define DV_BFIN_EBIU_SDC_H
#define BFIN_MMR_EBIU_SDC_SIZE (4 * 4)
/* EBIU_SDBCTL Masks */
#define EBE 0x0001 /* Enable SDRAM External Bank */
#define EBSZ_16 0x0000 /* Size = 16MB */
#define EBSZ_32 0x0002 /* Size = 32MB */
#define EBSZ_64 0x0004 /* Size = 64MB */
#define EBSZ_128 0x0006 /* Size = 128MB */
#define EBSZ_256 0x0008 /* Size = 256MB */
#define EBSZ_512 0x000A /* Size = 512MB */
#define EBCAW_8 0x0000 /* Column Address Width = 8 Bits */
#define EBCAW_9 0x0010 /* Column Address Width = 9 Bits */
#define EBCAW_10 0x0020 /* Column Address Width = 10 Bits */
#define EBCAW_11 0x0030 /* Column Address Width = 11 Bits */
#endif

603
sim/bfin/dv-bfin_emac.c Normal file
View File

@ -0,0 +1,603 @@
/* Blackfin Ethernet Media Access Controller (EMAC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#ifdef HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
#endif
#ifdef HAVE_LINUX_IF_TUN_H
# define WITH_TUN 1
#else
# define WITH_TUN 0
#endif
#include "sim-main.h"
#include "sim-hw.h"
#include "devices.h"
#include "dv-bfin_emac.h"
/* XXX: This doesn't support partial DMA transfers. */
/* XXX: The TUN pieces should be pushed to the PHY so that we work with
multiple "networks" and the PHY takes care of it. */
struct bfin_emac
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
int tap;
#if WITH_TUN
struct ifreq ifr;
#endif
bu32 rx_crc;
/* Order after here is important -- matches hardware MMR layout. */
bu32 opmode, addrlo, addrhi, hashlo, hashhi, staadd, stadat, flc, vlan1, vlan2;
bu32 _pad0;
bu32 wkup_ctl, wkup_ffmsk0, wkup_ffmsk1, wkup_ffmsk2, wkup_ffmsk3;
bu32 wkup_ffcmd, wkup_ffoff, wkup_ffcrc0, wkup_ffcrc1;
bu32 _pad1[4];
bu32 sysctl, systat, rx_stat, rx_stky, rx_irqe, tx_stat, tx_stky, tx_irqe;
bu32 mmc_ctl, mmc_rirqs, mmc_rirqe, mmc_tirqs, mmc_tirqe;
bu32 _pad2[3];
bu16 BFIN_MMR_16(ptp_ctl);
bu16 BFIN_MMR_16(ptp_ie);
bu16 BFIN_MMR_16(ptp_istat);
bu32 ptp_foff, ptp_fv1, ptp_fv2, ptp_fv3, ptp_addend, ptp_accr, ptp_offset;
bu32 ptp_timelo, ptp_timehi, ptp_rxsnaplo, ptp_rxsnaphi, ptp_txsnaplo;
bu32 ptp_txsnaphi, ptp_alarmlo, ptp_alarmhi, ptp_id_off, ptp_id_snap;
bu32 ptp_pps_startlo, ptp_pps_starthi, ptp_pps_period;
bu32 _pad3[1];
bu32 rxc_ok, rxc_fcs, rxc_lign, rxc_octet, rxc_dmaovf, rxc_unicst, rxc_multi;
bu32 rxc_broad, rxc_lnerri, rxc_lnerro, rxc_long, rxc_macctl, rxc_opcode;
bu32 rxc_pause, rxc_allfrm, rxc_alloct, rxc_typed, rxc_short, rxc_eq64;
bu32 rxc_lt128, rxc_lt256, rxc_lt512, rxc_lt1024, rxc_ge1024;
bu32 _pad4[8];
bu32 txc_ok, txc_1col, txc_gt1col, txc_octet, txc_defer, txc_latecl;
bu32 txc_xs_col, txc_dmaund, txc_crserr, txc_unicst, txc_multi, txc_broad;
bu32 txc_xs_dfr, txc_macctl, txc_allfrm, txc_alloct, txc_eq64, txc_lt128;
bu32 txc_lt256, txc_lt512, txc_lt1024, txc_ge1024, txc_abort;
};
#define mmr_base() offsetof(struct bfin_emac, opmode)
#define mmr_offset(mmr) (offsetof(struct bfin_emac, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const mmr_names[BFIN_MMR_EMAC_SIZE / 4] = {
"EMAC_OPMODE", "EMAC_ADDRLO", "EMAC_ADDRHI", "EMAC_HASHLO", "EMAC_HASHHI",
"EMAC_STAADD", "EMAC_STADAT", "EMAC_FLC", "EMAC_VLAN1", "EMAC_VLAN2", NULL,
"EMAC_WKUP_CTL", "EMAC_WKUP_FFMSK0", "EMAC_WKUP_FFMSK1", "EMAC_WKUP_FFMSK2",
"EMAC_WKUP_FFMSK3", "EMAC_WKUP_FFCMD", "EMAC_WKUP_FFOFF", "EMAC_WKUP_FFCRC0",
"EMAC_WKUP_FFCRC1", [mmr_idx (sysctl)] = "EMAC_SYSCTL", "EMAC_SYSTAT",
"EMAC_RX_STAT", "EMAC_RX_STKY", "EMAC_RX_IRQE", "EMAC_TX_STAT",
"EMAC_TX_STKY", "EMAC_TX_IRQE", "EMAC_MMC_CTL", "EMAC_MMC_RIRQS",
"EMAC_MMC_RIRQE", "EMAC_MMC_TIRQS", "EMAC_MMC_TIRQE",
[mmr_idx (ptp_ctl)] = "EMAC_PTP_CTL", "EMAC_PTP_IE", "EMAC_PTP_ISTAT",
"EMAC_PTP_FOFF", "EMAC_PTP_FV1", "EMAC_PTP_FV2", "EMAC_PTP_FV3",
"EMAC_PTP_ADDEND", "EMAC_PTP_ACCR", "EMAC_PTP_OFFSET", "EMAC_PTP_TIMELO",
"EMAC_PTP_TIMEHI", "EMAC_PTP_RXSNAPLO", "EMAC_PTP_RXSNAPHI",
"EMAC_PTP_TXSNAPLO", "EMAC_PTP_TXSNAPHI", "EMAC_PTP_ALARMLO",
"EMAC_PTP_ALARMHI", "EMAC_PTP_ID_OFF", "EMAC_PTP_ID_SNAP",
"EMAC_PTP_PPS_STARTLO", "EMAC_PTP_PPS_STARTHI", "EMAC_PTP_PPS_PERIOD",
[mmr_idx (rxc_ok)] = "EMAC_RXC_OK", "EMAC_RXC_FCS", "EMAC_RXC_LIGN",
"EMAC_RXC_OCTET", "EMAC_RXC_DMAOVF", "EMAC_RXC_UNICST", "EMAC_RXC_MULTI",
"EMAC_RXC_BROAD", "EMAC_RXC_LNERRI", "EMAC_RXC_LNERRO", "EMAC_RXC_LONG",
"EMAC_RXC_MACCTL", "EMAC_RXC_OPCODE", "EMAC_RXC_PAUSE", "EMAC_RXC_ALLFRM",
"EMAC_RXC_ALLOCT", "EMAC_RXC_TYPED", "EMAC_RXC_SHORT", "EMAC_RXC_EQ64",
"EMAC_RXC_LT128", "EMAC_RXC_LT256", "EMAC_RXC_LT512", "EMAC_RXC_LT1024",
"EMAC_RXC_GE1024",
[mmr_idx (txc_ok)] = "EMAC_TXC_OK", "EMAC_TXC_1COL", "EMAC_TXC_GT1COL",
"EMAC_TXC_OCTET", "EMAC_TXC_DEFER", "EMAC_TXC_LATECL", "EMAC_TXC_XS_COL",
"EMAC_TXC_DMAUND", "EMAC_TXC_CRSERR", "EMAC_TXC_UNICST", "EMAC_TXC_MULTI",
"EMAC_TXC_BROAD", "EMAC_TXC_XS_DFR", "EMAC_TXC_MACCTL", "EMAC_TXC_ALLFRM",
"EMAC_TXC_ALLOCT", "EMAC_TXC_EQ64", "EMAC_TXC_LT128", "EMAC_TXC_LT256",
"EMAC_TXC_LT512", "EMAC_TXC_LT1024", "EMAC_TXC_GE1024", "EMAC_TXC_ABORT",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static struct hw *
mii_find_phy (struct hw *me, bu8 addr)
{
struct hw *phy = hw_child (me);
while (phy && --addr)
phy = hw_sibling (phy);
return phy;
}
static void
mii_write (struct hw *me)
{
SIM_DESC sd = hw_system (me);
struct bfin_emac *emac = hw_data (me);
struct hw *phy;
bu8 addr = PHYAD (emac->staadd);
bu8 reg = REGAD (emac->staadd);
bu16 data = emac->stadat;
phy = mii_find_phy (me, addr);
if (!phy)
return;
sim_hw_io_write_buffer (sd, phy, &data, 1, reg, 2);
}
static void
mii_read (struct hw *me)
{
SIM_DESC sd = hw_system (me);
struct bfin_emac *emac = hw_data (me);
struct hw *phy;
bu8 addr = PHYAD (emac->staadd);
bu8 reg = REGAD (emac->staadd);
bu16 data;
phy = mii_find_phy (me, addr);
if (!phy || sim_hw_io_read_buffer (sd, phy, &data, 1, reg, 2) != 2)
data = 0xffff;
emac->stadat = data;
}
static unsigned
bfin_emac_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_emac *emac = hw_data (me);
bu32 mmr_off;
bu32 value;
bu32 *valuep;
/* XXX: 16bit accesses are allowed ... */
dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
value = dv_load_4 (source);
mmr_off = addr - emac->base;
valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(hashlo):
case mmr_offset(hashhi):
case mmr_offset(stadat):
case mmr_offset(flc):
case mmr_offset(vlan1):
case mmr_offset(vlan2):
case mmr_offset(wkup_ffmsk0):
case mmr_offset(wkup_ffmsk1):
case mmr_offset(wkup_ffmsk2):
case mmr_offset(wkup_ffmsk3):
case mmr_offset(wkup_ffcmd):
case mmr_offset(wkup_ffoff):
case mmr_offset(wkup_ffcrc0):
case mmr_offset(wkup_ffcrc1):
case mmr_offset(sysctl):
case mmr_offset(rx_irqe):
case mmr_offset(tx_irqe):
case mmr_offset(mmc_rirqe):
case mmr_offset(mmc_tirqe):
*valuep = value;
break;
case mmr_offset(opmode):
if (!(*valuep & RE) && (value & RE))
emac->rx_stat &= ~RX_COMP;
if (!(*valuep & TE) && (value & TE))
emac->tx_stat &= ~TX_COMP;
*valuep = value;
break;
case mmr_offset(addrlo):
case mmr_offset(addrhi):
*valuep = value;
break;
case mmr_offset(wkup_ctl):
dv_w1c_4_partial (valuep, value, 0xf20);
break;
case mmr_offset(systat):
dv_w1c_4 (valuep, value, 0x1e);
break;
case mmr_offset(staadd):
*valuep = value | STABUSY;
if (value & STAOP)
mii_write (me);
else
mii_read (me);
*valuep &= ~STABUSY;
break;
case mmr_offset(rx_stat):
case mmr_offset(tx_stat):
/* Discard writes to these. */
break;
case mmr_offset(rx_stky):
case mmr_offset(tx_stky):
case mmr_offset(mmc_rirqs):
case mmr_offset(mmc_tirqs):
dv_w1c_4 (valuep, value, 0);
break;
case mmr_offset(mmc_ctl):
/* Writing to bit 0 clears all counters. */
*valuep = value & ~1;
if (value & 1)
{
memset (&emac->rxc_ok, 0, mmr_offset (rxc_ge1024) - mmr_offset (rxc_ok) + 4);
memset (&emac->txc_ok, 0, mmr_offset (txc_abort) - mmr_offset (txc_ok) + 4);
}
break;
case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
/* XXX: Are these supposed to be read-only ? */
*valuep = value;
break;
case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
/* XXX: Only on some models; ignore for now. */
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_emac_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_emac *emac = hw_data (me);
bu32 mmr_off;
bu32 *valuep;
/* XXX: 16bit accesses are allowed ... */
dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
mmr_off = addr - emac->base;
valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(opmode):
case mmr_offset(addrlo):
case mmr_offset(addrhi):
case mmr_offset(hashlo):
case mmr_offset(hashhi):
case mmr_offset(staadd):
case mmr_offset(stadat):
case mmr_offset(flc):
case mmr_offset(vlan1):
case mmr_offset(vlan2):
case mmr_offset(wkup_ctl):
case mmr_offset(wkup_ffmsk0):
case mmr_offset(wkup_ffmsk1):
case mmr_offset(wkup_ffmsk2):
case mmr_offset(wkup_ffmsk3):
case mmr_offset(wkup_ffcmd):
case mmr_offset(wkup_ffoff):
case mmr_offset(wkup_ffcrc0):
case mmr_offset(wkup_ffcrc1):
case mmr_offset(sysctl):
case mmr_offset(systat):
case mmr_offset(rx_stat):
case mmr_offset(rx_stky):
case mmr_offset(rx_irqe):
case mmr_offset(tx_stat):
case mmr_offset(tx_stky):
case mmr_offset(tx_irqe):
case mmr_offset(mmc_rirqs):
case mmr_offset(mmc_rirqe):
case mmr_offset(mmc_tirqs):
case mmr_offset(mmc_tirqe):
case mmr_offset(mmc_ctl):
case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
dv_store_4 (dest, *valuep);
break;
case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
/* XXX: Only on some models; ignore for now. */
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static void
attach_bfin_emac_regs (struct hw *me, struct bfin_emac *emac)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_EMAC_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EMAC_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
emac->base = attach_address;
}
static struct dv_bfin *dma_tx;
static unsigned
bfin_emac_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
struct bfin_emac *emac = hw_data (me);
struct dv_bfin *dma = hw_data (emac->dma_master);
unsigned char *data = dest;
static bool flop; /* XXX: This sucks. */
bu16 len;
ssize_t ret;
HW_TRACE_DMA_READ ();
if (dma_tx == dma)
{
/* Handle the TX turn around and write the status. */
emac->tx_stat |= TX_OK;
emac->tx_stky |= TX_OK;
memcpy (data, &emac->tx_stat, 4);
dma->acked = true;
return 4;
}
if (!(emac->opmode & RE))
return 0;
if (!flop)
{
ssize_t pad_ret;
/* Outgoing DMA buffer has 16bit len prepended to it. */
data += 2;
/* This doesn't seem to work.
if (emac->sysctl & RXDWA)
{
memset (data, 0, 2);
data += 2;
} */
ret = read (emac->tap, data, nr_bytes);
if (ret < 0)
return 0;
ret += 4; /* include crc */
pad_ret = MAX (ret + 4, 64);
len = pad_ret;
memcpy (dest, &len, 2);
pad_ret = (pad_ret + 3) & ~3;
if (ret < pad_ret)
memset (data + ret, 0, pad_ret - ret);
pad_ret += 4;
/* XXX: Need to check -- u-boot doesn't look at this. */
if (emac->sysctl & RXCKS)
{
pad_ret += 4;
emac->rx_crc = 0;
}
ret = pad_ret;
/* XXX: Don't support promiscuous yet. */
emac->rx_stat |= RX_ACCEPT;
emac->rx_stat = (emac->rx_stat & ~RX_FRLEN) | len;
emac->rx_stat |= RX_COMP;
emac->rx_stky |= RX_COMP;
}
else
{
/* Write the RX status and crc info. */
emac->rx_stat |= RX_OK;
emac->rx_stky |= RX_OK;
ret = 4;
if (emac->sysctl & RXCKS)
{
memcpy (data, &emac->rx_crc, 4);
data += 4;
ret += 4;
}
memcpy (data, &emac->rx_stat, 4);
}
flop = !flop;
dma->acked = true;
return ret;
}
static unsigned
bfin_emac_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
struct bfin_emac *emac = hw_data (me);
struct dv_bfin *dma = hw_data (emac->dma_master);
const unsigned char *data = source;
bu16 len;
ssize_t ret;
HW_TRACE_DMA_WRITE ();
if (!(emac->opmode & TE))
return 0;
/* Incoming DMA buffer has 16bit len prepended to it. */
memcpy (&len, data, 2);
if (!len)
return 0;
ret = write (emac->tap, data + 2, len);
if (ret < 0)
return 0;
ret += 2;
emac->tx_stat |= TX_COMP;
emac->tx_stky |= TX_COMP;
dma_tx = dma;
dma->acked = true;
return ret;
}
static const struct hw_port_descriptor bfin_emac_ports[] = {
{ "tx", DV_PORT_TX, 0, output_port, },
{ "rx", DV_PORT_RX, 0, output_port, },
{ "stat", DV_PORT_STAT, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
bfin_emac_attach_address_callback (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client)
{
const hw_unit *unit = hw_unit_address (client);
HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
/* NOTE: At preset the space is assumed to be zero. Perhaphs the
space should be mapped onto something for instance: space0 -
unified memory; space1 - IO memory; ... */
sim_core_attach (hw_system (me),
NULL, /*cpu*/
level + 10 + unit->cells[unit->nr_cells - 1],
access_read_write_exec,
space, addr,
nr_bytes,
0, /* modulo */
client,
NULL);
}
static void
bfin_emac_delete (struct hw *me)
{
struct bfin_emac *emac = hw_data (me);
close (emac->tap);
}
static void
bfin_emac_tap_init (struct hw *me)
{
#if WITH_TUN
struct bfin_emac *emac = hw_data (me);
const hw_unit *unit;
int flags;
unit = hw_unit_address (me);
emac->tap = open ("/dev/net/tun", O_RDWR);
if (emac->tap == -1)
{
HW_TRACE ((me, "unable to open /dev/net/tun: %s", strerror (errno)));
return;
}
memset (&emac->ifr, 0, sizeof (emac->ifr));
emac->ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strcpy (emac->ifr.ifr_name, "tap-gdb");
flags = 1 * 1024 * 1024;
if (ioctl (emac->tap, TUNSETIFF, &emac->ifr) < 0
#ifdef TUNSETNOCSUM
|| ioctl (emac->tap, TUNSETNOCSUM) < 0
#endif
#ifdef TUNSETSNDBUF
|| ioctl (emac->tap, TUNSETSNDBUF, &flags) < 0
#endif
)
{
HW_TRACE ((me, "tap ioctl setup failed: %s", strerror (errno)));
close (emac->tap);
return;
}
flags = fcntl (emac->tap, F_GETFL);
fcntl (emac->tap, F_SETFL, flags | O_NONBLOCK);
#endif
}
static void
bfin_emac_finish (struct hw *me)
{
struct bfin_emac *emac;
emac = HW_ZALLOC (me, struct bfin_emac);
set_hw_data (me, emac);
set_hw_io_read_buffer (me, bfin_emac_io_read_buffer);
set_hw_io_write_buffer (me, bfin_emac_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_emac_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_emac_dma_write_buffer);
set_hw_ports (me, bfin_emac_ports);
set_hw_attach_address (me, bfin_emac_attach_address_callback);
set_hw_delete (me, bfin_emac_delete);
attach_bfin_emac_regs (me, emac);
/* Initialize the EMAC. */
emac->addrlo = 0xffffffff;
emac->addrhi = 0x0000ffff;
emac->vlan1 = 0x0000ffff;
emac->vlan2 = 0x0000ffff;
emac->sysctl = 0x00003f00;
emac->mmc_ctl = 0x0000000a;
bfin_emac_tap_init (me);
}
const struct hw_descriptor dv_bfin_emac_descriptor[] = {
{"bfin_emac", bfin_emac_finish,},
{NULL, NULL},
};

61
sim/bfin/dv-bfin_emac.h Normal file
View File

@ -0,0 +1,61 @@
/* Blackfin Ethernet Media Access Controller (EMAC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_EMAC_H
#define DV_BFIN_EMAC_H
#define BFIN_MMR_EMAC_BASE 0xFFC03000
#define BFIN_MMR_EMAC_SIZE 0x200
/* EMAC_OPMODE Masks */
#define RE (1 << 0)
#define ASTP (1 << 1)
#define PR (1 << 7)
#define TE (1 << 16)
/* EMAC_STAADD Masks */
#define STABUSY (1 << 0)
#define STAOP (1 << 1)
#define STADISPRE (1 << 2)
#define STAIE (1 << 3)
#define REGAD_SHIFT 6
#define REGAD_MASK (0x1f << REGAD_SHIFT)
#define REGAD(val) (((val) & REGAD_MASK) >> REGAD_SHIFT)
#define PHYAD_SHIFT 11
#define PHYAD_MASK (0x1f << PHYAD_SHIFT)
#define PHYAD(val) (((val) & PHYAD_MASK) >> PHYAD_SHIFT)
/* EMAC_SYSCTL Masks */
#define PHYIE (1 << 0)
#define RXDWA (1 << 1)
#define RXCKS (1 << 2)
#define TXDWA (1 << 4)
/* EMAC_RX_STAT Masks */
#define RX_FRLEN 0x7ff
#define RX_COMP (1 << 12)
#define RX_OK (1 << 13)
#define RX_ACCEPT (1 << 31)
/* EMAC_TX_STAT Masks */
#define TX_COMP (1 << 0)
#define TX_OK (1 << 1)
#endif

271
sim/bfin/dv-bfin_eppi.c Normal file
View File

@ -0,0 +1,271 @@
/* Blackfin Enhanced Parallel Port Interface (EPPI) model
For "new style" PPIs on BF54x/etc... parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_eppi.h"
#include "gui.h"
/* XXX: TX is merely a stub. */
struct bfin_eppi
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* GUI state. */
void *gui_state;
int color;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(status);
bu16 BFIN_MMR_16(hcount);
bu16 BFIN_MMR_16(hdelay);
bu16 BFIN_MMR_16(vcount);
bu16 BFIN_MMR_16(vdelay);
bu16 BFIN_MMR_16(frame);
bu16 BFIN_MMR_16(line);
bu16 BFIN_MMR_16(clkdiv);
bu32 control, fs1w_hbl, fs1p_avpl, fsw2_lvb, fs2p_lavf, clip, err;
};
#define mmr_base() offsetof(struct bfin_eppi, status)
#define mmr_offset(mmr) (offsetof(struct bfin_eppi, mmr) - mmr_base())
static const char * const mmr_names[] = {
"EPPI_STATUS", "EPPI_HCOUNT", "EPPI_HDELAY", "EPPI_VCOUNT", "EPPI_VDELAY",
"EPPI_FRAME", "EPPI_LINE", "EPPI_CLKDIV", "EPPI_CONTROL", "EPPI_FS1W_HBL",
"EPPI_FS1P_AVPL", "EPPI_FS2W_LVB", "EPPI_FS2P_LAVF", "EPPI_CLIP", "EPPI_ERR",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static void
bfin_eppi_gui_setup (struct bfin_eppi *eppi)
{
/* If we are in RX mode, nothing to do. */
if (!(eppi->control & PORT_DIR))
return;
eppi->gui_state = bfin_gui_setup (eppi->gui_state,
eppi->control & PORT_EN,
eppi->hcount,
eppi->vcount,
eppi->color);
}
static unsigned
bfin_eppi_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_eppi *eppi = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - eppi->base;
valuep = (void *)((unsigned long)eppi + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(status):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
dv_w1c_2 (value16p, value, 0);
break;
case mmr_offset(hcount):
case mmr_offset(hdelay):
case mmr_offset(vcount):
case mmr_offset(vdelay):
case mmr_offset(frame):
case mmr_offset(line):
case mmr_offset(clkdiv):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
*value16p = value;
break;
case mmr_offset(control):
*value32p = value;
bfin_eppi_gui_setup (eppi);
break;
case mmr_offset(fs1w_hbl):
case mmr_offset(fs1p_avpl):
case mmr_offset(fsw2_lvb):
case mmr_offset(fs2p_lavf):
case mmr_offset(clip):
case mmr_offset(err):
dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
*value32p = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_eppi_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_eppi *eppi = hw_data (me);
bu32 mmr_off;
bu16 *value16p;
bu32 *value32p;
void *valuep;
mmr_off = addr - eppi->base;
valuep = (void *)((unsigned long)eppi + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(status):
case mmr_offset(hcount):
case mmr_offset(hdelay):
case mmr_offset(vcount):
case mmr_offset(vdelay):
case mmr_offset(frame):
case mmr_offset(line):
case mmr_offset(clkdiv):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
case mmr_offset(control):
case mmr_offset(fs1w_hbl):
case mmr_offset(fs1p_avpl):
case mmr_offset(fsw2_lvb):
case mmr_offset(fs2p_lavf):
case mmr_offset(clip):
case mmr_offset(err):
dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
dv_store_4 (dest, *value32p);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bfin_eppi_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
HW_TRACE_DMA_READ ();
return 0;
}
static unsigned
bfin_eppi_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
struct bfin_eppi *eppi = hw_data (me);
HW_TRACE_DMA_WRITE ();
return bfin_gui_update (eppi->gui_state, source, nr_bytes);
}
static const struct hw_port_descriptor bfin_eppi_ports[] = {
{ "stat", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_eppi_regs (struct hw *me, struct bfin_eppi *eppi)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_EPPI_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EPPI_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
eppi->base = attach_address;
}
static void
bfin_eppi_finish (struct hw *me)
{
struct bfin_eppi *eppi;
const char *color;
eppi = HW_ZALLOC (me, struct bfin_eppi);
set_hw_data (me, eppi);
set_hw_io_read_buffer (me, bfin_eppi_io_read_buffer);
set_hw_io_write_buffer (me, bfin_eppi_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_eppi_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_eppi_dma_write_buffer);
set_hw_ports (me, bfin_eppi_ports);
attach_bfin_eppi_regs (me, eppi);
/* Initialize the EPPI. */
if (hw_find_property (me, "color"))
color = hw_find_string_property (me, "color");
else
color = NULL;
eppi->color = bfin_gui_color (color);
}
const struct hw_descriptor dv_bfin_eppi_descriptor[] = {
{"bfin_eppi", bfin_eppi_finish,},
{NULL, NULL},
};

30
sim/bfin/dv-bfin_eppi.h Normal file
View File

@ -0,0 +1,30 @@
/* Blackfin Enhanced Parallel Port Interface (EPPI) model
For "new style" PPIs on BF54x/etc... parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_EPPI_H
#define DV_BFIN_EPPI_H
#include "dv-bfin_ppi.h"
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_EPPI_SIZE 0x40
#endif

153
sim/bfin/dv-bfin_evt.c Normal file
View File

@ -0,0 +1,153 @@
/* Blackfin Event Vector Table (EVT) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_cec.h"
#include "dv-bfin_evt.h"
struct bfin_evt
{
bu32 base;
/* Order after here is important -- matches hardware MMR layout. */
bu32 evt[16];
};
#define mmr_base() offsetof(struct bfin_evt, evt[0])
#define mmr_offset(mmr) (offsetof(struct bfin_evt, mmr) - mmr_base())
static const char * const mmr_names[] = {
"EVT0", "EVT1", "EVT2", "EVT3", "EVT4", "EVT5", "EVT6", "EVT7", "EVT8",
"EVT9", "EVT10", "EVT11", "EVT12", "EVT13", "EVT14", "EVT15",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_evt_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_evt *evt = hw_data (me);
bu32 mmr_off;
bu32 value;
value = dv_load_4 (source);
mmr_off = addr - evt->base;
HW_TRACE_WRITE ();
evt->evt[mmr_off / 4] = value;
return nr_bytes;
}
static unsigned
bfin_evt_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_evt *evt = hw_data (me);
bu32 mmr_off;
bu32 value;
mmr_off = addr - evt->base;
HW_TRACE_READ ();
value = evt->evt[mmr_off / 4];
dv_store_4 (dest, value);
return nr_bytes;
}
static void
attach_bfin_evt_regs (struct hw *me, struct bfin_evt *evt)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_EVT_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_EVT_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
evt->base = attach_address;
}
static void
bfin_evt_finish (struct hw *me)
{
struct bfin_evt *evt;
evt = HW_ZALLOC (me, struct bfin_evt);
set_hw_data (me, evt);
set_hw_io_read_buffer (me, bfin_evt_io_read_buffer);
set_hw_io_write_buffer (me, bfin_evt_io_write_buffer);
attach_bfin_evt_regs (me, evt);
}
const struct hw_descriptor dv_bfin_evt_descriptor[] = {
{"bfin_evt", bfin_evt_finish,},
{NULL, NULL},
};
#define EVT_STATE(cpu) DV_STATE_CACHED (cpu, evt)
void
cec_set_evt (SIM_CPU *cpu, int ivg, bu32 handler_addr)
{
if (ivg > IVG15 || ivg < 0)
sim_io_error (CPU_STATE (cpu), "%s: ivg %i out of range !", __func__, ivg);
EVT_STATE (cpu)->evt[ivg] = handler_addr;
}
bu32
cec_get_evt (SIM_CPU *cpu, int ivg)
{
if (ivg > IVG15 || ivg < 0)
sim_io_error (CPU_STATE (cpu), "%s: ivg %i out of range !", __func__, ivg);
return EVT_STATE (cpu)->evt[ivg];
}
bu32
cec_get_reset_evt (SIM_CPU *cpu)
{
/* XXX: This should tail into the model to get via BMODE pins. */
return 0xef000000;
}

31
sim/bfin/dv-bfin_evt.h Normal file
View File

@ -0,0 +1,31 @@
/* Blackfin Event Vector Table (EVT) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_EVT_H
#define DV_BFIN_EVT_H
#define BFIN_COREMMR_EVT_BASE 0xFFE02000
#define BFIN_COREMMR_EVT_SIZE (4 * 16)
extern void cec_set_evt (SIM_CPU *, int ivg, bu32 handler_addr);
extern bu32 cec_get_evt (SIM_CPU *, int ivg);
extern bu32 cec_get_reset_evt (SIM_CPU *);
#endif

183
sim/bfin/dv-bfin_gptimer.c Normal file
View File

@ -0,0 +1,183 @@
/* Blackfin General Purpose Timers (GPtimer) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_gptimer.h"
/* XXX: This is merely a stub. */
struct bfin_gptimer
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(config);
bu32 counter, period, width;
};
#define mmr_base() offsetof(struct bfin_gptimer, config)
#define mmr_offset(mmr) (offsetof(struct bfin_gptimer, mmr) - mmr_base())
static const char * const mmr_names[] = {
"TIMER_CONFIG", "TIMER_COUNTER", "TIMER_PERIOD", "TIMER_WIDTH",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_gptimer_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_gptimer *gptimer = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - gptimer->base;
valuep = (void *)((unsigned long)gptimer + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(config):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
*value16p = value;
break;
case mmr_offset(counter):
case mmr_offset(period):
case mmr_offset(width):
dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
*value32p = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_gptimer_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_gptimer *gptimer = hw_data (me);
bu32 mmr_off;
bu16 *value16p;
bu32 *value32p;
void *valuep;
mmr_off = addr - gptimer->base;
valuep = (void *)((unsigned long)gptimer + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(config):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
case mmr_offset(counter):
case mmr_offset(period):
case mmr_offset(width):
dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
dv_store_4 (dest, *value32p);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static const struct hw_port_descriptor bfin_gptimer_ports[] = {
{ "stat", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_gptimer_regs (struct hw *me, struct bfin_gptimer *gptimer)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_GPTIMER_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_GPTIMER_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
gptimer->base = attach_address;
}
static void
bfin_gptimer_finish (struct hw *me)
{
struct bfin_gptimer *gptimer;
gptimer = HW_ZALLOC (me, struct bfin_gptimer);
set_hw_data (me, gptimer);
set_hw_io_read_buffer (me, bfin_gptimer_io_read_buffer);
set_hw_io_write_buffer (me, bfin_gptimer_io_write_buffer);
set_hw_ports (me, bfin_gptimer_ports);
attach_bfin_gptimer_regs (me, gptimer);
}
const struct hw_descriptor dv_bfin_gptimer_descriptor[] = {
{"bfin_gptimer", bfin_gptimer_finish,},
{NULL, NULL},
};

View File

@ -0,0 +1,27 @@
/* Blackfin General Purpose Timers (GPtimer) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_GPTIMER_H
#define DV_BFIN_GPTIMER_H
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_GPTIMER_SIZE (4 * 4)
#endif

157
sim/bfin/dv-bfin_jtag.c Normal file
View File

@ -0,0 +1,157 @@
/* Blackfin JTAG model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_jtag.h"
/* XXX: This is mostly a stub. There are more registers, but they're only
accessible via the JTAG scan chain and not the MMR interface. */
struct bfin_jtag
{
bu32 base;
/* Order after here is important -- matches hardware MMR layout. */
bu32 dspid;
bu32 _pad0;
bu32 dbgstat;
};
#define mmr_base() offsetof(struct bfin_jtag, dspid)
#define mmr_offset(mmr) (offsetof(struct bfin_jtag, mmr) - mmr_base())
static const char * const mmr_names[] = {
"DSPID", NULL, "DBGSTAT",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static unsigned
bfin_jtag_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_jtag *jtag = hw_data (me);
bu32 mmr_off;
bu32 value;
bu32 *valuep;
value = dv_load_4 (source);
mmr_off = addr - jtag->base;
valuep = (void *)((unsigned long)jtag + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(dbgstat):
dv_w1c_4 (valuep, value, ~0xc);
break;
case mmr_offset(dspid):
/* Discard writes to these. */
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_jtag_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_jtag *jtag = hw_data (me);
bu32 mmr_off;
bu32 value;
bu32 *valuep;
mmr_off = addr - jtag->base;
valuep = (void *)((unsigned long)jtag + mmr_base() + mmr_off);
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(dbgstat):
case mmr_offset(dspid):
value = *valuep;
break;
default:
while (1) /* Core MMRs -> exception -> doesn't return. */
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
dv_store_4 (dest, value);
return nr_bytes;
}
static void
attach_bfin_jtag_regs (struct hw *me, struct bfin_jtag *jtag)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_JTAG_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_JTAG_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
jtag->base = attach_address;
}
static void
bfin_jtag_finish (struct hw *me)
{
struct bfin_jtag *jtag;
jtag = HW_ZALLOC (me, struct bfin_jtag);
set_hw_data (me, jtag);
set_hw_io_read_buffer (me, bfin_jtag_io_read_buffer);
set_hw_io_write_buffer (me, bfin_jtag_io_write_buffer);
attach_bfin_jtag_regs (me, jtag);
/* Initialize the JTAG state. */
jtag->dspid = bfin_model_get_dspid (hw_system (me));
}
const struct hw_descriptor dv_bfin_jtag_descriptor[] = {
{"bfin_jtag", bfin_jtag_finish,},
{NULL, NULL},
};

27
sim/bfin/dv-bfin_jtag.h Normal file
View File

@ -0,0 +1,27 @@
/* Blackfin JTAG model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_JTAG_H
#define DV_BFIN_JTAG_H
#define BFIN_COREMMR_JTAG_BASE 0xFFE05000
#define BFIN_COREMMR_JTAG_SIZE (4 * 3)
#endif

574
sim/bfin/dv-bfin_mmu.c Normal file
View File

@ -0,0 +1,574 @@
/* Blackfin Memory Management Unit (MMU) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "sim-options.h"
#include "devices.h"
#include "dv-bfin_mmu.h"
#include "dv-bfin_cec.h"
/* XXX: Should this really be two blocks of registers ? PRM describes
these as two Content Addressable Memory (CAM) blocks. */
struct bfin_mmu
{
bu32 base;
/* Order after here is important -- matches hardware MMR layout. */
bu32 sram_base_address;
bu32 dmem_control, dcplb_fault_status, dcplb_fault_addr;
char _dpad0[0x100 - 0x0 - (4 * 4)];
bu32 dcplb_addr[16];
char _dpad1[0x200 - 0x100 - (4 * 16)];
bu32 dcplb_data[16];
char _dpad2[0x300 - 0x200 - (4 * 16)];
bu32 dtest_command;
char _dpad3[0x400 - 0x300 - (4 * 1)];
bu32 dtest_data[2];
char _dpad4[0x1000 - 0x400 - (4 * 2)];
bu32 idk; /* Filler MMR; hardware simply ignores. */
bu32 imem_control, icplb_fault_status, icplb_fault_addr;
char _ipad0[0x100 - 0x0 - (4 * 4)];
bu32 icplb_addr[16];
char _ipad1[0x200 - 0x100 - (4 * 16)];
bu32 icplb_data[16];
char _ipad2[0x300 - 0x200 - (4 * 16)];
bu32 itest_command;
char _ipad3[0x400 - 0x300 - (4 * 1)];
bu32 itest_data[2];
};
#define mmr_base() offsetof(struct bfin_mmu, sram_base_address)
#define mmr_offset(mmr) (offsetof(struct bfin_mmu, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const mmr_names[BFIN_COREMMR_MMU_SIZE / 4] = {
"SRAM_BASE_ADDRESS", "DMEM_CONTROL", "DCPLB_FAULT_STATUS", "DCPLB_FAULT_ADDR",
[mmr_idx (dcplb_addr[0])] = "DCPLB_ADDR0",
"DCPLB_ADDR1", "DCPLB_ADDR2", "DCPLB_ADDR3", "DCPLB_ADDR4", "DCPLB_ADDR5",
"DCPLB_ADDR6", "DCPLB_ADDR7", "DCPLB_ADDR8", "DCPLB_ADDR9", "DCPLB_ADDR10",
"DCPLB_ADDR11", "DCPLB_ADDR12", "DCPLB_ADDR13", "DCPLB_ADDR14", "DCPLB_ADDR15",
[mmr_idx (dcplb_data[0])] = "DCPLB_DATA0",
"DCPLB_DATA1", "DCPLB_DATA2", "DCPLB_DATA3", "DCPLB_DATA4", "DCPLB_DATA5",
"DCPLB_DATA6", "DCPLB_DATA7", "DCPLB_DATA8", "DCPLB_DATA9", "DCPLB_DATA10",
"DCPLB_DATA11", "DCPLB_DATA12", "DCPLB_DATA13", "DCPLB_DATA14", "DCPLB_DATA15",
[mmr_idx (dtest_command)] = "DTEST_COMMAND",
[mmr_idx (dtest_data[0])] = "DTEST_DATA0", "DTEST_DATA1",
[mmr_idx (imem_control)] = "IMEM_CONTROL", "ICPLB_FAULT_STATUS", "ICPLB_FAULT_ADDR",
[mmr_idx (icplb_addr[0])] = "ICPLB_ADDR0",
"ICPLB_ADDR1", "ICPLB_ADDR2", "ICPLB_ADDR3", "ICPLB_ADDR4", "ICPLB_ADDR5",
"ICPLB_ADDR6", "ICPLB_ADDR7", "ICPLB_ADDR8", "ICPLB_ADDR9", "ICPLB_ADDR10",
"ICPLB_ADDR11", "ICPLB_ADDR12", "ICPLB_ADDR13", "ICPLB_ADDR14", "ICPLB_ADDR15",
[mmr_idx (icplb_data[0])] = "ICPLB_DATA0",
"ICPLB_DATA1", "ICPLB_DATA2", "ICPLB_DATA3", "ICPLB_DATA4", "ICPLB_DATA5",
"ICPLB_DATA6", "ICPLB_DATA7", "ICPLB_DATA8", "ICPLB_DATA9", "ICPLB_DATA10",
"ICPLB_DATA11", "ICPLB_DATA12", "ICPLB_DATA13", "ICPLB_DATA14", "ICPLB_DATA15",
[mmr_idx (itest_command)] = "ITEST_COMMAND",
[mmr_idx (itest_data[0])] = "ITEST_DATA0", "ITEST_DATA1",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static bool bfin_mmu_skip_cplbs = false;
static unsigned
bfin_mmu_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_mmu *mmu = hw_data (me);
bu32 mmr_off;
bu32 value;
bu32 *valuep;
value = dv_load_4 (source);
mmr_off = addr - mmu->base;
valuep = (void *)((unsigned long)mmu + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(dmem_control):
case mmr_offset(imem_control):
/* XXX: IMC/DMC bit should add/remove L1 cache regions ... */
case mmr_offset(dtest_data[0]) ... mmr_offset(dtest_data[1]):
case mmr_offset(itest_data[0]) ... mmr_offset(itest_data[1]):
case mmr_offset(dcplb_addr[0]) ... mmr_offset(dcplb_addr[15]):
case mmr_offset(dcplb_data[0]) ... mmr_offset(dcplb_data[15]):
case mmr_offset(icplb_addr[0]) ... mmr_offset(icplb_addr[15]):
case mmr_offset(icplb_data[0]) ... mmr_offset(icplb_data[15]):
*valuep = value;
break;
case mmr_offset(sram_base_address):
case mmr_offset(dcplb_fault_status):
case mmr_offset(dcplb_fault_addr):
case mmr_offset(idk):
case mmr_offset(icplb_fault_status):
case mmr_offset(icplb_fault_addr):
/* Discard writes to these. */
break;
case mmr_offset(itest_command):
/* XXX: Not supported atm. */
if (value)
hw_abort (me, "ITEST_COMMAND unimplemented");
break;
case mmr_offset(dtest_command):
/* Access L1 memory indirectly. */
*valuep = value;
if (value)
{
bu32 addr = mmu->sram_base_address |
((value >> (26 - 11)) & (1 << 11)) | /* addr bit 11 (Way0/Way1) */
((value >> (24 - 21)) & (1 << 21)) | /* addr bit 21 (Data/Inst) */
((value >> (23 - 15)) & (1 << 15)) | /* addr bit 15 (Data Bank) */
((value >> (16 - 12)) & (3 << 12)) | /* addr bits 13:12 (Subbank) */
(value & 0x47F8); /* addr bits 14 & 10:3 */
if (!(value & TEST_DATA_ARRAY))
hw_abort (me, "DTEST_COMMAND tag array unimplemented");
if (value & 0xfa7cb801)
hw_abort (me, "DTEST_COMMAND bits undefined");
if (value & TEST_WRITE)
sim_write (hw_system (me), addr, (void *)mmu->dtest_data, 8);
else
sim_read (hw_system (me), addr, (void *)mmu->dtest_data, 8);
}
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_mmu_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_mmu *mmu = hw_data (me);
bu32 mmr_off;
bu32 *valuep;
mmr_off = addr - mmu->base;
valuep = (void *)((unsigned long)mmu + mmr_base() + mmr_off);
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(dmem_control):
case mmr_offset(imem_control):
case mmr_offset(dtest_command):
case mmr_offset(dtest_data[0]) ... mmr_offset(dtest_data[2]):
case mmr_offset(itest_command):
case mmr_offset(itest_data[0]) ... mmr_offset(itest_data[2]):
/* XXX: should do something here. */
case mmr_offset(dcplb_addr[0]) ... mmr_offset(dcplb_addr[15]):
case mmr_offset(dcplb_data[0]) ... mmr_offset(dcplb_data[15]):
case mmr_offset(icplb_addr[0]) ... mmr_offset(icplb_addr[15]):
case mmr_offset(icplb_data[0]) ... mmr_offset(icplb_data[15]):
case mmr_offset(sram_base_address):
case mmr_offset(dcplb_fault_status):
case mmr_offset(dcplb_fault_addr):
case mmr_offset(idk):
case mmr_offset(icplb_fault_status):
case mmr_offset(icplb_fault_addr):
dv_store_4 (dest, *valuep);
break;
default:
while (1) /* Core MMRs -> exception -> doesn't return. */
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static void
attach_bfin_mmu_regs (struct hw *me, struct bfin_mmu *mmu)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_MMU_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_MMU_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
mmu->base = attach_address;
}
static void
bfin_mmu_finish (struct hw *me)
{
struct bfin_mmu *mmu;
mmu = HW_ZALLOC (me, struct bfin_mmu);
set_hw_data (me, mmu);
set_hw_io_read_buffer (me, bfin_mmu_io_read_buffer);
set_hw_io_write_buffer (me, bfin_mmu_io_write_buffer);
attach_bfin_mmu_regs (me, mmu);
/* Initialize the MMU. */
mmu->sram_base_address = 0xff800000 - 0;
/*(4 * 1024 * 1024 * CPU_INDEX (hw_system_cpu (me)));*/
mmu->dmem_control = 0x00000001;
mmu->imem_control = 0x00000001;
}
const struct hw_descriptor dv_bfin_mmu_descriptor[] = {
{"bfin_mmu", bfin_mmu_finish,},
{NULL, NULL},
};
/* Device option parsing. */
static DECLARE_OPTION_HANDLER (bfin_mmu_option_handler);
enum {
OPTION_MMU_SKIP_TABLES = OPTION_START,
};
const OPTION bfin_mmu_options[] =
{
{ {"mmu-skip-cplbs", no_argument, NULL, OPTION_MMU_SKIP_TABLES },
'\0', NULL, "Skip parsing of CPLB tables (big speed increase)",
bfin_mmu_option_handler, NULL },
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
};
static SIM_RC
bfin_mmu_option_handler (SIM_DESC sd, sim_cpu *current_cpu, int opt,
char *arg, int is_command)
{
switch (opt)
{
case OPTION_MMU_SKIP_TABLES:
bfin_mmu_skip_cplbs = true;
return SIM_RC_OK;
default:
sim_io_eprintf (sd, "Unknown Blackfin MMU option %d\n", opt);
return SIM_RC_FAIL;
}
}
#define MMU_STATE(cpu) DV_STATE_CACHED (cpu, mmu)
static void
_mmu_log_ifault (SIM_CPU *cpu, struct bfin_mmu *mmu, bu32 pc, bool supv)
{
mmu->icplb_fault_addr = pc;
mmu->icplb_fault_status = supv << 17;
}
void
mmu_log_ifault (SIM_CPU *cpu)
{
_mmu_log_ifault (cpu, MMU_STATE (cpu), PCREG, cec_get_ivg (cpu) >= 0);
}
static void
_mmu_log_fault (SIM_CPU *cpu, struct bfin_mmu *mmu, bu32 addr, bool write,
bool inst, bool miss, bool supv, bool dag1, bu32 faults)
{
bu32 *fault_status, *fault_addr;
/* No logging in non-OS mode. */
if (!mmu)
return;
fault_status = inst ? &mmu->icplb_fault_status : &mmu->dcplb_fault_status;
fault_addr = inst ? &mmu->icplb_fault_addr : &mmu->dcplb_fault_addr;
/* ICPLB regs always get updated. */
if (!inst)
_mmu_log_ifault (cpu, mmu, PCREG, supv);
*fault_addr = addr;
*fault_status =
(miss << 19) |
(dag1 << 18) |
(supv << 17) |
(write << 16) |
faults;
}
static void
_mmu_process_fault (SIM_CPU *cpu, struct bfin_mmu *mmu, bu32 addr, bool write,
bool inst, bool unaligned, bool miss, bool supv, bool dag1)
{
int excp;
/* See order in mmu_check_addr() */
if (unaligned)
excp = inst ? VEC_MISALI_I : VEC_MISALI_D;
else if (addr >= BFIN_SYSTEM_MMR_BASE)
excp = VEC_ILL_RES;
else if (!mmu)
excp = inst ? VEC_CPLB_I_M : VEC_CPLB_M;
else
{
/* Misses are hardware errors. */
cec_hwerr (cpu, HWERR_EXTERN_ADDR);
return;
}
_mmu_log_fault (cpu, mmu, addr, write, inst, miss, supv, dag1, 0);
cec_exception (cpu, excp);
}
void
mmu_process_fault (SIM_CPU *cpu, bu32 addr, bool write, bool inst,
bool unaligned, bool miss)
{
SIM_DESC sd = CPU_STATE (cpu);
struct bfin_mmu *mmu;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
mmu = NULL;
else
mmu = MMU_STATE (cpu);
_mmu_process_fault (cpu, mmu, addr, write, inst, unaligned, miss,
cec_is_supervisor_mode (cpu),
BFIN_CPU_STATE.multi_pc == PCREG + 6);
}
/* Return values:
-2: no known problems
-1: valid
0: miss
1: protection violation
2: multiple hits
3: unaligned
4: miss; hwerr */
static int
mmu_check_implicit_addr (SIM_CPU *cpu, bu32 addr, bool inst, int size,
bool supv, bool dag1)
{
bool l1 = ((addr & 0xFF000000) == 0xFF000000);
bu32 amask = (addr & 0xFFF00000);
if (addr & (size - 1))
return 3;
/* MMRs may never be executable or accessed from usermode. */
if (addr >= BFIN_SYSTEM_MMR_BASE)
{
if (inst)
return 0;
else if (!supv || dag1)
return 1;
else
return -1;
}
else if (inst)
{
/* Some regions are not executable. */
/* XXX: Should this be in the model data ? Core B 561 ? */
if (l1)
return (amask == 0xFFA00000) ? -1 : 1;
}
else
{
/* Some regions are not readable. */
/* XXX: Should this be in the model data ? Core B 561 ? */
if (l1)
return (amask != 0xFFA00000) ? -1 : 4;
}
return -2;
}
/* Exception order per the PRM (first has highest):
Inst Multiple CPLB Hits
Inst Misaligned Access
Inst Protection Violation
Inst CPLB Miss
Only the alignment matters in non-OS mode though. */
static int
_mmu_check_addr (SIM_CPU *cpu, bu32 addr, bool write, bool inst, int size)
{
SIM_DESC sd = CPU_STATE (cpu);
struct bfin_mmu *mmu;
bu32 *fault_status, *fault_addr, *mem_control, *cplb_addr, *cplb_data;
bu32 faults;
bool supv, do_excp, dag1;
int i, hits;
supv = cec_is_supervisor_mode (cpu);
dag1 = (BFIN_CPU_STATE.multi_pc == PCREG + 6);
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT || bfin_mmu_skip_cplbs)
{
int ret = mmu_check_implicit_addr (cpu, addr, inst, size, supv, dag1);
/* Valid hits and misses are OK in non-OS envs. */
if (ret < 0)
return 0;
_mmu_process_fault (cpu, NULL, addr, write, inst, (ret == 3), false, supv, dag1);
}
mmu = MMU_STATE (cpu);
fault_status = inst ? &mmu->icplb_fault_status : &mmu->dcplb_fault_status;
fault_addr = inst ? &mmu->icplb_fault_addr : &mmu->dcplb_fault_addr;
mem_control = inst ? &mmu->imem_control : &mmu->dmem_control;
cplb_addr = inst ? &mmu->icplb_addr[0] : &mmu->dcplb_addr[0];
cplb_data = inst ? &mmu->icplb_data[0] : &mmu->dcplb_data[0];
faults = 0;
hits = 0;
do_excp = false;
/* CPLBs disabled -> little to do. */
if (!(*mem_control & ENCPLB))
{
hits = 1;
goto implicit_check;
}
/* Check all the CPLBs first. */
for (i = 0; i < 16; ++i)
{
const bu32 pages[4] = { 0x400, 0x1000, 0x100000, 0x400000 };
bu32 addr_lo, addr_hi;
/* Skip invalid entries. */
if (!(cplb_data[i] & CPLB_VALID))
continue;
/* See if this entry covers this address. */
addr_lo = cplb_addr[i];
addr_hi = cplb_addr[i] + pages[(cplb_data[i] & PAGE_SIZE) >> 16];
if (addr < addr_lo || addr >= addr_hi)
continue;
++hits;
faults |= (1 << i);
if (write)
{
if (!supv && !(cplb_data[i] & CPLB_USER_WR))
do_excp = true;
if (supv && !(cplb_data[i] & CPLB_SUPV_WR))
do_excp = true;
if ((cplb_data[i] & (CPLB_WT | CPLB_L1_CHBL | CPLB_DIRTY)) == CPLB_L1_CHBL)
do_excp = true;
}
else
{
if (!supv && !(cplb_data[i] & CPLB_USER_RD))
do_excp = true;
}
}
/* Handle default/implicit CPLBs. */
if (!do_excp && hits < 2)
{
int ihits;
implicit_check:
ihits = mmu_check_implicit_addr (cpu, addr, inst, size, supv, dag1);
switch (ihits)
{
/* No faults and one match -> good to go. */
case -1: return 0;
case -2:
if (hits == 1)
return 0;
break;
case 4:
cec_hwerr (cpu, HWERR_EXTERN_ADDR);
return 0;
default:
hits = ihits;
}
}
else
/* Normalize hit count so hits==2 is always multiple hit exception. */
hits = MIN (2, hits);
_mmu_log_fault (cpu, mmu, addr, write, inst, hits == 0, supv, dag1, faults);
if (inst)
{
int iexcps[] = { VEC_CPLB_I_M, VEC_CPLB_I_VL, VEC_CPLB_I_MHIT, VEC_MISALI_I };
return iexcps[hits];
}
else
{
int dexcps[] = { VEC_CPLB_M, VEC_CPLB_VL, VEC_CPLB_MHIT, VEC_MISALI_D };
return dexcps[hits];
}
}
void
mmu_check_addr (SIM_CPU *cpu, bu32 addr, bool write, bool inst, int size)
{
int excp = _mmu_check_addr (cpu, addr, write, inst, size);
if (excp)
cec_exception (cpu, excp);
}
void
mmu_check_cache_addr (SIM_CPU *cpu, bu32 addr, bool write, bool inst)
{
bu32 cacheaddr;
int excp;
cacheaddr = addr & ~(BFIN_L1_CACHE_BYTES - 1);
excp = _mmu_check_addr (cpu, cacheaddr, write, inst, BFIN_L1_CACHE_BYTES);
if (excp == 0)
return;
/* Most exceptions are ignored with cache funcs. */
/* XXX: Not sure if we should be ignoring CPLB misses. */
if (inst)
{
if (excp == VEC_CPLB_I_VL)
return;
}
else
{
if (excp == VEC_CPLB_VL)
return;
}
cec_exception (cpu, excp);
}

94
sim/bfin/dv-bfin_mmu.h Normal file
View File

@ -0,0 +1,94 @@
/* Blackfin Memory Management Unit (MMU) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_MMU_H
#define DV_BFIN_MMU_H
#define BFIN_COREMMR_MMU_BASE 0xFFE00000
#define BFIN_COREMMR_MMU_SIZE 0x2000
void mmu_check_addr (SIM_CPU *, bu32 addr, bool write, bool inst, int size);
void mmu_check_cache_addr (SIM_CPU *, bu32 addr, bool write, bool inst);
void mmu_process_fault (SIM_CPU *, bu32 addr, bool write, bool inst, bool unaligned, bool miss);
void mmu_log_ifault (SIM_CPU *);
/* MEM_CONTROL */
#define ENM (1 << 0)
#define ENCPLB (1 << 1)
#define MC (1 << 2)
#define ENDM ENM
#define ENDCPLB ENCPLB
#define DMC_AB_SRAM 0x0
#define DMC_AB_CACHE 0xc
#define DMC_ACACHE_BSRAM 0x8
/* CPLB_DATA */
#define CPLB_VALID (1 << 0)
#define CPLB_USER_RD (1 << 2)
#define CPLB_USER_WR (1 << 3)
#define CPLB_USER_RW (CPLB_USER_RD | CPLB_USER_WR)
#define CPLB_SUPV_WR (1 << 4)
#define CPLB_L1SRAM (1 << 5)
#define CPLB_DA0ACC (1 << 6)
#define CPLB_DIRTY (1 << 7)
#define CPLB_L1_CHBL (1 << 12)
#define CPLB_WT (1 << 14)
#define PAGE_SIZE (3 << 16)
#define PAGE_SIZE_1K (0 << 16)
#define PAGE_SIZE_4K (1 << 16)
#define PAGE_SIZE_1M (2 << 16)
#define PAGE_SIZE_4M (3 << 16)
/* CPLB_STATUS */
#define FAULT_CPLB0 (1 << 0)
#define FAULT_CPLB1 (1 << 1)
#define FAULT_CPLB2 (1 << 2)
#define FAULT_CPLB3 (1 << 3)
#define FAULT_CPLB4 (1 << 4)
#define FAULT_CPLB5 (1 << 5)
#define FAULT_CPLB6 (1 << 6)
#define FAULT_CPLB7 (1 << 7)
#define FAULT_CPLB8 (1 << 8)
#define FAULT_CPLB9 (1 << 9)
#define FAULT_CPLB10 (1 << 10)
#define FAULT_CPLB11 (1 << 11)
#define FAULT_CPLB12 (1 << 12)
#define FAULT_CPLB13 (1 << 13)
#define FAULT_CPLB14 (1 << 14)
#define FAULT_CPLB15 (1 << 15)
#define FAULT_READ (0 << 16)
#define FAULT_WRITE (1 << 16)
#define FAULT_USER (0 << 17)
#define FAULT_SUPV (1 << 17)
#define FAULT_DAG0 (0 << 18)
#define FAULT_DAG1 (1 << 18)
#define FAULT_ILLADDR (1 << 19)
/* DTEST_COMMAND */
#define TEST_READ (0 << 1)
#define TEST_WRITE (1 << 1)
#define TEST_TAG_ARRAY (0 << 2)
#define TEST_DATA_ARRAY (1 << 2)
#define TEST_DBANK (1 << 23)
#define TEST_DATA_SRAM (0 << 24)
#define TEST_INST_SRAM (1 << 24)
#endif

241
sim/bfin/dv-bfin_nfc.c Normal file
View File

@ -0,0 +1,241 @@
/* Blackfin NAND Flash Memory Controller (NFC) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_nfc.h"
/* XXX: This is merely a stub. */
struct bfin_nfc
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(ctl);
bu16 BFIN_MMR_16(stat);
bu16 BFIN_MMR_16(irqstat);
bu16 BFIN_MMR_16(irqmask);
bu16 BFIN_MMR_16(ecc0);
bu16 BFIN_MMR_16(ecc1);
bu16 BFIN_MMR_16(ecc2);
bu16 BFIN_MMR_16(ecc3);
bu16 BFIN_MMR_16(count);
bu16 BFIN_MMR_16(rst);
bu16 BFIN_MMR_16(pgctl);
bu16 BFIN_MMR_16(read);
bu32 _pad0[4];
bu16 BFIN_MMR_16(addr);
bu16 BFIN_MMR_16(cmd);
bu16 BFIN_MMR_16(data_wr);
bu16 BFIN_MMR_16(data_rd);
};
#define mmr_base() offsetof(struct bfin_nfc, ctl)
#define mmr_offset(mmr) (offsetof(struct bfin_nfc, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const mmr_names[] = {
"NFC_CTL", "NFC_STAT", "NFC_IRQSTAT", "NFC_IRQMASK", "NFC_ECC0", "NFC_ECC1",
"NFC_ECC2", "NFC_ECC3", "NFC_COUNT", "NFC_RST", "NFC_PGCTL", "NFC_READ",
[mmr_idx (addr)] = "NFC_ADDR", "NFC_CMD", "NFC_DATA_WR", "NFC_DATA_RD",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static unsigned
bfin_nfc_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_nfc *nfc = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *valuep;
value = dv_load_2 (source);
mmr_off = addr - nfc->base;
valuep = (void *)((unsigned long)nfc + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
switch (mmr_off)
{
case mmr_offset(ctl):
case mmr_offset(stat):
case mmr_offset(irqmask):
case mmr_offset(ecc0):
case mmr_offset(ecc1):
case mmr_offset(ecc2):
case mmr_offset(ecc3):
case mmr_offset(count):
case mmr_offset(rst):
case mmr_offset(pgctl):
case mmr_offset(read):
case mmr_offset(addr):
case mmr_offset(cmd):
case mmr_offset(data_wr):
*valuep = value;
break;
case mmr_offset(data_rd):
nfc->irqstat |= RD_RDY;
*valuep = value;
break;
case mmr_offset(irqstat):
dv_w1c_2 (valuep, value, 0);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_nfc_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_nfc *nfc = hw_data (me);
bu32 mmr_off;
bu16 *valuep;
mmr_off = addr - nfc->base;
valuep = (void *)((unsigned long)nfc + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
switch (mmr_off)
{
case mmr_offset(ctl):
case mmr_offset(stat):
case mmr_offset(irqstat):
case mmr_offset(irqmask):
case mmr_offset(ecc0):
case mmr_offset(ecc1):
case mmr_offset(ecc2):
case mmr_offset(ecc3):
case mmr_offset(count):
case mmr_offset(rst):
case mmr_offset(read):
dv_store_2 (dest, *valuep);
break;
case mmr_offset(pgctl):
case mmr_offset(addr):
case mmr_offset(cmd):
case mmr_offset(data_wr):
case mmr_offset(data_rd):
/* These regs are write only. */
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bfin_nfc_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
HW_TRACE_DMA_READ ();
return 0;
}
static unsigned
bfin_nfc_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
HW_TRACE_DMA_WRITE ();
return nr_bytes;
}
static const struct hw_port_descriptor bfin_nfc_ports[] = {
{ "stat", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_nfc_regs (struct hw *me, struct bfin_nfc *nfc)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_NFC_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_NFC_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
nfc->base = attach_address;
}
static void
bfin_nfc_finish (struct hw *me)
{
struct bfin_nfc *nfc;
nfc = HW_ZALLOC (me, struct bfin_nfc);
set_hw_data (me, nfc);
set_hw_io_read_buffer (me, bfin_nfc_io_read_buffer);
set_hw_io_write_buffer (me, bfin_nfc_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_nfc_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_nfc_dma_write_buffer);
set_hw_ports (me, bfin_nfc_ports);
attach_bfin_nfc_regs (me, nfc);
/* Initialize the NFC. */
nfc->ctl = 0x0200;
nfc->stat = 0x0011;
nfc->irqstat = 0x0004;
nfc->irqmask = 0x001F;
}
const struct hw_descriptor dv_bfin_nfc_descriptor[] = {
{"bfin_nfc", bfin_nfc_finish,},
{NULL, NULL},
};

41
sim/bfin/dv-bfin_nfc.h Normal file
View File

@ -0,0 +1,41 @@
/* Blackfin NAND Flash Memory Controller (NFC) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_NFC_H
#define DV_BFIN_NFC_H
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_NFC_SIZE 0x50
/* NFC_STAT masks. */
#define NBUSY (1 << 0)
#define WB_FULL (1 << 1)
#define PG_WR_STAT (1 << 2)
#define PG_RD_STAT (1 << 3)
#define WB_EMPTY (1 << 4)
/* NFC_IRQSTAT masks. */
#define NBUSYIRQ (1 << 0)
#define WB_OVF (1 << 1)
#define WB_EDGE (1 << 2)
#define RD_RDY (1 << 3)
#define WR_DONE (1 << 4)
#endif

307
sim/bfin/dv-bfin_otp.c Normal file
View File

@ -0,0 +1,307 @@
/* Blackfin One-Time Programmable Memory (OTP) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_otp.h"
/* XXX: No public documentation on this interface. This seems to work
with the on-chip ROM functions though and was figured out by
disassembling & walking that code. */
/* XXX: About only thing that should be done here are CRC fields. And
supposedly there is an interrupt that could be generated. */
struct bfin_otp
{
bu32 base;
/* The actual OTP storage -- 0x200 pages, each page is 128bits.
While certain pages have predefined and/or secure access, we don't
bother trying to implement that coverage. All pages are open for
reading & writing. */
bu32 mem[0x200 * 4];
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(control);
bu16 BFIN_MMR_16(ben);
bu16 BFIN_MMR_16(status);
bu32 timing;
bu32 _pad0[28];
bu32 data0, data1, data2, data3;
};
#define mmr_base() offsetof(struct bfin_otp, control)
#define mmr_offset(mmr) (offsetof(struct bfin_otp, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const mmr_names[] = {
"OTP_CONTROL", "OTP_BEN", "OTP_STATUS", "OTP_TIMING",
[mmr_idx (data0)] = "OTP_DATA0", "OTP_DATA1", "OTP_DATA2", "OTP_DATA3",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
/* XXX: This probably misbehaves with big endian hosts. */
static void
bfin_otp_transfer (struct bfin_otp *otp, void *vdst, void *vsrc)
{
bu8 *dst = vdst, *src = vsrc;
int bidx;
for (bidx = 0; bidx < 16; ++bidx)
if (otp->ben & (1 << bidx))
dst[bidx] = src[bidx];
}
static void
bfin_otp_read_page (struct bfin_otp *otp, bu16 page)
{
bfin_otp_transfer (otp, &otp->data0, &otp->mem[page * 4]);
}
static void
bfin_otp_write_page_val (struct bfin_otp *otp, bu16 page, bu64 val[2])
{
bfin_otp_transfer (otp, &otp->mem[page * 4], val);
}
static void
bfin_otp_write_page_val2 (struct bfin_otp *otp, bu16 page, bu64 lo, bu64 hi)
{
bu64 val[2] = { lo, hi };
bfin_otp_write_page_val (otp, page, val);
}
static void
bfin_otp_write_page (struct bfin_otp *otp, bu16 page)
{
bfin_otp_write_page_val (otp, page, (void *)&otp->data0);
}
static unsigned
bfin_otp_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_otp *otp = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - otp->base;
valuep = (void *)((unsigned long)otp + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(control):
{
int page;
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
/* XXX: Seems like these bits aren't writable. */
*value16p = value & 0x39FF;
/* Low bits seem to be the page address. */
page = value & PAGE_ADDR;
/* Write operation. */
if (value & DO_WRITE)
bfin_otp_write_page (otp, page);
/* Read operation. */
if (value & DO_READ)
bfin_otp_read_page (otp, page);
otp->status |= STATUS_DONE;
break;
}
case mmr_offset(ben):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
/* XXX: All bits seem to be writable. */
*value16p = value;
break;
case mmr_offset(status):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
/* XXX: All bits seem to be W1C. */
dv_w1c_2 (value16p, value, 0);
break;
case mmr_offset(timing):
case mmr_offset(data0):
case mmr_offset(data1):
case mmr_offset(data2):
case mmr_offset(data3):
dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
*value32p = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_otp_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_otp *otp = hw_data (me);
bu32 mmr_off;
bu16 *value16p;
bu32 *value32p;
void *valuep;
mmr_off = addr - otp->base;
valuep = (void *)((unsigned long)otp + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(control):
case mmr_offset(ben):
case mmr_offset(status):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
case mmr_offset(timing):
case mmr_offset(data0):
case mmr_offset(data1):
case mmr_offset(data2):
case mmr_offset(data3):
dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
dv_store_4 (dest, *value32p);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static void
attach_bfin_otp_regs (struct hw *me, struct bfin_otp *otp)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_OTP_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_OTP_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
otp->base = attach_address;
}
static void
bfin_otp_finish (struct hw *me)
{
char part_str[16];
struct bfin_otp *otp;
unsigned int fps03;
int type = hw_find_integer_property (me, "type");
otp = HW_ZALLOC (me, struct bfin_otp);
set_hw_data (me, otp);
set_hw_io_read_buffer (me, bfin_otp_io_read_buffer);
set_hw_io_write_buffer (me, bfin_otp_io_write_buffer);
attach_bfin_otp_regs (me, otp);
/* Initialize the OTP. */
otp->ben = 0xFFFF;
otp->timing = 0x00001485;
/* Semi-random value for unique chip id. */
bfin_otp_write_page_val2 (otp, FPS00, (unsigned long)otp, ~(unsigned long)otp);
memset (part_str, 0, sizeof (part_str));
sprintf (part_str, "ADSP-BF%iX", type);
switch (type)
{
case 512:
fps03 = FPS03_BF512;
break;
case 514:
fps03 = FPS03_BF514;
break;
case 516:
fps03 = FPS03_BF516;
break;
case 518:
fps03 = FPS03_BF518;
break;
case 522:
fps03 = FPS03_BF522;
break;
case 523:
fps03 = FPS03_BF523;
break;
case 524:
fps03 = FPS03_BF524;
break;
case 525:
fps03 = FPS03_BF525;
break;
case 526:
fps03 = FPS03_BF526;
break;
case 527:
fps03 = FPS03_BF527;
break;
default:
fps03 = 0;
break;
}
part_str[14] = (fps03 >> 0);
part_str[15] = (fps03 >> 8);
bfin_otp_write_page_val (otp, FPS03, (void *)part_str);
}
const struct hw_descriptor dv_bfin_otp_descriptor[] = {
{"bfin_otp", bfin_otp_finish,},
{NULL, NULL},
};

100
sim/bfin/dv-bfin_otp.h Normal file
View File

@ -0,0 +1,100 @@
/* Blackfin One-Time Programmable Memory (OTP) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_OTP_H
#define DV_BFIN_OTP_H
/* XXX: This should be pushed into the model data. */
/* XXX: Not exactly true; it's two sets of 4 regs near each other:
0xFFC03600 0x10 - Control
0xFFC03680 0x10 - Data */
#define BFIN_MMR_OTP_SIZE 0xa0
/* OTP Defined Pages. */
#define FPS00 0x004
#define FPS01 0x005
#define FPS02 0x006
#define FPS03 0x007
#define FPS04 0x008
#define FPS05 0x009
#define FPS06 0x00A
#define FPS07 0x00B
#define FPS08 0x00C
#define FPS09 0x00D
#define FPS10 0x00E
#define FPS11 0x00F
#define CPS00 0x010
#define CPS01 0x011
#define CPS02 0x012
#define CPS03 0x013
#define CPS04 0x014
#define CPS05 0x015
#define CPS06 0x016
#define CPS07 0x017
#define PBS00 0x018
#define PBS01 0x019
#define PBS02 0x01A
#define PBS03 0x01B
#define PUB000 0x01C
#define PUBCRC000 0x0E0
#define PRIV000 0x110
#define PRIVCRC000 0x1E0
/* FPS03 Part values. */
#define FPS03_BF51XF(n) (FPS03_BF##n | 0xF000)
#define FPS03_BF512 0x0200
#define FPS03_BF512F FPS03_BF51XF(512)
#define FPS03_BF514 0x0202
#define FPS03_BF514F FPS03_BF51XF(514)
#define FPS03_BF516 0x0204
#define FPS03_BF516F FPS03_BF51XF(516)
#define FPS03_BF518 0x0206
#define FPS03_BF518F FPS03_BF51XF(518)
#define FPS03_BF52X_C1(n) (FPS03_BF##n | 0x8000)
#define FPS03_BF52X_C2(n) (FPS03_BF##n | 0x4000)
#define FPS03_BF522 0x020A
#define FPS03_BF522_C1 FPS03_BF52X_C1(522)
#define FPS03_BF522_C2 FPS03_BF52X_C2(522)
#define FPS03_BF523 0x020B
#define FPS03_BF523_C1 FPS03_BF52X_C1(523)
#define FPS03_BF523_C2 FPS03_BF52X_C2(523)
#define FPS03_BF524 0x020C
#define FPS03_BF524_C1 FPS03_BF52X_C1(524)
#define FPS03_BF524_C2 FPS03_BF52X_C2(524)
#define FPS03_BF525 0x020D
#define FPS03_BF525_C1 FPS03_BF52X_C1(525)
#define FPS03_BF525_C2 FPS03_BF52X_C2(525)
#define FPS03_BF526 0x020E
#define FPS03_BF526_C1 FPS03_BF52X_C1(526)
#define FPS03_BF526_C2 FPS03_BF52X_C2(526)
#define FPS03_BF527 0x020F
#define FPS03_BF527_C1 FPS03_BF52X_C1(527)
#define FPS03_BF527_C2 FPS03_BF52X_C2(527)
/* OTP_CONTROL masks. */
#define PAGE_ADDR (0x1FF)
#define DO_READ (1 << 14)
#define DO_WRITE (1 << 15)
/* OTP_STATUS masks. */
#define STATUS_DONE (1 << 0)
#define STATUS_ERR (1 << 1)
#endif

187
sim/bfin/dv-bfin_pll.c Normal file
View File

@ -0,0 +1,187 @@
/* Blackfin Phase Lock Loop (PLL) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "machs.h"
#include "devices.h"
#include "dv-bfin_pll.h"
struct bfin_pll
{
bu32 base;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(pll_ctl);
bu16 BFIN_MMR_16(pll_div);
bu16 BFIN_MMR_16(vr_ctl);
bu16 BFIN_MMR_16(pll_stat);
bu16 BFIN_MMR_16(pll_lockcnt);
/* XXX: Not really the best place for this ... */
bu32 chipid;
};
#define mmr_base() offsetof(struct bfin_pll, pll_ctl)
#define mmr_offset(mmr) (offsetof(struct bfin_pll, mmr) - mmr_base())
static const char * const mmr_names[] = {
"PLL_CTL", "PLL_DIV", "VR_CTL", "PLL_STAT", "PLL_LOCKCNT", "CHIPID",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_pll_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_pll *pll = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - pll->base;
valuep = (void *)((unsigned long)pll + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(pll_stat):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
case mmr_offset(chipid):
/* Discard writes. */
break;
default:
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
*value16p = value;
break;
}
return nr_bytes;
}
static unsigned
bfin_pll_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_pll *pll = hw_data (me);
bu32 mmr_off;
bu32 *value32p;
bu16 *value16p;
void *valuep;
mmr_off = addr - pll->base;
valuep = (void *)((unsigned long)pll + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(chipid):
dv_store_4 (dest, *value32p);
break;
default:
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
}
return nr_bytes;
}
static const struct hw_port_descriptor bfin_pll_ports[] = {
{ "pll", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_pll_regs (struct hw *me, struct bfin_pll *pll)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_PLL_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PLL_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
pll->base = attach_address;
}
static void
bfin_pll_finish (struct hw *me)
{
struct bfin_pll *pll;
pll = HW_ZALLOC (me, struct bfin_pll);
set_hw_data (me, pll);
set_hw_io_read_buffer (me, bfin_pll_io_read_buffer);
set_hw_io_write_buffer (me, bfin_pll_io_write_buffer);
set_hw_ports (me, bfin_pll_ports);
attach_bfin_pll_regs (me, pll);
/* Initialize the PLL. */
/* XXX: Depends on part ? */
pll->pll_ctl = 0x1400;
pll->pll_div = 0x0005;
pll->vr_ctl = 0x40DB;
pll->pll_stat = 0x00A2;
pll->pll_lockcnt = 0x0200;
pll->chipid = bfin_model_get_chipid (hw_system (me));
/* XXX: slow it down! */
pll->pll_ctl = 0xa800;
pll->pll_div = 0x4;
pll->vr_ctl = 0x40fb;
pll->pll_stat = 0xa2;
pll->pll_lockcnt = 0x300;
}
const struct hw_descriptor dv_bfin_pll_descriptor[] = {
{"bfin_pll", bfin_pll_finish,},
{NULL, NULL},
};

27
sim/bfin/dv-bfin_pll.h Normal file
View File

@ -0,0 +1,27 @@
/* Blackfin Phase Lock Loop (PLL) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_PLL_H
#define DV_BFIN_PLL_H
#define BFIN_MMR_PLL_BASE 0xFFC00000
#define BFIN_MMR_PLL_SIZE (4 * 6)
#endif

231
sim/bfin/dv-bfin_ppi.c Normal file
View File

@ -0,0 +1,231 @@
/* Blackfin Parallel Port Interface (PPI) model
For "old style" PPIs on BF53x/etc... parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_ppi.h"
#include "gui.h"
/* XXX: TX is merely a stub. */
struct bfin_ppi
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* GUI state. */
void *gui_state;
int color;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(control);
bu16 BFIN_MMR_16(status);
bu16 BFIN_MMR_16(count);
bu16 BFIN_MMR_16(delay);
bu16 BFIN_MMR_16(frame);
};
#define mmr_base() offsetof(struct bfin_ppi, control)
#define mmr_offset(mmr) (offsetof(struct bfin_ppi, mmr) - mmr_base())
static const char * const mmr_names[] = {
"PPI_CONTROL", "PPI_STATUS", "PPI_COUNT", "PPI_DELAY", "PPI_FRAME",
};
#define mmr_name(off) mmr_names[(off) / 4]
static void
bfin_ppi_gui_setup (struct bfin_ppi *ppi)
{
int bpp;
/* If we are in RX mode, nothing to do. */
if (!(ppi->control & PORT_DIR))
return;
bpp = bfin_gui_color_depth (ppi->color);
ppi->gui_state = bfin_gui_setup (ppi->gui_state,
ppi->control & PORT_EN,
(ppi->count + 1) / (bpp / 8),
ppi->frame,
ppi->color);
}
static unsigned
bfin_ppi_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_ppi *ppi = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *valuep;
value = dv_load_2 (source);
mmr_off = addr - ppi->base;
valuep = (void *)((unsigned long)ppi + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
switch (mmr_off)
{
case mmr_offset(control):
*valuep = value;
bfin_ppi_gui_setup (ppi);
break;
case mmr_offset(count):
case mmr_offset(delay):
case mmr_offset(frame):
*valuep = value;
break;
case mmr_offset(status):
dv_w1c_2 (valuep, value, (1 << 10));
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_ppi_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_ppi *ppi = hw_data (me);
bu32 mmr_off;
bu16 *valuep;
mmr_off = addr - ppi->base;
valuep = (void *)((unsigned long)ppi + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
switch (mmr_off)
{
case mmr_offset(control):
case mmr_offset(count):
case mmr_offset(delay):
case mmr_offset(frame):
case mmr_offset(status):
dv_store_2 (dest, *valuep);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bfin_ppi_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
HW_TRACE_DMA_READ ();
return 0;
}
static unsigned
bfin_ppi_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
struct bfin_ppi *ppi = hw_data (me);
HW_TRACE_DMA_WRITE ();
return bfin_gui_update (ppi->gui_state, source, nr_bytes);
}
static const struct hw_port_descriptor bfin_ppi_ports[] = {
{ "stat", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_ppi_regs (struct hw *me, struct bfin_ppi *ppi)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_PPI_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PPI_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
ppi->base = attach_address;
}
static void
bfin_ppi_finish (struct hw *me)
{
struct bfin_ppi *ppi;
const char *color;
ppi = HW_ZALLOC (me, struct bfin_ppi);
set_hw_data (me, ppi);
set_hw_io_read_buffer (me, bfin_ppi_io_read_buffer);
set_hw_io_write_buffer (me, bfin_ppi_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_ppi_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_ppi_dma_write_buffer);
set_hw_ports (me, bfin_ppi_ports);
attach_bfin_ppi_regs (me, ppi);
/* Initialize the PPI. */
if (hw_find_property (me, "color"))
color = hw_find_string_property (me, "color");
else
color = NULL;
ppi->color = bfin_gui_color (color);
}
const struct hw_descriptor dv_bfin_ppi_descriptor[] = {
{"bfin_ppi", bfin_ppi_finish,},
{NULL, NULL},
};

32
sim/bfin/dv-bfin_ppi.h Normal file
View File

@ -0,0 +1,32 @@
/* Blackfin Parallel Port Interface (PPI) model
For "old style" PPIs on BF53x/etc... parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_PPI_H
#define DV_BFIN_PPI_H
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_PPI_SIZE (4 * 5)
/* PPI_CONTROL Masks. */
#define PORT_EN (1 << 0)
#define PORT_DIR (1 << 1)
#endif

194
sim/bfin/dv-bfin_rtc.c Normal file
View File

@ -0,0 +1,194 @@
/* Blackfin Real Time Clock (RTC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include <time.h>
#include "sim-main.h"
#include "dv-sockser.h"
#include "devices.h"
#include "dv-bfin_rtc.h"
/* XXX: This read-only stub setup is based on host system clock. */
struct bfin_rtc
{
bu32 base;
bu32 stat_shadow;
/* Order after here is important -- matches hardware MMR layout. */
bu32 stat;
bu16 BFIN_MMR_16(ictl);
bu16 BFIN_MMR_16(istat);
bu16 BFIN_MMR_16(swcnt);
bu32 alarm;
bu16 BFIN_MMR_16(pren);
};
#define mmr_base() offsetof(struct bfin_rtc, stat)
#define mmr_offset(mmr) (offsetof(struct bfin_rtc, mmr) - mmr_base())
static const char * const mmr_names[] = {
"RTC_STAT", "RTC_ICTL", "RTC_ISTAT", "RTC_SWCNT", "RTC_ALARM", "RTC_PREN",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_rtc_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_rtc *rtc = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - rtc->base;
valuep = (void *)((unsigned long)rtc + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
/* XXX: These probably need more work. */
switch (mmr_off)
{
case mmr_offset(stat):
/* XXX: Ignore these since we are wired to host. */
break;
case mmr_offset(istat):
dv_w1c_2 (value16p, value, 1 << 14);
break;
case mmr_offset(alarm):
break;
case mmr_offset(ictl):
/* XXX: This should schedule an event handler. */
case mmr_offset(swcnt):
case mmr_offset(pren):
break;
}
return nr_bytes;
}
static unsigned
bfin_rtc_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_rtc *rtc = hw_data (me);
bu32 mmr_off;
bu16 *value16p;
bu32 *value32p;
void *valuep;
mmr_off = addr - rtc->base;
valuep = (void *)((unsigned long)rtc + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(stat):
{
time_t t = time (NULL);
struct tm *tm = localtime (&t);
bu32 value =
(((tm->tm_year - 70) * 365 + tm->tm_yday) << 17) |
(tm->tm_hour << 12) |
(tm->tm_min << 6) |
(tm->tm_sec << 0);
dv_store_4 (dest, value);
break;
}
case mmr_offset(alarm):
dv_store_4 (dest, *value32p);
break;
case mmr_offset(istat):
case mmr_offset(ictl):
case mmr_offset(swcnt):
case mmr_offset(pren):
dv_store_2 (dest, *value16p);
break;
}
return nr_bytes;
}
static const struct hw_port_descriptor bfin_rtc_ports[] = {
{ "rtc", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_rtc_regs (struct hw *me, struct bfin_rtc *rtc)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_RTC_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_RTC_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
rtc->base = attach_address;
}
static void
bfin_rtc_finish (struct hw *me)
{
struct bfin_rtc *rtc;
rtc = HW_ZALLOC (me, struct bfin_rtc);
set_hw_data (me, rtc);
set_hw_io_read_buffer (me, bfin_rtc_io_read_buffer);
set_hw_io_write_buffer (me, bfin_rtc_io_write_buffer);
set_hw_ports (me, bfin_rtc_ports);
attach_bfin_rtc_regs (me, rtc);
/* Initialize the RTC. */
}
const struct hw_descriptor dv_bfin_rtc_descriptor[] = {
{"bfin_rtc", bfin_rtc_finish,},
{NULL, NULL},
};

26
sim/bfin/dv-bfin_rtc.h Normal file
View File

@ -0,0 +1,26 @@
/* Blackfin Real Time Clock (RTC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_RTC_H
#define DV_BFIN_RTC_H
#define BFIN_MMR_RTC_SIZE (4 * 6)
#endif

1439
sim/bfin/dv-bfin_sic.c Normal file

File diff suppressed because it is too large Load Diff

27
sim/bfin/dv-bfin_sic.h Normal file
View File

@ -0,0 +1,27 @@
/* Blackfin System Interrupt Controller (SIC) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_SIC_H
#define DV_BFIN_SIC_H
#define BFIN_MMR_SIC_BASE 0xFFC00100
#define BFIN_MMR_SIC_SIZE 0x100
#endif

229
sim/bfin/dv-bfin_spi.c Normal file
View File

@ -0,0 +1,229 @@
/* Blackfin Serial Peripheral Interface (SPI) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_spi.h"
/* XXX: This is merely a stub. */
struct bfin_spi
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(ctl);
bu16 BFIN_MMR_16(flg);
bu16 BFIN_MMR_16(stat);
bu16 BFIN_MMR_16(tdbr);
bu16 BFIN_MMR_16(rdbr);
bu16 BFIN_MMR_16(baud);
bu16 BFIN_MMR_16(shadow);
};
#define mmr_base() offsetof(struct bfin_spi, ctl)
#define mmr_offset(mmr) (offsetof(struct bfin_spi, mmr) - mmr_base())
static const char * const mmr_names[] = {
"SPI_CTL", "SPI_FLG", "SPI_STAT", "SPI_TDBR",
"SPI_RDBR", "SPI_BAUD", "SPI_SHADOW",
};
#define mmr_name(off) mmr_names[(off) / 4]
static bool
bfin_spi_enabled (struct bfin_spi *spi)
{
return (spi->ctl & SPE);
}
static bu16
bfin_spi_timod (struct bfin_spi *spi)
{
return (spi->ctl & TIMOD);
}
static unsigned
bfin_spi_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_spi *spi = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *valuep;
value = dv_load_2 (source);
mmr_off = addr - spi->base;
valuep = (void *)((unsigned long)spi + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
switch (mmr_off)
{
case mmr_offset(stat):
dv_w1c_2 (valuep, value, SPIF | TXS | RXS);
break;
case mmr_offset(tdbr):
*valuep = value;
if (bfin_spi_enabled (spi) && bfin_spi_timod (spi) == TDBR_CORE)
{
spi->stat |= RXS;
spi->stat &= ~TXS;
}
break;
case mmr_offset(rdbr):
case mmr_offset(ctl):
case mmr_offset(flg):
case mmr_offset(baud):
case mmr_offset(shadow):
*valuep = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_spi_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_spi *spi = hw_data (me);
bu32 mmr_off;
bu16 *valuep;
mmr_off = addr - spi->base;
valuep = (void *)((unsigned long)spi + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
switch (mmr_off)
{
case mmr_offset(rdbr):
dv_store_2 (dest, *valuep);
if (bfin_spi_enabled (spi) && bfin_spi_timod (spi) == RDBR_CORE)
spi->stat &= ~(RXS | TXS);
break;
case mmr_offset(ctl):
case mmr_offset(stat):
case mmr_offset(flg):
case mmr_offset(tdbr):
case mmr_offset(baud):
case mmr_offset(shadow):
dv_store_2 (dest, *valuep);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bfin_spi_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
HW_TRACE_DMA_READ ();
return 0;
}
static unsigned
bfin_spi_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
HW_TRACE_DMA_WRITE ();
return 0;
}
static const struct hw_port_descriptor bfin_spi_ports[] = {
{ "stat", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_spi_regs (struct hw *me, struct bfin_spi *spi)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_SPI_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_SPI_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
spi->base = attach_address;
}
static void
bfin_spi_finish (struct hw *me)
{
struct bfin_spi *spi;
spi = HW_ZALLOC (me, struct bfin_spi);
set_hw_data (me, spi);
set_hw_io_read_buffer (me, bfin_spi_io_read_buffer);
set_hw_io_write_buffer (me, bfin_spi_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_spi_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_spi_dma_write_buffer);
set_hw_ports (me, bfin_spi_ports);
attach_bfin_spi_regs (me, spi);
/* Initialize the SPI. */
spi->ctl = 0x0400;
spi->flg = 0xFF00;
spi->stat = 0x0001;
}
const struct hw_descriptor dv_bfin_spi_descriptor[] = {
{"bfin_spi", bfin_spi_finish,},
{NULL, NULL},
};

54
sim/bfin/dv-bfin_spi.h Normal file
View File

@ -0,0 +1,54 @@
/* Blackfin Serial Peripheral Interface (SPI) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_SPI_H
#define DV_BFIN_SPI_H
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_SPI_SIZE (4 * 7)
/* SPI_CTL Masks. */
#define TIMOD (3 << 0)
#define RDBR_CORE (0 << 0)
#define TDBR_CORE (1 << 0)
#define RDBR_DMA (2 << 0)
#define TDBR_DMA (3 << 0)
#define SZ (1 << 2)
#define GM (1 << 3)
#define PSSE (1 << 4)
#define EMISO (1 << 5)
#define SZE (1 << 8)
#define LSBF (1 << 9)
#define CPHA (1 << 10)
#define CPOL (1 << 11)
#define MSTR (1 << 12)
#define WOM (1 << 13)
#define SPE (1 << 14)
/* SPI_STAT Masks. */
#define SPIF (1 << 0)
#define MODF (1 << 1)
#define TXE (1 << 2)
#define TXS (1 << 3)
#define RBSY (1 << 4)
#define RXS (1 << 5)
#define TXCOL (1 << 6)
#endif

285
sim/bfin/dv-bfin_trace.c Normal file
View File

@ -0,0 +1,285 @@
/* Blackfin Trace (TBUF) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_cec.h"
#include "dv-bfin_trace.h"
/* Note: The circular buffering here might look a little buggy wrt mid-reads
and consuming the top entry, but this is simulating hardware behavior.
The hardware is simple, dumb, and fast. Don't write dumb Blackfin
software and you won't have a problem. */
/* The hardware is limited to 16 entries and defines TBUFCTL. Let's extend it ;). */
#ifndef SIM_BFIN_TRACE_DEPTH
#define SIM_BFIN_TRACE_DEPTH 6
#endif
#define SIM_BFIN_TRACE_LEN (1 << SIM_BFIN_TRACE_DEPTH)
#define SIM_BFIN_TRACE_LEN_MASK (SIM_BFIN_TRACE_LEN - 1)
struct bfin_trace_entry
{
bu32 src, dst;
};
struct bfin_trace
{
bu32 base;
struct bfin_trace_entry buffer[SIM_BFIN_TRACE_LEN];
int top, bottom;
bool mid;
/* Order after here is important -- matches hardware MMR layout. */
bu32 tbufctl, tbufstat;
char _pad[0x100 - 0x8];
bu32 tbuf;
};
#define mmr_base() offsetof(struct bfin_trace, tbufctl)
#define mmr_offset(mmr) (offsetof(struct bfin_trace, mmr) - mmr_base())
static const char * const mmr_names[] = {
"TBUFCTL", "TBUFSTAT", [mmr_offset (tbuf) / 4] = "TBUF",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
/* Ugh, circular buffers. */
#define TBUF_LEN(t) ((t)->top - (t)->bottom)
#define TBUF_IDX(i) ((i) & SIM_BFIN_TRACE_LEN_MASK)
/* TOP is the next slot to fill. */
#define TBUF_TOP(t) (&(t)->buffer[TBUF_IDX ((t)->top)])
/* LAST is the latest valid slot. */
#define TBUF_LAST(t) (&(t)->buffer[TBUF_IDX ((t)->top - 1)])
/* LAST_LAST is the second-to-last valid slot. */
#define TBUF_LAST_LAST(t) (&(t)->buffer[TBUF_IDX ((t)->top - 2)])
static unsigned
bfin_trace_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_trace *trace = hw_data (me);
bu32 mmr_off;
bu32 value;
value = dv_load_4 (source);
mmr_off = addr - trace->base;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(tbufctl):
trace->tbufctl = value;
break;
case mmr_offset(tbufstat):
case mmr_offset(tbuf):
/* Discard writes to these. */
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_trace_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_trace *trace = hw_data (me);
bu32 mmr_off;
bu32 value;
mmr_off = addr - trace->base;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(tbufctl):
value = trace->tbufctl;
break;
case mmr_offset(tbufstat):
/* Hardware is limited to 16 entries, so to stay compatible with
software, limit the value to 16. For software algorithms that
keep reading while (TBUFSTAT != 0), they'll get all of it. */
value = MIN (TBUF_LEN (trace), 16);
break;
case mmr_offset(tbuf):
{
struct bfin_trace_entry *e;
if (TBUF_LEN (trace) == 0)
{
value = 0;
break;
}
e = TBUF_LAST (trace);
if (trace->mid)
{
value = e->src;
--trace->top;
}
else
value = e->dst;
trace->mid = !trace->mid;
break;
}
default:
while (1) /* Core MMRs -> exception -> doesn't return. */
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
dv_store_4 (dest, value);
return nr_bytes;
}
static void
attach_bfin_trace_regs (struct hw *me, struct bfin_trace *trace)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_TRACE_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_TRACE_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
trace->base = attach_address;
}
static void
bfin_trace_finish (struct hw *me)
{
struct bfin_trace *trace;
trace = HW_ZALLOC (me, struct bfin_trace);
set_hw_data (me, trace);
set_hw_io_read_buffer (me, bfin_trace_io_read_buffer);
set_hw_io_write_buffer (me, bfin_trace_io_write_buffer);
attach_bfin_trace_regs (me, trace);
}
const struct hw_descriptor dv_bfin_trace_descriptor[] = {
{"bfin_trace", bfin_trace_finish,},
{NULL, NULL},
};
#define TRACE_STATE(cpu) DV_STATE_CACHED (cpu, trace)
/* This is not re-entrant, but neither is the cpu state, so this shouldn't
be a big deal ... */
void bfin_trace_queue (SIM_CPU *cpu, bu32 src_pc, bu32 dst_pc, int hwloop)
{
struct bfin_trace *trace = TRACE_STATE (cpu);
struct bfin_trace_entry *e;
int len, ivg;
/* Only queue if powered. */
if (!(trace->tbufctl & TBUFPWR))
return;
/* Only queue if enabled. */
if (!(trace->tbufctl & TBUFEN))
return;
/* Ignore hardware loops.
XXX: This is what the hardware does, but an option to ignore
could be useful for debugging ... */
if (hwloop >= 0)
return;
/* Only queue if at right level. */
ivg = cec_get_ivg (cpu);
if (ivg == IVG_RST)
/* XXX: This is what the hardware does, but an option to ignore
could be useful for debugging ... */
return;
if (ivg <= IVG_EVX && (trace->tbufctl & TBUFOVF))
/* XXX: This is what the hardware does, but an option to ignore
could be useful for debugging ... just don't throw an
exception when full and in EVT{0..3}. */
return;
/* Are we full ? */
len = TBUF_LEN (trace);
if (len == SIM_BFIN_TRACE_LEN)
{
if (trace->tbufctl & TBUFOVF)
{
cec_exception (cpu, VEC_OVFLOW);
return;
}
/* Overwrite next entry. */
++trace->bottom;
}
/* One level compression. */
if (len >= 1 && (trace->tbufctl & TBUFCMPLP))
{
e = TBUF_LAST (trace);
if (src_pc == (e->src & ~1) && dst_pc == (e->dst & ~1))
{
/* Hardware sets LSB when level is compressed. */
e->dst |= 1;
return;
}
}
/* Two level compression. */
if (len >= 2 && (trace->tbufctl & TBUFCMPLP_DOUBLE))
{
e = TBUF_LAST_LAST (trace);
if (src_pc == (e->src & ~1) && dst_pc == (e->dst & ~1))
{
/* Hardware sets LSB when level is compressed. */
e->src |= 1;
return;
}
}
e = TBUF_TOP (trace);
e->dst = dst_pc;
e->src = src_pc;
++trace->top;
}

37
sim/bfin/dv-bfin_trace.h Normal file
View File

@ -0,0 +1,37 @@
/* Blackfin Trace (TBUF) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_TRACE_H
#define DV_BFIN_TRACE_H
#define BFIN_COREMMR_TRACE_BASE 0xFFE06000
#define BFIN_COREMMR_TRACE_SIZE (4 * 65)
/* TBUFCTL Masks */
#define TBUFPWR 0x0001
#define TBUFEN 0x0002
#define TBUFOVF 0x0004
#define TBUFCMPLP_SINGLE 0x0008
#define TBUFCMPLP_DOUBLE 0x0010
#define TBUFCMPLP (TBUFCMPLP_SINGLE | TBUFCMPLP_DOUBLE)
void bfin_trace_queue (SIM_CPU *, bu32 src_pc, bu32 dst_pc, int hwloop);
#endif

227
sim/bfin/dv-bfin_twi.c Normal file
View File

@ -0,0 +1,227 @@
/* Blackfin Two Wire Interface (TWI) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_twi.h"
/* XXX: This is merely a stub. */
struct bfin_twi
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
bu16 xmt_fifo, rcv_fifo;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(clkdiv);
bu16 BFIN_MMR_16(control);
bu16 BFIN_MMR_16(slave_ctl);
bu16 BFIN_MMR_16(slave_stat);
bu16 BFIN_MMR_16(slave_addr);
bu16 BFIN_MMR_16(master_ctl);
bu16 BFIN_MMR_16(master_stat);
bu16 BFIN_MMR_16(master_addr);
bu16 BFIN_MMR_16(int_stat);
bu16 BFIN_MMR_16(int_mask);
bu16 BFIN_MMR_16(fifo_ctl);
bu16 BFIN_MMR_16(fifo_stat);
bu32 _pad0[20];
bu16 BFIN_MMR_16(xmt_data8);
bu16 BFIN_MMR_16(xmt_data16);
bu16 BFIN_MMR_16(rcv_data8);
bu16 BFIN_MMR_16(rcv_data16);
};
#define mmr_base() offsetof(struct bfin_twi, clkdiv)
#define mmr_offset(mmr) (offsetof(struct bfin_twi, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const mmr_names[] = {
"TWI_CLKDIV", "TWI_CONTROL", "TWI_SLAVE_CTL", "TWI_SLAVE_STAT",
"TWI_SLAVE_ADDR", "TWI_MASTER_CTL", "TWI_MASTER_STAT", "TWI_MASTER_ADDR",
"TWI_INT_STAT", "TWI_INT_MASK", "TWI_FIFO_CTL", "TWI_FIFO_STAT",
[mmr_idx (xmt_data8)] = "TWI_XMT_DATA8", "TWI_XMT_DATA16", "TWI_RCV_DATA8",
"TWI_RCV_DATA16",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static unsigned
bfin_twi_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_twi *twi = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *valuep;
value = dv_load_2 (source);
mmr_off = addr - twi->base;
valuep = (void *)((unsigned long)twi + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
switch (mmr_off)
{
case mmr_offset(clkdiv):
case mmr_offset(control):
case mmr_offset(slave_ctl):
case mmr_offset(slave_addr):
case mmr_offset(master_ctl):
case mmr_offset(master_addr):
case mmr_offset(int_mask):
case mmr_offset(fifo_ctl):
*valuep = value;
break;
case mmr_offset(int_stat):
dv_w1c_2 (valuep, value, 0);
break;
case mmr_offset(master_stat):
dv_w1c_2 (valuep, value, MPROG | SDASEN | SCLSEN | BUSBUSY);
break;
case mmr_offset(slave_stat):
case mmr_offset(fifo_stat):
case mmr_offset(rcv_data8):
case mmr_offset(rcv_data16):
/* These are all RO. XXX: Does these throw error ? */
break;
case mmr_offset(xmt_data8):
value &= 0xff;
case mmr_offset(xmt_data16):
twi->xmt_fifo = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_twi_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_twi *twi = hw_data (me);
bu32 mmr_off;
bu16 *valuep;
mmr_off = addr - twi->base;
valuep = (void *)((unsigned long)twi + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
switch (mmr_off)
{
case mmr_offset(clkdiv):
case mmr_offset(control):
case mmr_offset(slave_ctl):
case mmr_offset(slave_stat):
case mmr_offset(slave_addr):
case mmr_offset(master_ctl):
case mmr_offset(master_stat):
case mmr_offset(master_addr):
case mmr_offset(int_stat):
case mmr_offset(int_mask):
case mmr_offset(fifo_ctl):
case mmr_offset(fifo_stat):
dv_store_2 (dest, *valuep);
break;
case mmr_offset(rcv_data8):
case mmr_offset(rcv_data16):
dv_store_2 (dest, twi->rcv_fifo);
break;
case mmr_offset(xmt_data8):
case mmr_offset(xmt_data16):
/* These always read as 0. */
dv_store_2 (dest, 0);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static const struct hw_port_descriptor bfin_twi_ports[] = {
{ "stat", 0, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_twi_regs (struct hw *me, struct bfin_twi *twi)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_TWI_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_TWI_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
twi->base = attach_address;
}
static void
bfin_twi_finish (struct hw *me)
{
struct bfin_twi *twi;
twi = HW_ZALLOC (me, struct bfin_twi);
set_hw_data (me, twi);
set_hw_io_read_buffer (me, bfin_twi_io_read_buffer);
set_hw_io_write_buffer (me, bfin_twi_io_write_buffer);
set_hw_ports (me, bfin_twi_ports);
attach_bfin_twi_regs (me, twi);
}
const struct hw_descriptor dv_bfin_twi_descriptor[] = {
{"bfin_twi", bfin_twi_finish,},
{NULL, NULL},
};

38
sim/bfin/dv-bfin_twi.h Normal file
View File

@ -0,0 +1,38 @@
/* Blackfin Two Wire Interface (TWI) model
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_TWI_H
#define DV_BFIN_TWI_H
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_TWI_SIZE 0x90
/* TWI_MASTER_STAT Masks */
#define MPROG (1 << 0)
#define LOSTARG (1 << 1)
#define ANAK (1 << 2)
#define DNAK (1 << 3)
#define BUFRDERR (1 << 4)
#define BUFWRERR (1 << 5)
#define SDASEN (1 << 6)
#define SCLSEN (1 << 7)
#define BUSBUSY (1 << 8)
#endif

437
sim/bfin/dv-bfin_uart.c Normal file
View File

@ -0,0 +1,437 @@
/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
For "old style" UARTs on BF53x/etc... parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "dv-sockser.h"
#include "devices.h"
#include "dv-bfin_uart.h"
/* XXX: Should we bother emulating the TX/RX FIFOs ? */
/* Internal state needs to be the same as bfin_uart2. */
struct bfin_uart
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* This is aliased to DLH. */
bu16 ier;
/* These are aliased to DLL. */
bu16 thr, rbr;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(dll);
bu16 BFIN_MMR_16(dlh);
bu16 BFIN_MMR_16(iir);
bu16 BFIN_MMR_16(lcr);
bu16 BFIN_MMR_16(mcr);
bu16 BFIN_MMR_16(lsr);
bu16 BFIN_MMR_16(msr);
bu16 BFIN_MMR_16(scr);
bu16 _pad0[2];
bu16 BFIN_MMR_16(gctl);
};
#define mmr_base() offsetof(struct bfin_uart, dll)
#define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
static const char * const mmr_names[] = {
"UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
"UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
};
static const char *mmr_name (struct bfin_uart *uart, bu32 idx)
{
if (uart->lcr & DLAB)
if (idx < 2)
return idx == 0 ? "UART_DLL" : "UART_DLH";
return mmr_names[idx];
}
#define mmr_name(off) mmr_name (uart, (off) / 4)
#ifndef HAVE_DV_SOCKSER
# define dv_sockser_status(sd) -1
# define dv_sockser_write(sd, byte) do { ; } while (0)
# define dv_sockser_read(sd) 0xff
#endif
static void
bfin_uart_poll (struct hw *me, void *data)
{
struct bfin_uart *uart = data;
bu16 lsr;
uart->handler = NULL;
lsr = bfin_uart_get_status (me);
if (lsr & DR)
hw_port_event (me, DV_PORT_RX, 1);
bfin_uart_reschedule (me);
}
void
bfin_uart_reschedule (struct hw *me)
{
struct bfin_uart *uart = hw_data (me);
if (uart->ier & ERBFI)
{
if (!uart->handler)
uart->handler = hw_event_queue_schedule (me, 10000,
bfin_uart_poll, uart);
}
else
{
if (uart->handler)
{
hw_event_queue_deschedule (me, uart->handler);
uart->handler = NULL;
}
}
}
bu16
bfin_uart_write_byte (struct hw *me, bu16 thr)
{
unsigned char ch = thr;
bfin_uart_write_buffer (me, &ch, 1);
return thr;
}
static unsigned
bfin_uart_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_uart *uart = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *valuep;
value = dv_load_2 (source);
mmr_off = addr - uart->base;
valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
/* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
switch (mmr_off)
{
case mmr_offset(dll):
if (uart->lcr & DLAB)
uart->dll = value;
else
{
uart->thr = bfin_uart_write_byte (me, value);
if (uart->ier & ETBEI)
hw_port_event (me, DV_PORT_TX, 1);
}
break;
case mmr_offset(dlh):
if (uart->lcr & DLAB)
uart->dlh = value;
else
{
uart->ier = value;
bfin_uart_reschedule (me);
}
break;
case mmr_offset(iir):
case mmr_offset(lsr):
/* XXX: Writes are ignored ? */
break;
case mmr_offset(lcr):
case mmr_offset(mcr):
case mmr_offset(scr):
case mmr_offset(gctl):
*valuep = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
/* Switch between socket and stdin on the fly. */
bu16
bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bool *fresh)
{
SIM_DESC sd = hw_system (me);
struct bfin_uart *uart = hw_data (me);
int status = dv_sockser_status (sd);
bool _fresh;
/* NB: The "uart" here may only use interal state. */
if (!fresh)
fresh = &_fresh;
*fresh = false;
if (status & DV_SOCKSER_DISCONNECTED)
{
if (uart->saved_count > 0)
{
*fresh = true;
rbr = uart->saved_byte;
--uart->saved_count;
}
else
{
char byte;
int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
if (ret > 0)
{
*fresh = true;
rbr = byte;
}
}
}
else
rbr = dv_sockser_read (sd);
return rbr;
}
bu16
bfin_uart_get_status (struct hw *me)
{
SIM_DESC sd = hw_system (me);
struct bfin_uart *uart = hw_data (me);
int status = dv_sockser_status (sd);
bu16 lsr = 0;
if (status & DV_SOCKSER_DISCONNECTED)
{
if (uart->saved_count <= 0)
uart->saved_count = sim_io_poll_read (sd, 0/*STDIN*/,
&uart->saved_byte, 1);
lsr |= TEMT | THRE | (uart->saved_count > 0 ? DR : 0);
}
else
lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
(status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
return lsr;
}
static unsigned
bfin_uart_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_uart *uart = hw_data (me);
bu32 mmr_off;
bu16 *valuep;
mmr_off = addr - uart->base;
valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
switch (mmr_off)
{
case mmr_offset(dll):
if (uart->lcr & DLAB)
dv_store_2 (dest, uart->dll);
else
{
uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, NULL);
dv_store_2 (dest, uart->rbr);
}
break;
case mmr_offset(dlh):
if (uart->lcr & DLAB)
dv_store_2 (dest, uart->dlh);
else
dv_store_2 (dest, uart->ier);
break;
case mmr_offset(lsr):
/* XXX: Reads are destructive on most parts, but not all ... */
uart->lsr |= bfin_uart_get_status (me);
dv_store_2 (dest, *valuep);
uart->lsr = 0;
break;
case mmr_offset(iir):
/* XXX: Reads are destructive ... */
case mmr_offset(lcr):
case mmr_offset(mcr):
case mmr_offset(scr):
case mmr_offset(gctl):
dv_store_2 (dest, *valuep);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
unsigned
bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes)
{
SIM_DESC sd = hw_system (me);
struct bfin_uart *uart = hw_data (me);
int status = dv_sockser_status (sd);
unsigned i = 0;
if (status & DV_SOCKSER_DISCONNECTED)
{
int ret;
while (uart->saved_count > 0 && i < nr_bytes)
{
buffer[i++] = uart->saved_byte;
--uart->saved_count;
}
ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i);
if (ret > 0)
i += ret;
}
else
buffer[i++] = dv_sockser_read (sd);
return i;
}
static unsigned
bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
HW_TRACE_DMA_READ ();
return bfin_uart_read_buffer (me, dest, nr_bytes);
}
unsigned
bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer,
unsigned nr_bytes)
{
SIM_DESC sd = hw_system (me);
int status = dv_sockser_status (sd);
if (status & DV_SOCKSER_DISCONNECTED)
{
sim_io_write_stdout (sd, (const char *) buffer, nr_bytes);
sim_io_flush_stdout (sd);
}
else
{
/* Normalize errors to a value of 0. */
int ret = dv_sockser_write_buffer (sd, buffer, nr_bytes);
nr_bytes = CLAMP (ret, 0, nr_bytes);
}
return nr_bytes;
}
static unsigned
bfin_uart_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
struct bfin_uart *uart = hw_data (me);
unsigned ret;
HW_TRACE_DMA_WRITE ();
ret = bfin_uart_write_buffer (me, source, nr_bytes);
if (ret == nr_bytes && (uart->ier & ETBEI))
hw_port_event (me, DV_PORT_TX, 1);
return ret;
}
static const struct hw_port_descriptor bfin_uart_ports[] = {
{ "tx", DV_PORT_TX, 0, output_port, },
{ "rx", DV_PORT_RX, 0, output_port, },
{ "stat", DV_PORT_STAT, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_UART_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
uart->base = attach_address;
}
static void
bfin_uart_finish (struct hw *me)
{
struct bfin_uart *uart;
uart = HW_ZALLOC (me, struct bfin_uart);
set_hw_data (me, uart);
set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
set_hw_ports (me, bfin_uart_ports);
attach_bfin_uart_regs (me, uart);
/* Initialize the UART. */
uart->dll = 0x0001;
uart->iir = 0x0001;
uart->lsr = 0x0060;
}
const struct hw_descriptor dv_bfin_uart_descriptor[] = {
{"bfin_uart", bfin_uart_finish,},
{NULL, NULL},
};

49
sim/bfin/dv-bfin_uart.h Normal file
View File

@ -0,0 +1,49 @@
/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
For "old style" UARTs on BF53x/etc... parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_UART_H
#define DV_BFIN_UART_H
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_UART_SIZE 0x30
struct bfin_uart;
bu16 bfin_uart_get_next_byte (struct hw *, bu16, bool *fresh);
bu16 bfin_uart_write_byte (struct hw *, bu16);
bu16 bfin_uart_get_status (struct hw *);
unsigned bfin_uart_write_buffer (struct hw *, const unsigned char *, unsigned);
unsigned bfin_uart_read_buffer (struct hw *, unsigned char *, unsigned);
void bfin_uart_reschedule (struct hw *);
/* UART_LCR */
#define DLAB (1 << 7)
/* UART_LSR */
#define TEMT (1 << 6)
#define THRE (1 << 5)
#define DR (1 << 0)
/* UART_IER */
#define ERBFI (1 << 0)
#define ETBEI (1 << 1)
#define ELSI (1 << 2)
#endif

258
sim/bfin/dv-bfin_uart2.c Normal file
View File

@ -0,0 +1,258 @@
/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
For "new style" UARTs on BF50x/BF54x parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_uart2.h"
/* XXX: Should we bother emulating the TX/RX FIFOs ? */
/* Internal state needs to be the same as bfin_uart. */
struct bfin_uart
{
/* This top portion matches common dv_bfin struct. */
bu32 base;
struct hw *dma_master;
bool acked;
struct hw_event *handler;
char saved_byte;
int saved_count;
/* Accessed indirectly by ier_{set,clear}. */
bu16 ier;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(dll);
bu16 BFIN_MMR_16(dlh);
bu16 BFIN_MMR_16(gctl);
bu16 BFIN_MMR_16(lcr);
bu16 BFIN_MMR_16(mcr);
bu16 BFIN_MMR_16(lsr);
bu16 BFIN_MMR_16(msr);
bu16 BFIN_MMR_16(scr);
bu16 BFIN_MMR_16(ier_set);
bu16 BFIN_MMR_16(ier_clear);
bu16 BFIN_MMR_16(thr);
bu16 BFIN_MMR_16(rbr);
};
#define mmr_base() offsetof(struct bfin_uart, dll)
#define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
static const char * const mmr_names[] = {
"UART_DLL", "UART_DLH", "UART_GCTL", "UART_LCR", "UART_MCR", "UART_LSR",
"UART_MSR", "UART_SCR", "UART_IER_SET", "UART_IER_CLEAR", "UART_THR",
"UART_RBR",
};
#define mmr_name(off) mmr_names[(off) / 4]
static unsigned
bfin_uart_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_uart *uart = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *valuep;
value = dv_load_2 (source);
mmr_off = addr - uart->base;
valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
/* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
switch (mmr_off)
{
case mmr_offset(thr):
uart->thr = bfin_uart_write_byte (me, value);
if (uart->ier & ETBEI)
hw_port_event (me, DV_PORT_TX, 1);
break;
case mmr_offset(ier_set):
uart->ier |= value;
break;
case mmr_offset(ier_clear):
dv_w1c_2 (&uart->ier, value, 0);
break;
case mmr_offset(lsr):
dv_w1c_2 (valuep, value, TEMT | THRE | DR);
break;
case mmr_offset(rbr):
/* XXX: Writes are ignored ? */
break;
case mmr_offset(msr):
dv_w1c_2 (valuep, value, SCTS);
break;
case mmr_offset(dll):
case mmr_offset(dlh):
case mmr_offset(gctl):
case mmr_offset(lcr):
case mmr_offset(mcr):
case mmr_offset(scr):
*valuep = value;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_uart_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_uart *uart = hw_data (me);
bu32 mmr_off;
bu16 *valuep;
mmr_off = addr - uart->base;
valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
HW_TRACE_READ ();
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
switch (mmr_off)
{
case mmr_offset(rbr):
uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, NULL);
dv_store_2 (dest, uart->rbr);
break;
case mmr_offset(ier_set):
case mmr_offset(ier_clear):
dv_store_2 (dest, uart->ier);
bfin_uart_reschedule (me);
break;
case mmr_offset(lsr):
uart->lsr |= bfin_uart_get_status (me);
case mmr_offset(thr):
case mmr_offset(msr):
case mmr_offset(dll):
case mmr_offset(dlh):
case mmr_offset(gctl):
case mmr_offset(lcr):
case mmr_offset(mcr):
case mmr_offset(scr):
dv_store_2 (dest, *valuep);
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
return nr_bytes;
}
static unsigned
bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
unsigned_word addr, unsigned nr_bytes)
{
HW_TRACE_DMA_READ ();
return bfin_uart_read_buffer (me, dest, nr_bytes);
}
static unsigned
bfin_uart_dma_write_buffer (struct hw *me, const void *source,
int space, unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
struct bfin_uart *uart = hw_data (me);
unsigned ret;
HW_TRACE_DMA_WRITE ();
ret = bfin_uart_write_buffer (me, source, nr_bytes);
if (ret == nr_bytes && (uart->ier & ETBEI))
hw_port_event (me, DV_PORT_TX, 1);
return ret;
}
static const struct hw_port_descriptor bfin_uart_ports[] = {
{ "tx", DV_PORT_TX, 0, output_port, },
{ "rx", DV_PORT_RX, 0, output_port, },
{ "stat", DV_PORT_STAT, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_UART2_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART2_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
uart->base = attach_address;
}
static void
bfin_uart_finish (struct hw *me)
{
struct bfin_uart *uart;
uart = HW_ZALLOC (me, struct bfin_uart);
set_hw_data (me, uart);
set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
set_hw_ports (me, bfin_uart_ports);
attach_bfin_uart_regs (me, uart);
/* Initialize the UART. */
uart->dll = 0x0001;
uart->lsr = 0x0060;
}
const struct hw_descriptor dv_bfin_uart2_descriptor[] = {
{"bfin_uart2", bfin_uart_finish,},
{NULL, NULL},
};

33
sim/bfin/dv-bfin_uart2.h Normal file
View File

@ -0,0 +1,33 @@
/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
For "new style" UARTs on BF50x/BF54x parts.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_UART2_H
#define DV_BFIN_UART2_H
#include "dv-bfin_uart.h"
/* XXX: This should be pushed into the model data. */
#define BFIN_MMR_UART2_SIZE 0x30
/* UART_MSR */
#define SCTS (1 << 0)
#endif

206
sim/bfin/dv-bfin_wdog.c Normal file
View File

@ -0,0 +1,206 @@
/* Blackfin Watchdog (WDOG) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "dv-sockser.h"
#include "devices.h"
#include "dv-bfin_wdog.h"
/* XXX: Should we bother emulating the TX/RX FIFOs ? */
struct bfin_wdog
{
bu32 base;
/* Order after here is important -- matches hardware MMR layout. */
bu16 BFIN_MMR_16(ctl);
bu32 cnt, stat;
};
#define mmr_base() offsetof(struct bfin_wdog, ctl)
#define mmr_offset(mmr) (offsetof(struct bfin_wdog, mmr) - mmr_base())
static const char * const mmr_names[] = {
"WDOG_CTL", "WDOG_CNT", "WDOG_STAT",
};
#define mmr_name(off) mmr_names[(off) / 4]
static bool
bfin_wdog_enabled (struct bfin_wdog *wdog)
{
return ((wdog->ctl & WDEN) != WDDIS);
}
static unsigned
bfin_wdog_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_wdog *wdog = hw_data (me);
bu32 mmr_off;
bu32 value;
bu16 *value16p;
bu32 *value32p;
void *valuep;
if (nr_bytes == 4)
value = dv_load_4 (source);
else
value = dv_load_2 (source);
mmr_off = addr - wdog->base;
valuep = (void *)((unsigned long)wdog + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(ctl):
dv_w1c_2_partial (value16p, value, WDRO);
/* XXX: Should enable an event here to handle timeouts. */
break;
case mmr_offset(cnt):
/* Writes are discarded when enabeld. */
if (!bfin_wdog_enabled (wdog))
{
*value32p = value;
/* Writes to CNT preloads the STAT. */
wdog->stat = wdog->cnt;
}
break;
case mmr_offset(stat):
/* When enabled, writes to STAT reload the counter. */
if (bfin_wdog_enabled (wdog))
wdog->stat = wdog->cnt;
/* XXX: When disabled, are writes just ignored ? */
break;
}
return nr_bytes;
}
static unsigned
bfin_wdog_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct bfin_wdog *wdog = hw_data (me);
bu32 mmr_off;
bu16 *value16p;
bu32 *value32p;
void *valuep;
mmr_off = addr - wdog->base;
valuep = (void *)((unsigned long)wdog + mmr_base() + mmr_off);
value16p = valuep;
value32p = valuep;
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(ctl):
dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
dv_store_2 (dest, *value16p);
break;
case mmr_offset(cnt):
case mmr_offset(stat):
dv_store_4 (dest, *value32p);
break;
}
return nr_bytes;
}
static const struct hw_port_descriptor bfin_wdog_ports[] = {
{ "reset", WDEV_RESET, 0, output_port, },
{ "nmi", WDEV_NMI, 0, output_port, },
{ "gpi", WDEV_GPI, 0, output_port, },
{ NULL, 0, 0, 0, },
};
static void
bfin_wdog_port_event (struct hw *me, int my_port, struct hw *source,
int source_port, int level)
{
struct bfin_wdog *wdog = hw_data (me);
bu16 wdev;
wdog->ctl |= WDRO;
wdev = (wdog->ctl & WDEV);
if (wdev != WDEV_NONE)
hw_port_event (me, wdev, 1);
}
static void
attach_bfin_wdog_regs (struct hw *me, struct bfin_wdog *wdog)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_MMR_WDOG_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_WDOG_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
wdog->base = attach_address;
}
static void
bfin_wdog_finish (struct hw *me)
{
struct bfin_wdog *wdog;
wdog = HW_ZALLOC (me, struct bfin_wdog);
set_hw_data (me, wdog);
set_hw_io_read_buffer (me, bfin_wdog_io_read_buffer);
set_hw_io_write_buffer (me, bfin_wdog_io_write_buffer);
set_hw_ports (me, bfin_wdog_ports);
set_hw_port_event (me, bfin_wdog_port_event);
attach_bfin_wdog_regs (me, wdog);
/* Initialize the Watchdog. */
wdog->ctl = WDDIS;
}
const struct hw_descriptor dv_bfin_wdog_descriptor[] = {
{"bfin_wdog", bfin_wdog_finish,},
{NULL, NULL},
};

36
sim/bfin/dv-bfin_wdog.h Normal file
View File

@ -0,0 +1,36 @@
/* Blackfin Watchdog (WDOG) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_WDOG_H
#define DV_BFIN_WDOG_H
#define BFIN_MMR_WDOG_SIZE (4 * 3)
/* WDOG_CTL */
#define WDEV 0x0006 /* event generated on roll over */
#define WDEV_RESET 0x0000 /* generate reset event on roll over */
#define WDEV_NMI 0x0002 /* generate NMI event on roll over */
#define WDEV_GPI 0x0004 /* generate GP IRQ on roll over */
#define WDEV_NONE 0x0006 /* no event on roll over */
#define WDEN 0x0FF0 /* enable watchdog */
#define WDDIS 0x0AD0 /* disable watchdog */
#define WDRO 0x8000 /* watchdog rolled over latch */
#endif

188
sim/bfin/dv-bfin_wp.c Normal file
View File

@ -0,0 +1,188 @@
/* Blackfin Watchpoint (WP) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#include "dv-bfin_wp.h"
/* XXX: This is mostly a stub. */
#define WPI_NUM 6 /* 6 instruction watchpoints. */
#define WPD_NUM 2 /* 2 data watchpoints. */
struct bfin_wp
{
bu32 base;
/* Order after here is important -- matches hardware MMR layout. */
bu32 iactl;
bu32 _pad0[15];
bu32 ia[WPI_NUM];
bu32 _pad1[16 - WPI_NUM];
bu32 iacnt[WPI_NUM];
bu32 _pad2[32 - WPI_NUM];
bu32 dactl;
bu32 _pad3[15];
bu32 da[WPD_NUM];
bu32 _pad4[16 - WPD_NUM];
bu32 dacnt[WPD_NUM];
bu32 _pad5[32 - WPD_NUM];
bu32 stat;
};
#define mmr_base() offsetof(struct bfin_wp, iactl)
#define mmr_offset(mmr) (offsetof(struct bfin_wp, mmr) - mmr_base())
#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
static const char * const mmr_names[] = {
[mmr_idx (iactl)] = "WPIACTL",
[mmr_idx (ia)] = "WPIA0", "WPIA1", "WPIA2", "WPIA3", "WPIA4", "WPIA5",
[mmr_idx (iacnt)] = "WPIACNT0", "WPIACNT1", "WPIACNT2",
"WPIACNT3", "WPIACNT4", "WPIACNT5",
[mmr_idx (dactl)] = "WPDACTL",
[mmr_idx (da)] = "WPDA0", "WPDA1", "WPDA2", "WPDA3", "WPDA4", "WPDA5",
[mmr_idx (dacnt)] = "WPDACNT0", "WPDACNT1", "WPDACNT2",
"WPDACNT3", "WPDACNT4", "WPDACNT5",
[mmr_idx (stat)] = "WPSTAT",
};
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
static unsigned
bfin_wp_io_write_buffer (struct hw *me, const void *source, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_wp *wp = hw_data (me);
bu32 mmr_off;
bu32 value;
bu32 *valuep;
value = dv_load_4 (source);
mmr_off = addr - wp->base;
valuep = (void *)((unsigned long)wp + mmr_base() + mmr_off);
HW_TRACE_WRITE ();
switch (mmr_off)
{
case mmr_offset(iactl):
case mmr_offset(ia[0]) ... mmr_offset(ia[WPI_NUM - 1]):
case mmr_offset(iacnt[0]) ... mmr_offset(iacnt[WPI_NUM - 1]):
case mmr_offset(dactl):
case mmr_offset(da[0]) ... mmr_offset(da[WPD_NUM - 1]):
case mmr_offset(dacnt[0]) ... mmr_offset(dacnt[WPD_NUM - 1]):
*valuep = value;
break;
case mmr_offset(stat):
/* Yes, the hardware is this dumb -- clear all bits on any write. */
*valuep = 0;
break;
default:
dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
break;
}
return nr_bytes;
}
static unsigned
bfin_wp_io_read_buffer (struct hw *me, void *dest, int space,
address_word addr, unsigned nr_bytes)
{
struct bfin_wp *wp = hw_data (me);
bu32 mmr_off;
bu32 value;
bu32 *valuep;
mmr_off = addr - wp->base;
valuep = (void *)((unsigned long)wp + mmr_base() + mmr_off);
HW_TRACE_READ ();
switch (mmr_off)
{
case mmr_offset(iactl):
case mmr_offset(ia[0]) ... mmr_offset(ia[WPI_NUM - 1]):
case mmr_offset(iacnt[0]) ... mmr_offset(iacnt[WPI_NUM - 1]):
case mmr_offset(dactl):
case mmr_offset(da[0]) ... mmr_offset(da[WPD_NUM - 1]):
case mmr_offset(dacnt[0]) ... mmr_offset(dacnt[WPD_NUM - 1]):
case mmr_offset(stat):
value = *valuep;
break;
default:
while (1) /* Core MMRs -> exception -> doesn't return. */
dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
break;
}
dv_store_4 (dest, value);
return nr_bytes;
}
static void
attach_bfin_wp_regs (struct hw *me, struct bfin_wp *wp)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != BFIN_COREMMR_WP_SIZE)
hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_WP_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
wp->base = attach_address;
}
static void
bfin_wp_finish (struct hw *me)
{
struct bfin_wp *wp;
wp = HW_ZALLOC (me, struct bfin_wp);
set_hw_data (me, wp);
set_hw_io_read_buffer (me, bfin_wp_io_read_buffer);
set_hw_io_write_buffer (me, bfin_wp_io_write_buffer);
attach_bfin_wp_regs (me, wp);
}
const struct hw_descriptor dv_bfin_wp_descriptor[] = {
{"bfin_wp", bfin_wp_finish,},
{NULL, NULL},
};

27
sim/bfin/dv-bfin_wp.h Normal file
View File

@ -0,0 +1,27 @@
/* Blackfin Watchpoint (WP) model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 DV_BFIN_WP_H
#define DV_BFIN_WP_H
#define BFIN_COREMMR_WP_BASE 0xFFE07000
#define BFIN_COREMMR_WP_SIZE 0x204
#endif

206
sim/bfin/dv-eth_phy.c Normal file
View File

@ -0,0 +1,206 @@
/* Ethernet Physical Receiver model.
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "sim-main.h"
#include "devices.h"
#ifdef HAVE_LINUX_MII_H
/* Workaround old/broken linux headers. */
#define _LINUX_TYPES_H
#define __u16 unsigned short
#include <linux/mii.h>
#define REG_PHY_SIZE 0x20
struct eth_phy
{
bu32 base;
bu16 regs[REG_PHY_SIZE];
};
#define reg_base() offsetof(struct eth_phy, regs[0])
#define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
#define reg_idx(reg) (reg_offset (reg) / 4)
static const char * const reg_names[] = {
[MII_BMCR ] = "MII_BMCR",
[MII_BMSR ] = "MII_BMSR",
[MII_PHYSID1 ] = "MII_PHYSID1",
[MII_PHYSID2 ] = "MII_PHYSID2",
[MII_ADVERTISE ] = "MII_ADVERTISE",
[MII_LPA ] = "MII_LPA",
[MII_EXPANSION ] = "MII_EXPANSION",
#ifdef MII_CTRL1000
[MII_CTRL1000 ] = "MII_CTRL1000",
#endif
#ifdef MII_STAT1000
[MII_STAT1000 ] = "MII_STAT1000",
#endif
#ifdef MII_ESTATUS
[MII_ESTATUS ] = "MII_ESTATUS",
#endif
[MII_DCOUNTER ] = "MII_DCOUNTER",
[MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
[MII_NWAYTEST ] = "MII_NWAYTEST",
[MII_RERRCOUNTER] = "MII_RERRCOUNTER",
[MII_SREVISION ] = "MII_SREVISION",
[MII_RESV1 ] = "MII_RESV1",
[MII_LBRERROR ] = "MII_LBRERROR",
[MII_PHYADDR ] = "MII_PHYADDR",
[MII_RESV2 ] = "MII_RESV2",
[MII_TPISTATUS ] = "MII_TPISTATUS",
[MII_NCONFIG ] = "MII_NCONFIG",
};
#define mmr_name(off) (reg_names[off] ? : "<INV>")
#define mmr_off reg_off
static unsigned
eth_phy_io_write_buffer (struct hw *me, const void *source,
int space, address_word addr, unsigned nr_bytes)
{
struct eth_phy *phy = hw_data (me);
bu16 reg_off;
bu16 value;
bu16 *valuep;
value = dv_load_2 (source);
reg_off = addr - phy->base;
valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
HW_TRACE_WRITE ();
switch (reg_off)
{
case MII_BMCR:
*valuep = value;
break;
case MII_PHYSID1:
case MII_PHYSID2:
/* Discard writes to these. */
break;
default:
/* XXX: Discard writes to unknown regs ? */
*valuep = value;
break;
}
return nr_bytes;
}
static unsigned
eth_phy_io_read_buffer (struct hw *me, void *dest,
int space, address_word addr, unsigned nr_bytes)
{
struct eth_phy *phy = hw_data (me);
bu16 reg_off;
bu16 *valuep;
reg_off = addr - phy->base;
valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
HW_TRACE_READ ();
switch (reg_off)
{
case MII_BMCR:
dv_store_2 (dest, *valuep);
break;
case MII_BMSR:
/* XXX: Let people control this ? */
*valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
dv_store_2 (dest, *valuep);
break;
case MII_LPA:
/* XXX: Let people control this ? */
*valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
dv_store_2 (dest, *valuep);
break;
default:
dv_store_2 (dest, *valuep);
break;
}
return nr_bytes;
}
static void
attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
{
address_word attach_address;
int attach_space;
unsigned attach_size;
reg_property_spec reg;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain three addr/size entries");
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&attach_space, &attach_address, me);
hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
if (attach_size != REG_PHY_SIZE)
hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
hw_attach_address (hw_parent (me),
0, attach_space, attach_address, attach_size, me);
phy->base = attach_address;
}
static void
eth_phy_finish (struct hw *me)
{
struct eth_phy *phy;
phy = HW_ZALLOC (me, struct eth_phy);
set_hw_data (me, phy);
set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
attach_eth_phy_regs (me, phy);
/* Initialize the PHY. */
phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */
phy->regs[MII_PHYSID2] = 0xAD; /* Product */
}
#else
static void
eth_phy_finish (struct hw *me)
{
HW_TRACE ((me, "No linux/mii.h support found"));
}
#endif
const struct hw_descriptor dv_eth_phy_descriptor[] = {
{"eth_phy", eth_phy_finish,},
{NULL, NULL},
};

286
sim/bfin/gui.c Normal file
View File

@ -0,0 +1,286 @@
/* Blackfin GUI (SDL) helper code
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#ifdef HAVE_SDL
# include <SDL.h>
#endif
#ifdef HAVE_DLFCN_H
# include <dlfcn.h>
#endif
#include "libiberty.h"
#include "gui.h"
#ifdef HAVE_SDL
static struct {
void *handle;
int (*Init) (Uint32 flags);
void (*Quit) (void);
SDL_Surface *(*SetVideoMode) (int width, int height, int bpp, Uint32 flags);
void (*WM_SetCaption) (const char *title, const char *icon);
int (*ShowCursor) (int toggle);
int (*LockSurface) (SDL_Surface *surface);
void (*UnlockSurface) (SDL_Surface *surface);
void (*GetRGB) (Uint32 pixel, const SDL_PixelFormat * const fmt, Uint8 *r, Uint8 *g, Uint8 *b);
Uint32 (*MapRGB) (const SDL_PixelFormat * const format, const Uint8 r, const Uint8 g, const Uint8 b);
void (*UpdateRect) (SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h);
} sdl;
static const char * const sdl_syms[] = {
"SDL_Init",
"SDL_Quit",
"SDL_SetVideoMode",
"SDL_WM_SetCaption",
"SDL_ShowCursor",
"SDL_LockSurface",
"SDL_UnlockSurface",
"SDL_GetRGB",
"SDL_MapRGB",
"SDL_UpdateRect",
};
struct gui_state {
SDL_Surface *screen;
const SDL_PixelFormat *format;
int throttle, throttle_limit;
enum gui_color color;
int curr_line;
};
/* Load the SDL lib on the fly to avoid hard linking against it. */
static int
bfin_gui_sdl_setup (void)
{
int i;
uintptr_t **funcs;
if (sdl.handle)
return 0;
sdl.handle = dlopen ("libSDL-1.2.so.0", RTLD_LAZY);
if (sdl.handle == NULL)
return -1;
funcs = (void *) &sdl.Init;
for (i = 0; i < ARRAY_SIZE (sdl_syms); ++i)
{
funcs[i] = dlsym (sdl.handle, sdl_syms[i]);
if (funcs[i] == NULL)
{
dlclose (sdl.handle);
sdl.handle = NULL;
return -1;
}
}
return 0;
}
static const SDL_PixelFormat *bfin_gui_color_format (enum gui_color color);
void *
bfin_gui_setup (void *state, int enabled, int width, int height,
enum gui_color color)
{
if (bfin_gui_sdl_setup ())
return NULL;
/* Create an SDL window if enabled and we don't have one yet. */
if (enabled && !state)
{
struct gui_state *gui = xmalloc (sizeof (*gui));
if (!gui)
return NULL;
if (sdl.Init (SDL_INIT_VIDEO))
goto error;
gui->color = color;
gui->format = bfin_gui_color_format (gui->color);
gui->screen = sdl.SetVideoMode (width, height, 32,
SDL_ANYFORMAT|SDL_HWSURFACE);
if (!gui->screen)
{
sdl.Quit();
goto error;
}
sdl.WM_SetCaption ("GDB Blackfin Simulator", NULL);
sdl.ShowCursor (0);
gui->curr_line = 0;
gui->throttle = 0;
gui->throttle_limit = 0xf; /* XXX: let people control this ? */
return gui;
error:
free (gui);
return NULL;
}
/* Else break down a window if disabled and we had one. */
else if (!enabled && state)
{
sdl.Quit();
free (state);
return NULL;
}
/* Retain existing state, whatever that may be. */
return state;
}
static int
SDL_ConvertBlitLineFrom (const Uint8 *src, const SDL_PixelFormat * const format,
SDL_Surface *dst, int dsty)
{
Uint8 r, g, b;
Uint32 *pixels;
unsigned i, j;
if (SDL_MUSTLOCK (dst))
if (sdl.LockSurface (dst))
return 1;
pixels = dst->pixels;
pixels += (dsty * dst->pitch / 4);
for (i = 0; i < dst->w; ++i)
{
/* Exract the packed source pixel; RGB or BGR. */
Uint32 pix = 0;
for (j = 0; j < format->BytesPerPixel; ++j)
if (format->Rshift)
pix = (pix << 8) | src[j];
else
pix = pix | ((Uint32)src[j] << (j * 8));
/* Unpack the source pixel into its components. */
sdl.GetRGB (pix, format, &r, &g, &b);
/* Translate into the screen pixel format. */
*pixels++ = sdl.MapRGB (dst->format, r, g, b);
src += format->BytesPerPixel;
}
if (SDL_MUSTLOCK (dst))
sdl.UnlockSurface (dst);
sdl.UpdateRect (dst, 0, dsty, dst->w, 1);
return 0;
}
unsigned
bfin_gui_update (void *state, const void *source, unsigned nr_bytes)
{
struct gui_state *gui = state;
int ret;
if (!gui)
return 0;
/* XXX: Make this an option ? */
gui->throttle = (gui->throttle + 1) & gui->throttle_limit;
if (gui->throttle)
return 0;
ret = SDL_ConvertBlitLineFrom (source, gui->format, gui->screen,
gui->curr_line);
if (ret)
return 0;
gui->curr_line = (gui->curr_line + 1) % gui->screen->h;
return nr_bytes;
}
#define FMASK(cnt, shift) (((1 << (cnt)) - 1) << (shift))
#define _FORMAT(bpp, rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) \
NULL, bpp, (bpp)/8, 8-(rcnt), 8-(gcnt), 8-(bcnt), 8-(acnt), rsh, gsh, bsh, ash, \
FMASK (rcnt, rsh), FMASK (gcnt, gsh), FMASK (bcnt, bsh), FMASK (acnt, ash),
#define FORMAT(rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) \
_FORMAT(((((rcnt) + (gcnt) + (bcnt) + (acnt)) + 7) / 8) * 8, \
rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash)
static const SDL_PixelFormat sdl_rgb_565 = {
FORMAT (5, 6, 5, 0, 11, 5, 0, 0)
};
static const SDL_PixelFormat sdl_bgr_565 = {
FORMAT (5, 6, 5, 0, 0, 5, 11, 0)
};
static const SDL_PixelFormat sdl_rgb_888 = {
FORMAT (8, 8, 8, 0, 16, 8, 0, 0)
};
static const SDL_PixelFormat sdl_bgr_888 = {
FORMAT (8, 8, 8, 0, 0, 8, 16, 0)
};
static const SDL_PixelFormat sdl_rgba_8888 = {
FORMAT (8, 8, 8, 8, 24, 16, 8, 0)
};
static const struct {
const char *name;
const SDL_PixelFormat *format;
enum gui_color color;
} color_spaces[] = {
{ "rgb565", &sdl_rgb_565, GUI_COLOR_RGB_565, },
{ "bgr565", &sdl_bgr_565, GUI_COLOR_BGR_565, },
{ "rgb888", &sdl_rgb_888, GUI_COLOR_RGB_888, },
{ "bgr888", &sdl_bgr_888, GUI_COLOR_BGR_888, },
{ "rgba8888", &sdl_rgba_8888, GUI_COLOR_RGBA_8888, },
};
enum gui_color bfin_gui_color (const char *color)
{
int i;
if (!color)
goto def;
for (i = 0; i < ARRAY_SIZE (color_spaces); ++i)
if (!strcmp (color, color_spaces[i].name))
return color_spaces[i].color;
/* Pick a random default. */
def:
return GUI_COLOR_RGB_888;
}
static const SDL_PixelFormat *bfin_gui_color_format (enum gui_color color)
{
int i;
for (i = 0; i < ARRAY_SIZE (color_spaces); ++i)
if (color == color_spaces[i].color)
return color_spaces[i].format;
return NULL;
}
int bfin_gui_color_depth (enum gui_color color)
{
const SDL_PixelFormat *format = bfin_gui_color_format (color);
return format ? format->BitsPerPixel : 0;
}
#endif

50
sim/bfin/gui.h Normal file
View File

@ -0,0 +1,50 @@
/* Blackfin GUI (SDL) helper code
Copyright (C) 2010-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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 BFIN_GUI_H
#define BFIN_GUI_H
#ifdef HAVE_SDL
enum gui_color {
GUI_COLOR_RGB_565,
GUI_COLOR_BGR_565,
GUI_COLOR_RGB_888,
GUI_COLOR_BGR_888,
GUI_COLOR_RGBA_8888,
};
enum gui_color bfin_gui_color (const char *color);
int bfin_gui_color_depth (enum gui_color color);
void *bfin_gui_setup (void *state, int enabled, int height, int width,
enum gui_color color);
unsigned bfin_gui_update (void *state, const void *source, unsigned nr_bytes);
#else
# define bfin_gui_color(...) 0
# define bfin_gui_color_depth(...) 0
# define bfin_gui_setup(...) NULL
# define bfin_gui_update(...) 0
#endif
#endif

62
sim/bfin/insn_list.def Normal file
View File

@ -0,0 +1,62 @@
/* Blackfin instruction classes list
Copyright (C) 2005-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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/>. */
/* Only bother with insn groups rather than exact insn (for now?). */
I(ProgCtrl_nop)
I(ProgCtrl_branch)
I(ProgCtrl_sync)
I(ProgCtrl_cec)
I(ProgCtrl_atomic)
I(CaCTRL)
I(PushPopReg)
I(PushPopMultiple)
I(ccMV)
I(CCflag)
I(CC2dreg)
I(CC2stat)
I(BRCC)
I(UJUMP)
I(REGMV)
I(ALU2op)
I(PTR2op)
I(LOGI2op)
I(COMP3op)
I(COMPI2opD)
I(COMPI2opP)
I(LDSTpmod)
I(dagMODim)
I(dagMODik)
I(dspLDST)
I(LDST)
I(LDSTiiFP)
I(LDSTii)
I(LoopSetup)
I(LDIMMhalf)
I(CALLa)
I(LDSTidxI)
I(linkage)
I(dsp32mac)
I(dsp32mult)
I(dsp32alu)
I(dsp32shift)
I(dsp32shiftimm)
I(psedoDEBUG)
I(psedoOChar)
I(psedodbg_assert)

1241
sim/bfin/interp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/* DO NOT EDIT: Autogenerated from linux-fixed-code.s. */
static const unsigned char bfin_linux_fixed_code[] = {
0x28, 0xe1, 0xad, 0x00,
0xa0, 0x00,
0x00, 0x20,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x91,
0x01, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x91,
0x08, 0x08,
0x02, 0x10,
0x02, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x01, 0x91,
0x01, 0x50,
0x00, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x01, 0x91,
0x01, 0x52,
0x00, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x01, 0x91,
0x01, 0x56,
0x00, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x01, 0x91,
0x01, 0x54,
0x00, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x01, 0x91,
0x01, 0x58,
0x00, 0x93,
0x10, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0xa4, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
};

View File

@ -0,0 +1,85 @@
/* Linux fixed code userspace ABI
Copyright (C) 2005-2011 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of 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 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/>. */
/* For more info, see this page:
http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:fixed-code */
.text
.align 16
_sigreturn_stub:
P0 = 173;
EXCPT 0;
0: JUMP.S 0b;
.align 16
_atomic_xchg32:
R0 = [P0];
[P0] = R1;
rts;
.align 16
_atomic_cas32:
R0 = [P0];
CC = R0 == R1;
IF !CC JUMP 1f;
[P0] = R2;
1:
rts;
.align 16
_atomic_add32:
R1 = [P0];
R0 = R1 + R0;
[P0] = R0;
rts;
.align 16
_atomic_sub32:
R1 = [P0];
R0 = R1 - R0;
[P0] = R0;
rts;
.align 16
_atomic_ior32:
R1 = [P0];
R0 = R1 | R0;
[P0] = R0;
rts;
.align 16
_atomic_and32:
R1 = [P0];
R0 = R1 & R0;
[P0] = R0;
rts;
.align 16
_atomic_xor32:
R1 = [P0];
R0 = R1 ^ R0;
[P0] = R0;
rts;
.align 16
_safe_user_instruction:
NOP; NOP; NOP; NOP;
EXCPT 0x4;

1992
sim/bfin/linux-targ-map.h Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More