(sim_open): Create a device tree.
(sim-hw.h): Include.
(do_interrupt): Delete, needs to use dv-mn103cpu.c
* dv-mn103int.c, dv-mn103cpu.c: New files.
config.in
configure
configure.in
+dv-mn103cpu.c
+dv-mn103int.c
mn10300_sim.h
gencode.c
interp.c
+Wed Mar 25 15:08:49 1998 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * interp.c (sim_open): Create second 1mb memory region at
+ 0x40000000.
+ (sim_open): Create a device tree.
+ (sim-hw.h): Include.
+ (do_interrupt): Delete, needs to use dv-mn103cpu.c
+
+ * dv-mn103int.c, dv-mn103cpu.c: New files.
+
Wed Mar 25 08:47:38 1998 Andrew Cagney <cagney@b1.cygnus.com>
* mn10300_sim.h (EXTRACT_PSW_LM, INSERT_PSW_LM, PSW_IE, PSW_LM):
--enable-sim-reserved-bits Specify whether to check reserved bits in instruction."
ac_help="$ac_help
--enable-sim-bitsize=N Specify target bitsize (32 or 64)."
+ac_help="$ac_help
+ --enable-sim-hardware=LIST Specify the hardware to be included in the build."
ac_help="$ac_help
--enable-sim-common Enable common simulator"
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:630: checking how to run the C preprocessor" >&5
+echo "configure:632: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <<EOF
-#line 645 "configure"
+#line 647 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:651: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:653: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF
-#line 662 "configure"
+#line 664 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:668: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:670: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
fi
echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:741: checking host system type" >&5
+echo "configure:743: checking host system type" >&5
host_alias=$host
case "$host_alias" in
echo "$ac_t""$host" 1>&6
echo $ac_n "checking target system type""... $ac_c" 1>&6
-echo "configure:762: checking target system type" >&5
+echo "configure:764: checking target system type" >&5
target_alias=$target
case "$target_alias" in
echo "$ac_t""$target" 1>&6
echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:780: checking build system type" >&5
+echo "configure:782: checking build system type" >&5
build_alias=$build
case "$build_alias" in
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:824: checking for $ac_word" >&5
+echo "configure:826: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:853: checking for $ac_word" >&5
+echo "configure:855: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:901: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:903: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext <<EOF
-#line 911 "configure"
+#line 913 "configure"
#include "confdefs.h"
main(){return(0);}
EOF
-if { (eval echo configure:915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:917: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:935: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:937: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:940: checking whether we are using GNU C" >&5
+echo "configure:942: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
yes;
#endif
EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:949: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:951: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:964: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:966: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1003: checking for a BSD compatible install" >&5
+echo "configure:1005: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1069: checking for $ac_word" >&5
+echo "configure:1071: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1103: checking for $ac_hdr" >&5
+echo "configure:1105: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1108 "configure"
+#line 1110 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1113: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1115: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1143: checking for $ac_hdr" >&5
+echo "configure:1145: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1148 "configure"
+#line 1150 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1153: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1155: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1183: checking for $ac_hdr" >&5
+echo "configure:1185: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1188 "configure"
+#line 1190 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1193: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1195: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
for ac_func in getrusage time sigaction
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1222: checking for $ac_func" >&5
+echo "configure:1224: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1227 "configure"
+#line 1229 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1250: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1252: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:1423: checking return type of signal handlers" >&5
+echo "configure:1425: checking return type of signal handlers" >&5
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1428 "configure"
+#line 1430 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <signal.h>
int i;
; return 0; }
EOF
-if { (eval echo configure:1445: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1447: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_type_signal=void
else
if test "x$cross_compiling" = "xno"; then
echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1595: checking whether byte ordering is bigendian" >&5
+echo "configure:1597: checking whether byte ordering is bigendian" >&5
if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_cv_c_bigendian=unknown
# See if sys/param.h defines the BYTE_ORDER macro.
cat > conftest.$ac_ext <<EOF
-#line 1602 "configure"
+#line 1604 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/param.h>
#endif
; return 0; }
EOF
-if { (eval echo configure:1613: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1615: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
# It does; now see whether it defined to BIG_ENDIAN or not.
cat > conftest.$ac_ext <<EOF
-#line 1617 "configure"
+#line 1619 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/param.h>
#endif
; return 0; }
EOF
-if { (eval echo configure:1628: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1630: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_bigendian=yes
else
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <<EOF
-#line 1648 "configure"
+#line 1650 "configure"
#include "confdefs.h"
main () {
/* Are we little or big endian? From Harbison&Steele. */
exit (u.c[sizeof (long) - 1] == 1);
}
EOF
-if { (eval echo configure:1661: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_c_bigendian=no
else
fi
+sim_hardware="-DWITH_HW=1"
+sim_hw_obj="hw-device.o hw-ports.o hw-properties.o hw-base.o hw-tree.o"
+hardware="core pal glue mn103cpu mn103int"
+# Check whether --enable-sim-hardware or --disable-sim-hardware was given.
+if test "${enable_sim_hardware+set}" = set; then
+ enableval="$enable_sim_hardware"
+
+case "${enableval}" in
+ yes) ;;
+ no) hardware=""; sim_hardware="-DWITH_HW=0"; sim_hw_obj="";;
+ ,*) hardware="${hardware} `echo ${enableval} | sed -e 's/,/ /'`";;
+ *,) hardware="`echo ${enableval} | sed -e 's/,/ /'` ${hardware}";;
+ *) hardware="`echo ${enableval} | sed -e 's/,/ /'`"'';;
+esac
+sim_hw=""
+for i in x $hardware ; do
+ case " $f " in
+ x) ;;
+ *" $i "*) ;;
+ *) sim_hw="$sim_hw $i" ;;
+ esac
+done
+sim_hw_obj="$sim_hw_obj `echo $sim_hw | sed -e 's/\([^ ]*\)/dv-\1.o/g'`"
+if test x"$silent" != x"yes" && test x"$hardware" != x""; then
+ echo "Setting hardware to $sim_hardware, $sim_hw, $sim_hw_obj"
+fi
+else
+
+sim_hw="$hardware"
+sim_hw_obj="$sim_hw_obj `echo $sim_hw | sed -e 's/\([^ ]*\)/dv-\1.o/g'`"
+if test x"$silent" != x"yes"; then
+ echo "Setting hardware to $sim_hardware, $sim_hw, $sim_hw_obj"
+fi
+fi
+
+
for ac_func in time chmod utime fork execve execv chown
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1791: checking for $ac_func" >&5
+echo "configure:1829: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1796 "configure"
+#line 1834 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1819: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1847: checking for $ac_hdr" >&5
+echo "configure:1885: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1852 "configure"
+#line 1890 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1857: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1895: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
SIM_AC_OPTION_WARNINGS
SIM_AC_OPTION_RESERVED_BITS
SIM_AC_OPTION_BITSIZE(32,31)
+SIM_AC_OPTION_HARDWARE(,mn103cpu mn103int)
AC_CHECK_FUNCS(time chmod utime fork execve execv chown)
AC_CHECK_HEADERS(unistd.h stdlib.h string.h strings.h utime.h time.h)
--- /dev/null
+/* This file is part of the program GDB, the GU debugger.
+
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ 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.
+
+ */
+
+
+#include "sim-main.h"
+#include "hw-base.h"
+
+/* DEVICE
+
+
+ mn103cpu - mn10300 cpu virtual device
+
+
+ DESCRIPTION
+
+
+ Implements the external mn10300 functionality. This includes the
+ delivery of of interrupts generated from other devices and the
+ handling of device specific registers.
+
+
+ PROPERTIES
+
+
+ reg = <address> <size>
+
+ Specify the address of the mn10300's control register block. This
+ block contains the Interrupt Vector Registers.
+
+ The reg property value `0x20000000 0x42' locates the register block
+ at the address specified in the mn10300 user guide.
+
+
+ PORTS
+
+
+ reset (input)
+
+ Currently ignored.
+
+
+ nmi (input)
+
+ Deliver a non-maskable interrupt to the processor.
+
+
+ level (input)
+
+ Maskable interrupt level port port. The interrupt controller
+ notifies the processor of any change in the level of pending
+ requested interrupts via this port.
+
+
+ ack (output)
+
+ Output signal indicating that the processor is delivering a level
+ interrupt. The value passed with the event specfies the level of
+ the interrupt being delivered.
+
+
+ BUGS
+
+
+ When delivering an interrupt, this code assumes that there is only
+ one processor (number 0).
+
+ This code does not attempt to be efficient at handling pending
+ interrupts. It simply schedules the interrupt delivery handler
+ every instruction cycle until all pending interrupts go away. An
+ alternative implementation might modify instructions that change
+ the PSW and have them check to see if the change makes an interrupt
+ delivery possible.
+
+ */
+
+
+/* The interrupt vectors */
+
+enum { NR_VECTORS = 7, };
+
+
+/* The interrupt controller register address blocks */
+
+struct mn103cpu_block {
+ unsigned_word base;
+ unsigned_word bound;
+};
+
+
+struct mn103cpu {
+ struct mn103cpu_block block;
+ hw_event *pending_handler;
+ int pending_level;
+ int pending_nmi;
+ int pending_reset;
+ /* the visible registers */
+ unsigned16 interrupt_vector[NR_VECTORS];
+ unsigned16 internal_memory_control;
+ unsigned16 cpu_mode;
+};
+
+
+
+/* input port ID's */
+
+enum {
+ RESET_PORT,
+ NMI_PORT,
+ LEVEL_PORT,
+};
+
+
+/* input port ID's */
+
+enum {
+ ACK_PORT,
+};
+
+static const struct hw_port_descriptor mn103cpu_ports[] = {
+
+ /* interrupt inputs */
+ { "reset", RESET_PORT, 0, input_port, },
+ { "nmi", NMI_PORT, 0, input_port, },
+ { "level", LEVEL_PORT, 0, input_port, },
+
+ /* interrupt ack (latch) output from cpu */
+ { "ack", ACK_PORT, 0, output_port, },
+
+ { NULL, },
+};
+
+
+/* Finish off the partially created hw device. Attach our local
+ callbacks. Wire up our port names etc */
+
+static hw_io_read_buffer_callback mn103cpu_io_read_buffer;
+static hw_io_write_buffer_callback mn103cpu_io_write_buffer;
+static hw_port_event_callback mn103cpu_port_event;
+
+static void
+attach_mn103cpu_regs (struct hw *me,
+ struct mn103cpu *controller)
+{
+ unsigned_word attach_address;
+ int attach_space;
+ unsigned attach_size;
+ reg_property_spec reg;
+ if (hw_find_property (me, "reg") == NULL)
+ hw_abort (me, "Missing \"reg\" property");
+ if (!hw_find_reg_array_property (me, "reg", 0, ®))
+ hw_abort (me, "\"reg\" property must contain three addr/size entries");
+ hw_unit_address_to_attach_address (hw_parent (me),
+ ®.address,
+ &attach_space,
+ &attach_address,
+ me);
+ controller->block.base = attach_address;
+ hw_unit_size_to_attach_size (hw_parent (me),
+ ®.size,
+ &attach_size, me);
+ controller->block.bound = attach_address + (attach_size - 1);
+ if ((controller->block.base & 3) != 0)
+ hw_abort (me, "cpu register block must be 4 byte aligned");
+ hw_attach_address (hw_parent (me),
+ 0,
+ attach_space, attach_address, attach_size,
+ me);
+}
+
+
+static void
+mn103cpu_finish (struct hw *me)
+{
+ struct mn103cpu *controller;
+
+ controller = HW_ZALLOC (me, struct mn103cpu);
+ set_hw_data (me, controller);
+ set_hw_io_read_buffer (me, mn103cpu_io_read_buffer);
+ set_hw_io_write_buffer (me, mn103cpu_io_write_buffer);
+ set_hw_ports (me, mn103cpu_ports);
+ set_hw_port_event (me, mn103cpu_port_event);
+
+ /* Attach ourself to our parent bus */
+ attach_mn103cpu_regs (me, controller);
+
+ /* Initialize the read-only registers */
+ controller->pending_level = 7; /* FIXME */
+ /* ... */
+}
+
+
+
+/* An event arrives on an interrupt port */
+
+static void
+deliver_mn103cpu_interrupt (struct hw *me,
+ void *data)
+{
+ struct mn103cpu *controller = hw_data (me);
+ SIM_DESC simulator = hw_system (me);
+ sim_cpu *cpu = STATE_CPU (simulator, 0);
+
+ if (controller->pending_reset)
+ {
+ controller->pending_reset = 0;
+ /* need to clear all registers et.al! */
+ HW_TRACE ((me, "Reset!"));
+ hw_abort (me, "Reset!");
+ }
+ else if (controller->pending_nmi)
+ {
+ controller->pending_nmi = 0;
+ store_half (SP - 4, CIA_GET (cpu));
+ store_half (SP - 8, PSW);
+ PSW &= ~PSW_IE;
+ SP = SP - 8;
+ CIA_SET (cpu, 0x40000008);
+ HW_TRACE ((me, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
+ (long) CIA_GET (cpu), (unsigned) PSW, (long) SP));
+ }
+ else if ((controller->pending_level < EXTRACT_PSW_LM)
+ && (PSW & PSW_IE))
+ {
+ /* Don't clear pending level. Request continues to be pending
+ until the interrupt controller clears/changes it */
+ store_half (SP - 4, CIA_GET (cpu));
+ store_half (SP - 8, PSW);
+ PSW &= ~PSW_IE;
+ PSW &= ~PSW_LM;
+ PSW |= INSERT_PSW_LM (controller->pending_level);
+ SP = SP - 8;
+ CIA_SET (cpu, 0x40000000 + controller->interrupt_vector[controller->pending_level]);
+ HW_TRACE ((me, "port-out ack %d", controller->pending_level));
+ hw_port_event (me, ACK_PORT, controller->pending_level, NULL, NULL_CIA);
+ HW_TRACE ((me, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
+ controller->pending_level,
+ (long) CIA_GET (cpu), (unsigned) PSW, (long) SP));
+ }
+
+ /* As long as there is the potential need to deliver an interrupt we
+ keep rescheduling this routine. */
+ if (controller->pending_level < 7) /* FIXME */
+ {
+ if (controller->pending_handler != NULL)
+ controller->pending_handler =
+ hw_event_queue_schedule (me, 1, deliver_mn103cpu_interrupt, NULL);
+ }
+
+}
+
+
+static void
+mn103cpu_port_event (struct hw *me,
+ int my_port,
+ struct hw *source,
+ int source_port,
+ int level,
+ sim_cpu *processor,
+ sim_cia cia)
+{
+ struct mn103cpu *controller = hw_data (me);
+
+ /* Schedule our event handler *now* */
+ if (controller->pending_handler == NULL)
+ controller->pending_handler =
+ hw_event_queue_schedule (me, 0, deliver_mn103cpu_interrupt, NULL);
+
+ switch (my_port)
+ {
+
+ case RESET_PORT:
+ controller->pending_reset = 1;
+ HW_TRACE ((me, "port-in reset"));
+ break;
+
+ case NMI_PORT:
+ controller->pending_nmi = 1;
+ HW_TRACE ((me, "port-in nmi"));
+ break;
+
+ case LEVEL_PORT:
+ controller->pending_level = level;
+ HW_TRACE ((me, "port-in level=%d", level));
+ break;
+
+ default:
+ hw_abort (me, "bad switch");
+ break;
+
+ }
+}
+
+
+/* Read/write to a CPU register */
+
+enum mn103cpu_regs {
+ INVALID_REG,
+ IVR0_REG,
+ IVR1_REG,
+ IVR2_REG,
+ IVR3_REG,
+ IVR4_REG,
+ IVR5_REG,
+ IVR6_REG,
+ IMCR_REG,
+ CPUM_REG,
+};
+
+static enum mn103cpu_regs
+decode_mn103cpu_addr (struct hw *me,
+ struct mn103cpu *controller,
+ unsigned_word base)
+{
+ switch (base - controller->block.base)
+ {
+ case 0x000: return IVR0_REG;
+ case 0x004: return IVR1_REG;
+ case 0x008: return IVR2_REG;
+ case 0x00c: return IVR3_REG;
+ case 0x010: return IVR4_REG;
+ case 0x014: return IVR5_REG;
+ case 0x018: return IVR6_REG;
+ case 0x020: return IMCR_REG;
+ case 0x040: return CPUM_REG;
+ default: return INVALID_REG;
+ }
+}
+
+static unsigned
+mn103cpu_io_read_buffer (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ sim_cpu *processor,
+ sim_cia cia)
+{
+ struct mn103cpu *controller = hw_data (me);
+ unsigned16 val = 0;
+ enum mn103cpu_regs reg = decode_mn103cpu_addr (me, controller, base);
+
+ switch (reg)
+ {
+ case IVR0_REG:
+ case IVR1_REG:
+ case IVR2_REG:
+ case IVR3_REG:
+ case IVR4_REG:
+ case IVR5_REG:
+ case IVR6_REG:
+ val = controller->interrupt_vector[reg - IVR0_REG];
+ break;
+ case IMCR_REG:
+ val = controller->internal_memory_control;
+ break;
+ case CPUM_REG:
+ val = controller->cpu_mode;
+ break;
+ default:
+ /* just ignore the read */
+ break;
+ }
+
+ if (nr_bytes == 2)
+ *(unsigned16*) dest = H2LE_2 (val);
+
+ return nr_bytes;
+}
+
+static unsigned
+mn103cpu_io_write_buffer (struct hw *me,
+ const void *source,
+ int space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ sim_cpu *cpu,
+ sim_cia cia)
+{
+ struct mn103cpu *controller = hw_data (me);
+ unsigned16 val;
+ enum mn103cpu_regs reg;
+
+ if (nr_bytes != 2)
+ hw_abort (me, "must be two byte write");
+
+ reg = decode_mn103cpu_addr (me, controller, base);
+ val = LE2H_2 (* (unsigned16 *) source);
+
+ switch (reg)
+ {
+ case IVR0_REG:
+ case IVR1_REG:
+ case IVR2_REG:
+ case IVR3_REG:
+ case IVR4_REG:
+ case IVR5_REG:
+ case IVR6_REG:
+ controller->interrupt_vector[reg - IVR0_REG] = val;
+ HW_TRACE ((me, "ivr%d = 0x%04lx", reg - IVR0_REG, (long) val));
+ break;
+ default:
+ /* just ignore the write */
+ break;
+ }
+
+ return nr_bytes;
+}
+
+
+const struct hw_device_descriptor dv_mn103cpu_descriptor[] = {
+ { "mn103cpu", mn103cpu_finish, },
+ { NULL },
+};
--- /dev/null
+/* This file is part of the program GDB, the GU debugger.
+
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ 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.
+
+ */
+
+
+#include "sim-main.h"
+#include "hw-base.h"
+
+/* DEVICE
+
+
+ mn103int - mn10300 interrupt controller
+
+
+ DESCRIPTION
+
+
+ Implements the mn10300 interrupt controller described in the
+ mn10300 user guide.
+
+
+ PROPERTIES
+
+
+ reg = <icr-adr> <icr-siz> <iagr-adr> <iadr-siz> <extmd-adr> <extmd-siz>
+
+ Specify the address of the ICR (total of 25 registers), IAGR and
+ EXTMD registers (within the parent bus).
+
+ The reg property value `0x34000100 0x68 0x34000200 0x8 0x3400280
+ 0x8' locates the interrupt controller at the addresses specified in
+ the mn10300 interrupt controller user guide.
+
+
+ PORTS
+
+
+ nmi (output)
+
+ Non-maskable interrupt output port. An event on this output ports
+ indicates a NMI request from the interrupt controller. The value
+ attached to the event should be ignored.
+
+
+ level (output)
+
+ Maskable interrupt level output port. An event on this output port
+ indicates a maskable interrupt request at the specified level. The
+ event value defines the level being requested.
+
+ The interrupt controller will generate an event on this port
+ whenever there is a change to the internal state of the interrupt
+ controller.
+
+
+ ack (input)
+
+ Signal from processor indicating that a maskable interrupt has been
+ accepted and the interrupt controller should latch the IAGR with
+ value of the current highest priority interrupting group.
+
+ The event value is the interrupt level being accepted by the
+ processor. It should be consistent with the most recent LEVEL sent
+ to the processor from the interrupt controller.
+
+
+ int[0..100] (input)
+
+ Level or edge triggered interrupt input port. Each of the 25
+ groups (0..24) can have up to 4 (0..3) interrupt inputs. The
+ interpretation of a port event/value is determined by the
+ configuration of the corresponding interrupt group.
+
+ For convenience, numerous aliases to these interrupt inputs are
+ provided.
+
+
+ BUGS
+
+
+ For edge triggered interrupts, the interrupt controller does not
+ differentiate between POSITIVE (rising) and NEGATIVE (falling)
+ edges. Instead any input port event is considered to be an
+ interrupt trigger.
+
+ For level sensative interrupts, the interrupt controller ignores
+ active HIGH/LOW settings and instead always interprets a nonzero
+ port value as an interupt assertion and a zero port value as a
+ negation.
+
+ */
+
+
+/* The interrupt groups - numbered according to mn10300 convention */
+
+enum mn103int_trigger {
+ ACTIVE_LOW,
+ ACTIVE_HIGH,
+ POSITIVE_EDGE,
+ NEGATIVE_EDGE,
+};
+
+enum mn103int_type {
+ NMI_GROUP,
+ INT_GROUP,
+};
+
+struct mn103int_group {
+ int level;
+ unsigned enable;
+ unsigned request;
+ unsigned input;
+ enum mn103int_trigger trigger;
+ enum mn103int_type type;
+};
+
+enum {
+ FIRST_NMI_GROUP = 0,
+ LAST_NMI_GROUP = 1,
+ FIRST_INT_GROUP = 2,
+ LAST_INT_GROUP = 24,
+ NR_GROUPS,
+};
+
+enum {
+ LOWEST_LEVEL = 7,
+};
+
+/* The interrupt controller register address blocks */
+
+struct mn103int_block {
+ unsigned_word base;
+ unsigned_word bound;
+};
+
+enum { ICR_BLOCK, IAGR_BLOCK, EXTMD_BLOCK, NR_BLOCKS };
+
+
+struct mn103int {
+ struct mn103int_block block[NR_BLOCKS];
+ struct mn103int_group group[NR_GROUPS];
+ unsigned interrupt_accepted_group;
+};
+
+
+
+/* output port ID's */
+
+enum {
+ NMI_PORT,
+ LEVEL_PORT,
+};
+
+
+/* input port ID's */
+
+enum {
+ G0_PORT = 0,
+ G1_PORT = 4,
+ G2_PORT = 8,
+ G3_PORT = 12,
+ G4_PORT = 16,
+ G5_PORT = 20,
+ G6_PORT = 24,
+ G7_PORT = 28,
+ G8_PORT = 32,
+ G9_PORT = 36,
+ G10_PORT = 40,
+ G11_PORT = 44,
+ G12_PORT = 48,
+ G13_PORT = 52,
+ G14_PORT = 56,
+ G15_PORT = 60,
+ G16_PORT = 64,
+ G17_PORT = 68,
+ G18_PORT = 72,
+ G19_PORT = 76,
+ G20_PORT = 80,
+ G21_PORT = 84,
+ G22_PORT = 88,
+ G23_PORT = 92,
+ G24_PORT = 96,
+ NR_G_PORTS = 100,
+ ACK_PORT,
+};
+
+static const struct hw_port_descriptor mn103int_ports[] = {
+
+ /* interrupt outputs */
+
+ { "nmi", NMI_PORT, 0, output_port, },
+ { "level", LEVEL_PORT, 0, output_port, },
+
+ /* interrupt ack (latch) input from cpu */
+
+ { "ack", ACK_PORT, 0, input_port, },
+
+ /* interrupt inputs (as names) */
+
+ { "nmirq", G0_PORT + 0, 0, input_port, },
+ { "watchdog", G0_PORT + 1, 0, input_port, },
+ { "syserr", G0_PORT + 2, 0, input_port, },
+
+ { "timer-0-underflow", G2_PORT + 0, 0, input_port, },
+ { "timer-1-underflow", G2_PORT + 1, 0, input_port, },
+ { "timer-2-underflow", G2_PORT + 2, 0, input_port, },
+ { "timer-3-underflow", G2_PORT + 3, 0, input_port, },
+ { "timer-4-underflow", G3_PORT + 0, 0, input_port, },
+ { "timer-5-underflow", G3_PORT + 1, 0, input_port, },
+ { "timer-6-underflow", G3_PORT + 2, 0, input_port, },
+ { "timer-7-underflow", G3_PORT + 3, 0, input_port, },
+
+ { "timer-8-underflow", G4_PORT + 0, 0, input_port, },
+ { "timer-8-compare-a", G4_PORT + 1, 0, input_port, },
+ { "timer-8-compare-b", G4_PORT + 2, 0, input_port, },
+
+ { "timer-9-underflow", G5_PORT + 0, 0, input_port, },
+ { "timer-9-compare-a", G5_PORT + 1, 0, input_port, },
+ { "timer-9-compare-b", G5_PORT + 2, 0, input_port, },
+
+ { "timer-10-underflow", G6_PORT + 0, 0, input_port, },
+ { "timer-10-compare-a", G6_PORT + 1, 0, input_port, },
+ { "timer-10-compare-b", G6_PORT + 2, 0, input_port, },
+ { "timer-10-compare-c", G6_PORT + 3, 0, input_port, },
+
+ { "timer-11-underflow", G7_PORT + 0, 0, input_port, },
+ { "timer-11-compare-a", G7_PORT + 1, 0, input_port, },
+ { "timer-11-compare-b", G7_PORT + 2, 0, input_port, },
+ { "timer-11-compare-c", G7_PORT + 3, 0, input_port, },
+
+ { "timer-12-underflow", G8_PORT + 0, 0, input_port, },
+ { "timer-12-compare-a", G8_PORT + 1, 0, input_port, },
+ { "timer-12-compare-b", G8_PORT + 2, 0, input_port, },
+ { "timer-12-compare-c", G8_PORT + 3, 0, input_port, },
+
+ { "timer-11-compare-d", G9_PORT + 0, 0, input_port, },
+ { "timer-12-compare-d", G9_PORT + 1, 0, input_port, },
+
+ { "dma-0-end", G10_PORT, 0, input_port, },
+ { "dma-1-end", G11_PORT, 0, input_port, },
+ { "dma-2-end", G12_PORT, 0, input_port, },
+ { "dma-3-end", G13_PORT, 0, input_port, },
+
+ { "serial-0-recieve", G14_PORT + 0, 0, input_port, },
+ { "serial-0-transmit", G14_PORT + 1, 0, input_port, },
+
+ { "serial-1-recieve", G15_PORT + 0, 0, input_port, },
+ { "serial-1-transmit", G15_PORT + 1, 0, input_port, },
+
+ { "irq-0", G16_PORT, 0, input_port, },
+ { "irq-1", G17_PORT, 0, input_port, },
+ { "irq-2", G18_PORT, 0, input_port, },
+ { "irq-3", G19_PORT, 0, input_port, },
+ { "irq-4", G20_PORT, 0, input_port, },
+ { "irq-5", G21_PORT, 0, input_port, },
+ { "irq-6", G22_PORT, 0, input_port, },
+ { "irq-7", G23_PORT, 0, input_port, },
+
+ { "ad-end", G24_PORT, 0, input_port, },
+
+ /* interrupt inputs (as generic numbers) */
+
+ { "int", 0, NR_G_PORTS, input_port, },
+
+ { NULL, },
+};
+
+
+/* Macros for extracting/restoring the various register bits */
+
+#define EXTRACT_ID(X) (LSEXTRACTED8 ((X), 3, 0))
+#define INSERT_ID(X) (LSINSERTED8 ((X), 3, 0))
+
+#define EXTRACT_IR(X) (LSEXTRACTED8 ((X), 7, 4))
+#define INSERT_IR(X) (LSINSERTED8 ((X), 7, 4))
+
+#define EXTRACT_IE(X) (LSEXTRACTED8 ((X), 3, 0))
+#define INSERT_IE(X) (LSINSERTED8 ((X), 3, 0))
+
+#define EXTRACT_LV(X) (LSEXTRACTED8 ((X), 6, 4))
+#define INSERT_LV(X) (LSINSERTED8 ((X), 6, 4))
+
+
+
+/* Finish off the partially created hw device. Attach our local
+ callbacks. Wire up our port names etc */
+
+static hw_io_read_buffer_callback mn103int_io_read_buffer;
+static hw_io_write_buffer_callback mn103int_io_write_buffer;
+static hw_port_event_callback mn103int_port_event;
+
+static void
+attach_mn103int_regs (struct hw *me,
+ struct mn103int *controller)
+{
+ int i;
+ if (hw_find_property (me, "reg") == NULL)
+ hw_abort (me, "Missing \"reg\" property");
+ for (i = 0; i < NR_BLOCKS; i++)
+ {
+ unsigned_word attach_address;
+ int attach_space;
+ unsigned attach_size;
+ reg_property_spec reg;
+ if (!hw_find_reg_array_property (me, "reg", i, ®))
+ 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);
+ controller->block[i].base = attach_address;
+ hw_unit_size_to_attach_size (hw_parent (me),
+ ®.size,
+ &attach_size, me);
+ controller->block[i].bound = attach_address + (attach_size - 1);
+ hw_attach_address (hw_parent (me),
+ 0,
+ attach_space, attach_address, attach_size,
+ me);
+ }
+}
+
+static void
+mn103int_finish (struct hw *me)
+{
+ int gid;
+ struct mn103int *controller;
+
+ controller = HW_ZALLOC (me, struct mn103int);
+ set_hw_data (me, controller);
+ set_hw_io_read_buffer (me, mn103int_io_read_buffer);
+ set_hw_io_write_buffer (me, mn103int_io_write_buffer);
+ set_hw_ports (me, mn103int_ports);
+ set_hw_port_event (me, mn103int_port_event);
+
+ /* Attach ourself to our parent bus */
+ attach_mn103int_regs (me, controller);
+
+ /* Initialize all the groups according to their default configuration */
+ for (gid = 0; gid < NR_GROUPS; gid++)
+ {
+ struct mn103int_group *group = &controller->group[gid];
+ group->enable = 0xf;
+ group->trigger = NEGATIVE_EDGE;
+ if (FIRST_NMI_GROUP <= gid && gid <= LAST_NMI_GROUP)
+ {
+ group->type = NMI_GROUP;
+ }
+ else if (FIRST_INT_GROUP <= gid && gid <= LAST_INT_GROUP)
+ {
+ group->type = INT_GROUP;
+ }
+ else
+ hw_abort (me, "internal error - unknown group id");
+ }
+}
+
+
+
+/* Perform the nasty work of figuring out which of the interrupt
+ groups should have its interrupt delivered. */
+
+static int
+find_highest_interrupt_group (struct hw *me,
+ struct mn103int *controller)
+{
+ int gid;
+ int selected;
+
+ /* FIRST_NMI_GROUP (group zero) is used as a special default value
+ when searching for an interrupt group */
+ selected = FIRST_NMI_GROUP;
+ controller->group[FIRST_NMI_GROUP].level = 7;
+
+ for (gid = FIRST_INT_GROUP; gid <= LAST_INT_GROUP; gid++)
+ {
+ struct mn103int_group *group = &controller->group[gid];
+ if ((group->request & group->enable) != 0)
+ {
+ if (group->level > controller->group[selected].level)
+ {
+ selected = gid;
+ }
+ }
+ }
+ return selected;
+}
+
+
+/* Notify the processor of an interrupt level update */
+
+static void
+push_interrupt_level (struct hw *me,
+ struct mn103int *controller)
+{
+ int selected = find_highest_interrupt_group (me, controller);
+ int level = controller->group[selected].level;
+ HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level));
+ hw_port_event (me, LEVEL_PORT, level, NULL, NULL_CIA);
+}
+
+
+/* An event arrives on an interrupt port */
+
+static void
+mn103int_port_event (struct hw *me,
+ int my_port,
+ struct hw *source,
+ int source_port,
+ int level,
+ sim_cpu *processor,
+ sim_cia cia)
+{
+ struct mn103int *controller = hw_data (me);
+
+ switch (my_port)
+ {
+
+ case ACK_PORT:
+ {
+ int selected = find_highest_interrupt_group (me, controller);
+ if (controller->group[selected].level != level)
+ hw_abort (me, "botched level synchronisation");
+ controller->interrupt_accepted_group = selected;
+ HW_TRACE ((me, "port-event port=ack level=%d - selected=%d",
+ level, selected));
+ break;
+ }
+
+ default:
+ {
+ int gid;
+ int iid;
+ struct mn103int_group *group;
+ unsigned interrupt;
+ if (my_port > NR_G_PORTS)
+ hw_abort (me, "Event on unknown port %d", my_port);
+
+ /* map the port onto an interrupt group */
+ gid = (my_port % NR_G_PORTS) / 4;
+ group = &controller->group[gid];
+ iid = (my_port % 4);
+ interrupt = 1 << iid;
+
+ /* update our cached input */
+ if (level)
+ group->input |= interrupt;
+ else
+ group->input &= ~interrupt;
+
+ /* update the request bits */
+ switch (group->trigger)
+ {
+ case ACTIVE_LOW:
+ case ACTIVE_HIGH:
+ if (level)
+ group->request |= interrupt;
+ break;
+ case NEGATIVE_EDGE:
+ case POSITIVE_EDGE:
+ group->request |= interrupt;
+ }
+
+ /* force a corresponding output */
+ switch (group->type)
+ {
+
+ case NMI_GROUP:
+ {
+ /* for NMI's the event is the trigger */
+ HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - NMI",
+ my_port, gid, iid));
+ if ((group->request & group->enable) != 0)
+ {
+ HW_TRACE ((me, "port-out NMI"));
+ hw_port_event (me, NMI_PORT, 0, NULL, NULL_CIA);
+ }
+ break;
+ }
+
+ case INT_GROUP:
+ {
+ /* if an interrupt is now pending */
+ HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT",
+ my_port, gid, iid));
+ push_interrupt_level (me, controller);
+ break;
+ }
+ }
+ break;
+ }
+
+ }
+}
+
+/* Read/write to to an ICR (group control register) */
+
+static unsigned8
+read_icr (struct hw *me,
+ struct mn103int *controller,
+ struct mn103int_group *group,
+ unsigned_word offset)
+{
+ unsigned8 val = 0;
+ switch (group->type)
+ {
+
+ case NMI_GROUP:
+ switch (offset)
+ {
+ case 0:
+ val = INSERT_ID (group->request);
+ HW_TRACE ((me, "read-icr 0x%02x", val));
+ break;
+ }
+ break;
+
+ case INT_GROUP:
+ switch (offset)
+ {
+ case 0:
+ val = (INSERT_IR (group->request)
+ | INSERT_ID (group->request & group->enable));
+ HW_TRACE ((me, "read-icr 0:0x%02x", val));
+ break;
+ case 1:
+ val = (INSERT_LV (group->level)
+ | INSERT_IE (group->enable));
+ HW_TRACE ((me, "read-icr 1:0x%02x", val));
+ break;
+ }
+ }
+
+ return val;
+}
+
+static void
+write_icr (struct hw *me,
+ struct mn103int *controller,
+ struct mn103int_group *group,
+ unsigned_word offset,
+ unsigned8 val)
+{
+ switch (group->type)
+ {
+
+ case NMI_GROUP:
+ switch (offset)
+ {
+ case 0:
+ HW_TRACE ((me, "write-icr 0x%02x", val));
+ group->request &= ~EXTRACT_ID (val);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case INT_GROUP:
+ switch (offset)
+ {
+ case 0: /* request/detect */
+ /* Clear any ID bits and then set them according to IR */
+ HW_TRACE ((me, "write-icr 0:0x%02x", val));
+ group->request &= EXTRACT_ID (val);
+ group->request |= EXTRACT_IR (val) & EXTRACT_ID (val);
+ break;
+ case 1: /* level/enable */
+ HW_TRACE ((me, "write-icr 1:0x%02x", val));
+ group->level = EXTRACT_LV (val);
+ group->enable = EXTRACT_IE (val);
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+ push_interrupt_level (me, controller);
+ break;
+
+ }
+}
+
+
+/* Read the IAGR (Interrupt accepted group register) */
+
+static unsigned8
+read_iagr (struct hw *me,
+ struct mn103int *controller,
+ unsigned_word offset)
+{
+ unsigned8 val;
+ switch (offset)
+ {
+ case 0:
+ {
+ val = (controller->interrupt_accepted_group << 2);
+ if (!(controller->group[val].request
+ & controller->group[val].enable))
+ /* oops, lost the request */
+ val = 0;
+ break;
+ }
+ default:
+ val = 0;
+ }
+ return val;
+}
+
+
+/* Reads/writes to the EXTMD (external interrupt trigger configuration
+ register) */
+
+static struct mn103int_group *
+external_group (struct mn103int *controller,
+ unsigned_word offset)
+{
+ switch (offset)
+ {
+ case 0:
+ return &controller->group[16];
+ case 1:
+ return &controller->group[20];
+ default:
+ return NULL;
+ }
+}
+
+static unsigned8
+read_extmd (struct hw *me,
+ struct mn103int *controller,
+ unsigned_word offset)
+{
+ int gid;
+ unsigned8 val = 0;
+ struct mn103int_group *group = external_group (controller, offset);
+ if (group != NULL)
+ {
+ for (gid = 0; gid < 4; gid++)
+ {
+ val |= (group[gid].trigger << (gid * 2));
+ }
+ }
+ return val;
+}
+
+static void
+write_extmd (struct hw *me,
+ struct mn103int *controller,
+ unsigned_word offset,
+ unsigned8 val)
+{
+ int gid;
+ struct mn103int_group *group = external_group (controller, offset);
+ if (group != NULL)
+ {
+ for (gid = 0; gid < 4; gid++)
+ {
+ group[gid].trigger = (val >> (gid * 2)) & 0x3;
+ /* MAYBE: interrupts already pending? */
+ }
+ }
+}
+
+
+/* generic read/write */
+
+static int
+decode_addr (struct hw *me,
+ struct mn103int *controller,
+ unsigned_word addr)
+{
+ int i;
+ for (i = 0; i < NR_BLOCKS; i++)
+ {
+ if (addr >= controller->block[i].base
+ && addr <= controller->block[i].bound)
+ return i;
+ }
+ hw_abort (me, "bad address");
+ return -1;
+}
+
+static struct mn103int_group *
+decode_group (struct hw *me,
+ struct mn103int *controller,
+ unsigned_word addr)
+{
+ unsigned_word offset = (addr - controller->block[ICR_BLOCK].base);
+ int gid = (offset / 8) % NR_GROUPS;
+ return &controller->group[gid];
+}
+
+static unsigned
+mn103int_io_read_buffer (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ sim_cpu *processor,
+ sim_cia cia)
+{
+ struct mn103int *controller = hw_data (me);
+ unsigned8 *buf = dest;
+ unsigned byte;
+ for (byte = 0; byte < nr_bytes; byte++)
+ {
+ unsigned_word address = base + byte;
+ switch (decode_addr (me, controller, address))
+ {
+ case ICR_BLOCK:
+ buf[byte] = read_icr (me, controller,
+ decode_group (me, controller, address),
+ address);
+ break;
+ case IAGR_BLOCK:
+ buf[byte] = read_iagr (me, controller, address);
+ break;
+ case EXTMD_BLOCK:
+ buf[byte] = read_extmd (me, controller, address);
+ break;
+ default:
+ hw_abort (me, "bad switch");
+ }
+ }
+ return nr_bytes;
+}
+
+static unsigned
+mn103int_io_write_buffer (struct hw *me,
+ const void *source,
+ int space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ sim_cpu *cpu,
+ sim_cia cia)
+{
+ struct mn103int *controller = hw_data (me);
+ const unsigned8 *buf = source;
+ unsigned byte;
+ for (byte = 0; byte < nr_bytes; byte++)
+ {
+ unsigned_word address = base + byte;
+ switch (decode_addr (me, controller, address))
+ {
+ case ICR_BLOCK:
+ write_icr (me, controller,
+ decode_group (me, controller, address),
+ address, buf[byte]);
+ break;
+ case IAGR_BLOCK:
+ /* not allowed */
+ break;
+ case EXTMD_BLOCK:
+ write_extmd (me, controller, address, buf[byte]);
+ break;
+ default:
+ hw_abort (me, "bad switch");
+ }
+ }
+ return nr_bytes;
+}
+
+
+const struct hw_device_descriptor dv_mn103int_descriptor[] = {
+ { "mn103int", mn103int_finish, },
+ { NULL },
+};
#if WITH_COMMON
#include "sim-main.h"
#include "sim-options.h"
+#include "sim-hw.h"
#else
#include "mn10300_sim.h"
#endif
/* For compatibility */
SIM_DESC simulator;
-/* mn10300 interrupt model */
-
-enum interrupt_type
-{
- int_reset,
- int_nmi,
- int_intov1,
- int_intp10,
- int_intp11,
- int_intp12,
- int_intp13,
- int_intcm4,
- num_int_types
-};
-
-char *interrupt_names[] = {
- "reset",
- "nmi",
- "intov1",
- "intp10",
- "intp11",
- "intp12",
- "intp13",
- "intcm4",
- NULL
-};
-
-
-static void
-do_interrupt (sd, data)
- SIM_DESC sd;
- void *data;
-{
-#if 0
- char **interrupt_name = (char**)data;
- enum interrupt_type inttype;
- inttype = (interrupt_name - STATE_WATCHPOINTS (sd)->interrupt_names);
-
- /* For a hardware reset, drop everything and jump to the start
- address */
- if (inttype == int_reset)
- {
- PC = 0;
- PSW = 0x20;
- ECR = 0;
- sim_engine_restart (sd, NULL, NULL, NULL_CIA);
- }
-
- /* Deliver an NMI when allowed */
- if (inttype == int_nmi)
- {
- if (PSW & PSW_NP)
- {
- /* We're already working on an NMI, so this one must wait
- around until the previous one is done. The processor
- ignores subsequent NMIs, so we don't need to count them.
- Just keep re-scheduling a single NMI until it manages to
- be delivered */
- if (STATE_CPU (sd, 0)->pending_nmi != NULL)
- sim_events_deschedule (sd, STATE_CPU (sd, 0)->pending_nmi);
- STATE_CPU (sd, 0)->pending_nmi =
- sim_events_schedule (sd, 1, do_interrupt, data);
- return;
- }
- else
- {
- /* NMI can be delivered. Do not deschedule pending_nmi as
- that, if still in the event queue, is a second NMI that
- needs to be delivered later. */
- FEPC = PC;
- FEPSW = PSW;
- /* Set the FECC part of the ECR. */
- ECR &= 0x0000ffff;
- ECR |= 0x10;
- PSW |= PSW_NP;
- PSW &= ~PSW_EP;
- PSW |= PSW_ID;
- PC = 0x10;
- sim_engine_restart (sd, NULL, NULL, NULL_CIA);
- }
- }
-
- /* deliver maskable interrupt when allowed */
- if (inttype > int_nmi && inttype < num_int_types)
- {
- if ((PSW & PSW_NP) || (PSW & PSW_ID))
- {
- /* Can't deliver this interrupt, reschedule it for later */
- sim_events_schedule (sd, 1, do_interrupt, data);
- return;
- }
- else
- {
- /* save context */
- EIPC = PC;
- EIPSW = PSW;
- /* Disable further interrupts. */
- PSW |= PSW_ID;
- /* Indicate that we're doing interrupt not exception processing. */
- PSW &= ~PSW_EP;
- /* Clear the EICC part of the ECR, will set below. */
- ECR &= 0xffff0000;
- switch (inttype)
- {
- case int_intov1:
- PC = 0x80;
- ECR |= 0x80;
- break;
- case int_intp10:
- PC = 0x90;
- ECR |= 0x90;
- break;
- case int_intp11:
- PC = 0xa0;
- ECR |= 0xa0;
- break;
- case int_intp12:
- PC = 0xb0;
- ECR |= 0xb0;
- break;
- case int_intp13:
- PC = 0xc0;
- ECR |= 0xc0;
- break;
- case int_intcm4:
- PC = 0xd0;
- ECR |= 0xd0;
- break;
- default:
- /* Should never be possible. */
- sim_engine_abort (sd, NULL, NULL_CIA,
- "do_interrupt - internal error - bad switch");
- break;
- }
- }
- sim_engine_restart (sd, NULL, NULL, NULL_CIA);
- }
-
- /* some other interrupt? */
- sim_engine_abort (sd, NULL, NULL_CIA,
- "do_interrupt - internal error - interrupt %d unknown",
- inttype);
-#endif /* 0 */
-}
-
/* These default values correspond to expected usage for the chip. */
SIM_DESC
char **argv;
{
SIM_DESC sd = sim_state_alloc (kind, cb);
+ struct hw *hw;
mn10300_callback = cb;
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
/* for compatibility */
simulator = sd;
- /* FIXME: should be better way of setting up interrupts */
+ /* FIXME: should be better way of setting up interrupts. For
+ moment, only support watchpoints causing a breakpoint (gdb
+ halt). */
STATE_WATCHPOINTS (sd)->pc = &(PC);
STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
- STATE_WATCHPOINTS (sd)->interrupt_handler = do_interrupt;
- STATE_WATCHPOINTS (sd)->interrupt_names = interrupt_names;
+ STATE_WATCHPOINTS (sd)->interrupt_handler = NULL;
+ STATE_WATCHPOINTS (sd)->interrupt_names = NULL;
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
return 0;
/* Allocate core managed memory */
-
- /* "Mirror" the ROM addresses below 1MB. */
sim_do_command (sd, "memory region 0,0x100000");
+ sim_do_command (sd, "memory region 0x40000000,0x100000");
/* getopt will print the error message so we just have to exit if this fails.
FIXME: Hmmm... in the case of gdb we need getopt to call
return 0;
}
+ hw = hw_tree_create (sd, "core");
+ hw_tree_parse (hw, "/");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/trace? true");
+
+
+ /* interrupt controller */
+
+ hw_tree_parse (hw, "/mn103int@0x34000100");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/mn103int/trace? true");
+ hw_tree_parse (hw, "/mn103int/reg 0x34000100 0x68 0x34000200 0x8 0x3400280 0x8");
+
+ /* NMI input's */
+ hw_tree_parse (hw, "/glue@0x30000000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x30000000/trace? true");
+ hw_tree_parse (hw, "/glue@0x30000000/reg 0x30000000 16");
+ hw_tree_parse (hw, "/glue@0x30000000 > int1 nmirq /mn103int");
+ hw_tree_parse (hw, "/glue@0x30000000 > int2 watchdog /mn103int");
+ hw_tree_parse (hw, "/glue@0x30000000 > int3 syserr /mn103int");
+
+ /* NMI output */
+ hw_tree_parse (hw, "/mn103int > nmi int0 /glue@0x30000000");
+
+ /* ACK input */
+ hw_tree_parse (hw, "/glue@0x30002000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x30002000/trace? true");
+ hw_tree_parse (hw, "/glue@0x30002000/reg 0x30002000 4");
+ hw_tree_parse (hw, "/glue@0x30002000 > int ack /mn103int");
+
+ /* LEVEL output */
+ hw_tree_parse (hw, "/glue@0x30004000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x30004000/trace? true");
+ hw_tree_parse (hw, "/glue@0x30004000/reg 0x30004000 4");
+ hw_tree_parse (hw, "/mn103int > level int /glue@0x30004000");
+
+ /* A bunch of interrupt inputs */
+ hw_tree_parse (hw, "/glue@0x30006000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x30006000/trace? true");
+ hw_tree_parse (hw, "/glue@0x30006000/reg 0x30006000 16");
+ hw_tree_parse (hw, "/glue@0x30006000 > int0 irq-0 /mn103int");
+ hw_tree_parse (hw, "/glue@0x30006000 > int1 irq-1 /mn103int");
+ hw_tree_parse (hw, "/glue@0x30006000 > int2 irq-2 /mn103int");
+ hw_tree_parse (hw, "/glue@0x30006000 > int3 irq-3 /mn103int");
+
+
+ /* processor interrupt device */
+
+ /* the device */
+ hw_tree_parse (hw, "/mn103cpu@0x20000000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/mn103cpu@0x20000000/trace? true");
+ hw_tree_parse (hw, "/mn103cpu@0x20000000/reg 0x20000000 0x42");
+
+ /* DEBUG: ACK output wired upto a glue device */
+ hw_tree_parse (hw, "/glue@0x20002000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x20002000/trace? true");
+ hw_tree_parse (hw, "/glue@0x20002000/reg 0x20002000 4");
+ hw_tree_parse (hw, "/mn103cpu > ack int0 /glue@0x20002000");
+
+ /* DEBUG: RESET/NMI/LEVEL wired up to a glue device */
+ hw_tree_parse (hw, "/glue@0x20004000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x20004000/trace? true");
+ hw_tree_parse (hw, "/glue@0x20004000/reg 0x20004000 12");
+ hw_tree_parse (hw, "/glue@0x20004000 > int0 reset /mn103cpu");
+ hw_tree_parse (hw, "/glue@0x20004000 > int1 nmi /mn103cpu");
+ hw_tree_parse (hw, "/glue@0x20004000 > int2 level /mn103cpu");
+
+ /* The processor wired up to the real interrupt controller */
+ hw_tree_parse (hw, "/mn103cpu > ack ack /mn103int");
+ hw_tree_parse (hw, "/mn103int > level level /mn103cpu");
+ hw_tree_parse (hw, "/mn103int > nmi nmi /mn103cpu");
+
+
+ /* PAL */
+
+ /* the device */
+ hw_tree_parse (hw, "/pal@0x31000000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/pal@0x31000000/trace? true");
+ hw_tree_parse (hw, "/pal@0x31000000/reg 0x31000000 64");
+
+ /* DEBUG: PAL wired up to a glue device */
+ hw_tree_parse (hw, "/glue@0x31002000");
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_parse (hw, "/glue@0x31002000/trace? true");
+ hw_tree_parse (hw, "/glue@0x31002000/reg 0x31002000 16");
+ hw_tree_parse (hw, "/pal@0x31000000 > countdown int0 /glue@0x31002000");
+ hw_tree_parse (hw, "/pal@0x31000000 > timer int1 /glue@0x31002000");
+ hw_tree_parse (hw, "/pal@0x31000000 > int int2 /glue@0x31002000");
+ hw_tree_parse (hw, "/glue@0x31002000 > int0 int3 /glue@0x31002000");
+ hw_tree_parse (hw, "/glue@0x31002000 > int1 int3 /glue@0x31002000");
+ hw_tree_parse (hw, "/glue@0x31002000 > int2 int3 /glue@0x31002000");
+
+ /* The PAL wired up to the real interrupt controller */
+ hw_tree_parse (hw, "/pal@0x31000000 > countdown irq-0 /mn103int");
+ hw_tree_parse (hw, "/pal@0x31000000 > timer irq-1 /mn103int");
+ hw_tree_parse (hw, "/pal@0x31000000 > int irq-2 /mn103int");
+
+
+
+ hw_tree_finish (hw);
+ if (STATE_VERBOSE_P (sd))
+ hw_tree_print (hw);
+
/* check for/establish the a reference program image */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL