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:
parent
7dcf22fd41
commit
ef016f835f
110 changed files with 30357 additions and 0 deletions
|
@ -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
82
include/gdb/sim-bfin.h
Normal 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
|
||||
};
|
||||
|
|
@ -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.
|
||||
|
|
|
@ -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
97
sim/bfin/Makefile.in
Normal 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
28
sim/bfin/TODO
Normal 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
171
sim/bfin/aclocal.m4
vendored
Normal 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
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
350
sim/bfin/bfin-sim.h
Normal 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
43
sim/bfin/bfroms/all.h
Normal 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"
|
3
sim/bfin/bfroms/bf50x-0.0.h
Normal file
3
sim/bfin/bfroms/bf50x-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf50x_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf51x-0.0.h
Normal file
3
sim/bfin/bfroms/bf51x-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf51x_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf51x-0.1.h
Normal file
3
sim/bfin/bfroms/bf51x-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf51x_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf51x-0.2.h
Normal file
3
sim/bfin/bfroms/bf51x-0.2.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf51x_0_2[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf526-0.0.h
Normal file
3
sim/bfin/bfroms/bf526-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf526_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf526-0.1.h
Normal file
3
sim/bfin/bfroms/bf526-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf526_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf527-0.0.h
Normal file
3
sim/bfin/bfroms/bf527-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf527_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf527-0.1.h
Normal file
3
sim/bfin/bfroms/bf527-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf527_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf527-0.2.h
Normal file
3
sim/bfin/bfroms/bf527-0.2.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf527_0_2[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf533-0.1.h
Normal file
3
sim/bfin/bfroms/bf533-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf533_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf533-0.2.h
Normal file
3
sim/bfin/bfroms/bf533-0.2.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf533_0_2[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf533-0.3.h
Normal file
3
sim/bfin/bfroms/bf533-0.3.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf533_0_3[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf537-0.0.h
Normal file
3
sim/bfin/bfroms/bf537-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf537_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf537-0.1.h
Normal file
3
sim/bfin/bfroms/bf537-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf537_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf537-0.3.h
Normal file
3
sim/bfin/bfroms/bf537-0.3.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf537_0_3[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf538-0.0.h
Normal file
3
sim/bfin/bfroms/bf538-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf538_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf54x-0.0.h
Normal file
3
sim/bfin/bfroms/bf54x-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf54x_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf54x-0.1.h
Normal file
3
sim/bfin/bfroms/bf54x-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf54x_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf54x-0.2.h
Normal file
3
sim/bfin/bfroms/bf54x-0.2.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf54x_0_2[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf54x_l1-0.0.h
Normal file
3
sim/bfin/bfroms/bf54x_l1-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf54x_l1_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf54x_l1-0.1.h
Normal file
3
sim/bfin/bfroms/bf54x_l1-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf54x_l1_0_1[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf54x_l1-0.2.h
Normal file
3
sim/bfin/bfroms/bf54x_l1-0.2.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf54x_l1_0_2[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf561-0.5.h
Normal file
3
sim/bfin/bfroms/bf561-0.5.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf561_0_5[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf59x-0.0.h
Normal file
3
sim/bfin/bfroms/bf59x-0.0.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf59x_0_0[] = {
|
||||
};
|
3
sim/bfin/bfroms/bf59x_l1-0.1.h
Normal file
3
sim/bfin/bfroms/bf59x_l1-0.1.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* DO NOT EDIT: Autogenerated. */
|
||||
static const char bfrom_bf59x_l1_0_1[] = {
|
||||
};
|
176
sim/bfin/config.in
Normal file
176
sim/bfin/config.in
Normal 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
6779
sim/bfin/configure
vendored
Executable file
File diff suppressed because it is too large
Load diff
75
sim/bfin/configure.ac
Normal file
75
sim/bfin/configure.ac
Normal 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
163
sim/bfin/devices.c
Normal 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
156
sim/bfin/devices.h
Normal 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
807
sim/bfin/dv-bfin_cec.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
139
sim/bfin/dv-bfin_cec.h
Normal 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
267
sim/bfin/dv-bfin_ctimer.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
33
sim/bfin/dv-bfin_ctimer.h
Normal 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
553
sim/bfin/dv-bfin_dma.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
65
sim/bfin/dv-bfin_dma.h
Normal 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
469
sim/bfin/dv-bfin_dmac.c
Normal 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
32
sim/bfin/dv-bfin_dmac.h
Normal 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
456
sim/bfin/dv-bfin_ebiu_amc.c
Normal 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, ®))
|
||||
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),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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},
|
||||
};
|
31
sim/bfin/dv-bfin_ebiu_amc.h
Normal file
31
sim/bfin/dv-bfin_ebiu_amc.h
Normal 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
|
184
sim/bfin/dv-bfin_ebiu_ddrc.c
Normal file
184
sim/bfin/dv-bfin_ebiu_ddrc.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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},
|
||||
};
|
26
sim/bfin/dv-bfin_ebiu_ddrc.h
Normal file
26
sim/bfin/dv-bfin_ebiu_ddrc.h
Normal 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
201
sim/bfin/dv-bfin_ebiu_sdc.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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},
|
||||
};
|
39
sim/bfin/dv-bfin_ebiu_sdc.h
Normal file
39
sim/bfin/dv-bfin_ebiu_sdc.h
Normal 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
603
sim/bfin/dv-bfin_emac.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
61
sim/bfin/dv-bfin_emac.h
Normal 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
271
sim/bfin/dv-bfin_eppi.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
30
sim/bfin/dv-bfin_eppi.h
Normal 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
153
sim/bfin/dv-bfin_evt.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
31
sim/bfin/dv-bfin_evt.h
Normal 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
183
sim/bfin/dv-bfin_gptimer.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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},
|
||||
};
|
27
sim/bfin/dv-bfin_gptimer.h
Normal file
27
sim/bfin/dv-bfin_gptimer.h
Normal 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
157
sim/bfin/dv-bfin_jtag.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
27
sim/bfin/dv-bfin_jtag.h
Normal 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
574
sim/bfin/dv-bfin_mmu.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
94
sim/bfin/dv-bfin_mmu.h
Normal 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
241
sim/bfin/dv-bfin_nfc.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
41
sim/bfin/dv-bfin_nfc.h
Normal 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
307
sim/bfin/dv-bfin_otp.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
100
sim/bfin/dv-bfin_otp.h
Normal 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
187
sim/bfin/dv-bfin_pll.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
27
sim/bfin/dv-bfin_pll.h
Normal 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
231
sim/bfin/dv-bfin_ppi.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
32
sim/bfin/dv-bfin_ppi.h
Normal 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
194
sim/bfin/dv-bfin_rtc.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
26
sim/bfin/dv-bfin_rtc.h
Normal 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
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
27
sim/bfin/dv-bfin_sic.h
Normal 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
229
sim/bfin/dv-bfin_spi.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
54
sim/bfin/dv-bfin_spi.h
Normal 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
285
sim/bfin/dv-bfin_trace.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
37
sim/bfin/dv-bfin_trace.h
Normal 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
227
sim/bfin/dv-bfin_twi.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
38
sim/bfin/dv-bfin_twi.h
Normal 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
437
sim/bfin/dv-bfin_uart.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
49
sim/bfin/dv-bfin_uart.h
Normal 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
258
sim/bfin/dv-bfin_uart2.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
33
sim/bfin/dv-bfin_uart2.h
Normal 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
206
sim/bfin/dv-bfin_wdog.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
36
sim/bfin/dv-bfin_wdog.h
Normal 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
188
sim/bfin/dv-bfin_wp.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
27
sim/bfin/dv-bfin_wp.h
Normal 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
206
sim/bfin/dv-eth_phy.c
Normal 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, ®))
|
||||
hw_abort (me, "\"reg\" property must contain three addr/size entries");
|
||||
|
||||
hw_unit_address_to_attach_address (hw_parent (me),
|
||||
®.address,
|
||||
&attach_space, &attach_address, me);
|
||||
hw_unit_size_to_attach_size (hw_parent (me), ®.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
286
sim/bfin/gui.c
Normal 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
50
sim/bfin/gui.h
Normal 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
62
sim/bfin/insn_list.def
Normal 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
1241
sim/bfin/interp.c
Normal file
File diff suppressed because it is too large
Load diff
74
sim/bfin/linux-fixed-code.h
Normal file
74
sim/bfin/linux-fixed-code.h
Normal 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,
|
||||
};
|
85
sim/bfin/linux-fixed-code.s
Normal file
85
sim/bfin/linux-fixed-code.s
Normal 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
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
Loading…
Add table
Reference in a new issue