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
@ -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…
x
Reference in New Issue
Block a user