* cris/dv-cris.c, cris/dv-rv.c, cris/rvdummy.c: New files.
authorHans-Peter Nilsson <hp@axis.com>
Mon, 3 Apr 2006 03:01:45 +0000 (03:01 +0000)
committerHans-Peter Nilsson <hp@axis.com>
Mon, 3 Apr 2006 03:01:45 +0000 (03:01 +0000)
* cris/Makefile.in (CONFIG_DEVICES): Remove redundant setting.
(dv-cris.o, dv-rv.o rvdummy$(EXEEXT), rvdummy.o): New rules.
(all): Depend on rvdummy$(EXEEXT).
* cris/configure.ac: Call SIM_AC_OPTION_WARNINGS.  Check for
sys/socket.h and sys/select.h.  Call SIM_AC_OPTION_HARDWARE,
default off.
* cris/configure: Regenerate.
* cris/cris-sim.h (cris_have_900000xxif): Declare here.
(enum cris_interrupt_type, crisv10deliver_interrupt)
(crisv32deliver_interrupt: New declarations.
* cris/cris-tmpl.c [WITH_HW] (MY (f_model_insn_after)): Call
sim_events_tickn and set state-events member work_pending when it's
time for the next event.
[WITH_HW] (MY (f_specific_init)): Set CPU-model-specific
interrupt-delivery function.
* cris/crisv10f.c (MY (deliver_interrupt)): New function.
* cris/crisv32f.c (MY (deliver_interrupt)): New function.
* cris/devices.c: Include hw-device.h.
(device_io_read_buffer) [WITH_HW]: Call hw_io_read_buffer.
(device_io_write_buffer): Only perform 0x900000xx-functions if
cris_have_900000xxif is nonzero.  Else if WITH_HW defined,
call hw_io_write_buffer.  Add return 0 last in function.
* cris/sim-if.c (cris_have_900000xxif): Now global.
(sim_open) [WITH_HW]: Clear deliver_interrupt cpu member.
Force "-model" option, effectively.
* cris/sim-main.h (cris_interrupt_delivery_fn): New type.
(struct _sim_cpu) [WITH_HW]: New member deliver_interrupt.

14 files changed:
sim/ChangeLog
sim/cris/Makefile.in
sim/cris/configure
sim/cris/configure.ac
sim/cris/cris-sim.h
sim/cris/cris-tmpl.c
sim/cris/crisv10f.c
sim/cris/crisv32f.c
sim/cris/devices.c
sim/cris/dv-cris.c [new file with mode: 0644]
sim/cris/dv-rv.c [new file with mode: 0644]
sim/cris/rvdummy.c [new file with mode: 0644]
sim/cris/sim-if.c
sim/cris/sim-main.h

index 4d45bda70e4cc32ffc4e01c236f00ccada3e4b12..144426a6aa6f321ec2a3262604762f1184893403 100644 (file)
@@ -1,3 +1,34 @@
+2006-04-03  Hans-Peter Nilsson  <hp@axis.com>
+
+       * cris/dv-cris.c, cris/dv-rv.c, cris/rvdummy.c: New files.
+       * cris/Makefile.in (CONFIG_DEVICES): Remove redundant setting.
+       (dv-cris.o, dv-rv.o rvdummy$(EXEEXT), rvdummy.o): New rules.
+       (all): Depend on rvdummy$(EXEEXT).
+       * cris/configure.ac: Call SIM_AC_OPTION_WARNINGS.  Check for
+       sys/socket.h and sys/select.h.  Call SIM_AC_OPTION_HARDWARE,
+       default off.
+       * cris/configure: Regenerate.
+       * cris/cris-sim.h (cris_have_900000xxif): Declare here.
+       (enum cris_interrupt_type, crisv10deliver_interrupt)
+       (crisv32deliver_interrupt: New declarations.
+       * cris/cris-tmpl.c [WITH_HW] (MY (f_model_insn_after)): Call
+       sim_events_tickn and set state-events member work_pending when it's
+       time for the next event.
+       [WITH_HW] (MY (f_specific_init)): Set CPU-model-specific
+       interrupt-delivery function.
+       * cris/crisv10f.c (MY (deliver_interrupt)): New function.
+       * cris/crisv32f.c (MY (deliver_interrupt)): New function.
+       * cris/devices.c: Include hw-device.h.
+       (device_io_read_buffer) [WITH_HW]: Call hw_io_read_buffer.
+       (device_io_write_buffer): Only perform 0x900000xx-functions if
+       cris_have_900000xxif is nonzero.  Else if WITH_HW defined,
+       call hw_io_write_buffer.  Add return 0 last in function.
+       * cris/sim-if.c (cris_have_900000xxif): Now global.
+       (sim_open) [WITH_HW]: Clear deliver_interrupt cpu member.
+       Force "-model" option, effectively.
+       * cris/sim-main.h (cris_interrupt_delivery_fn): New type.
+       (struct _sim_cpu) [WITH_HW]: New member deliver_interrupt.
+
 2006-04-02  Hans-Peter Nilsson  <hp@axis.com>
 
        * cris/Makefile.in (CRISV10F_OBJS): Remove semcrisv10f-switch.o.
index 313a0630dd6e6953593d3a72531818e84279ab73..e30740143e34e67110cf069963d982cbff3f7fad 100644 (file)
@@ -23,7 +23,6 @@
 CRISV10F_OBJS = crisv10f.o cpuv10.o decodev10.o modelv10.o mloopv10f.o
 CRISV32F_OBJS = crisv32f.o cpuv32.o decodev32.o modelv32.o mloopv32f.o
 
-CONFIG_DEVICES = dv-sockser.o
 CONFIG_DEVICES =
 
 SIM_OBJS = \
@@ -62,11 +61,29 @@ arch = cris
 
 sim-if.o: sim-if.c $(SIM_MAIN_DEPS) $(sim-core_h) $(sim-options_h)
 
+# Needs CPU-specific knowledge.
+dv-cris.o: dv-cris.c $(SIM_MAIN_DEPS) $(sim-core_h)
+
+# This is the same rule as dv-core.o etc.
+dv-rv.o: dv-rv.c $(hw_main_headers) $(sim_main_headers)
+
 arch.o: arch.c $(SIM_MAIN_DEPS)
 
 traps.o: traps.c targ-vals.h $(SIM_MAIN_DEPS) $(sim-options_h)
 devices.o: devices.c $(SIM_MAIN_DEPS)
 
+# rvdummy is just used for testing.  It does nothing if
+# --enable-sim-hardware isn't active.
+
+all: rvdummy$(EXEEXT)
+
+check: rvdummy$(EXEEXT)
+
+rvdummy$(EXEEXT): rvdummy.o $(EXTRA_LIBDEPS)
+       $(CC) $(ALL_CFLAGS) -o rvdummy$(EXEEXT) rvdummy.o $(EXTRA_LIBS)
+
+rvdummy.o: rvdummy.c config.h tconfig.h $(remote_sim_h) $(callback_h)
+
 # CRISV10 objs
 
 CRISV10F_INCLUDE_DEPS = \
index 253368c2ec7747f05cec5b444a16a2540079610b..b15e7dc6004578003b9dbb7f132a5084010fa8b1 100755 (executable)
@@ -861,6 +861,9 @@ Optional Features:
   --enable-sim-alignment=align         Specify strict,  nonstrict or forced alignment of memory accesses.
   --enable-sim-hostendian=end          Specify host byte endian orientation.
   --enable-sim-scache=size             Specify simulator execution cache size.
+  --enable-build-warnings Enable build-time compiler warnings if gcc is used
+  --enable-gdb-build-warnings Enable SIM specific build-time compiler warnings if gcc is used
+  --enable-sim-hardware=LIST           Specify the hardware to be included in the build.
   --enable-sim-default-model=model     Specify default model to simulate.
   --enable-sim-environment=environment Specify mixed, user, virtual or operating environment.
   --enable-sim-inline=inlines          Specify which functions should be inlined.
@@ -7040,6 +7043,159 @@ sim_link_files="${sim_link_files} ${TARG_VALS_DEF}"
 sim_link_links="${sim_link_links} targ-vals.def"
 
 
+# For dv-rv and rvdummy.
+
+
+for ac_header in sys/socket.h sys/select.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
 wire_alignment="NONSTRICT_ALIGNMENT"
 default_alignment=""
 
@@ -7367,6 +7523,180 @@ else
 fi;
 
 
+# NOTE: Don't add -Wall or -Wunused, they both include
+# -Wunused-parameter which reports bogus warnings.
+# NOTE: If you add to this list, remember to update
+# gdb/doc/gdbint.texinfo.
+build_warnings="-Wimplicit -Wreturn-type -Wcomment -Wtrigraphs \
+-Wformat -Wparentheses -Wpointer-arith"
+# GCC supports -Wuninitialized only with -O or -On, n != 0.
+if test x${CFLAGS+set} = xset; then
+  case "${CFLAGS}" in
+    *"-O0"* ) ;;
+    *"-O"* )
+      build_warnings="${build_warnings} -Wuninitialized"
+    ;;
+  esac
+else
+  build_warnings="${build_warnings} -Wuninitialized"
+fi
+# Up for debate: -Wswitch -Wcomment -trigraphs -Wtrigraphs
+# -Wunused-function -Wunused-label -Wunused-variable -Wunused-value
+# -Wchar-subscripts -Wtraditional -Wshadow -Wcast-qual
+# -Wcast-align -Wwrite-strings -Wconversion -Wstrict-prototypes
+# -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls
+# -Woverloaded-virtual -Winline -Werror"
+# Check whether --enable-build-warnings or --disable-build-warnings was given.
+if test "${enable_build_warnings+set}" = set; then
+  enableval="$enable_build_warnings"
+  case "${enableval}" in
+  yes) ;;
+  no)  build_warnings="-w";;
+  ,*)   t=`echo "${enableval}" | sed -e "s/,/ /g"`
+        build_warnings="${build_warnings} ${t}";;
+  *,)   t=`echo "${enableval}" | sed -e "s/,/ /g"`
+        build_warnings="${t} ${build_warnings}";;
+  *)    build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;;
+esac
+if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then
+  echo "Setting compiler warning flags = $build_warnings" 6>&1
+fi
+fi; # Check whether --enable-sim-build-warnings or --disable-sim-build-warnings was given.
+if test "${enable_sim_build_warnings+set}" = set; then
+  enableval="$enable_sim_build_warnings"
+  case "${enableval}" in
+  yes) ;;
+  no)  build_warnings="-w";;
+  ,*)   t=`echo "${enableval}" | sed -e "s/,/ /g"`
+        build_warnings="${build_warnings} ${t}";;
+  *,)   t=`echo "${enableval}" | sed -e "s/,/ /g"`
+        build_warnings="${t} ${build_warnings}";;
+  *)    build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;;
+esac
+if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then
+  echo "Setting GDB specific compiler warning flags = $build_warnings" 6>&1
+fi
+fi; WARN_CFLAGS=""
+WERROR_CFLAGS=""
+if test "x${build_warnings}" != x -a "x$GCC" = xyes
+then
+    echo "$as_me:$LINENO: checking compiler warning flags" >&5
+echo $ECHO_N "checking compiler warning flags... $ECHO_C" >&6
+    # Separate out the -Werror flag as some files just cannot be
+    # compiled with it enabled.
+    for w in ${build_warnings}; do
+       case $w in
+       -Werr*) WERROR_CFLAGS=-Werror ;;
+       *) # Check that GCC accepts it
+           saved_CFLAGS="$CFLAGS"
+           CFLAGS="$CFLAGS $w"
+           cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  WARN_CFLAGS="${WARN_CFLAGS} $w"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+           CFLAGS="$saved_CFLAGS"
+       esac
+    done
+    echo "$as_me:$LINENO: result: ${WARN_CFLAGS}${WERROR_CFLAGS}" >&5
+echo "${ECHO_T}${WARN_CFLAGS}${WERROR_CFLAGS}" >&6
+fi
+
+
+if test x"no" = x"yes"; then
+  sim_hw_p=yes
+else
+  sim_hw_p=no
+fi
+if test ""; then
+  hardware="core pal glue"
+else
+  hardware="core pal glue rv cris"
+fi
+sim_hw_cflags="-DWITH_HW=1"
+sim_hw="$hardware"
+sim_hw_objs="\$(SIM_COMMON_HW_OBJS) `echo $sim_hw | sed -e 's/\([^ ][^ ]*\)/dv-\1.o/g'`"
+# 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) sim_hw_p=yes;;
+  no)  sim_hw_p=no;;
+  ,*)   sim_hw_p=yes; hardware="${hardware} `echo ${enableval} | sed -e 's/,/ /'`";;
+  *,)   sim_hw_p=yes; hardware="`echo ${enableval} | sed -e 's/,/ /'` ${hardware}";;
+  *)   sim_hw_p=yes; hardware="`echo ${enableval} | sed -e 's/,/ /'`"'';;
+esac
+if test "$sim_hw_p" != yes; then
+  sim_hw_objs=
+  sim_hw_cflags="-DWITH_HW=0"
+  sim_hw=
+else
+  sim_hw_cflags="-DWITH_HW=1"
+  # remove duplicates
+  sim_hw=""
+  sim_hw_objs="\$(SIM_COMMON_HW_OBJS)"
+  for i in $hardware ; do
+    case " $sim_hw " in
+      *" $i "*) ;;
+      *) sim_hw="$sim_hw $i" ; sim_hw_objs="$sim_hw_objs dv-$i.o";;
+    esac
+  done
+fi
+if test x"$silent" != x"yes" && test "$sim_hw_p" = "yes"; then
+  echo "Setting hardware to $sim_hw_cflags, $sim_hw, $sim_hw_objs"
+fi
+else
+
+if test "$sim_hw_p" != yes; then
+  sim_hw_objs=
+  sim_hw_cflags="-DWITH_HW=0"
+  sim_hw=
+fi
+if test x"$silent" != x"yes"; then
+  echo "Setting hardware to $sim_hw_cflags, $sim_hw, $sim_hw_objs"
+fi
+fi;
+
 # The default model shouldn't matter as long as there's a BFD.
 
 default_sim_default_model="crisv32"
index a34a50bae8be10d6b20c51d567cdc0f89b6affe4..a349d8da94593997ab227a05df024ac1c814a465 100644 (file)
@@ -9,9 +9,14 @@ sinclude(../common/aclocal.m4)
 # it by inlining the macro's contents.
 sinclude(../common/common.m4)
 
+# For dv-rv and rvdummy.
+AC_CHECK_HEADERS(sys/socket.h sys/select.h)
+
 SIM_AC_OPTION_ALIGNMENT(NONSTRICT_ALIGNMENT)
 SIM_AC_OPTION_HOSTENDIAN
 SIM_AC_OPTION_SCACHE(16384)
+SIM_AC_OPTION_WARNINGS
+SIM_AC_OPTION_HARDWARE(no,,rv cris)
 
 # The default model shouldn't matter as long as there's a BFD.
 SIM_AC_OPTION_DEFAULT_MODEL(crisv32)
index 66f736510f1976c9bef7042b9c3e73f870c38e33..49a6f61e583a62263f2861f5063e413715ebfc84 100644 (file)
@@ -1,5 +1,5 @@
 /* Collection of junk for CRIS.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Axis Communications.
 
 This file is part of the GNU simulators.
@@ -86,6 +86,14 @@ extern USI crisv10f_break_handler (SIM_CPU *, USI, USI);
 extern USI crisv32f_break_handler (SIM_CPU *, USI, USI);
 extern USI cris_break_13_handler (SIM_CPU *, USI, USI, USI, USI, USI, USI,
                                  USI, USI);
+extern char cris_have_900000xxif;
+enum cris_interrupt_type { CRIS_INT_NMI, CRIS_INT_RESET, CRIS_INT_INT };
+extern int crisv10deliver_interrupt (SIM_CPU *,
+                                    enum cris_interrupt_type,
+                                      unsigned int);
+extern int crisv32deliver_interrupt (SIM_CPU *,
+                                    enum cris_interrupt_type,
+                                    unsigned int);
 
 /* Using GNU syntax (not C99) so we can compile this on RH 6.2
    (egcs-1.1.2/gcc-2.91.66).  */
index 8994a11de696fd54d365f9dd7ea95f51c8186deb..81d1ca2de79b5b4b20ec799d4c127a498e0bee98 100644 (file)
@@ -178,6 +178,18 @@ MY (f_model_insn_after) (SIM_CPU *current_cpu, int last_p ATTRIBUTE_UNUSED,
   PROFILE_MODEL_TOTAL_CYCLES (p) += cycles;
   CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count += cycles;
   PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles;
+
+#if WITH_HW
+  /* For some reason, we don't get to the sim_events_tick call in
+     cgen-run.c:engine_run_1.  Besides, more than one cycle has
+     passed, so we want sim_events_tickn anyway.  The "events we want
+     to process" is usually to initiate an interrupt, but might also
+     be other events.  We can't do the former until the main loop is
+     at point where it accepts changing the PC without internal
+     inconsistency, so just set a flag and wait.  */
+  if (sim_events_tickn (CPU_STATE (current_cpu), cycles))
+    STATE_EVENTS (CPU_STATE (current_cpu))->work_pending = 1;
+#endif
 }
 
 /* Initialize cycle counting for an insn.
@@ -245,6 +257,9 @@ MY (f_specific_init) (SIM_CPU *current_cpu)
 {
   current_cpu->make_thread_cpu_data = MY (make_thread_cpu_data);
   current_cpu->thread_cpu_data_size = sizeof (current_cpu->cpu_data);
+#if WITH_HW
+  current_cpu->deliver_interrupt = MY (deliver_interrupt);
+#endif
 }
 \f
 /* Model function for arbitrary single stall cycles.  */
index 0c2a17c801fced4fe075f89eb96591819705aedd..976badb56838e82dec3367d1fe93af841529b895 100644 (file)
@@ -1,5 +1,5 @@
 /* CRIS v10 simulator support code
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Axis Communications.
 
 This file is part of the GNU simulators.
@@ -40,3 +40,62 @@ MY (XCONCAT3 (f_model_crisv,BASENUM,
 }
 
 #endif /* WITH_PROFILE_MODEL_P */
+
+/* Do the interrupt sequence if possible, and return 1.  If interrupts
+   are disabled or some other lockout is active, return 0 and do
+   nothing.
+
+   Beware, the v10 implementation is incomplete and doesn't properly
+   lock out interrupts e.g. after special-register access and doesn't
+   handle user-mode.  */
+
+int
+MY (deliver_interrupt) (SIM_CPU *current_cpu,
+                       enum cris_interrupt_type type,
+                       unsigned int vec)
+{
+  unsigned char entryaddr_le[4];
+  int was_user;
+  SIM_DESC sd = CPU_STATE (current_cpu);
+  unsigned32 entryaddr;
+
+  /* We haven't implemented other interrupt-types yet.  */
+  if (type != CRIS_INT_INT)
+    abort ();
+
+  /* We're supposed to be called outside of prefixes and branch
+     delay-slots etc, but why not check.  */
+  if (GET_H_INSN_PREFIXED_P ())
+    abort ();
+
+  if (!GET_H_IBIT ())
+    return 0;
+
+  /* User mode isn't supported for interrupts.  (And we shouldn't see
+     this as 1 anyway.  The user-mode bit isn't visible from user
+     mode.  It doesn't make it into the U bit until the next
+     interrupt/exception.)  */
+  if (GET_H_UBIT ())
+    abort ();
+
+  SET_H_PBIT (1);
+
+  if (sim_core_read_buffer (sd,
+                           current_cpu,
+                           read_map, entryaddr_le,
+                           GET_H_SR (H_SR_PRE_V32_IBR) + vec * 4, 4) == 0)
+    {
+      /* Nothing to do actually; either abort or send a signal.  */
+      sim_core_signal (sd, current_cpu, CIA_GET (current_cpu), 0, 4,
+                      GET_H_SR (H_SR_PRE_V32_IBR) + vec * 4,
+                      read_transfer, sim_core_unmapped_signal);
+      return 0;
+    }
+
+  entryaddr = bfd_getl32 (entryaddr_le);
+
+  SET_H_SR (H_SR_PRE_V32_IRP, GET_H_PC ());
+  SET_H_PC (entryaddr);
+
+  return 1;
+}
index d1d5fc96e0efab070f098522fe1f7e3bdc735218..cd14d3e3c678801ce8deff68f4db3c49fff9ca18 100644 (file)
@@ -1,5 +1,5 @@
 /* CRIS v32 simulator support code
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Axis Communications.
 
 This file is part of the GNU simulators.
@@ -556,3 +556,71 @@ MY (XCONCAT3 (f_model_crisv,BASENUM,
 }
 
 #endif /* WITH_PROFILE_MODEL_P */
+
+int
+MY (deliver_interrupt) (SIM_CPU *current_cpu,
+                       enum cris_interrupt_type type,
+                       unsigned int vec)
+{
+  unsigned32 old_ccs, shifted_ccs, new_ccs;
+  unsigned char entryaddr_le[4];
+  int was_user;
+  SIM_DESC sd = CPU_STATE (current_cpu);
+  unsigned32 entryaddr;
+
+  /* We haven't implemented other interrupt-types yet.  */
+  if (type != CRIS_INT_INT)
+    abort ();
+
+  /* We're called outside of branch delay slots etc, so we don't check
+     for that.  */
+  if (!GET_H_IBIT_V32 ())
+    return 0;
+
+  old_ccs = GET_H_SR_V32 (H_SR_CCS);
+  shifted_ccs = (old_ccs << 10) & ((1 << 30) - 1);
+
+  /* The M bit is handled by code below and the M bit setter function, but
+     we need to preserve the Q bit.  */
+  new_ccs = shifted_ccs | (old_ccs & (unsigned32) 0x80000000UL);
+  was_user = GET_H_UBIT_V32 ();
+
+  /* We need to force kernel mode since the setter method doesn't allow
+     it.  Then we can use setter methods at will, since they then
+     recognize that we're in kernel mode.  */
+  CPU (h_ubit_v32) = 0;
+
+  if (was_user)
+    {
+      /* These methods require that user mode is unset.  */
+      SET_H_SR (H_SR_USP, GET_H_GR (H_GR_SP));
+      SET_H_GR (H_GR_SP, GET_H_KERNEL_SP ());
+    }
+
+  /* ERP setting is simplified by not taking interrupts in delay-slots
+     or when halting.  */
+  /* For all other exceptions than guru and NMI, store the return
+     address in ERP and set EXS and EXD here.  */
+  SET_H_SR (H_SR_ERP, GET_H_PC ());
+
+  /* Simplified by not having exception types (fault indications).  */
+  SET_H_SR_V32 (H_SR_EXS, (vec * 256));
+  SET_H_SR_V32 (H_SR_EDA, 0);
+
+  if (sim_core_read_buffer (sd,
+                           current_cpu,
+                           read_map, entryaddr_le,
+                           GET_H_SR (H_SR_EBP) + vec * 4, 4) == 0)
+    {
+      /* Nothing to do actually; either abort or send a signal.  */
+      sim_core_signal (sd, current_cpu, CIA_GET (current_cpu), 0, 4,
+                      GET_H_SR (H_SR_EBP) + vec * 4,
+                      read_transfer, sim_core_unmapped_signal);
+      return 0;
+    }
+
+  entryaddr = bfd_getl32 (entryaddr_le);
+  SET_H_PC (entryaddr);
+
+  return 1;
+}
index feb901ae4eaba0753c84b2542c8a555b23db753b..e694ff3168ac72f21f196bdf18c25600279c31be 100644 (file)
@@ -1,5 +1,5 @@
 /* CRIS device support
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Axis Communications.
 
 This file is part of the GNU simulators.
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "dv-sockser.h"
 #endif
 
+#include "hw-device.h"
+
 /* Placeholder definition.  */
 struct _device { char dummy; } cris_devices;
 
