* interp.c (sim_open): Create second 1mb memory region at 0x40000000.
authorAndrew Cagney <cagney@redhat.com>
Wed, 25 Mar 1998 04:15:38 +0000 (04:15 +0000)
committerAndrew Cagney <cagney@redhat.com>
Wed, 25 Mar 1998 04:15:38 +0000 (04:15 +0000)
(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.

sim/mn10300/.Sanitize
sim/mn10300/ChangeLog
sim/mn10300/configure
sim/mn10300/configure.in
sim/mn10300/dv-mn103cpu.c [new file with mode: 0644]
sim/mn10300/dv-mn103int.c [new file with mode: 0644]
sim/mn10300/interp.c

index 6918ca8..d49e8fb 100644 (file)
@@ -28,6 +28,8 @@ Makefile.in
 config.in
 configure
 configure.in
+dv-mn103cpu.c
+dv-mn103int.c
 mn10300_sim.h
 gencode.c
 interp.c
index 02a8b9e..7a3f3f5 100644 (file)
@@ -1,3 +1,13 @@
+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):
index b3eefec..c0d6273 100755 (executable)
@@ -115,6 +115,8 @@ ac_help="$ac_help
 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"
 
 # Initialize some variables set by options.
@@ -626,7 +628,7 @@ fi
 
 
 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=
@@ -641,13 +643,13 @@ else
   # 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
   :
@@ -658,13 +660,13 @@ else
   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
   :
@@ -737,7 +739,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 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
@@ -758,7 +760,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 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
@@ -776,7 +778,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 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
@@ -820,7 +822,7 @@ test "$program_transform_name" = "" && program_transform_name="s,x,x,"
 # 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
@@ -849,7 +851,7 @@ if test -z "$CC"; then
   # 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
@@ -897,7 +899,7 @@ fi
 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.
@@ -907,11 +909,11 @@ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS
 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
@@ -931,12 +933,12 @@ if test $ac_cv_prog_cc_works = no; 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
@@ -945,7 +947,7 @@ 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
@@ -960,7 +962,7 @@ if test $ac_cv_prog_gcc = yes; then
   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
@@ -999,7 +1001,7 @@ fi
 # 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
@@ -1065,7 +1067,7 @@ AR=${AR-ar}
 # 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
@@ -1099,17 +1101,17 @@ for ac_hdr in stdlib.h string.h strings.h unistd.h time.h
 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*
@@ -1139,17 +1141,17 @@ for ac_hdr in sys/time.h sys/resource.h
 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*
@@ -1179,17 +1181,17 @@ for ac_hdr in fcntl.h
 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*
@@ -1218,12 +1220,12 @@ done
 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.  */
@@ -1246,7 +1248,7 @@ $ac_func();
 
 ; 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
@@ -1419,12 +1421,12 @@ fi
 
 
 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>
@@ -1441,7 +1443,7 @@ int main() {
 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
@@ -1591,14 +1593,14 @@ 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>
@@ -1609,11 +1611,11 @@ int main() {
 #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>
@@ -1624,7 +1626,7 @@ int main() {
 #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
@@ -1644,7 +1646,7 @@ if test "$cross_compiling" = yes; then
     { 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.  */
@@ -1657,7 +1659,7 @@ main () {
   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
@@ -1784,15 +1786,51 @@ fi
 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.  */
@@ -1815,7 +1853,7 @@ $ac_func();
 
 ; 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
@@ -1843,17 +1881,17 @@ for ac_hdr in unistd.h stdlib.h string.h strings.h utime.h time.h
 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*
index 7bbd463..8aeee59 100644 (file)
@@ -12,6 +12,7 @@ SIM_AC_OPTION_HOSTENDIAN
 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)
diff --git a/sim/mn10300/dv-mn103cpu.c b/sim/mn10300/dv-mn103cpu.c
new file mode 100644 (file)
index 0000000..87c684e
--- /dev/null
@@ -0,0 +1,431 @@
+/*  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, &reg))
+    hw_abort (me, "\"reg\" property must contain three addr/size entries");
+  hw_unit_address_to_attach_address (hw_parent (me),
+                                    &reg.address,
+                                    &attach_space,
+                                    &attach_address,
+                                    me);
+  controller->block.base = attach_address;
+  hw_unit_size_to_attach_size (hw_parent (me),
+                              &reg.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 },
+};
diff --git a/sim/mn10300/dv-mn103int.c b/sim/mn10300/dv-mn103int.c
new file mode 100644 (file)
index 0000000..061b9b8
--- /dev/null
@@ -0,0 +1,785 @@
+/*  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, &reg))
+       hw_abort (me, "\"reg\" property must contain three addr/size entries");
+      hw_unit_address_to_attach_address (hw_parent (me),
+                                        &reg.address,
+                                        &attach_space,
+                                        &attach_address,
+                                        me);
+      controller->block[i].base = attach_address;
+      hw_unit_size_to_attach_size (hw_parent (me),
+                                  &reg.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 },
+};
index eede9a7..4c14b70 100644 (file)
@@ -3,6 +3,7 @@
 #if WITH_COMMON
 #include "sim-main.h"
 #include "sim-options.h"
+#include "sim-hw.h"
 #else
 #include "mn10300_sim.h"
 #endif
@@ -892,151 +893,6 @@ sim_load (sd, prog, abfd, from_tty)
 /* 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
@@ -1047,6 +903,7 @@ sim_open (kind, cb, abfd, argv)
      char **argv;
 {
   SIM_DESC sd = sim_state_alloc (kind, cb);
+  struct hw *hw;
   mn10300_callback = cb;
 
   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
@@ -1054,19 +911,20 @@ sim_open (kind, cb, abfd, argv)
   /* 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
@@ -1079,6 +937,117 @@ sim_open (kind, cb, abfd, argv)
       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