@@ -48,7 +50,11 @@ device_io_read_buffer (device *me ATTRIBUTE_UNUSED,
                       SIM_CPU *cpu ATTRIBUTE_UNUSED,
                       sim_cia cia ATTRIBUTE_UNUSED)
 {
+#if WITH_HW
+  return hw_io_read_buffer ((struct hw *) me, source, space, addr, nr_bytes);
+#else
   abort ();
+#endif
 }
 
 int
@@ -61,13 +67,22 @@ device_io_write_buffer (device *me ATTRIBUTE_UNUSED,
   static const unsigned char ok[] = { 4, 0, 0, 0x90};
   static const unsigned char bad[] = { 8, 0, 0, 0x90};
 
-  if (addr == 0x90000004 && memcmp (source, ok, sizeof ok) == 0)
-    cris_break_13_handler (cpu, 1, 0, 0, 0, 0, 0, 0, cia);
-  else if (addr == 0x90000008
-          && memcmp (source, bad, sizeof bad) == 0)
-    cris_break_13_handler (cpu, 1, 34, 0, 0, 0, 0, 0, cia);
+  if (cris_have_900000xxif)
+    {
+      if (addr == 0x90000004 && memcmp (source, ok, sizeof ok) == 0)
+       return cris_break_13_handler (cpu, 1, 0, 0, 0, 0, 0, 0, cia);
+      else if (addr == 0x90000008
+              && memcmp (source, bad, sizeof bad) == 0)
+       return cris_break_13_handler (cpu, 1, 34, 0, 0, 0, 0, 0, cia);
+    }
+#if WITH_HW
+  else
+    return hw_io_write_buffer ((struct hw *) me, source, space, addr, nr_bytes);
+#endif
 
   /* If it wasn't one of those, send an invalid-memory signal.  */
   sim_core_signal (sd, cpu, cia, 0, nr_bytes, addr,
                   write_transfer, sim_core_unmapped_signal);
+
+  return 0;
 }
diff --git a/sim/cris/dv-cris.c b/sim/cris/dv-cris.c
new file mode 100644 (file)
index 0000000..b98a6b7
--- /dev/null
@@ -0,0 +1,314 @@
+/* The CRIS interrupt framework for GDB, the GNU Debugger.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 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-main.h"
+
+/* DEVICE
+
+   CRIS cpu virtual device (very rudimental; generic enough for all
+   currently used CRIS versions).
+
+
+   DESCRIPTION
+
+   Implements the external CRIS functionality.  This includes the
+   delivery of interrupts generated from other devices.
+
+
+   PROPERTIES
+
+   vec-for-int = <int-a> <vec-a> <int-b> <vec-b> ...
+   These are the translations to interrupt vector for values appearing
+   on the "int" port, as pairs of the value and the corresponding
+   vector.  Defaults to no translation.  All values that may appear on
+   the "int" port must be defined, or the device aborts.
+
+   multiple-int = ("abort" | "ignore_previous" | <vector>)
+   If multiple interrupt values are dispatched, this property decides
+   what to do.  The value is either a number corresponding to the
+   vector to use, or the string "abort" to cause a hard abort, or the
+   string "ignore_previous", to silently use the new vector instead.
+   The default is "abort".
+
+
+   PORTS
+
+   int (input)
+   Interrupt port.  An event with a non-zero value on this port causes
+   an interrupt.  If, after an event but before the interrupt has been
+   properly dispatched, a non-zero value appears that is different
+   after mapping than the previous, then the property multiple_int
+   decides what to do.
+
+   FIXME: reg port so internal registers can be read.  Requires
+   chip-specific versions, though.  Ports "nmi" and "reset".
+
+
+   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.
+   It also works around a bug in sim_events_process when doing so.
+   */
+
+/* Keep this an enum for simple addition of "reset" and "nmi".  */
+enum
+ {
+   INT_PORT,
+ };
+
+static const struct hw_port_descriptor cris_ports[] =
+ {
+   { "int", INT_PORT, 0, input_port },
+   { NULL, 0, 0, 0 }
+ };
+
+struct cris_vec_tr
+ {
+   unsigned32 portval, vec;
+ };
+
+enum cris_multiple_ints
+  {
+    cris_multint_abort,
+    cris_multint_ignore_previous,
+    cris_multint_vector
+  };
+
+struct cris_hw
+ {
+   struct hw_event *pending_handler;
+   unsigned32 pending_vector;
+   struct cris_vec_tr *int_to_vec;
+   enum cris_multiple_ints multi_int_action;
+   unsigned32 multiple_int_vector;
+ };
+
+/* An event function, calling the actual CPU-model-specific
+   interrupt-delivery function.  */
+
+static void
+deliver_cris_interrupt (struct hw *me, void *data)
+{
+  struct cris_hw *crishw = hw_data (me);
+  SIM_DESC simulator = hw_system (me);
+  sim_cpu *cpu = STATE_CPU (simulator, 0);
+  unsigned int intno = crishw->pending_vector;
+
+ if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
+    {
+      crishw->pending_vector = 0;
+      crishw->pending_handler = NULL;
+      return;
+    }
+
+ {
+   /* Bug workaround: at time T with a pending number of cycles N to
+      process, if re-scheduling an event at time T+M, M < N,
+      sim_events_process gets stuck at T (updating the "time" to
+      before the event rather than after the event, or somesuch).
+
+      Hacking this locally is thankfully easy: if we see the same
+      simulation time, increase the number of cycles.  Do this every
+      time we get here, until a new time is seen (supposedly unstuck
+      re-delivery).  (Fixing in SIM/GDB source will hopefully then
+      also be easier, having a tangible test-case.)  */
+   static signed64 last_events_time = 0;
+   static signed64 delta = 1;
+   signed64 this_events_time = hw_event_queue_time (me);
+
+   if (this_events_time == last_events_time)
+     delta++;
+   else
+     {
+       delta = 1;
+       last_events_time = this_events_time;
+     }
+
+   crishw->pending_handler
+     = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
+ }
+}
+
+
+/* A port-event function for events arriving to an interrupt port.  */
+
+static void
+cris_port_event (struct hw *me,
+                int my_port,
+                struct hw *source,
+                int source_port,
+                int intparam)
+{
+  struct cris_hw *crishw = hw_data (me);
+  unsigned32 vec;
+
+  /* A few placeholders; only the INT port is implemented.  */
+  switch (my_port)
+    {
+    case INT_PORT:
+      HW_TRACE ((me, "INT value=0x%x", intparam));
+      break;
+
+    default:
+      hw_abort (me, "bad switch");
+      break;
+    }
+
+  if (intparam == 0)
+    return;
+
+  if (crishw->int_to_vec != NULL)
+    {
+      unsigned int i;
+      for (i = 0; crishw->int_to_vec[i].portval != 0; i++)
+       if (crishw->int_to_vec[i].portval == intparam)
+         break;
+
+      if (crishw->int_to_vec[i].portval == 0)
+       hw_abort (me, "unsupported value for int port: 0x%x", intparam);
+
+      vec = crishw->int_to_vec[i].vec;
+    }
+  else
+    vec = (unsigned32) intparam;
+
+  if (crishw->pending_vector != 0)
+    {
+      if (vec == crishw->pending_vector)
+       return;
+
+      switch (crishw->multi_int_action)
+       {
+       case cris_multint_abort:
+         hw_abort (me, "int 0x%x (0x%x) while int 0x%x hasn't been delivered",
+                   vec, intparam, crishw->pending_vector);
+         break;
+
+       case cris_multint_ignore_previous:
+         break;
+
+       case cris_multint_vector:
+         vec = crishw->multiple_int_vector;
+         break;
+
+       default:
+         hw_abort (me, "bad switch");
+       }
+    }
+
+  crishw->pending_vector = vec;
+
+  /* Schedule our event handler *now*.  */
+  if (crishw->pending_handler == NULL)
+    crishw->pending_handler
+      = hw_event_queue_schedule (me, 0, deliver_cris_interrupt, NULL);
+}
+
+/* Instance initializer function.  */
+
+static void
+cris_finish (struct hw *me)
+{
+  struct cris_hw *crishw;
+  const struct hw_property *vec_for_int;
+  const struct hw_property *multiple_int;
+
+  crishw = HW_ZALLOC (me, struct cris_hw);
+  set_hw_data (me, crishw);
+  set_hw_ports (me, cris_ports);
+  set_hw_port_event (me, cris_port_event);
+
+  vec_for_int = hw_find_property (me, "vec-for-int");
+  if (vec_for_int != NULL)
+    {
+      unsigned32 vecsize;
+      unsigned32 i;
+
+      if (hw_property_type (vec_for_int) != array_property)
+       hw_abort (me, "property \"vec-for-int\" has the wrong type");
+
+      vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell);
+
+      if ((vecsize % 2) != 0)
+       hw_abort (me, "translation vector does not consist of even pairs");
+
+      crishw->int_to_vec
+       = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0]));
+
+      for (i = 0; i < vecsize/2; i++)
+       {
+         signed_cell portval_sc;
+         signed_cell vec_sc;
+
+         if (!hw_find_integer_array_property (me, "vec-for-int", i*2,
+                                              &portval_sc)
+             || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1,
+                                                 &vec_sc)
+             || portval_sc < 0
+             || vec_sc < 0)
+           hw_abort (me, "no valid vector translation pair %u", i);
+
+         crishw->int_to_vec[i].portval = (unsigned32) portval_sc;
+         crishw->int_to_vec[i].vec = (unsigned32) vec_sc;
+       }
+
+      crishw->int_to_vec[i].portval = 0;
+      crishw->int_to_vec[i].vec = 0;
+    }
+
+  multiple_int = hw_find_property (me, "multiple-int");
+  if (multiple_int != NULL)
+    {
+      if (hw_property_type (multiple_int) == integer_property)
+       {
+         crishw->multiple_int_vector
+           = hw_find_integer_property (me, "multiple-int");
+         crishw->multi_int_action = cris_multint_vector;
+       }
+      else
+       {
+         const char *action = hw_find_string_property (me, "multiple-int");
+
+         if (action == NULL)
+           hw_abort (me, "property \"multiple-int\" has the wrong type");
+
+         if (strcmp (action, "abort") == 0)
+           crishw->multi_int_action = cris_multint_abort;
+         else if (strcmp (action, "ignore_previous") == 0)
+           crishw->multi_int_action = cris_multint_ignore_previous;
+         else
+           hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n"
+                     "\"abort\" and \"ignore_previous\", not \"%s\"", action);
+       }
+    }
+  else
+    crishw->multi_int_action = cris_multint_abort;
+}
+
+const struct hw_descriptor dv_cris_descriptor[] = {
+  { "cris", cris_finish, },
+  { NULL },
+};
diff --git a/sim/cris/dv-rv.c b/sim/cris/dv-rv.c
new file mode 100644 (file)
index 0000000..30845e3
--- /dev/null
@@ -0,0 +1,1221 @@
+/* The remote-virtual-component simulator framework
+   for GDB, the GNU Debugger.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 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-main.h"
+
+#include "hw-tree.h"
+
+#include <ctype.h>
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+/* Not guarded in dv-sockser.c, so why here.  */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+
+/* DEVICE
+
+
+   rv - Remote Virtual component
+
+
+   DESCRIPTION
+
+
+   Socket connection to a remote simulator component, for example one
+   for testing a verilog construction.  Protocol defined below.
+
+   There is a set of 32-bit I/O ports, with a mapping from local to
+   remote addresses.  There is a set of interrupts expressed as a
+   bit-mask, with a mapping from remote to local.  There is a set of
+   memory ranges (actual memory defined elsewhere), also with a
+   mapping from remote to local addresses, that is expected to be
+   accessible to the remote simulator in 32-byte chunks (simulating
+   DMA).  There is a mapping from remote cycles (or an appropriate
+   elsewhere defined time-slice) to local cycles.
+
+   PROPERTIES
+
+   reg = <address> <size>
+   The address (within the parent bus) that this device is to
+   be located.
+
+   remote-reg = <remote-address>
+   The address of reg on the remote side.  Defaults to 0.
+
+   mem = <address> <size>
+   Specify an address-range (within the parent bus) that the remote
+   device can access.  The memory is assumed to be already defined.
+   If there's no memory defined but the remote side asks for a memory
+   access, the simulation is aborted.
+
+   remote-mem = <remote-address>
+   The address of mem on the remote side.  Defaults to 0.
+
+   mbox = <address>
+   Address of the mailbox interface.  Writes to this address with the
+   local address of a mailbox command, a complete packet with length
+   and command; (4 or 6)) invokes the mailbox interface.  Reads are
+   invalid.  Replies are written to the same address.  Address space
+   from <address> up-to-and-including <address>+3 is allocated.
+
+   max-poll-ticks = <local-count>
+   Sets the maximum interval between polling the external component,
+   expressed in internal cycles.  Defaults to 10000.
+
+   watchdog-interval = <seconds>
+   Sets the wallclock seconds between watchdog packets sent to the
+   remote side (may be larger if there's no rv activity in that time).
+   Defaults to 30.  If set to 0, no watchdog packets are sent.
+
+   intnum = <local-int-0> <local-int-1> ... <local-int-31>
+   Defines a map from remote bit numbers to local values to be emitted
+   on the "int" port, with the external bit number as the ordinal - 1
+   of the local translation.  E.g. 43 121 would mean map external
+   (1<<0) to internal 43 and external (1<<1) to internal 121.  The
+   default is unity; no translation.  If more than one bit is set in
+   the remote interrupt word, the intmultiple property can be used to
+   control the translation.
+
+   intmultiple = <intvalue>
+   When more than one bit is set in the remote interrupt word, you may
+   want to map this situation to a separate interrupt value.  If this
+   property is non-zero, it is used as that value.  If it is zero, the
+   local value for the "int" port is the bitwise-or of the translated
+   local values.
+
+   host = <hostid>
+   The hostname or address where the simulator to be used listens.
+   Defaults to "127.0.0.1"
+
+   port = <portnumber>
+   The hostname or address where the simulator to be used listens.
+   Defaults to 10000.
+
+   dummy = <value>
+    or
+   dummy = <filename>
+   Don't connect to a remote side; use initial dummy contents from
+   <filename> (which has to be at least as big as the <size> argument
+   of reg above) or filled with byte-value <value>.  Mailboxes are not
+   supported (can be defined but can not be used) and remote-memory
+   accesses don't apply.  The main purpose for this property is to
+   simplify use of configuration and simulated hardware that is
+   e.g. only trivially initialized but not actually used.
+
+
+   PORTS
+
+   int (output)
+   Driven as a result of a remote interrupt request.  The value is a
+   32-bit bitset of active interrupts.
+
+
+   BUGS
+
+   All and none.
+
+
+   PROTOCOL
+
+   This is version 1.0 of this protocol, defining packet format and
+   actions in a supposedly upward-compatible manner where client and
+   servers of different versions are expected to interoperate; the
+   format and the definitions below are hopefully generic enough to
+   allow this.
+
+   Each connection has a server and a client (this code); the roles
+   are known beforehand.  The client usually corresponds to a CPU and
+   memory system and the server corresponds to a memory-mapped
+   register hardware interface and/or a DMA controller.  They
+   communicate using packets with specific commands, of which some
+   require replies from the other side; most are intiated by the
+   client with one exception.  A reply uses the same format as the
+   command.
+
+   Packets are at least three bytes long, where the first two bytes
+   form a header, a 16-bit little-endian number that is the total
+   length of the packet including the header.  There is also a
+   one-byte command.  The payload is optional, depending on the
+   command.
+
+   [[16-bit-low-byte-of-length] [16-bit-high-byte-of-length]
+    [command/reply] [payload byte 0] [payload byte 1]
+    ... [payload byte (length-of-packet - 3)]]
+
+   Commands:
+
+   A client or server that reads an undocumented command may exit with
+   a hard error.  Payload not defined or disallowed below is ignored.
+
+   It is expected that future client versions find out the version of
+   the server side by polling with base commands, assuming earlier
+   versions if a certain reply isn't seen, with newly defined payload
+   parts where earlier versions left it undefined.  New commands and
+   formats are sent only to the other side after the client and server
+   has found out each others version.  Not all servers support all
+   commands; the type of server and supported set of commands is
+   expected to be known beforehand.
+
+   RV_READ_CMD = 0
+   Initiated by the client, requires a reply from the server.  The
+   payload from the client is at least 4 bytes, forming a 4-byte
+   little-endian address, the rest being undefined.  The reply from
+   the server is at least 8 bytes, forming the same address data as in
+   the request and the second 4-byte data being the little-endian
+   contents.
+
+   RV_WRITE_CMD = 1
+   Initiated by the client, requires a reply from the server.  Payload
+   from the client is at least 8 bytes, forming a 4-byte little-endian
+   word being the address, the rest being the little-endian contents
+   to write.  The reply from the server is 8 bytes unless elsewhere
+   agreed otherwise, forming the same address and data as in the
+   request.  The data sent back may have been altered to correspond to
+   defined parts but can safely be discarded.
+
+   RV_IRQ_CMD = 2
+   Initiated by the server, no reply.  The payload is 4 bytes, forming
+   a little-endian word with bits numbers corresponding to currently
+   active interrupt sources; value (1<<N) indicating interrupt source
+   N being active.
+
+   RV_MEM_RD_CMD = 3
+   Initiated by the server, requires a reply.  A client must know
+   beforehand when (in command sequence or constant) the server can
+   send this command and if so must then not send any commands of its
+   own (including watchdog commands); the server is allowed to assume
+   that incoming data is only replies to this command.  The format is
+   8 bytes of data; 4 bytes of little-endian address followed by a
+   32-bit little endian word with the number of bytes to read.  The
+   reply is the same address and number of bytes, followed by the data
+   that had been read.
+
+   RV_MEM_WR_CMD = 4
+   Initiated by the server, no reply.  The format is the same as a
+   reply to RV_MEM_RD_CMD; a 32-bit little-endian address, followed by
+   the 32-bit little-endian number of bytes to write (redundant
+   information but must be consistent with the packet header).
+
+   RV_MBOX_HANDLE_CMD = 5
+   Initiated by the client, requires a reply.  The payload is 4
+   undefined bytes followed by an binary blob, the size of the
+   blob given by the packet header.  The reply is a 32-bit little
+   endian number at the same index as the undefined bytes.  Actual
+   semantics are application-specific.
+
+   RV_MBOX_PUT_CMD = 6
+   Initiated by the client, requires a reply, with the reply using the
+   RV_MBOX_HANDLE_CMD reply format (i.e. *both* that command and
+   32-bit little-endian number).  The payload is a 32-bit little
+   endian number followed by an undefined payload, at most 20 bytes
+   long.  The reply is a 32-bit little endian number.  Actual
+   semantics are application-specific.
+
+   RV_WATCHDOG_CMD = 7
+   Initiated by the client, no reply.  A version 1.0 client sends no
+   payload; a version 1.0 server should ignore any such payload.  A
+   version 1.0 server must not send a reply.
+
+
+   Possible future enhancements:
+
+   Synchronization; server and client reports the number of elapsed
+   cycles (unit to-be-defined) at each request or notification.
+   Pretty much the top-of-the-todo-list item.
+
+   Large addresses; 1.0 being restricted to 32-bit addresses.
+
+   Variable-size data; currently restricted to 32-bit register
+   accesses.
+
+   Specified data endianness (not the packet header) perhaps as part
+   of an initial format request; currently little-endian only.
+
+
+   Usage notes:
+   When used with servers sending RV_MEM_RD_CMD but being
+   narrow-minded about indata, set watchdog-interval to 0.  Use
+   multiple rv instances when there are e.g. separate register and
+   memory servers.  Alway log, setting "/rv/trace? true", at the
+   development phase.  Borrow from the test-suite.
+   */
+
+#define RV_FAMILY_NAME "rv"
+
+enum rv_command {
+  RV_READ_CMD = 0,
+  RV_WRITE_CMD = 1,
+  RV_IRQ_CMD = 2,
+  RV_MEM_RD_CMD = 3,
+  RV_MEM_WR_CMD = 4,
+  RV_MBOX_HANDLE_CMD = 5,
+  RV_MBOX_PUT_CMD = 6,
+  RV_WATCHDOG_CMD = 7
+};
+
+
+typedef struct _hw_rv_device
+{
+  /* Mapping of remote interrupt bit-numbers to local ones.  */
+  unsigned32 remote_to_local_int[32];
+
+  /* When multiple bits are set, a non-zero value here indicates that
+     this value should be used instead.  */
+  unsigned32 intmultiple;
+
+  /* Local address of registers.  */
+  unsigned32 reg_address;
+
+  /* Size of register bank in bytes.  */
+  unsigned32 reg_size;
+
+  /* Remote address of registers.  */
+  unsigned32 remote_reg_address;
+
+  /* Local address of DMA:able memory.  */
+  unsigned32 mem_address;
+
+  /* Size of DMA:able memory in bytes.  */
+  unsigned32 mem_size;
+
+  /* Bitmask for valid DMA request size.  */
+  unsigned32 mem_burst_mask;
+
+  /* Remote address of DMA:able memory.  */
+  unsigned32 remote_mem_address;
+
+  /* (Local) address of mbox; where to put a pointer to the mbox to be
+     sent.  */
+  unsigned32 mbox_address;
+
+  /* Probably not 127.0.0.1:10000.  */
+  const char *host;
+  int port;
+
+  /* If non-NULL, points to memory to use instead of connection.  */
+  unsigned8 *dummy;
+
+  /* File descriptor for the socket.  Set to -1 when error.  Only one
+     of dummy and this is active.  */
+  int fd;
+
+  /* Stashed errno, as we don't emit an error right away.  */
+  int saved_errno;
+
+  /* This, plus latency because the CPU might not be checking until a
+     CTI insn (usually a branch or a jump) is the interval in cycles
+     between the rv is polled for e.g. DMA requests.  */
+  unsigned32 max_tick_poll_interval;
+
+  /* Running counter for exponential backoff up to
+     max_tick_poll_interval to avoid polling the connection
+     unnecessarily often.  Set to 1 when rv activity (read/write
+     register, DMA request) is detected.  */
+  unsigned32 next_period;
+
+  /* This is the interval in wall-clock seconds between watchdog
+     packets are sent to the remote side.  Zero means no watchdog
+     packets. */
+  unsigned32 watchdog_interval;
+
+  /* Last time we sent a watchdog packet.  */
+  struct timeval last_wdog_time;
+
+  /* Mostly used as a kludge for knowing which rv:s have poll events
+     active.  */
+  struct hw_event *poll_callback;
+} hw_rv_device;
+
+
+/* We might add ports in the future, so keep this an enumeration.  */
+enum
+  {
+    INT_PORT
+  };
+
+/* Our ports.  */
+static const struct hw_port_descriptor hw_rv_ports[] = {
+  { "int", INT_PORT, 0, output_port },
+  { NULL }
+};
+
+/* Send LEN bytes of data from BUF to the socket.  Abort on
+   errors.  */
+
+static void
+hw_rv_write (struct hw *me,
+            void *buf,
+            unsigned int len)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned8 *bufp = buf;
+
+  /* If we don't have a valid fd here, it's because we got an error
+     initially, and we suppressed that error.  */
+  if (rv->fd < 0)
+    hw_abort (me, "couldn't open a connection to %s:%d because: %s",
+             rv->host, rv->port, strerror (rv->saved_errno));
+
+  while (len > 0)
+    {
+      ssize_t ret = write (rv->fd, bufp, len);
+      if (ret < 0)
+       /* FIXME: More graceful exit.  */
+       hw_abort (me, "write to %s:%d failed: %s\n", rv->host, rv->port,
+                 strerror (errno));
+
+      len -= ret;
+      bufp += ret;
+    }
+}
+
+/* Read LEN bytes of data into BUF from the socket.  Set the file
+   descriptor to -1 if there's an error.  */
+
+static void
+hw_rv_read (struct hw *me,
+           void *buf,
+           unsigned int len)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned8 *bufp = buf;
+
+  while (len > 0)
+    {
+      ssize_t ret = read (rv->fd, bufp, len);
+
+      /* We get all zero if the remote end quits, but no error
+        indication; even select says there's data active.  */
+      if (ret <= 0)
+       {
+         if (close (rv->fd) != 0)
+           /* FIXME: More graceful exit.  */
+           hw_abort (me, "read from %s:%d failed: %d\n", rv->host, rv->port, errno);
+         rv->fd = -1;
+         return;
+       }
+
+      len -= ret;
+      bufp += ret;
+    }
+}
+
+/* Construct and send a packet of data of type CMD and len
+   LEN_NOHEADER (not counting the header...).  */
+
+static void
+hw_rv_send (struct hw *me,
+           unsigned int cmd,
+           void *msg,
+           unsigned int len_noheader)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned8 buf[32+3];
+  unsigned8 *bufp;
+  unsigned int len = len_noheader + 3;
+  int ret;
+
+  buf[0] = len & 255;
+  buf[1] = (len >> 8) & 255;
+  buf[2] = cmd;
+
+  if (len > sizeof (buf))
+    {
+      hw_rv_write (me, buf, 3);
+      len = len_noheader;
+      bufp = msg;
+    }
+  else
+    {
+      memcpy (buf + 3, msg, len_noheader);
+      bufp = buf;
+    }
+
+  hw_rv_write (me, bufp, len);
+}
+
+/* Handle incoming DMA requests as per the RV_MEM_RD_CMD packet.
+   Abort on errors.  */
+
+static void
+hw_rv_read_mem (struct hw *me, unsigned int len)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  /* If you change this size, please adjust the mem2 testcase.  */
+  unsigned8 buf[32+8];
+  unsigned8 *bufp = buf;
+  unsigned32 leaddr;
+  unsigned32 addr;
+  unsigned32 lelen;
+  unsigned32 i;
+
+  if (len != 8)
+    hw_abort (me, "expected DMA read request len 8+3, got %d+3", len);
+
+  hw_rv_read (me, &leaddr, 4);
+  hw_rv_read (me, &lelen, 4);
+  len = LE2H_4 (lelen);
+  addr = LE2H_4 (leaddr);
+
+  if (addr < rv->remote_mem_address
+      || addr >= rv->remote_mem_address + rv->mem_size)
+    hw_abort (me, "DMA read at remote 0x%x; outside [0x%x..0x%x-1]",
+             (unsigned) addr, (unsigned) rv->remote_mem_address,
+             (unsigned) (rv->remote_mem_address + rv->mem_size));
+  addr = addr - rv->remote_mem_address + rv->mem_address;
+
+  if (len == 0)
+    hw_abort (me, "DMA read request for 0 bytes isn't supported");
+
+  if (len & ~rv->mem_burst_mask)
+    hw_abort (me, "DMA trying to read %d bytes; not matching mask of 0x%x",
+             len, rv->mem_burst_mask);
+  if (len + 8 > sizeof (buf))
+    bufp = hw_malloc (me, len + 8);
+
+  HW_TRACE ((me, "DMA R 0x%x..0x%x", addr, addr + len -1));
+  hw_dma_read_buffer (me, bufp + 8, 0, addr, len);
+  if (hw_trace_p (me))
+    for (i = 0; i < len; i += 4)
+      HW_TRACE ((me, "0x%x: %02x %02x %02x %02x",
+                addr + i,
+                bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11]));
+
+  memcpy (bufp, &leaddr, 4);
+  memcpy (bufp + 4, &lelen, 4);
+  hw_rv_send (me, RV_MEM_RD_CMD, bufp, len + 8);
+  if (bufp != buf)
+    hw_free (me, bufp);
+}
+
+/* Handle incoming DMA requests as per the RV_MEM_WR_CMD packet.
+   Abort on errors.  */
+
+static void
+hw_rv_write_mem (struct hw *me, unsigned int plen)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  /* If you change this size, please adjust the mem2 testcase.  */
+  unsigned8 buf[32+8];
+  unsigned8 *bufp = buf;
+  unsigned32 leaddr;
+  unsigned32 addr;
+  unsigned32 lelen;
+  unsigned32 len;
+  unsigned32 i;
+
+  hw_rv_read (me, &leaddr, 4);
+  hw_rv_read (me, &lelen, 4);
+  len = LE2H_4 (lelen);
+  addr = LE2H_4 (leaddr);
+
+  if (len != plen - 8)
+    hw_abort (me,
+             "inconsistency in DMA write request packet: "
+             "envelope %d+3, inner %d bytes", plen, len);
+
+  if (addr < rv->remote_mem_address
+      || addr >= rv->remote_mem_address + rv->mem_size)
+    hw_abort (me, "DMA write at remote 0x%x; outside [0x%x..0x%x-1]",
+             (unsigned) addr, (unsigned) rv->remote_mem_address,
+             (unsigned) (rv->remote_mem_address + rv->mem_size));
+
+  addr = addr - rv->remote_mem_address + rv->mem_address;
+  if (len == 0)
+    hw_abort (me, "DMA write request for 0 bytes isn't supported");
+
+  if (len & ~rv->mem_burst_mask)
+    hw_abort (me, "DMA trying to write %d bytes; not matching mask of 0x%x",
+             len, rv->mem_burst_mask);
+  if (len + 8 > sizeof (buf))
+    bufp = hw_malloc (me, len + 8);
+
+  hw_rv_read (me, bufp + 8, len);
+  HW_TRACE ((me, "DMA W 0x%x..0x%x", addr, addr + len - 1));
+  hw_dma_write_buffer (me, bufp + 8, 0, addr, len, 0);
+  if (hw_trace_p (me))
+    for (i = 0; i < len; i += 4)
+      HW_TRACE ((me, "0x%x: %02x %02x %02x %02x",
+                addr + i,
+                bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11]));
+  if (bufp != buf)
+    hw_free (me, bufp);
+}
+
+static void
+hw_rv_irq (struct hw *me, unsigned int len)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned32 intbitsle;
+  unsigned32 intbits_ext;
+  unsigned32 intval = 0;
+  int i;
+
+  if (len != 4)
+    hw_abort (me, "IRQ with %d data not supported", len);
+
+  hw_rv_read (me, &intbitsle, 4);
+  intbits_ext = LE2H_4 (intbitsle);
+  for (i = 0; i < 32; i++)
+    if ((intbits_ext & (1 << i)) != 0)
+      intval |= rv->remote_to_local_int[i];
+  if ((intbits_ext & ~(intbits_ext - 1)) != intbits_ext
+      && rv->intmultiple != 0)
+    intval = rv->intmultiple;
+
+  HW_TRACE ((me, "IRQ 0x%x", intval));
+  hw_port_event (me, INT_PORT, intval);
+}
+
+/* Handle incoming interrupt notifications as per the RV_IRQ_CMD
+   packet.  Abort on errors.  */
+
+static void
+hw_rv_handle_incoming (struct hw *me,
+                      int expected_type,
+                      unsigned8 *buf,
+                      unsigned int *return_len)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned8 cbuf[32];
+  unsigned int len;
+  unsigned int cmd;
+
+  while (1)
+    {
+      hw_rv_read (me, cbuf, 3);
+
+      if (rv->fd < 0)
+       return;
+
+      len = cbuf[0] + cbuf[1] * 256 - 3;
+      cmd = cbuf[2];
+
+      /* These come in "asynchronously"; not as a reply.  */
+      switch (cmd)
+       {
+       case RV_IRQ_CMD:
+         hw_rv_irq (me, len);
+         break;
+
+       case RV_MEM_RD_CMD:
+         hw_rv_read_mem (me, len);
+         break;
+
+       case RV_MEM_WR_CMD:
+         hw_rv_write_mem (me, len);
+         break;
+       }
+
+      /* Something is incoming from the other side, so tighten up all
+        slack at the next wait.  */
+      rv->next_period = 1;
+
+      switch (cmd)
+       {
+       case RV_MEM_RD_CMD:
+       case RV_MEM_WR_CMD:
+       case RV_IRQ_CMD:
+         /* Don't try to handle more than one of these if we were'nt
+            expecting a reply.  */
+         if (expected_type == -1)
+           return;
+         continue;
+       }
+
+      /* Require a match between this supposed-reply and the command
+        for the rest.  */
+      if (cmd != expected_type)
+       hw_abort (me, "unexpected reply, expected command %d, got %d",
+                 expected_type, cmd);
+
+      switch (cmd)
+       {
+       case RV_MBOX_PUT_CMD:
+       case RV_MBOX_HANDLE_CMD:
+       case RV_WRITE_CMD:
+       case RV_READ_CMD:
+         hw_rv_read (me, buf, len <= *return_len ? len : *return_len);
+         *return_len = len;
+         break;
+       }
+      break;
+    }
+}
+
+/* Send a watchdog packet.  Make a note of wallclock time.  */
+
+static void
+hw_rv_send_wdog (struct hw *me)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  HW_TRACE ((me, "WD"));
+  gettimeofday (&rv->last_wdog_time, NULL);
+  hw_rv_send (me, RV_WATCHDOG_CMD, "", 0);
+}
+
+/* Poll the remote side: see if there's any incoming traffic; handle a
+   packet if so.  Send a watchdog packet if it's time to do so.
+   Beware that the Linux select call indicates traffic for a socket
+   that the remote side has closed (which may be because it was
+   finished; don't hork until we need to write something just because
+   we're polling).  */
+
+static void
+hw_rv_poll_once (struct hw *me)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  fd_set rfds;
+  fd_set efds;
+  struct timeval now;
+  int ret;
+  struct timeval tv;
+
+  if (rv->fd < 0)
+    /* Connection has died or was never initiated.  */
+    return;
+
+  FD_ZERO (&rfds);
+  FD_SET (rv->fd, &rfds);
+  FD_ZERO (&efds);
+  FD_SET (rv->fd, &efds);
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  ret = select (rv->fd + 1, &rfds, NULL, &efds, &tv);
+  gettimeofday (&now, NULL);
+
+  if (ret < 0)
+    hw_abort (me, "select failed: %d\n", errno);
+
+  if (rv->watchdog_interval != 0
+      && now.tv_sec - rv->last_wdog_time.tv_sec >= rv->watchdog_interval)
+    hw_rv_send_wdog (me);
+
+  if (FD_ISSET (rv->fd, &rfds))
+    hw_rv_handle_incoming (me, -1, NULL, NULL);
+}
+
+/* Initialize mapping of remote-to-local interrupt data.  */
+
+static void
+hw_rv_map_ints (struct hw *me)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  int i;
+
+  for (i = 0; i < 32; i++)
+    rv->remote_to_local_int[i] = 1 << i;
+
+  if (hw_find_property (me, "intnum") != NULL)
+    for (i = 0; i < 32; i++)
+      {
+       signed_cell val = -1;
+       if (hw_find_integer_array_property (me, "intnum", i, &val) > 0)
+         {
+           if (val > 0)
+             rv->remote_to_local_int[i] = val;
+           else
+             hw_abort (me, "property \"intnum@%d\" must be > 0; is %d",
+                       i, (int) val);
+         }
+      }
+}
+
+/* Handle the after-N-ticks "poll event", calling the poll-the-fd
+   method.  Update the period.  */
+
+static void
+do_poll_event (struct hw *me, void *data)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned32 new_period;
+
+  if (rv->dummy != NULL)
+    return;
+
+  hw_rv_poll_once (me);
+  if (rv->fd >= 0)
+    rv->poll_callback
+      = hw_event_queue_schedule (me, rv->next_period, do_poll_event, NULL);
+
+  new_period = rv->next_period * 2;
+  if (new_period <= rv->max_tick_poll_interval)
+    rv->next_period = new_period;
+}
+
+/* HW tree traverse function for hw_rv_add_init.  */
+
+static void
+hw_rv_add_poller (struct hw *me, void *data)
+{
+  hw_rv_device *rv;
+
+  if (hw_family (me) == NULL
+      || strcmp (hw_family (me), RV_FAMILY_NAME) != 0)
+    return;
+
+  rv = (hw_rv_device *) hw_data (me);
+  if (rv->poll_callback != NULL)
+    return;
+
+  rv->poll_callback
+    = hw_event_queue_schedule (me, 1, do_poll_event, NULL);
+}
+
+/* Simulator module init function for hw_rv_add_init.  */
+
+/* FIXME: For the call so hw_tree_traverse, we need to know that the
+   first member of struct sim_hw is the struct hw *root, but there's
+   no accessor method and struct sim_hw is defined in sim-hw.c only.
+   Hence this hack, until an accessor is added, or there's a traverse
+   function that takes a SIM_DESC argument.  */
+struct sim_hw { struct hw *tree; };
+
+static SIM_RC
+hw_rv_add_rv_pollers (SIM_DESC sd)
+{
+  hw_tree_traverse (STATE_HW (sd)->tree, hw_rv_add_poller, NULL, NULL);
+  return SIM_RC_OK;
+}
+
+/* We need to add events for polling, but we can't add one from the
+   finish-function, and there are no other call points, at least for
+   instances without "reg" (when there are just DMA requests from the
+   remote end; no locally initiated activity).  Therefore we add a
+   simulator module init function, but those don't have private
+   payload arguments; just a SD argument.  We cope by parsing the HW
+   root and making sure *all* "rv":s have poll callbacks installed.
+   Luckily, this is just an initialization step, and not many
+   simultaneous instances of rv are expected: we get a N**2 complexity
+   for visits to each rv node by this method.  */
+
+static void
+hw_rv_add_init (struct hw *me)
+{
+  sim_module_add_init_fn (hw_system (me), hw_rv_add_rv_pollers);
+}
+
+/* Open up a connection to the other side.  Abort on errors.  */
+
+static void
+hw_rv_init_socket (struct hw *me)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  int sock;
+  struct sockaddr_in server;
+
+  rv->fd = -1;
+
+  if (rv->dummy != NULL)
+    return;
+
+  memset (&server, 0, sizeof (server));
+  server.sin_family = AF_INET;
+  server.sin_addr.s_addr = inet_addr (rv->host);
+
+  /* Solaris 2.7 lacks this macro.  */
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+  if (server.sin_addr.s_addr == INADDR_NONE)
+    {
+      struct hostent *h;
+      h = gethostbyname (rv->host);
+      if (h != NULL)
+       {
+         memcpy (&server.sin_addr, h->h_addr, h->h_length);
+         server.sin_family = h->h_addrtype;
+       }
+      else
+       hw_abort (me, "can't resolve host %s", rv->host);
+    }
+
+  server.sin_port = htons (rv->port);
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+
+  if (sock < 0)
+    hw_abort (me, "can't get a socket for %s:%d connection",
+             rv->host, rv->port);
+
+  if (connect (sock, (struct sockaddr *) &server, sizeof server) >= 0)
+    {
+      rv->fd = sock;
+
+      /* FIXME: init packet here.  Maybe start packet too.  */
+      if (rv->watchdog_interval != 0)
+       hw_rv_send_wdog (me);
+    }
+  else
+    /* Stash the errno for later display, if some connection activity
+       is requested.  Don't emit an error here; we might have been
+       called just for test purposes.  */
+    rv->saved_errno = errno;
+}
+
+/* Local rv register reads end up here.  */
+
+static unsigned int
+hw_rv_reg_read (struct hw *me,
+               void *dest,
+               int space,
+               unsigned_word addr,
+               unsigned int nr_bytes)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+  unsigned8 addr_data[8] = "";
+  unsigned32 a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address);
+  unsigned int len = 8;
+
+  if (nr_bytes != 4)
+    hw_abort (me, "must be four byte read");
+
+  if (addr == rv->mbox_address)
+    hw_abort (me, "invalid read of mbox address 0x%x",
+             (unsigned) rv->mbox_address);
+
+  memcpy (addr_data, &a_l, 4);
+  HW_TRACE ((me, "REG R 0x%x", addr));
+  if (rv->dummy != NULL)
+    {
+      len = 8;
+      memcpy (addr_data + 4, rv->dummy + addr - rv->reg_address, 4);
+    }
+  else
+    {
+      hw_rv_send (me, RV_READ_CMD, addr_data, len);
+      hw_rv_handle_incoming (me, RV_READ_CMD, addr_data, &len);
+    }
+
+  if (len != 8)
+    hw_abort (me, "read %d != 8 bytes returned", len);
+  HW_TRACE ((me, ":= 0x%02x%02x%02x%02x",
+            addr_data[7], addr_data[6], addr_data[5], addr_data[4]));
+  memcpy (dest, addr_data + 4, 4);
+  return nr_bytes;
+}
+
+/* Local rv mbox requests (handle or put) end up here.  */
+
+static void
+hw_rv_mbox (struct hw *me, unsigned_word address)
+{
+  unsigned8 buf[256+3];
+  unsigned int cmd;
+  unsigned int rlen;
+  unsigned32 i;
+  unsigned int len
+    = hw_dma_read_buffer (me, buf, 0, address, 3);
+
+  if (len != 3)
+    hw_abort (me, "mbox read %d != 3 bytes returned", len);
+
+  cmd = buf[2];
+  if (cmd != RV_MBOX_HANDLE_CMD && cmd != RV_MBOX_PUT_CMD)
+    hw_abort (me, "unsupported mbox command %d", cmd);
+
+  len = buf[0] + buf[1]*256;
+
+  if (len > sizeof (buf))
+    hw_abort (me, "mbox cmd %d send size %d unsupported", cmd, len);
+
+  rlen = hw_dma_read_buffer (me, buf + 3, 0, address + 3, len - 3);
+  if (rlen != len - 3)
+    hw_abort (me, "mbox read %d != %d bytes returned", rlen, len - 3);
+
+  HW_TRACE ((me, "MBOX %s 0x%x..0x%x",
+            cmd == RV_MBOX_HANDLE_CMD ? "H" : "P",
+            address, address + len - 1));
+  for (i = 0; i < rlen; i += 8)
+    HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x",
+              address + 3 + i,
+              buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i],
+              buf[9+i], buf[10+i]));
+
+  len -= 3;
+  hw_rv_send (me, cmd, buf + 3, len);
+
+  /* Note: both ..._PUT and ..._HANDLE get the ..._HANDLE reply.  */
+  hw_rv_handle_incoming (me, RV_MBOX_HANDLE_CMD, buf + 3, &len);
+  if (len > sizeof (buf))
+    hw_abort (me, "mbox cmd %d receive size %d unsupported", cmd, len);
+  HW_TRACE ((me, "-> 0x%x..0x%x", address, address + len + 3 - 1));
+  for (i = 0; i < len; i += 8)
+    HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x",
+              address + 3 + i,
+              buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i],
+              buf[9+i], buf[10+i]));
+
+  len += 3;
+  buf[0] = len & 255;
+  buf[1] = len / 256;
+  rlen = hw_dma_write_buffer (me, buf, 0, address, len, 0);
+  if (rlen != len)
+    hw_abort (me, "mbox write %d != %d bytes", rlen, len);
+}
+
+/* Local rv register writes end up here.  */
+
+static unsigned int
+hw_rv_reg_write (struct hw *me,
+                const void *source,
+                int space,
+                unsigned_word addr,
+                unsigned int nr_bytes)
+{
+  hw_rv_device *rv = (hw_rv_device *) hw_data (me);
+
+  unsigned8 addr_data[8] = "";
+  unsigned32 a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address);
+  unsigned int len = 8;
+
+  if (nr_bytes != 4)
+    hw_abort (me, "must be four byte write");
+
+  memcpy (addr_data, &a_l, 4);
+  memcpy (addr_data + 4, source, 4);
+
+  if (addr == rv->mbox_address)
+    {
+      unsigned32 mbox_addr_le;
+      if (rv->dummy != NULL)
+       hw_abort (me, "mbox not supported for a dummy instance");
+      memcpy (&mbox_addr_le, source, 4);
+      hw_rv_mbox (me, LE2H_4 (mbox_addr_le));
+      return nr_bytes;
+    }
+
+  HW_TRACE ((me, "REG W 0x%x := 0x%02x%02x%02x%02x", addr,
+            addr_data[7], addr_data[6], addr_data[5], addr_data[4]));
+  if (rv->dummy != NULL)
+    {
+      len = 8;
+      memcpy (rv->dummy + addr - rv->reg_address, addr_data + 4, 4);
+    }
+  else
+    {
+      hw_rv_send (me, RV_WRITE_CMD, addr_data, len);
+      hw_rv_handle_incoming (me, RV_WRITE_CMD, addr_data, &len);
+    }
+
+  if (len != 8)
+    hw_abort (me, "read %d != 8 bytes returned", len);
+
+  /* We had an access: tighten up all slack.  */
+  rv->next_period = 1;
+
+  return nr_bytes;
+}
+
+/* Instance initializer function.  */
+
+static void
+hw_rv_finish (struct hw *me)
+{
+  hw_rv_device *rv = HW_ZALLOC (me, hw_rv_device);
+  int i;
+  const struct hw_property *mem_prop;
+  const struct hw_property *dummy_prop;
+  const struct hw_property *mbox_prop;
+
+  set_hw_data (me, rv);
+
+#undef RV_GET_IPROP
+#undef RV_GET_PROP
+#define RV_GET_PROP(T, N, M, D)                                \
+  do                                                   \
+    {                                                  \
+      if (hw_find_property (me, N) != NULL)            \
+       rv->M = hw_find_ ## T ## _property (me, N);     \
+      else                                             \
+       rv->M = (D);                                    \
+    }                                                  \
+  while (0)
+#define RV_GET_IPROP(N, M, D) RV_GET_PROP (integer, N, M, D)
+
+  RV_GET_PROP (string, "host", host, "127.0.0.1");
+  RV_GET_IPROP ("port", port, 10000);
+  RV_GET_IPROP ("remote-reg", remote_reg_address, 0);
+  RV_GET_IPROP ("max-poll-ticks", max_tick_poll_interval, 10000);
+  RV_GET_IPROP ("watchdog-interval", watchdog_interval, 30);
+  RV_GET_IPROP ("remote-mem", remote_mem_address, 0);
+  RV_GET_IPROP ("mem-burst-mask", mem_burst_mask, 0xffff);
+  RV_GET_IPROP ("intmultiple", intmultiple, 0);
+
+  set_hw_io_read_buffer (me, hw_rv_reg_read);
+  set_hw_io_write_buffer (me, hw_rv_reg_write);
+  set_hw_ports (me, hw_rv_ports);
+  rv->next_period = 1;
+
+  /* FIXME: We only support zero or one reg and zero or one mem area.  */
+  if (hw_find_property (me, "reg") != NULL)
+    {
+      reg_property_spec reg;
+      if (hw_find_reg_array_property (me, "reg", 0, &reg))
+       {
+         unsigned_word attach_address;
+         int attach_space;
+         unsigned int attach_size;
+
+         hw_unit_address_to_attach_address (hw_parent (me),
+                                            &reg.address,
+                                            &attach_space,
+                                            &attach_address,
+                                            me);
+         rv->reg_address = attach_address;
+         hw_unit_size_to_attach_size (hw_parent (me),
+                                      &reg.size,
+                                      &attach_size, me);
+         rv->reg_size = attach_size;
+         if ((attach_address & 3) != 0)
+           hw_abort (me, "register block must be 4 byte aligned");
+         hw_attach_address (hw_parent (me),
+                            0,
+                            attach_space, attach_address, attach_size,
+                            me);
+       }
+      else
+       hw_abort (me, "property \"reg\" has the wrong type");
+    }
+
+  dummy_prop = hw_find_property (me, "dummy");
+  if (dummy_prop != NULL)
+    {
+      if (rv->reg_size == 0)
+       hw_abort (me, "dummy argument requires a \"reg\" property");
+
+      if (hw_property_type (dummy_prop) == integer_property)
+       {
+         unsigned32 dummyfill = hw_find_integer_property (me, "dummy");
+         unsigned8 *dummymem = hw_malloc (me, rv->reg_size);
+         memset (dummymem, dummyfill, rv->reg_size);
+         rv->dummy = dummymem;
+       }
+      else
+       {
+         const char *dummyarg = hw_find_string_property (me, "dummy");
+         unsigned8 *dummymem = hw_malloc (me, rv->reg_size);
+         FILE *f = fopen (dummyarg, "rb");
+
+         if (f == NULL)
+           hw_abort (me, "opening dummy-file \"%s\": %s",
+                     dummyarg, strerror (errno));
+         if (fread (dummymem, 1, rv->reg_size, f) != rv->reg_size)
+           hw_abort (me, "reading dummy-file \"%s\": %s",
+                     dummyarg, strerror (errno));
+         fclose (f);
+         rv->dummy = dummymem;
+       }
+    }
+
+  mbox_prop = hw_find_property (me, "mbox");
+  if (mbox_prop != NULL)
+    {
+      if (hw_property_type (mbox_prop) == integer_property)
+       {
+         signed_cell attach_address_sc
+           = hw_find_integer_property (me, "mbox");
+
+         rv->mbox_address = (unsigned32) attach_address_sc;
+         hw_attach_address (hw_parent (me),
+                            0,
+                            0, (unsigned32) attach_address_sc, 4, me);
+       }
+      else
+       hw_abort (me, "property \"mbox\" has the wrong type");
+    }
+
+  mem_prop = hw_find_property (me, "mem");
+  if (mem_prop != NULL)
+    {
+      signed_cell attach_address_sc;
+      signed_cell attach_size_sc;
+
+      /* Only specific names are reg_array_properties, the rest are
+        array_properties.  */
+      if (hw_property_type (mem_prop) == array_property
+         && hw_property_sizeof_array (mem_prop) == 2 * sizeof (attach_address_sc)
+         && hw_find_integer_array_property (me, "mem", 0, &attach_address_sc)
+         && hw_find_integer_array_property (me, "mem", 1, &attach_size_sc))
+       {
+         /* Unfortunate choice of types forces us to dance around a bit.  */
+         rv->mem_address = (unsigned32) attach_address_sc;
+         rv->mem_size = (unsigned32) attach_size_sc;
+         if ((attach_address_sc & 3) != 0)
+           hw_abort (me, "memory block must be 4 byte aligned");
+       }
+      else
+       hw_abort (me, "property \"mem\" has the wrong type");
+    }
+
+  hw_rv_map_ints (me);
+
+  hw_rv_init_socket (me);
+
+  /* We need an extra initialization pass, after all others currently
+     scheduled (mostly, after the simulation events machinery has been
+     initialized so the events we want don't get thrown out).  */
+  hw_rv_add_init (me);
+}
+
+/* Our root structure; see dv-* build machinery for usage.  */
+
+const struct hw_descriptor dv_rv_descriptor[] = {
+  { RV_FAMILY_NAME, hw_rv_finish },
+  { NULL }
+};
diff --git a/sim/cris/rvdummy.c b/sim/cris/rvdummy.c
new file mode 100644 (file)
index 0000000..633eddb
--- /dev/null
@@ -0,0 +1,536 @@
+/* Test-driver for the remote-virtual-component simulator framework
+   for GDB, the GNU Debugger.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 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.  */
+
+/* Avoid any problems whatsoever building this program if we're not
+   also building hardware support.  */
+
+#if !WITH_HW
+int
+main (int argc, char *argv[])
+{
+  return 2;
+}
+#else
+
+#ifdef HAVE_CONFIG_H
+#include "cconfig.h"
+#include "tconfig.h"
+#endif
+
+#include "getopt.h"
+#include "libiberty.h"
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+/* Not guarded in dv-sockser.c, so why here.  */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+enum rv_command {
+  RV_READ_CMD = 0,
+  RV_WRITE_CMD = 1,
+  RV_IRQ_CMD = 2,
+  RV_MEM_RD_CMD = 3,
+  RV_MEM_WR_CMD = 4,
+  RV_MBOX_HANDLE_CMD = 5,
+  RV_MBOX_PUT_CMD = 6,
+  RV_WATCHDOG_CMD = 7
+};
+
+enum opts { OPT_PORT = 1, OPT_TIMEOUT, OPT_VERBOSE };
+
+struct option longopts[] =
+  {
+    {"port", required_argument, NULL, OPT_PORT},
+    {"timeout", required_argument, NULL, OPT_TIMEOUT},
+    {"verbose", no_argument, NULL, OPT_VERBOSE},
+    {NULL, 0, NULL, 0}
+  };
+
+int port = 10000;
+time_t timeout = 30000;
+char *progname = "(unknown)";
+int verbose = 0;
+
+/* Required forward-declarations.  */
+static void handle_input_file (int, char *);
+
+/* Set up a "server" listening to the port in PORT for a raw TCP
+   connection.  Return a file descriptor for the connection or -1 on
+   error.  */
+
+int setupsocket (void)
+{
+  int s;
+  socklen_t len;
+  int reuse = 1;
+  struct sockaddr_in sa_in;
+  struct sockaddr_in from;
+
+  len = sizeof (from);
+  memset (&from, 0, len);
+  memset (&sa_in, 0, sizeof (sa_in));
+
+  s = socket (AF_INET, SOCK_STREAM, 0);
+  if (s < 0)
+    return -1;
+
+  if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse) != 0)
+    return -1;
+
+  sa_in.sin_port = htons (port);
+  sa_in.sin_family = AF_INET;
+
+  if (bind (s, (struct sockaddr *) & sa_in, sizeof sa_in) < 0)
+    return -1;
+
+  if (listen (s, 1) < 0)
+    return -1;
+
+  return accept (s, (struct sockaddr *) &from, &len);
+}
+
+/* Basic host-to-little-endian 32-bit value.  Could use the BFD
+   machinery, but let's avoid it for this only dependency.  */
+
+static void
+h2le32 (unsigned char *dest, unsigned int val)
+{
+  dest[0] = val & 255;
+  dest[1] = (val >> 8) & 255;
+  dest[2] = (val >> 16) & 255;
+  dest[3] = (val >> 24) & 255;
+}
+
+/* Send a blob of data.  */
+
+static void
+send_output (int fd, unsigned char *buf, int nbytes)
+{
+  while (nbytes > 0)
+    {
+      ssize_t written = write (fd, buf, nbytes);
+      if (written < 0)
+       {
+         fprintf (stderr, "%s: write to socket failed: %s\n",
+                 progname, strerror (errno));
+         exit (2);
+       }
+      nbytes -= written;
+    }
+}
+
+/* Receive a blob of data, NBYTES large.  Compare to the first NCOMP
+   bytes of BUF; if not a match, write error message to stderr and
+   exit (2).  Else put it in buf.  */
+
+static void
+expect_input (int fd, unsigned char *buf, int nbytes, int ncomp)
+{
+  unsigned char byt;
+  int i;
+
+  for (i = 0; i < nbytes; i++)
+    {
+      int r;
+
+      do
+       {
+         errno = 0;
+         r = read (fd, &byt, 1);
+       }
+      while (r <= 0 && (r == 0 || errno == EAGAIN));
+
+      if (r != 1)
+       {
+         fprintf (stderr, "%s: read from socket failed: %s",
+                 progname, strerror (errno));
+         exit (2);
+       }
+
+      if (i < ncomp && byt != buf[i])
+       {
+         int j;
+         fprintf (stderr, "%s: unexpected input,\n ", progname);
+         if (i == 0)
+           fprintf (stderr, "nothing,");
+         else
+           for (j = 0; j < i; j++)
+             fprintf (stderr, "%02x", buf[j]);
+         fprintf (stderr, "\nthen %02x instead of %02x\n", byt, buf[i]);
+         exit (2);
+       }
+      else
+       buf[i] = byt;
+    }
+}
+
+/* Handle everything about a nil-terminated line of input.
+   Call exit (2) on error with error text on stderr.  */
+
+static void
+handle_input (int fd, char *buf, char *fname, int lineno)
+{
+  int nbytes = 0;
+  int n = -1;
+  char *s = buf + 2;
+  unsigned int data;
+  static unsigned char bytes[1024];
+  int i;
+
+  memset (bytes, 0, sizeof bytes);
+  lineno++;
+
+  if (buf[1] != ',')
+    goto syntax_error;
+
+  switch (buf[0])
+    {
+      /* Comment characters and empty lines.  */
+    case 0: case '!': case '#':
+      break;
+
+      /* Include another file.  */
+    case '@':
+      handle_input_file (fd, s);
+      break;
+
+      /* Raw input (to be expected).  */
+    case 'i':
+      do
+       {
+         n = -1;
+         sscanf (s, "%02x%n", &data, &n);
+         s += n;
+         if (n > 0)
+           bytes[nbytes++] = data;
+       }
+      while (n > 0);
+      expect_input (fd, bytes, nbytes, nbytes);
+      if (verbose)
+       {
+         printf ("i,");
+         for (i = 0; i < nbytes; i++)
+           printf ("%02x", bytes[i]);
+         printf ("\n");
+       }
+      break;
+
+      /* Raw output (to be written).  */
+    case 'o':
+      do
+       {
+         n = -1;
+         sscanf (s, "%02x%n", &data, &n);
+         if (n > 0)
+           {
+             s += n;
+             bytes[nbytes++] = data;
+           }
+       }
+      while (n > 0);
+      if (*s != 0)
+       goto syntax_error;
+      send_output (fd, bytes, nbytes);
+      if (verbose)
+       {
+         printf ("o,");
+         for (i = 0; i < nbytes; i++)
+           printf ("%02x", bytes[i]);
+         printf ("\n");
+       }
+      break;
+
+      /* Read a register.  */
+    case 'r':
+      {
+       unsigned int addr;
+       sscanf (s, "%x,%x%n", &addr, &data, &n);
+       if (n < 0 || s[n] != 0)
+         goto syntax_error;
+       bytes[0] = 11;
+       bytes[1] = 0;
+       bytes[2] = RV_READ_CMD;
+       h2le32 (bytes + 3, addr);
+       expect_input (fd, bytes, 11, 7);
+       h2le32 (bytes + 7, data);
+       send_output (fd, bytes, 11);
+       if (verbose)
+         printf ("r,%x,%x\n", addr, data);
+      }
+      break;
+
+      /* Write a register.  */
+    case 'w':
+      {
+       unsigned int addr;
+       sscanf (s, "%x,%x%n", &addr, &data, &n);
+       if (n < 0 || s[n] != 0)
+         goto syntax_error;
+       bytes[0] = 11;
+       bytes[1] = 0;
+       bytes[2] = RV_WRITE_CMD;
+       h2le32 (bytes + 3, addr);
+       h2le32 (bytes + 7, data);
+       expect_input (fd, bytes, 11, 11);
+       send_output (fd, bytes, 11);
+       if (verbose)
+         printf ("w,%x,%x\n", addr, data);
+      }
+      break;
+
+      /* Wait for some milliseconds.  */
+    case 't':
+      {
+       int del = 0;
+       struct timeval to;
+       sscanf (s, "%d%n", &del, &n);
+       if (n < 0 || s[n] != 0 || del == 0)
+         goto syntax_error;
+
+       to.tv_sec = del / 1000;
+       to.tv_usec = (del % 1000) * 1000;
+
+       if (select (0, NULL, NULL, NULL, &to) != 0)
+         {
+           fprintf (stderr, "%s: problem waiting for %d ms:\n %s\n",
+                    progname, del, strerror (errno));
+           exit (2);
+         }
+       if (verbose)
+         printf ("t,%d\n", del);
+      }
+      break;
+
+      /* Expect a watchdog command.  */
+    case 'W':
+      if (*s != 0)
+       goto syntax_error;
+      bytes[0] = 3;
+      bytes[1] = 0;
+      bytes[2] = RV_WATCHDOG_CMD;
+      expect_input (fd, bytes, 3, 3);
+      if (verbose)
+       printf ("W\n");
+      break;
+
+      /* Send an IRQ notification.  */
+    case 'I':
+      sscanf (s, "%x%n", &data, &n);
+      if (n < 0 || s[n] != 0)
+       goto syntax_error;
+      bytes[0] = 7;
+      bytes[1] = 0;
+      bytes[2] = RV_IRQ_CMD;
+      h2le32 (bytes + 3, data);
+      send_output (fd, bytes, 7);
+      if (verbose)
+       printf ("I,%x\n", data);
+      break;
+
+      /* DMA store (to CPU).  */
+    case 's':
+      {
+       unsigned int addr;
+       sscanf (s, "%x,%n", &addr, &n);
+
+       if (n < 0 || s[n] == 0)
+         goto syntax_error;
+       s += n;
+       do
+         {
+           n = -1;
+           sscanf (s, "%02x%n", &data, &n);
+           if (n > 0)
+             {
+               s += n;
+               bytes[11 + nbytes++] = data;
+             }
+         }
+       while (n > 0);
+
+       if (*s != 0)
+         goto syntax_error;
+       h2le32 (bytes, nbytes + 11);
+       bytes[2] = RV_MEM_WR_CMD;
+       h2le32 (bytes + 3, addr);
+       h2le32 (bytes + 7, nbytes);
+       send_output (fd, bytes, nbytes + 11);
+       if (verbose)
+         {
+           printf ("s,%x,", addr);
+           for (i = 0; i < nbytes; i++)
+             printf ("%02x", bytes[i]);
+           printf ("\n");
+         }
+      }
+      break;
+
+      /* DMA load (from CPU).  */
+    case 'l':
+      {
+       unsigned int addr;
+       sscanf (s, "%x,%n", &addr, &n);
+
+       if (n < 0 || s[n] == 0)
+         goto syntax_error;
+       s += n;
+       do
+         {
+           n = -1;
+           sscanf (s, "%02x%n", &data, &n);
+           if (n > 0)
+             {
+               s += n;
+               bytes[11 + nbytes++] = data;
+             }
+         }
+       while (n > 0);
+
+       if (*s != 0)
+         goto syntax_error;
+       h2le32 (bytes, nbytes + 11);
+       bytes[0] = 11;
+       bytes[1] = 0;
+       bytes[2] = RV_MEM_RD_CMD;
+       h2le32 (bytes + 3, addr);
+       h2le32 (bytes + 7, nbytes);
+       send_output (fd, bytes, 11);
+       bytes[0] = (nbytes + 11) & 255;
+       bytes[1] = ((nbytes + 11) >> 8) & 255;
+       expect_input (fd, bytes, nbytes + 11, nbytes + 11);
+       if (verbose)
+         {
+           printf ("l,%x,", addr);
+           for (i = 0; i < nbytes; i++)
+             printf ("%02x", bytes[i]);
+           printf ("\n");
+         }
+      }
+      break;
+
+    syntax_error:
+    default:
+      fprintf (stderr, "%s: invalid command line in %s:%d:\n %s",
+              progname, fname, lineno, strerror (errno));
+      exit (2);
+    }
+}
+
+/* Loop over the contents of FNAME, using handle_input to parse each line.
+   Errors to stderr, exit (2).  */
+
+static void
+handle_input_file (int fd, char *fname)
+{
+  static char buf[2048] = {0};
+  int lineno = 0;
+  FILE *f = fopen (fname, "r");
+
+  if (f == NULL)
+    {
+      fprintf (stderr, "%s: problem opening %s: %s\n",
+              progname, fname, strerror (errno));
+      exit (2);
+    }
+
+  /* Let's cut the buffer short, so we always get a newline.  */
+  while (fgets (buf, sizeof (buf) - 1, f) != NULL)
+    {
+      buf[strlen (buf) - 1] = 0;
+      lineno++;
+      handle_input (fd, buf, fname, lineno);
+    }
+
+  fclose (f);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int optc;
+  int fd;
+  FILE *f;
+  int i;
+
+  progname = argv[0];
+  while ((optc = getopt_long (argc, argv, "", longopts, NULL)) != -1)
+    switch (optc)
+      {
+      case OPT_PORT:
+       port = atoi (optarg);
+       break;
+
+      case OPT_TIMEOUT:
+       timeout = (time_t) atoi (optarg);
+       break;
+
+      case OPT_VERBOSE:
+       verbose = 1;
+       break;
+      }
+
+  fd = setupsocket ();
+  if (fd < 0)
+    {
+      fprintf (stderr, "%s: problem setting up the connection: %s\n",
+              progname, strerror (errno));
+      exit (2);
+    }
+
+  for (i = optind; i < argc; i++)
+    handle_input_file (fd, argv[i]);
+
+  /* FIXME: option-controlled test for remaining input?  */
+  close (fd);
+  return 1;
+}
+#endif
index 507ba579464ad24cb7d753fb8c6d340a6fa255e9..86d19b2f187c0f541ad1615cd1ecb2bc05a29a14 100644 (file)
@@ -1,5 +1,5 @@
 /* Main simulator entry points specific to the CRIS.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Axis Communications.
 
 This file is part of the GNU simulators.
@@ -78,7 +78,7 @@ static CGEN_DISASSEMBLER cris_disassemble_insn;
 static char cris_bare_iron = 0;
 
 /* Whether 0x9000000xx have simulator-specific meanings.  */
-static char cris_have_900000xxif = 0;
+char cris_have_900000xxif = 0;
 
 /* Records simulator descriptor so utilities like cris_dump_regs can be
    called from gdb.  */
@@ -506,7 +506,15 @@ sim_open (SIM_OPEN_KIND kind, host_callback *callback, struct bfd *abfd,
        memset (cpu->sighandler, 0, sizeof (cpu->sighandler));
        cpu->make_thread_cpu_data = NULL;
        cpu->thread_cpu_data_size = 0;
+#if WITH_HW
+       cpu->deliver_interrupt = NULL;
+#endif
       }
+#if WITH_HW
+    /* Always be cycle-accurate and call before/after functions if
+       with-hardware.  */
+    sim_profile_set_option (sd, "-model", PROFILE_MODEL_IDX, "on");
+#endif
   }
 
   /* Initialize various cgen things not done by common framework.
index b35b927278ef4e9af65dd11ee4ba53f4affab672..483046d90ee18749b1bd7d9ba8734785b3525d23 100644 (file)
@@ -1,5 +1,5 @@
 /* Main header for the CRIS simulator, based on the m32r header.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Axis Communications.
 
 This file is part of the GNU simulators.
@@ -117,6 +117,10 @@ struct cris_thread_info {
   char sigsuspended;
 };
 
+typedef int (*cris_interrupt_delivery_fn) (SIM_CPU *,
+                                          enum cris_interrupt_type,
+                                          unsigned int);
+
 struct _sim_cpu {
   /* sim/common cpu base.  */
   sim_cpu_base base;
@@ -132,6 +136,11 @@ struct _sim_cpu {
   CRIS_MISC_PROFILE cris_prev_misc_profile;
 #define CPU_CRIS_PREV_MISC_PROFILE(cpu) (& (cpu)->cris_prev_misc_profile)
 
+#if WITH_HW
+  cris_interrupt_delivery_fn deliver_interrupt;
+#define CPU_CRIS_DELIVER_INTERRUPT(cpu) (cpu->deliver_interrupt)
+#endif
+
   /* Simulator environment data.  */
   USI endmem;
   USI endbrk;