This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA:] The CRIS simulator.


Assumes ok on all my previous patches.  The simulator calls use the Linux
ABI, which means that statically linked binaries work on both target and
simulator.  (It shouldn't be too hard to support dynamically linked
binaries, but I haven't needed it yet.)  Not all syscalls are implemented
of course, and only a subset of valid parameters, but a good deal more
than what's necessary for "hello, world" and the GCC testsuite.  I don't
use the nltvals machinery for any of the constants, because it has
mismatches with the Linux definitions.  I also didn't find it useful to
spread out the ABI; better to keep it in one file.  The manually written
files are warnings-free with "-W -Wall" using the RH 7.3 derivate of gcc,
which cannot be said of the automatically generated files nor of
sim/common.  Ugh.  Testsuite directory later; this patch is already 167k.

Ok to commit?

	* cris: New directory, simulator for Axis Communications CRIS
	including CRISv32, CGEN-based.
	* configure.in: Add corresponding configury.
	* MAINTAINERS: Add myself as maintainer of the CRIS port.
	* configure: Regenerate.

Index: MAINTAINERS
===================================================================
RCS file: /cvs/src/src/sim/MAINTAINERS,v
retrieving revision 1.15
diff -c -p -r1.15 MAINTAINERS
*** MAINTAINERS	10 Mar 2004 02:58:24 -0000	1.15
--- MAINTAINERS	18 Dec 2004 01:36:54 -0000
*************** gdb-patches@sources.redhat.com 
*** 10,15 ****
--- 10,16 ----
  	Maintainers for particular sims:
  
  arm	        Nick Clifton <nickc@redhat.com>
+ cris		Hans-Peter Nilsson <hp@axis.com>
  frv		Dave Brolley <brolley@redhat.com>
  igen		(igen simulators)
  ppc		Andrew Cagney <ac131313@redhat.com>
Index: configure.in
===================================================================
RCS file: /cvs/src/src/sim/configure.in,v
retrieving revision 1.15
diff -c -p -r1.15 configure.in
*** configure.in	26 Jan 2004 08:12:43 -0000	1.15
--- configure.in	18 Dec 2004 01:18:26 -0000
*************** case "${target}" in
*** 58,63 ****
--- 58,67 ----
    	sim_target=arm
  	extra_subdirs="${extra_subdirs} testsuite"
  	;;
+   cris-*-* | crisv32-*-*)
+ 	sim_target=cris
+ 	extra_subdirs="${extra_subdirs} testsuite"
+ 	;;
    d10v-*-*)		sim_target=d10v ;;
  # OBSOLETE   d30v-*-*)
  # OBSOLETE 	sim_target=d30v
diff -uprN none/Makefile.in cris/Makefile.in
--- none/Makefile.in	Thu Jan  1 01:00:00 1970
+++ cris/Makefile.in	Thu Dec 16 06:14:25 2004
@@ -0,0 +1,166 @@
+# Makefile template for Configure for the CRIS simulator, based on a mix
+# of the ones for m32r and i960.
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Contributed by Axis Communications.
+#
+# 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.
+
+## COMMON_PRE_CONFIG_FRAG
+
+CRISV10F_OBJS = crisv10f.o cpuv10.o decodev10.o semcrisv10f-switch.o modelv10.o mloopv10f.o
+CRISV32F_OBJS = crisv32f.o cpuv32.o decodev32.o semcrisv32f-switch.o modelv32.o mloopv32f.o
+
+CONFIG_DEVICES = dv-sockser.o
+CONFIG_DEVICES =
+
+SIM_OBJS = \
+	$(SIM_NEW_COMMON_OBJS) \
+	sim-cpu.o \
+	sim-hload.o \
+	sim-hrw.o \
+	sim-model.o \
+	sim-reg.o \
+	cgen-utils.o cgen-trace.o cgen-scache.o \
+	cgen-run.o sim-reason.o sim-engine.o sim-stop.o \
+	sim-if.o arch.o \
+	$(CRISV10F_OBJS) \
+	$(CRISV32F_OBJS) \
+	traps.o devices.o \
+	$(CONFIG_DEVICES) \
+	cris-desc.o
+
+# Extra headers included by sim-main.h.
+# FIXME: $(srccom)/cgen-ops.h should be in CGEN_INCLUDE_DEPS.
+SIM_EXTRA_DEPS = \
+	$(CGEN_INCLUDE_DEPS) $(srccom)/cgen-ops.h \
+	arch.h cpuall.h cris-sim.h cris-desc.h
+
+SIM_EXTRA_CFLAGS = -DHAVE_SIM_LSTAT -DHAVE_SIM_RENAME -DHAVE_SIM_PIPE
+
+SIM_RUN_OBJS = nrun.o
+SIM_EXTRA_CLEAN = cris-clean
+
+# This selects the cris newlib/libgloss syscall definitions.
+NL_TARGET = -DNL_TARGET_cris
+
+## COMMON_POST_CONFIG_FRAG
+
+CGEN_CPU_DIR = $(CGENDIR)/../cpu
+
+arch = cris
+
+sim-if.o: sim-if.c $(SIM_MAIN_DEPS) $(sim-core_h) $(sim-options_h)
+
+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)
+
+# CRISV10 objs
+
+CRISV10F_INCLUDE_DEPS = \
+	$(CGEN_MAIN_CPU_DEPS) \
+	cpuv10.h decodev10.h engv10.h
+
+crisv10f.o: crisv10f.c cris-tmpl.c $(CRISV10F_INCLUDE_DEPS)
+
+# FIXME: What is mono and what does "Use of `mono' is wip" mean (other
+# than the apparent; some "mono" feature is work in progress)?
+mloopv10f.c engv10.h: stamp-v10fmloop
+stamp-v10fmloop: $(srcdir)/../common/genmloop.sh mloop.in Makefile
+	$(SHELL) $(srccom)/genmloop.sh \
+		-mono -no-fast -pbb -switch semcrisv10f-switch.c \
+		-cpu crisv10f -infile $(srcdir)/mloop.in
+	$(SHELL) $(srcroot)/move-if-change eng.hin engv10.h
+	$(SHELL) $(srcroot)/move-if-change mloop.cin mloopv10f.c
+	touch stamp-v10fmloop
+mloopv10f.o: mloopv10f.c semcrisv10f-switch.c $(CRISV10F_INCLUDE_DEPS)
+
+cpuv10.o: cpuv10.c $(CRISV10F_INCLUDE_DEPS)
+decodev10.o: decodev10.c $(CRISV10F_INCLUDE_DEPS)
+semcrisv10f-switch.o: semcrisv10f-switch.c $(CRISV10F_INCLUDE_DEPS)
+modelv10.o: modelv10.c $(CRISV10F_INCLUDE_DEPS)
+
+# CRISV32 objs
+
+CRISV32F_INCLUDE_DEPS = \
+	$(CGEN_MAIN_CPU_DEPS) \
+	cpuv32.h decodev32.h engv32.h
+
+crisv32f.o: crisv32f.c cris-tmpl.c $(CRISV32F_INCLUDE_DEPS)
+
+# FIXME: What is mono and what does "Use of `mono' is wip" mean (other
+# than the apparent; some "mono" feature is work in progress)?
+mloopv32f.c engv32.h: stamp-v32fmloop
+stamp-v32fmloop: $(srcdir)/../common/genmloop.sh mloop.in Makefile
+	$(SHELL) $(srccom)/genmloop.sh \
+		-mono -no-fast -pbb -switch semcrisv32f-switch.c \
+		-cpu crisv32f -infile $(srcdir)/mloop.in
+	$(SHELL) $(srcroot)/move-if-change eng.hin engv32.h
+	$(SHELL) $(srcroot)/move-if-change mloop.cin mloopv32f.c
+	touch stamp-v32fmloop
+mloopv32f.o: mloopv32f.c semcrisv32f-switch.c $(CRISV32F_INCLUDE_DEPS)
+
+cpuv32.o: cpuv32.c $(CRISV32F_INCLUDE_DEPS)
+decodev32.o: decodev32.c $(CRISV32F_INCLUDE_DEPS)
+semcrisv32f-switch.o: semcrisv32f-switch.c $(CRISV32F_INCLUDE_DEPS)
+modelv32.o: modelv32.c $(CRISV32F_INCLUDE_DEPS)
+
+cris-clean:
+	for v in 10 32; do \
+	  rm -f mloopv$${v}f.c engv$${v}.h stamp-v$${v}fmloop; \
+	  rm -f stamp-v$${v}fcpu; \
+	done
+	-rm -f stamp-arch stamp-desc
+	-rm -f tmp-*
+
+# cgen support, enable with --enable-cgen-maint
+CGEN_MAINT = ; @true
+# The following line is commented in or out depending upon --enable-cgen-maint.
+@CGEN_MAINT@CGEN_MAINT =
+
+# Useful when making CGEN-generated files manually, without --enable-cgen-maint.
+stamps: stamp-v10fmloop stamp-v32fmloop stamp-arch stamp-v10fcpu stamp-v32fcpu stamp-desc
+
+stamp-arch: $(CGEN_READ_SCM) $(CGEN_ARCH_SCM) $(CGEN_CPU_DIR)/cris.cpu Makefile
+	$(MAKE) cgen-arch $(CGEN_FLAGS_TO_PASS) mach=crisv10,crisv32 \
+	  archfile=$(CGEN_CPU_DIR)/cris.cpu \
+	  FLAGS="with-scache with-profile=fn"
+	touch stamp-arch
+arch.h arch.c cpuall.h: $(CGEN_MAINT) stamp-arch
+
+stamp-v10fcpu: $(CGEN_READ_SCM) $(CGEN_CPU_SCM) $(CGEN_DECODE_SCM) $(CGEN_CPU_DIR)/cris.cpu Makefile
+	$(MAKE) cgen-cpu-decode $(CGEN_FLAGS_TO_PASS) \
+	  archfile=$(CGEN_CPU_DIR)/cris.cpu \
+	  cpu=crisv10f mach=crisv10 SUFFIX=v10 FLAGS="with-scache with-profile=fn" EXTRAFILES="$(CGEN_CPU_SEMSW)"
+	$(SHELL) $(srcroot)/move-if-change $(srcdir)/semv10-switch.c $(srcdir)/semcrisv10f-switch.c
+	touch stamp-v10fcpu
+cpuv10.h cpuv10.c semcrisv10f-switch.c modelv10.c decodev10.c decodev10.h: $(CGEN_MAINT) stamp-v10fcpu
+
+stamp-v32fcpu: $(CGEN_READ_SCM) $(CGEN_CPU_SCM) $(CGEN_DECODE_SCM) $(CGEN_CPU_DIR)/cris.cpu Makefile
+	$(MAKE) cgen-cpu-decode $(CGEN_FLAGS_TO_PASS) \
+	  archfile=$(CGEN_CPU_DIR)/cris.cpu \
+	  cpu=crisv32f mach=crisv32 SUFFIX=v32 FLAGS="with-scache with-profile=fn" EXTRAFILES="$(CGEN_CPU_SEMSW)"
+	$(SHELL) $(srcroot)/move-if-change $(srcdir)/semv32-switch.c $(srcdir)/semcrisv32f-switch.c
+	touch stamp-v32fcpu
+cpuv32.h cpuv32.c semcrisv32f-switch.c modelv32.c decodev32.c decodev32.h: $(CGEN_MAINT) stamp-v32fcpu
+
+stamp-desc: $(CGEN_READ_SCM) $(CGEN_DESC_SCM) $(CGEN_CPU_DIR)/cris.cpu Makefile
+	$(MAKE) cgen-desc $(CGEN_FLAGS_TO_PASS) \
+		archfile=$(CGEN_CPU_DIR)/cris.cpu \
+		cpu=cris mach=all
+	touch stamp-desc
+cris-desc.c cris-desc.h cris-opc.h: $(CGEN_MAINT) stamp-desc
diff -uprN none/configure.in cris/configure.in
--- none/configure.in	Thu Jan  1 01:00:00 1970
+++ cris/configure.in	Tue Dec  7 18:45:26 2004
@@ -0,0 +1,20 @@
+dnl Process this file with autoconf to produce a configure script.
+sinclude(../common/aclocal.m4)
+AC_PREREQ(2.5)dnl
+AC_INIT(Makefile.in)
+
+SIM_AC_COMMON
+
+SIM_AC_OPTION_ALIGNMENT(NONSTRICT_ALIGNMENT)
+SIM_AC_OPTION_HOSTENDIAN
+
+dnl FIXME: What's a good value here when the minimum cache size is 8k?
+SIM_AC_OPTION_SCACHE(16384)
+
+# The default model shouldn't matter as long as there's a BFD.
+SIM_AC_OPTION_DEFAULT_MODEL(crisv32)
+SIM_AC_OPTION_ENVIRONMENT
+SIM_AC_OPTION_INLINE()
+SIM_AC_OPTION_CGEN_MAINT
+
+SIM_AC_OUTPUT
diff -uprN none/cris-sim.h cris/cris-sim.h
--- none/cris-sim.h	Thu Jan  1 01:00:00 1970
+++ cris/cris-sim.h	Thu Dec 16 06:11:42 2004
@@ -0,0 +1,170 @@
+/* Collection of junk for CRIS.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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.  */
+
+/* For other arch:s, this file is described as a "collection of junk", so
+   let's collect some nice junk of our own.  Keep it; it might be useful
+   some day!  */
+
+#ifndef CRIS_SIM_H
+#define CRIS_SIM_H
+
+typedef struct {
+  /* Whether the branch for the current insn was taken.  Placed first
+     here, in hope it'll get closer to the main simulator data.  */
+  USI branch_taken;
+
+  /* PC of the insn of the branch.  */
+  USI old_pc;
+
+  /* Static cycle count for all insns executed so far, including
+     non-context-specific stall cycles, for example when adding to PC.  */
+  unsigned64 basic_cycle_count;
+
+  /* Stall cycles for unaligned access of memory operands.  FIXME:
+     Should or should not include unaligned [PC+] operands?  */
+  unsigned64 unaligned_mem_dword_count;
+
+  /* Context-specific stall cycles.  */
+  unsigned64 memsrc_stall_count;
+  unsigned64 memraw_stall_count;
+  unsigned64 movemsrc_stall_count;
+  unsigned64 movemaddr_stall_count;
+  unsigned64 movemdst_stall_count;
+  unsigned64 mulsrc_stall_count;
+  unsigned64 jumpsrc_stall_count;
+  unsigned64 branch_stall_count;
+  unsigned64 jumptarget_stall_count;
+
+  /* What kind of target-specific trace to perform.  */
+  int flags;
+
+  /* Just the basic cycle count.  */
+#define FLAG_CRIS_MISC_PROFILE_SIMPLE 1
+
+  /* Show unaligned accesses.  */
+#define FLAG_CRIS_MISC_PROFILE_UNALIGNED 2
+
+  /* Show schedulable entities.  */
+#define FLAG_CRIS_MISC_PROFILE_SCHEDULABLE 4
+
+  /* Show everything.  */
+#define FLAG_CRIS_MISC_PROFILE_ALL		\
+ (FLAG_CRIS_MISC_PROFILE_SIMPLE			\
+  | FLAG_CRIS_MISC_PROFILE_UNALIGNED		\
+  | FLAG_CRIS_MISC_PROFILE_SCHEDULABLE)
+
+  /* Emit trace of each insn, xsim style.  */
+#define FLAG_CRIS_MISC_PROFILE_XSIM_TRACE 8
+
+#define N_CRISV32_BRANCH_PREDICTORS 256
+  unsigned char branch_predictors[N_CRISV32_BRANCH_PREDICTORS];
+
+} CRIS_MISC_PROFILE;
+
+/* Handler prototypes for functions called from the CGEN description.  */
+
+extern USI cris_bmod_handler (SIM_CPU *, UINT, USI);
+extern void cris_flush_simulator_decode_cache (SIM_CPU *, USI);
+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);
+
+/* Using GNU syntax (not C99) so we can compile this on RH 6.2
+   (egcs-1.1.2/gcc-2.91.66).  */
+#define cris_trace_printf(SD, CPU, FMT...)			\
+  do								\
+    {								\
+      if (TRACE_FILE (STATE_TRACE_DATA (SD)) != NULL)		\
+	fprintf (TRACE_FILE (CPU_TRACE_DATA (CPU)), FMT);	\
+      else							\
+	sim_io_printf (SD, FMT);				\
+    }								\
+  while (0)
+
+#if WITH_PROFILE_MODEL_P
+#define crisv32f_branch_taken(cpu, oldpc, newpc, taken)	\
+  do								\
+    {								\
+      CPU_CRIS_MISC_PROFILE (cpu)->old_pc = oldpc;		\
+      CPU_CRIS_MISC_PROFILE (cpu)->branch_taken = taken;	\
+    }								\
+  while (0)
+#else
+#define crisv32f_branch_taken(cpu, oldpc, newpc, taken)
+#endif
+
+#define crisv10f_branch_taken(cpu, oldpc, newpc, taken)
+
+#define crisv32f_read_supr(cpu, index)				\
+ (cgen_rtx_error (current_cpu,					\
+		  "Read of support register is unimplemented"),	\
+  0)
+
+#define crisv32f_write_supr(cpu, index, val)			\
+ cgen_rtx_error (current_cpu,					\
+		 "Write to support register is unimplemented")	\
+
+#define crisv32f_rfg_handler(cpu, pc)				\
+ cgen_rtx_error (current_cpu, "RFG isn't implemented")
+
+#define crisv32f_halt_handler(cpu, pc)				\
+ (cgen_rtx_error (current_cpu, "HALT isn't implemented"), 0)
+
+#define crisv32f_fidxi_handler(cpu, pc, indx)			\
+ (cgen_rtx_error (current_cpu, "FIDXI isn't implemented"), 0)
+
+#define crisv32f_ftagi_handler(cpu, pc, indx)			\
+ (cgen_rtx_error (current_cpu, "FTAGI isn't implemented"), 0)
+
+#define crisv32f_fidxd_handler(cpu, pc, indx)			\
+ (cgen_rtx_error (current_cpu, "FIDXD isn't implemented"), 0)
+
+#define crisv32f_ftagd_handler(cpu, pc, indx)			\
+ (cgen_rtx_error (current_cpu, "FTAGD isn't implemented"), 0)
+
+/* We have nothing special to do when interrupts or NMI are enabled
+   after having been disabled, so empty macros are enough for these
+   hooks.  */
+#define crisv32f_interrupts_enabled(cpu)
+#define crisv32f_nmi_enabled(cpu)
+
+/* Better warn for this case here, because everything needed is
+   somewhere within the CPU.  Compare to trying to use interrupts and
+   NMI, which would fail earlier, when trying to make nonexistent
+   external components generate those exceptions.  */
+#define crisv32f_single_step_enabled(cpu)			\
+ ((crisv32f_h_qbit_get (cpu) != 0				\
+   || (crisv32f_h_sr_get (cpu, H_SR_SPC) & ~1) != 0)		\
+  ? (cgen_rtx_error (cpu,					\
+		     "single-stepping isn't implemented"), 0)	\
+  : 0)
+
+/* We don't need to track the value of the PID register here.  */
+#define crisv32f_write_pid_handler(cpu, val)
+
+/* Neither do we need to know of transitions to user mode.  */
+#define crisv32f_usermode_enabled(cpu)
+
+/* House-keeping exported from traps.c  */
+extern void cris_set_callbacks (host_callback *);
+
+/* FIXME: Add more junk.  */
+#endif
diff -uprN none/cris-tmpl.c cris/cris-tmpl.c
--- none/cris-tmpl.c	Thu Jan  1 01:00:00 1970
+++ cris/cris-tmpl.c	Thu Dec 16 06:12:04 2004
@@ -0,0 +1,382 @@
+/* CRIS base simulator support code
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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.  */
+
+/* The infrastructure is based on that of i960.c.  */
+
+#define WANT_CPU
+
+#include "sim-main.h"
+#include "cgen-mem.h"
+#include "cgen-ops.h"
+
+#define MY(f) XCONCAT3(crisv,BASENUM,f)
+
+/* Dispatcher for break insn.  */
+
+USI
+MY (f_break_handler) (SIM_CPU *cpu, USI breaknum, USI pc)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  USI ret = pc + 2;
+
+  MY (f_h_pc_set) (cpu, ret);
+
+  /* FIXME: Error out if IBR or ERP set.  */
+  switch (breaknum)
+    {
+    case 13:
+      MY (f_h_gr_set (cpu, 10,
+		      cris_break_13_handler (cpu,
+					     MY (f_h_gr_get (cpu, 9)),
+					     MY (f_h_gr_get (cpu, 10)),
+					     MY (f_h_gr_get (cpu, 11)),
+					     MY (f_h_gr_get (cpu, 12)),
+					     MY (f_h_gr_get (cpu, 13)),
+					     MY (f_h_sr_get (cpu, 7)),
+					     MY (f_h_sr_get (cpu, 11)),
+					     pc)));
+      break;
+
+    case 14:
+      sim_io_printf (sd, "%x\n", MY (f_h_gr_get (cpu, 3)));
+      break;
+
+    case 15:
+      /* Re-use the Linux exit call.  */
+      cris_break_13_handler (cpu, /* TARGET_SYS_exit */ 1, 0,
+			     0, 0, 0, 0, 0, pc);
+
+    default:
+      abort ();
+    }
+
+  return MY (f_h_pc_get) (cpu);
+}
+
+/* Accessor function for simulator internal use.
+   Note the contents of BUF are in target byte order.  */
+
+int
+MY (f_fetch_register) (SIM_CPU *current_cpu, int rn,
+		      unsigned char *buf, int len ATTRIBUTE_UNUSED)
+{
+  SETTSI (buf, XCONCAT3(crisv,BASENUM,f_h_gr_get) (current_cpu, rn));
+  return -1;
+}
+
+/* Accessor function for simulator internal use.
+   Note the contents of BUF are in target byte order.  */
+
+int
+MY (f_store_register) (SIM_CPU *current_cpu, int rn,
+		      unsigned char *buf, int len ATTRIBUTE_UNUSED)
+{
+  XCONCAT3(crisv,BASENUM,f_h_gr_set) (current_cpu, rn, GETTSI (buf));
+  return -1;
+}
+
+#if WITH_PROFILE_MODEL_P
+
+/* FIXME: Some of these should be inline or macros.  Later.  */
+
+/* Initialize cycle counting for an insn.
+   FIRST_P is non-zero if this is the first insn in a set of parallel
+   insns.  */
+
+void
+MY (f_model_insn_before) (SIM_CPU *current_cpu, int first_p ATTRIBUTE_UNUSED)
+{
+  /* To give the impression that we actually know what PC is, we have to
+     dump register contents *before* the *next* insn, not after the
+     *previous* insn.  Uhh...  */
+
+  /* FIXME: Move this to separate, overridable function.  */
+  if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags
+       & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE)
+#ifdef GET_H_INSN_PREFIXED_P
+      /* For versions with prefixed insns, trace the combination as
+	 one insn.  */
+      && !GET_H_INSN_PREFIXED_P ()
+#endif
+      && 1)
+  {
+    int i;
+    char flags[7];
+    SIM_DESC sd = CPU_STATE (current_cpu);
+
+    cris_trace_printf (sd, current_cpu, "%lx ", (unsigned long) (CPU (h_pc)));
+
+    for (i = 0; i < 15; i++)
+      cris_trace_printf (sd, current_cpu, "%lx ",
+			 (unsigned long) (XCONCAT3(crisv,BASENUM,
+						   f_h_gr_get) (current_cpu,
+								i)));
+    flags[0] = GET_H_IBIT () != 0 ? 'I' : 'i';
+    flags[1] = GET_H_XBIT () != 0 ? 'X' : 'x';
+    flags[2] = GET_H_NBIT () != 0 ? 'N' : 'n';
+    flags[3] = GET_H_ZBIT () != 0 ? 'Z' : 'z';
+    flags[4] = GET_H_VBIT () != 0 ? 'V' : 'v';
+    flags[5] = GET_H_CBIT () != 0 ? 'C' : 'c';
+    flags[6] = 0;
+
+    /* Emit ACR after flags and cycle count for this insn.  */
+    if (BASENUM == 32)
+      cris_trace_printf (sd, current_cpu, "%s %d %lx\n", flags,
+			 (int)
+			 ((CPU_CRIS_MISC_PROFILE (current_cpu)
+			   ->basic_cycle_count
+			   - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)
+			   ->basic_cycle_count)
+			  + (CPU_CRIS_MISC_PROFILE (current_cpu)
+			     ->unaligned_mem_dword_count
+			     - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)
+			     ->unaligned_mem_dword_count)),
+			 (unsigned long) (XCONCAT3(crisv,BASENUM,
+						   f_h_gr_get) (current_cpu,
+								15)));
+    else
+      cris_trace_printf (sd, current_cpu, "%s %d\n", flags,
+			 (int)
+			 ((CPU_CRIS_MISC_PROFILE (current_cpu)
+			   ->basic_cycle_count
+			   - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)
+			   ->basic_cycle_count)
+			  + (CPU_CRIS_MISC_PROFILE (current_cpu)
+			     ->unaligned_mem_dword_count
+			     - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)
+			     ->unaligned_mem_dword_count)));
+
+    CPU_CRIS_PREV_MISC_PROFILE (current_cpu)[0]
+      = CPU_CRIS_MISC_PROFILE (current_cpu)[0];
+  }
+}
+
+/* Record the cycles computed for an insn.
+   LAST_P is non-zero if this is the last insn in a set of parallel insns,
+   and we update the total cycle count.
+   CYCLES is the cycle count of the insn.  */
+
+void
+MY (f_model_insn_after) (SIM_CPU *current_cpu, int last_p ATTRIBUTE_UNUSED,
+			 int cycles)
+{
+  PROFILE_DATA *p = CPU_PROFILE_DATA (current_cpu);
+
+  PROFILE_MODEL_TOTAL_CYCLES (p) += cycles;
+  CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count += cycles;
+  PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles;
+}
+
+/* Initialize cycle counting for an insn.
+   FIRST_P is non-zero if this is the first insn in a set of parallel
+   insns.  */
+
+void
+MY (f_model_init_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+			       int first_p ATTRIBUTE_UNUSED)
+{
+  abort ();
+}
+
+/* Record the cycles computed for an insn.
+   LAST_P is non-zero if this is the last insn in a set of parallel insns,
+   and we update the total cycle count.  */
+
+void
+MY (f_model_update_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+				 int last_p ATTRIBUTE_UNUSED)
+{
+  abort ();
+}
+
+#if 0
+void
+MY (f_model_record_cycles) (SIM_CPU *current_cpu, unsigned long cycles)
+{
+  abort ();
+}
+
+void
+MY (f_model_mark_get_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf)
+{
+  abort ();
+}
+
+void
+MY (f_model_mark_set_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf)
+{
+  abort ();
+}
+#endif
+
+/* Create the context for a thread.  */
+
+void *
+MY (make_thread_cpu_data) (SIM_CPU *current_cpu, void *context)
+{
+  void *info = xmalloc (current_cpu->thread_cpu_data_size);
+
+  if (context != NULL)
+    memcpy (info,
+	    context,
+	    current_cpu->thread_cpu_data_size);
+  else
+    memset (info, 0, current_cpu->thread_cpu_data_size),abort();
+  return info;
+}
+
+/* Hook function for per-cpu simulator initialization.  */
+
+void
+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);
+}
+
+/* Model function for arbitrary single stall cycles.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_stall)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+			  const IDESC *idesc,
+			  int unit_num,
+			  int referenced ATTRIBUTE_UNUSED)
+{
+  return idesc->timing->units[unit_num].done;
+}
+
+#ifndef SPECIFIC_U_SKIP4_FN
+
+/* Model function for u-skip4 unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_skip4)) (SIM_CPU *current_cpu,
+			  const IDESC *idesc,
+			  int unit_num,
+			  int referenced ATTRIBUTE_UNUSED)
+{
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU (h_pc) += 4;
+  return idesc->timing->units[unit_num].done;
+}
+
+#endif
+
+#ifndef SPECIFIC_U_EXEC_FN
+
+/* Model function for u-exec unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_exec)) (SIM_CPU *current_cpu,
+			 const IDESC *idesc,
+			 int unit_num, int referenced ATTRIBUTE_UNUSED)
+{
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU (h_pc) += 2;
+  return idesc->timing->units[unit_num].done;
+}
+#endif
+
+#ifndef SPECIFIC_U_MEM_FN
+
+/* Model function for u-mem unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_mem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+			const IDESC *idesc,
+			int unit_num,
+			int referenced ATTRIBUTE_UNUSED)
+{
+  return idesc->timing->units[unit_num].done;
+}
+#endif
+
+#ifndef SPECIFIC_U_CONST16_FN
+
+/* Model function for u-const16 unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_const16)) (SIM_CPU *current_cpu,
+			    const IDESC *idesc,
+			    int unit_num,
+			    int referenced ATTRIBUTE_UNUSED)
+{
+  CPU (h_pc) += 2;
+  return idesc->timing->units[unit_num].done;
+}
+#endif /* SPECIFIC_U_CONST16_FN */
+
+#ifndef SPECIFIC_U_CONST32_FN
+
+/* This will be incorrect for early models, where a dword always take
+   two cycles.  */
+#define CRIS_MODEL_MASK_PC_STALL 2
+
+/* Model function for u-const32 unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_const32)) (SIM_CPU *current_cpu,
+			    const IDESC *idesc,
+			    int unit_num,
+			    int referenced ATTRIBUTE_UNUSED)
+{
+  int unaligned_extra
+    = (((CPU (h_pc) + 2) & CRIS_MODEL_MASK_PC_STALL)
+       == CRIS_MODEL_MASK_PC_STALL);
+
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU_CRIS_MISC_PROFILE (current_cpu)->unaligned_mem_dword_count
+    += unaligned_extra;
+
+  CPU (h_pc) += 4;
+  return idesc->timing->units[unit_num].done;
+}
+#endif /* SPECIFIC_U_CONST32_FN */
+
+#ifndef SPECIFIC_U_MOVEM_FN
+
+/* Model function for u-movem unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_movem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+			  const IDESC *idesc ATTRIBUTE_UNUSED,
+			  int unit_num ATTRIBUTE_UNUSED,
+			  int referenced ATTRIBUTE_UNUSED,
+			  INT limreg)
+{
+  /* FIXME: Add cycles for misalignment.  */
+
+  if (limreg == -1)
+    abort ();
+
+  /* We don't record movem move cycles in movemsrc_stall_count since
+     those cycles have historically been handled as ordinary cycles.  */
+  return limreg + 1;
+}
+#endif /* SPECIFIC_U_MOVEM_FN */
+
+#endif /* WITH_PROFILE_MODEL_P */
diff -uprN none/crisv10f.c cris/crisv10f.c
--- none/crisv10f.c	Thu Jan  1 01:00:00 1970
+++ cris/crisv10f.c	Thu Dec 16 06:06:18 2004
@@ -0,0 +1,42 @@
+/* CRIS v10 simulator support code
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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.  */
+
+/* The infrastructure is based on that of i960.c.  */
+
+#define WANT_CPU_CRISV10F
+
+#define BASENUM 10
+#include "cris-tmpl.c"
+
+#if WITH_PROFILE_MODEL_P
+
+/* Model function for u-multiply unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_multiply)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+			     const IDESC *idesc ATTRIBUTE_UNUSED,
+			     int unit_num ATTRIBUTE_UNUSED,
+			     int referenced ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+#endif /* WITH_PROFILE_MODEL_P */
diff -uprN none/crisv32f.c cris/crisv32f.c
--- none/crisv32f.c	Thu Jan  1 01:00:00 1970
+++ cris/crisv32f.c	Thu Dec 16 06:06:18 2004
@@ -0,0 +1,558 @@
+/* CRIS v32 simulator support code
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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.  */
+
+/* The infrastructure is based on that of i960.c.  */
+
+#define WANT_CPU_CRISV32F
+
+#define SPECIFIC_U_EXEC_FN
+#define SPECIFIC_U_SKIP4_FN
+#define SPECIFIC_U_CONST16_FN
+#define SPECIFIC_U_CONST32_FN
+#define SPECIFIC_U_MEM_FN
+#define SPECIFIC_U_MOVEM_FN
+#define BASENUM 32
+#include "cris-tmpl.c"
+
+#if WITH_PROFILE_MODEL_P
+
+/* Re-use the bit position for the BZ register, since there are no stall
+   cycles for reading or writing it.  */
+#define CRIS_BZ_REGNO 16
+#define CRIS_MODF_JUMP_MASK (1 << CRIS_BZ_REGNO)
+/* Likewise for the WZ register, marking memory writes.  */
+#define CRIS_WZ_REGNO 20
+#define CRIS_MODF_MEM_WRITE_MASK (1 << CRIS_WZ_REGNO)
+#define CRIS_MOF_REGNO (16 + 7)
+#define CRIS_ALWAYS_CONDITION 14
+
+/* This macro must only be used in context where there's only one
+   dynamic cause for a penalty, except in the u-exec unit.  */
+
+#define PENALIZE1(CNT)					\
+  do							\
+    {							\
+      CPU_CRIS_MISC_PROFILE (current_cpu)->CNT++;	\
+      model_data->prev_prev_prev_modf_regs		\
+	= model_data->prev_prev_modf_regs;		\
+      model_data->prev_prev_modf_regs			\
+	= model_data->prev_modf_regs;			\
+      model_data->prev_modf_regs = 0;			\
+      model_data->prev_prev_prev_movem_dest_regs	\
+	= model_data->prev_prev_movem_dest_regs;	\
+      model_data->prev_prev_movem_dest_regs		\
+	= model_data->prev_movem_dest_regs;		\
+      model_data->prev_movem_dest_regs = 0;		\
+    }							\
+  while (0)
+
+
+/* Model function for u-skip4 unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_skip4)) (SIM_CPU *current_cpu,
+			  const IDESC *idesc ATTRIBUTE_UNUSED,
+			  int unit_num ATTRIBUTE_UNUSED,
+			  int referenced ATTRIBUTE_UNUSED)
+{
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU (h_pc) += 4;
+  return 0;
+}
+
+/* Model function for u-exec unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_exec)) (SIM_CPU *current_cpu,
+			 const IDESC *idesc ATTRIBUTE_UNUSED,
+			 int unit_num ATTRIBUTE_UNUSED,
+			 int referenced ATTRIBUTE_UNUSED,
+			 INT destreg_in,
+			 INT srcreg,
+			 INT destreg_out)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+  UINT modf_regs
+    = ((destreg_out == -1 ? 0 : (1 << destreg_out))
+       | model_data->modf_regs);
+
+  if (srcreg != -1)
+    {
+      if (model_data->prev_movem_dest_regs & (1 << srcreg))
+	{
+	  PENALIZE1 (movemdst_stall_count);
+	  PENALIZE1 (movemdst_stall_count);
+	  PENALIZE1 (movemdst_stall_count);
+	}
+      else if (model_data->prev_prev_movem_dest_regs & (1 << srcreg))
+	{
+	  PENALIZE1 (movemdst_stall_count);
+	  PENALIZE1 (movemdst_stall_count);
+	}
+      else if (model_data->prev_prev_prev_movem_dest_regs & (1 << srcreg))
+	PENALIZE1 (movemdst_stall_count);
+    }
+
+  if (destreg_in != -1)
+    {
+      if (model_data->prev_movem_dest_regs & (1 << destreg_in))
+	{
+	  PENALIZE1 (movemdst_stall_count);
+	  PENALIZE1 (movemdst_stall_count);
+	  PENALIZE1 (movemdst_stall_count);
+	}
+      else if (model_data->prev_prev_movem_dest_regs & (1 << destreg_in))
+	{
+	  PENALIZE1 (movemdst_stall_count);
+	  PENALIZE1 (movemdst_stall_count);
+	}
+      else if (model_data->prev_prev_prev_movem_dest_regs & (1 << destreg_in))
+	PENALIZE1 (movemdst_stall_count);
+    }
+
+  model_data->prev_prev_prev_modf_regs
+    = model_data->prev_prev_modf_regs;
+  model_data->prev_prev_modf_regs = model_data->prev_modf_regs;
+  model_data->prev_modf_regs = modf_regs;
+  model_data->modf_regs = 0;
+
+  model_data->prev_prev_prev_movem_dest_regs
+    = model_data->prev_prev_movem_dest_regs;
+  model_data->prev_prev_movem_dest_regs = model_data->prev_movem_dest_regs;
+  model_data->prev_movem_dest_regs = model_data->movem_dest_regs;
+  model_data->movem_dest_regs = 0;
+
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU (h_pc) += 2;
+  return 1;
+}
+
+/* Special case used when the destination is a special register.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_exec_to_sr)) (SIM_CPU *current_cpu,
+			       const IDESC *idesc ATTRIBUTE_UNUSED,
+			       int unit_num ATTRIBUTE_UNUSED,
+			       int referenced ATTRIBUTE_UNUSED,
+			       INT srcreg,
+			       INT specreg)
+{
+  int specdest;
+
+  if (specreg != -1)
+    specdest = specreg + 16;
+  else
+    abort ();
+
+  return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec))
+    (current_cpu, NULL, 0, 0, -1, srcreg,
+     /* The positions for constant-zero registers BZ and WZ are recycled
+	for jump and memory-write markers.  We must take precautions
+	here not to add false markers for them.  It might be that the
+	hardware inserts stall cycles for instructions that actually try
+	and write those registers, but we'll burn that bridge when we
+	get to it; we'd have to find other free bits or make new
+	model_data variables.  However, it's doubtful that there will
+	ever be a need to be cycle-correct for useless code, at least in
+	this particular simulator, mainly used for GCC testing.  */
+     specdest == CRIS_BZ_REGNO || specdest == CRIS_WZ_REGNO
+     ? -1 : specdest);
+}
+
+
+/* Special case for movem.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_exec_movem)) (SIM_CPU *current_cpu,
+			       const IDESC *idesc ATTRIBUTE_UNUSED,
+			       int unit_num ATTRIBUTE_UNUSED,
+			       int referenced ATTRIBUTE_UNUSED,
+			       INT srcreg,
+			       INT destreg_out)
+{
+  return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec))
+    (current_cpu, NULL, 0, 0, -1, srcreg, destreg_out);
+}
+
+/* Model function for u-const16 unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_const16)) (SIM_CPU *current_cpu,
+			    const IDESC *idesc ATTRIBUTE_UNUSED,
+			    int unit_num ATTRIBUTE_UNUSED,
+			    int referenced ATTRIBUTE_UNUSED)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  /* If the previous insn was a jump of some sort and this insn
+     straddles a cache-line, there's a one-cycle penalty.
+     FIXME: Test-cases for normal const16 and others, like branch.  */
+  if ((model_data->prev_modf_regs & CRIS_MODF_JUMP_MASK)
+      && (CPU (h_pc) & 0x1e) == 0x1e)
+    PENALIZE1 (jumptarget_stall_count);
+
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU (h_pc) += 2;
+
+  return 0;
+}
+
+/* Model function for u-const32 unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_const32)) (SIM_CPU *current_cpu,
+			    const IDESC *idesc ATTRIBUTE_UNUSED,
+			    int unit_num ATTRIBUTE_UNUSED,
+			    int referenced ATTRIBUTE_UNUSED)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  /* If the previous insn was a jump of some sort and this insn
+     straddles a cache-line, there's a one-cycle penalty.  */
+  if ((model_data->prev_modf_regs & CRIS_MODF_JUMP_MASK)
+      && (CPU (h_pc) & 0x1e) == 0x1c)
+    PENALIZE1 (jumptarget_stall_count);
+
+  /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
+  CPU (h_pc) += 4;
+
+  return 0;
+}
+
+/* Model function for u-mem unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_mem)) (SIM_CPU *current_cpu,
+			const IDESC *idesc ATTRIBUTE_UNUSED,
+			int unit_num ATTRIBUTE_UNUSED,
+			int referenced ATTRIBUTE_UNUSED,
+			INT srcreg)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  if (srcreg == -1)
+    abort ();
+
+  /* If srcreg references a register modified in the previous cycle
+     through other than autoincrement, then there's a penalty: one
+     cycle.  */
+  if (model_data->prev_modf_regs & (1 << srcreg))
+    PENALIZE1 (memsrc_stall_count);
+
+  return 0;
+}
+
+/* Model function for u-mem-r unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_mem_r)) (SIM_CPU *current_cpu,
+			  const IDESC *idesc ATTRIBUTE_UNUSED,
+			  int unit_num ATTRIBUTE_UNUSED,
+			  int referenced ATTRIBUTE_UNUSED)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  /* There's a two-cycle penalty for read after a memory write in any of
+     the two previous cycles, known as a cache read-after-write hazard.
+
+     This model function (the model_data member access) depends on being
+     executed before the u-exec unit.  */
+  if ((model_data->prev_modf_regs & CRIS_MODF_MEM_WRITE_MASK)
+      || (model_data->prev_prev_modf_regs & CRIS_MODF_MEM_WRITE_MASK))
+    {
+      PENALIZE1 (memraw_stall_count);
+      PENALIZE1 (memraw_stall_count);
+    }
+
+  return 0;
+}
+
+/* Model function for u-mem-w unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_mem_w)) (SIM_CPU *current_cpu,
+			  const IDESC *idesc ATTRIBUTE_UNUSED,
+			  int unit_num ATTRIBUTE_UNUSED,
+			  int referenced ATTRIBUTE_UNUSED)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  /* Mark that memory has been written.  This model function (the
+     model_data member access) depends on being executed after the
+     u-exec unit.  */
+  model_data->prev_modf_regs |= CRIS_MODF_MEM_WRITE_MASK;
+
+  return 0;
+}
+
+/* Model function for u-movem-rtom unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_movem_rtom)) (SIM_CPU *current_cpu,
+			       const IDESC *idesc ATTRIBUTE_UNUSED,
+			       int unit_num ATTRIBUTE_UNUSED,
+			       int referenced ATTRIBUTE_UNUSED,
+			       /* Deliberate order.  */
+			       INT addrreg, INT limreg)
+{
+  USI addr;
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  if (limreg == -1 || addrreg == -1)
+    abort ();
+
+  addr = GET_H_GR (addrreg);
+
+  /* The movem-to-memory instruction must not move a register modified
+     in one of the previous two cycles.  Enforce by adding penalty
+     cycles.  */
+  if (model_data->prev_modf_regs & ((1 << (limreg + 1)) - 1))
+    {
+      PENALIZE1 (movemsrc_stall_count);
+      PENALIZE1 (movemsrc_stall_count);
+    }
+  else if (model_data->prev_prev_modf_regs & ((1 << (limreg + 1)) - 1))
+    PENALIZE1 (movemsrc_stall_count);
+
+  /* One-cycle penalty for each cache-line straddled.  Use the
+     documented expressions.  Unfortunately no penalty cycles are
+     eliminated by any penalty cycles above.  We file these numbers
+     separately, since they aren't schedulable for all cases.  */
+  if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5))
+    ;
+  else if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5) - 1)
+    PENALIZE1 (movemaddr_stall_count);
+  else if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5) - 2)
+    {
+      PENALIZE1 (movemaddr_stall_count);
+      PENALIZE1 (movemaddr_stall_count);
+    }
+  else
+    abort ();
+
+  return 0;
+}
+
+/* Model function for u-movem-mtor unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_movem_mtor)) (SIM_CPU *current_cpu,
+			       const IDESC *idesc ATTRIBUTE_UNUSED,
+			       int unit_num ATTRIBUTE_UNUSED,
+			       int referenced ATTRIBUTE_UNUSED,
+			       /* Deliberate order.  */
+			       INT addrreg, INT limreg)
+{
+  USI addr;
+  int nregs = limreg + 1;
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  if (limreg == -1 || addrreg == -1)
+    abort ();
+
+  addr = GET_H_GR (addrreg);
+
+  /* One-cycle penalty for each cache-line straddled.  Use the
+     documented expressions.  One cycle is the norm; more cycles are
+     counted as penalties.  Unfortunately no penalty cycles here
+     eliminate penalty cycles indicated in ->movem_dest_regs.  */
+  if ((addr >> 5) == (((addr + 4 * nregs) - 1) >> 5) - 1)
+    PENALIZE1 (movemaddr_stall_count);
+  else if ((addr >> 5) == (((addr + 4 * nregs) - 1) >> 5) - 2)
+    {
+      PENALIZE1 (movemaddr_stall_count);
+      PENALIZE1 (movemaddr_stall_count);
+    }
+
+  model_data->modf_regs |= ((1 << nregs) - 1);
+  model_data->movem_dest_regs  |= ((1 << nregs) - 1);
+  return 0;
+}
+
+
+/* Model function for u-branch unit.
+   FIXME: newpc and cc are always wrong.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,_u_branch)) (SIM_CPU *current_cpu,
+						 const IDESC *idesc,
+						 int unit_num, int referenced)
+{
+  CRIS_MISC_PROFILE *profp = CPU_CRIS_MISC_PROFILE (current_cpu);
+  USI pc = profp->old_pc;
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+  int taken = profp->branch_taken;
+  int branch_index = (pc & (N_CRISV32_BRANCH_PREDICTORS - 1)) >> 1;
+  int pred_taken = (profp->branch_predictors[branch_index] & 2) != 0;
+
+  if (taken != pred_taken)
+    {
+      PENALIZE1 (branch_stall_count);
+      PENALIZE1 (branch_stall_count);
+    }
+
+  if (taken)
+    {
+      if (profp->branch_predictors[branch_index] < 3)
+	profp->branch_predictors[branch_index]++;
+
+      return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump))
+	(current_cpu, idesc, unit_num, referenced, -1);
+    }
+
+  if (profp->branch_predictors[branch_index] != 0)
+    profp->branch_predictors[branch_index]--;
+
+  return 0;
+}
+
+/* Model function for u-jump-r unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_jump_r)) (SIM_CPU *current_cpu,
+			   const IDESC *idesc ATTRIBUTE_UNUSED,
+			   int unit_num ATTRIBUTE_UNUSED,
+			   int referenced ATTRIBUTE_UNUSED,
+			   int regno)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  if (regno == -1)
+    abort ();
+
+  /* For jump-to-register, the register must not have been modified the
+     last two cycles.  Penalty: two cycles from the modifying insn.  */
+  if ((1 << regno) & model_data->prev_modf_regs)
+    {
+      PENALIZE1 (jumpsrc_stall_count);
+      PENALIZE1 (jumpsrc_stall_count);
+    }
+  else if ((1 << regno) & model_data->prev_prev_modf_regs)
+    PENALIZE1 (jumpsrc_stall_count);
+
+  return 0;
+}
+
+/* Model function for u-jump-sr unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump_sr)) (SIM_CPU *current_cpu,
+						  const IDESC *idesc,
+						  int unit_num, int referenced,
+						  int sr_regno)
+{
+  int regno;
+
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  if (sr_regno == -1)
+    abort ();
+
+  regno = sr_regno + 16;
+
+  /* For jump-to-register, the register must not have been modified the
+     last two cycles.  Penalty: two cycles from the modifying insn.  */
+  if ((1 << regno) & model_data->prev_modf_regs)
+    {
+      PENALIZE1 (jumpsrc_stall_count);
+      PENALIZE1 (jumpsrc_stall_count);
+    }
+  else if ((1 << regno) & model_data->prev_prev_modf_regs)
+    PENALIZE1 (jumpsrc_stall_count);
+
+  return
+    MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump)) (current_cpu, idesc,
+						   unit_num, referenced, -1);
+}
+
+/* Model function for u-jump unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_jump)) (SIM_CPU *current_cpu,
+			 const IDESC *idesc ATTRIBUTE_UNUSED,
+			 int unit_num ATTRIBUTE_UNUSED,
+			 int referenced ATTRIBUTE_UNUSED,
+			 int out_sr_regno)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  /* Mark that we made a jump.  */
+  model_data->modf_regs
+    |= (CRIS_MODF_JUMP_MASK
+	| (out_sr_regno == -1 || out_sr_regno == CRIS_BZ_REGNO
+	   ? 0 : (1 << (out_sr_regno + 16))));
+  return 0;
+}
+
+/* Model function for u-multiply unit.  */
+
+int
+MY (XCONCAT3 (f_model_crisv,BASENUM,
+	      _u_multiply)) (SIM_CPU *current_cpu,
+			     const IDESC *idesc ATTRIBUTE_UNUSED,
+			     int unit_num ATTRIBUTE_UNUSED,
+			     int referenced ATTRIBUTE_UNUSED,
+			     int srcreg, int destreg)
+{
+  MODEL_CRISV32_DATA *model_data
+    = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
+
+  /* Sanity-check for cases that should never happen.  */
+  if (srcreg == -1 || destreg == -1)
+    abort ();
+
+  /* This takes extra cycles when one of the inputs has been modified
+     through other than autoincrement in the previous cycle.  Penalty:
+     one cycle.  */
+  if (((1 << srcreg) | (1 << destreg)) & model_data->prev_modf_regs)
+    PENALIZE1 (mulsrc_stall_count);
+
+  /* We modified the multiplication destination (marked in u-exec) and
+     the MOF register.  */
+  model_data->modf_regs |= (1 << CRIS_MOF_REGNO);
+  return 0;
+}
+
+#endif /* WITH_PROFILE_MODEL_P */
diff -uprN none/devices.c cris/devices.c
--- none/devices.c	Thu Jan  1 01:00:00 1970
+++ cris/devices.c	Thu Dec 16 06:12:27 2004
@@ -0,0 +1,73 @@
+/* CRIS device support
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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.  */
+
+/* Based on the i960 devices.c (for the purposes, the same as all the
+   others).  */
+
+#include "sim-main.h"
+
+#ifdef HAVE_DV_SOCKSER
+#include "dv-sockser.h"
+#endif
+
+/* Placeholder definition.  */
+struct _device { char dummy; } cris_devices;
+
+void
+device_error (device *me ATTRIBUTE_UNUSED,
+	      char *message ATTRIBUTE_UNUSED,
+	      ...)
+{
+  abort ();
+}
+
+int
+device_io_read_buffer (device *me ATTRIBUTE_UNUSED,
+		       void *source ATTRIBUTE_UNUSED,
+		       int space ATTRIBUTE_UNUSED,
+		       address_word addr ATTRIBUTE_UNUSED,
+		       unsigned nr_bytes ATTRIBUTE_UNUSED,
+		       SIM_DESC sd ATTRIBUTE_UNUSED,
+		       SIM_CPU *cpu ATTRIBUTE_UNUSED,
+		       sim_cia cia ATTRIBUTE_UNUSED)
+{
+  abort ();
+}
+
+int
+device_io_write_buffer (device *me ATTRIBUTE_UNUSED,
+			const void *source,
+			int space ATTRIBUTE_UNUSED,
+			address_word addr, unsigned nr_bytes,
+			SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
+{
+  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 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);
+}
diff -uprN none/mloop.in cris/mloop.in
--- none/mloop.in	Thu Jan  1 01:00:00 1970
+++ cris/mloop.in	Thu Dec 16 06:06:18 2004
@@ -0,0 +1,294 @@
+# Simulator main loop for CRIS. -*- C -*-
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Contributed by Axis Communications.
+#
+# This file is part of the GNU simulators.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, 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.
+
+# Based on the fr30 file.
+
+# Syntax:
+# /bin/sh mainloop.in command
+#
+# Command is one of:
+#
+# init
+# support
+# extract-{simple,scache,pbb}
+# {full,fast}-exec-{simple,scache,pbb}
+#
+# A target need only provide a "full" version of one of simple,scache,pbb.
+# If the target wants it can also provide a fast version of same.
+# It can't provide more than this, however for illustration's sake the CRIS
+# port provides examples of all.
+
+# ??? After a few more ports are done, revisit.
+# Will eventually need to machine generate a lot of this.
+
+case "x$1" in
+
+xsupport)
+
+cat <<EOF
+/* It seems we don't have a templated header file corresponding to
+   cris-tmpl.c, so we have to get out declarations the hackish way.  */
+extern void @cpu@_specific_init (SIM_CPU *current_cpu);
+
+static INLINE const IDESC *
+extract (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, ARGBUF *abuf,
+         int fast_p)
+{
+  const IDESC *id = @cpu@_decode (current_cpu, pc, insn,
+#if CGEN_INT_INSN_P
+				  insn,
+#endif
+				  abuf);
+  @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
+  if (! fast_p)
+    {
+      int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
+      int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
+      @cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p);
+    }
+  return id;
+}
+
+static INLINE SEM_PC
+execute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p)
+{
+  SEM_PC vpc;
+
+  if (fast_p)
+    {
+#if ! WITH_SEM_SWITCH_FAST
+#if WITH_SCACHE
+      vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc);
+#else
+      vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, &sc->argbuf);
+#endif
+#else
+      abort ();
+#endif /* WITH_SEM_SWITCH_FAST */
+    }
+  else
+    {
+#if ! WITH_SEM_SWITCH_FULL
+      ARGBUF *abuf = &sc->argbuf;
+      const IDESC *idesc = abuf->idesc;
+#if WITH_SCACHE_PBB
+      int virtual_p = CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_VIRTUAL);
+#else
+      int virtual_p = 0;
+#endif
+
+      if (! virtual_p)
+	{
+	  /* FIXME: call x-before */
+	  if (ARGBUF_PROFILE_P (abuf))
+	    PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num);
+	  /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */
+	  if (PROFILE_MODEL_P (current_cpu)
+	      && ARGBUF_PROFILE_P (abuf))
+	    @cpu@_model_insn_before (current_cpu, 1 /*first_p*/);
+	  TRACE_INSN_INIT (current_cpu, abuf, 1);
+	  TRACE_INSN (current_cpu, idesc->idata,
+		      (const struct argbuf *) abuf, abuf->addr);
+	}
+#if WITH_SCACHE
+      vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc);
+#else
+      vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, abuf);
+#endif
+      if (! virtual_p)
+	{
+	  /* FIXME: call x-after */
+	  if (PROFILE_MODEL_P (current_cpu)
+	      && ARGBUF_PROFILE_P (abuf))
+	    {
+	      int cycles;
+
+	      cycles = (*idesc->timing->model_fn) (current_cpu, sc);
+	      @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
+	    }
+	  TRACE_INSN_FINI (current_cpu, abuf, 1);
+	}
+#else
+      abort ();
+#endif /* WITH_SEM_SWITCH_FULL */
+    }
+
+  return vpc;
+}
+
+EOF
+
+;;
+
+xinit)
+
+cat <<EOF
+  /* This seemed the only sane location to emit a call to a
+     model-specific init function.  It may not work for all simulator
+     types.  FIXME: Introduce a model-init hook.  */
+
+  /* We use the same condition as the code that's expected to follow, so
+     GCC can consolidate the code with only one conditional.  */
+  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+    @cpu@_specific_init (current_cpu);
+EOF
+
+;;
+
+xextract-simple | xextract-scache)
+
+# Inputs:  current_cpu, vpc, sc, FAST_P
+# Outputs: sc filled in
+
+cat <<EOF
+{
+  CGEN_INSN_INT insn = GETIMEMUHI (current_cpu, vpc);
+  extract (current_cpu, vpc, insn, SEM_ARGBUF (sc), FAST_P);
+}
+EOF
+
+;;
+
+xextract-pbb)
+
+# Inputs:  current_cpu, pc, sc, max_insns, FAST_P
+# Outputs: sc, pc
+# sc must be left pointing past the last created entry.
+# pc must be left pointing past the last created entry.
+# If the pbb is terminated by a cti insn, SET_CTI_VPC(sc) must be called
+# to record the vpc of the cti insn.
+# SET_INSN_COUNT(n) must be called to record number of real insns.
+
+cat <<EOF
+{
+  const IDESC *idesc;
+  int icount = 0;
+
+  /* Make sure the buffer doesn't overflow for profiled insns if
+     max_insns happens to not be a multiple of 3.  */
+  if (!FAST_P)
+     max_insns -= 2 + 3;
+  else
+     /* There might be two real insns handled per loop.  */
+     max_insns--;
+
+  while (max_insns > 0)
+    {
+      UHI insn = GETIMEMUHI (current_cpu, pc);
+      int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
+      int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
+      int befaft_p = profile_p || trace_p;
+
+      if (befaft_p)
+	{
+	  @cpu@_emit_before (current_cpu, sc, pc, 1);
+	  ++sc;
+	  sc->argbuf.trace_p = trace_p;
+	  sc->argbuf.profile_p = profile_p;
+	  --max_insns;
+	}
+
+      idesc = extract (current_cpu, pc, insn, &sc->argbuf, FAST_P);
+      ++sc;
+      --max_insns;
+      ++icount;
+
+      if (befaft_p)
+	{
+	  @cpu@_emit_after (current_cpu, sc, pc);
+	  ++sc;
+	  --max_insns;
+	}
+
+      pc += idesc->length;
+
+      if (IDESC_CTI_P (idesc))
+	{
+	  SET_CTI_VPC (sc - 1);
+
+	  /* Delay slot?  Ignore for zero-instructions (bcc .+2) since
+	     those are treated as exit insns to avoid runaway sessions
+	     for invalid programs.  */
+	  if (insn != 0 && CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_DELAY_SLOT))
+	    {
+	      UHI insn;
+	      trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
+	      profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
+	      befaft_p = profile_p || trace_p;
+
+	      if (befaft_p)
+		{
+		  @cpu@_emit_before (current_cpu, sc, pc, 1);
+		  ++sc;
+		  sc->argbuf.trace_p = trace_p;
+		  sc->argbuf.profile_p = profile_p;
+		  --max_insns;
+		}
+
+	      insn = GETIMEMUHI (current_cpu, pc);
+	      idesc = extract (current_cpu, pc, insn, &sc->argbuf, FAST_P);
+	      ++sc;
+	      --max_insns;
+	      ++icount;
+
+	      if (befaft_p)
+		{
+		  @cpu@_emit_after (current_cpu, sc, pc);
+		  ++sc;
+		  --max_insns;
+		}
+	      pc += idesc->length;
+	    }
+	  break;
+	}
+    }
+
+ Finish:
+  SET_INSN_COUNT (icount);
+}
+EOF
+
+;;
+
+xfull-exec-* | xfast-exec-*)
+
+# Inputs: current_cpu, sc, FAST_P
+# Outputs: vpc
+# vpc contains the address of the next insn to execute
+
+cat <<EOF
+{
+#if (! FAST_P && WITH_SEM_SWITCH_FULL) || (FAST_P && WITH_SEM_SWITCH_FAST)
+#define DEFINE_SWITCH
+#include "sem@cpu@-switch.c"
+#else
+  vpc = execute (current_cpu, vpc, FAST_P);
+#endif
+}
+EOF
+
+;;
+
+*)
+  echo "Invalid argument to mainloop.in: $1" >&2
+  exit 1
+  ;;
+
+esac
diff -uprN none/sim-if.c cris/sim-if.c
--- none/sim-if.c	Thu Jan  1 01:00:00 1970
+++ cris/sim-if.c	Thu Dec 16 06:13:48 2004
@@ -0,0 +1,590 @@
+/* Main simulator entry points specific to the CRIS.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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.  */
+
+/* Based on the fr30 file, mixing in bits from the i960 and pruning of
+   dead code.  */
+
+#include "libiberty.h"
+#include "bfd.h"
+
+#include "sim-main.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "sim-options.h"
+#include "dis-asm.h"
+
+/* Apparently the autoconf bits are missing (though HAVE_ENVIRON is used
+   in other dirs; also lacking there).  Patch around it for major systems.  */
+#if defined (HAVE_ENVIRON) || defined (__GLIBC__)
+extern char **environ;
+#define GET_ENVIRON() environ
+#else
+char *missing_environ[] = { "SHELL=/bin/sh", "PATH=/bin:/usr/bin", NULL };
+#define GET_ENVIRON() missing_environ
+#endif
+
+/* AUX vector entries.  */
+#define TARGET_AT_NULL 0
+#define TARGET_AT_PHDR 3
+#define TARGET_AT_PHENT 4
+#define TARGET_AT_PHNUM 5
+#define TARGET_AT_PAGESZ 6
+#define TARGET_AT_BASE 7
+#define TARGET_AT_FLAGS 8
+#define TARGET_AT_ENTRY 9
+#define TARGET_AT_UID 11
+#define TARGET_AT_EUID 12
+#define TARGET_AT_GID 13
+#define TARGET_AT_EGID 14
+#define TARGET_AT_HWCAP 16
+#define TARGET_AT_CLKTCK 17
+
+/* Used with get_progbounds to find out how much memory is needed for the
+   program.  We don't want to allocate more, since that could mask
+   invalid memory accesses program bugs.  */
+struct progbounds {
+  USI startmem;
+  USI endmem;
+};
+
+static void free_state (SIM_DESC);
+static void get_progbounds (bfd *, asection *, void *);
+static SIM_RC cris_option_handler (SIM_DESC, sim_cpu *, int, char *, int);
+
+/* Since we don't build the cgen-opcode table, we use the old
+   disassembler.  */
+static CGEN_DISASSEMBLER cris_disassemble_insn;
+
+/* By default, we set up stack and environment variables like the Linux
+   kernel.  */
+static char cris_bare_iron = 0;
+
+/* Whether 0x9000000xx have simulator-specific meanings.  */
+static char cris_have_900000xxif = 0;
+
+/* Records simulator descriptor so utilities like cris_dump_regs can be
+   called from gdb.  */
+SIM_DESC current_state;
+
+/* CRIS-specific options.  */
+typedef enum {
+  OPTION_CRIS_STATS = OPTION_START,
+  OPTION_CRIS_TRACE,
+  OPTION_CRIS_NAKED,
+  OPTION_CRIS_900000XXIF,
+} CRIS_OPTIONS;
+
+static const OPTION cris_options[] =
+{
+  { {"cris-cycles", required_argument, NULL, OPTION_CRIS_STATS},
+      '\0', "basic|unaligned|schedulable|all",
+    "Dump execution statistics",
+      cris_option_handler, NULL },
+  { {"cris-trace", required_argument, NULL, OPTION_CRIS_TRACE},
+      '\0', "basic",
+    "Emit trace information while running",
+      cris_option_handler, NULL },
+  { {"cris-naked", no_argument, NULL, OPTION_CRIS_NAKED},
+     '\0', NULL, "Don't set up stack and environment",
+     cris_option_handler, NULL },
+  { {"cris-900000xx", no_argument, NULL, OPTION_CRIS_900000XXIF},
+     '\0', NULL, "Define addresses at 0x900000xx with simulator semantics",
+     cris_option_handler, NULL },
+  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
+};
+
+/* Add the CRIS-specific option list to the simulator.  */
+
+SIM_RC
+cris_option_install (SIM_DESC sd)
+{
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+  if (sim_add_option_table (sd, NULL, cris_options) != SIM_RC_OK)
+    return SIM_RC_FAIL;
+  return SIM_RC_OK;
+}
+
+/* Handle CRIS-specific options.  */
+
+static SIM_RC
+cris_option_handler (SIM_DESC sd, sim_cpu *cpu ATTRIBUTE_UNUSED, int opt,
+		     char *arg, int is_command ATTRIBUTE_UNUSED)
+{
+  /* The options are CRIS-specific, but cpu-specific option-handling is
+     broken; required to being with "--cpu0-".  We store the flags in an
+     unused field in the global state structure and move the flags over
+     to the module-specific CPU data when we store things in the
+     cpu-specific structure.  */
+  char *tracefp = STATE_TRACE_FLAGS (sd);
+
+  switch ((CRIS_OPTIONS) opt)
+    {
+      case OPTION_CRIS_STATS:
+	if (strcmp (arg, "basic") == 0)
+	  *tracefp = FLAG_CRIS_MISC_PROFILE_SIMPLE;
+	else if (strcmp (arg, "unaligned") == 0)
+	  *tracefp
+	    = (FLAG_CRIS_MISC_PROFILE_UNALIGNED
+	       | FLAG_CRIS_MISC_PROFILE_SIMPLE);
+	else if (strcmp (arg, "schedulable") == 0)
+	  *tracefp
+	    = (FLAG_CRIS_MISC_PROFILE_SCHEDULABLE
+	       | FLAG_CRIS_MISC_PROFILE_SIMPLE);
+	else if (strcmp (arg, "all") == 0)
+	  *tracefp = FLAG_CRIS_MISC_PROFILE_ALL;
+	else
+	  {
+	    /* We'll actually never get here; the caller handles the
+	       error case.  */
+	    sim_io_eprintf (sd, "Unknown option `--cris-stats=%s'\n", arg);
+	    return SIM_RC_FAIL;
+	  }
+	break;
+
+      case OPTION_CRIS_TRACE:
+	if (strcmp (arg, "basic") == 0)
+	  *tracefp |= FLAG_CRIS_MISC_PROFILE_XSIM_TRACE;
+	else
+	  {
+	    sim_io_eprintf (sd, "Unknown option `--cris-trace=%s'\n", arg);
+	    return SIM_RC_FAIL;
+	  }
+	break;
+
+      case OPTION_CRIS_NAKED:
+	cris_bare_iron = 1;
+	break;
+
+      case OPTION_CRIS_900000XXIF:
+	cris_have_900000xxif = 1;
+	break;
+
+      default:
+	/* We'll actually never get here; the caller handles the error
+	   case.  */
+	sim_io_eprintf (sd, "Unknown option `%s'\n", arg);
+	return SIM_RC_FAIL;
+    }
+
+  /* Imply --profile-model=on.  */
+  return sim_profile_set_option (sd, "-model", PROFILE_MODEL_IDX, "on");
+}
+
+/* Cover function of sim_state_free to free the cpu buffers as well.  */
+
+static void
+free_state (SIM_DESC sd)
+{
+  if (STATE_MODULES (sd) != NULL)
+    sim_module_uninstall (sd);
+  sim_cpu_free_all (sd);
+  sim_state_free (sd);
+}
+
+/* BFD section iterator to find the highest allocated section address
+   (plus one).  If we could, we should use the program header table
+   instead, but we can't get to that using bfd.  */
+
+void
+get_progbounds (bfd *abfd ATTRIBUTE_UNUSED, asection *s, void *vp)
+{
+  struct progbounds *pbp = (struct progbounds *) vp;
+
+  if ((bfd_get_section_flags (abfd, s) & SEC_ALLOC))
+    {
+      bfd_size_type sec_size = bfd_get_section_size (s);
+      bfd_size_type sec_start = bfd_get_section_vma (abfd, s);
+      bfd_size_type sec_end = sec_start + sec_size;
+
+      if (sec_end > pbp->endmem)
+	pbp->endmem = sec_end;
+
+      if (sec_start < pbp->startmem)
+	pbp->startmem = sec_start;
+    }
+}
+
+/* Create an instance of the simulator.  */
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *callback, struct bfd *abfd,
+	  char **argv)
+{
+  char c;
+  int i;
+  USI startmem = 0;
+  USI endmem = CRIS_DEFAULT_MEM_SIZE;
+  USI endbrk = endmem;
+  USI stack_low = 0;
+  SIM_DESC sd = sim_state_alloc (kind, callback);
+
+  /* Can't initialize to "" below.  It's either a GCC bug in old
+     releases (up to and including 2.95.3 (.4 in debian) or a bug in the
+     standard ;-) that the rest of the elements won't be initialized.  */
+  bfd_byte sp_init[4] = {0, 0, 0, 0};
+
+  /* The cpu data is kept in a separately allocated chunk of memory.  */
+  if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* 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
+     print_filtered.  */
+  if (sim_parse_args (sd, argv) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* If we have a binary program, endianness-setting would not be taken
+     from elsewhere unfortunately, so set it here.  At the time of this
+     writing, it isn't used until sim_config, but that might change so
+     set it here before memory is defined or touched.  */
+  current_target_byte_order = LITTLE_ENDIAN;
+
+  /* check for/establish the reference program image */
+  if (sim_analyze_program (sd,
+			   (STATE_PROG_ARGV (sd) != NULL
+			    ? *STATE_PROG_ARGV (sd)
+			    : NULL),
+			   abfd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* For CRIS simulator-specific use, we need to find out the bounds of
+     the program as well, which is not done by sim_analyze_program
+     above.  */
+  if (STATE_PROG_BFD (sd))
+    {
+      struct progbounds pb;
+
+      /* The sections should now be accessible using bfd functions.  */
+      pb.startmem = 0x7fffffff;
+      pb.endmem = 0;
+      bfd_map_over_sections (STATE_PROG_BFD (sd), get_progbounds, &pb);
+
+      /* We align the area that the program uses to page boundaries.  */
+      startmem = pb.startmem & ~8191;
+      endbrk = pb.endmem;
+      endmem = (endbrk + 8191) & ~8191;
+    }
+
+  /* Find out how much room is needed for the environment and argv, create
+     that memory and fill it.  Only do this when there's a program
+     specified.  */
+  if (STATE_PROG_BFD (sd) && !cris_bare_iron)
+    {
+      char *name = bfd_get_filename (STATE_PROG_BFD (sd));
+      char **my_environ = GET_ENVIRON ();
+      /* We use these maps to give the same behavior as the old xsim
+	 simulator.  */
+      USI envtop = 0x40000000;
+      USI stacktop = 0x3e000000;
+      USI envstart;
+      int envc;
+      int len = strlen (name) + 1;
+      USI epp, epp0;
+      USI stacklen;
+      int i;
+      char **prog_argv = STATE_PROG_ARGV (sd);
+      int my_argc = 0;
+      /* All CPU:s have the same memory map, apparently.  */
+      SIM_CPU *cpu = STATE_CPU (sd, 0);
+      USI csp;
+      bfd_byte buf[4];
+
+      /* Count in the environment as well. */
+      for (envc = 0; my_environ[envc] != NULL; envc++)
+	len += strlen (my_environ[envc]) + 1;
+
+      for (i = 0; prog_argv[i] != NULL; my_argc++, i++)
+	len += strlen (prog_argv[i]) + 1;
+
+      envstart = (envtop - len) & ~8191;
+
+      /* Create read-only block for the environment strings.  */
+      sim_core_attach (sd, NULL, 0, access_read, 0,
+		       envstart, (len + 8191) & ~8191,
+		       0, NULL, NULL);
+
+      /* This shouldn't happen.  */
+      if (envstart < stacktop)
+	stacktop = envstart - 64 * 8192;
+
+      csp = stacktop;
+
+      /* Note that the linux kernel does not correctly compute the storage
+	 needs for the static-exe AUX vector.  */
+      csp -= 4 * 4 * 2;
+
+      csp -= (envc + 1) * 4;
+      csp -= (my_argc + 1) * 4;
+      csp -= 4;
+
+      /* Write the target representation of the start-up-value for the
+	 stack-pointer suitable for register initialization below.  */
+      bfd_putl32 (csp, sp_init);
+
+      /* If we make this 1M higher; say 8192*1024, we have to take
+	 special precautions for pthreads, because pthreads assumes that
+	 the memory that low isn't mmapped, and that it can mmap it
+	 without fallback in case of failure (and we fail ungracefully
+	 long before *that*: the memory isn't accounted for in our mmap
+	 list).  */
+      stack_low = (csp - (7168*1024)) & ~8191;
+
+      stacklen = stacktop - stack_low;
+
+      /* Tee hee, we have an executable stack.  Well, it's necessary to
+	 test GCC trampolines...  */
+      sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
+		       stack_low, stacklen,
+		       0, NULL, NULL);
+
+      epp = epp0 = envstart;
+
+      /* Can't use sim_core_write_unaligned_4 without everything
+	 initialized when tracing, and then these writes would get into
+	 the trace.  */
+#define write_dword(addr, data)						\
+ do									\
+   {									\
+     USI data_ = data;							\
+     USI addr_ = addr;							\
+     bfd_putl32 (data_, buf);						\
+     if (sim_core_write_buffer (sd, cpu, 0, buf, addr_, 4) != 4)	\
+	goto abandon_chip;						\
+   }									\
+ while (0)
+
+      write_dword (csp, my_argc);
+      csp += 4;
+
+      for (i = 0; i < my_argc; i++, csp += 4)
+	{
+	  size_t strln = strlen (prog_argv[i]) + 1;
+
+	  if (sim_core_write_buffer (sd, cpu, 0, prog_argv[i], epp, strln)
+	      != strln)
+	  goto abandon_chip;
+
+	  write_dword (csp, envstart + epp - epp0);
+	  epp += strln;
+	}
+
+      write_dword (csp, 0);
+      csp += 4;
+
+      for (i = 0; i < envc; i++, csp += 4)
+	{
+	  unsigned int strln = strlen (my_environ[i]) + 1;
+
+	  if (sim_core_write_buffer (sd, cpu, 0, my_environ[i], epp, strln)
+	      != strln)
+	    goto abandon_chip;
+
+	  write_dword (csp, envstart + epp - epp0);
+	  epp += strln;
+	}
+
+      write_dword (csp, 0);
+      csp += 4;
+
+#define NEW_AUX_ENT(nr, id, val)			\
+ do							\
+   {							\
+     write_dword (csp + (nr) * 4 * 2, (id));		\
+     write_dword (csp + (nr) * 4 * 2 + 4, (val));	\
+   }							\
+ while (0)
+
+      /* Note that there are some extra AUX entries for a dynlinked
+	 program loaded image.  */
+
+      /* AUX entries always present. */
+      NEW_AUX_ENT (0, TARGET_AT_HWCAP, 0);
+      NEW_AUX_ENT (1, TARGET_AT_PAGESZ, 8192);
+      NEW_AUX_ENT (2, TARGET_AT_CLKTCK, 100);
+
+      csp += 4 * 2 * 3;
+      NEW_AUX_ENT (0, TARGET_AT_NULL, 0);
+#undef NEW_AUX_ENT
+
+      /* Register R10 should hold 0 at static start (no initfunc), but
+	 that's the default, so don't bother.  */
+    }
+
+  /* Allocate core managed memory if none specified by user.  */
+  if (sim_core_read_buffer (sd, NULL, read_map, &c, startmem, 1) == 0)
+    sim_do_commandf (sd, "memory region 0x%lx,0x%lx", startmem,
+		     endmem - startmem);
+
+  /* Allocate simulator I/O managed memory if none specified by user.  */
+  if (cris_have_900000xxif)
+    {
+      if (sim_core_read_buffer (sd, NULL, read_map, &c, 0x90000000, 1) == 0)
+	sim_core_attach (sd, NULL, 0, access_write, 0, 0x90000000, 0x100,
+			 0, &cris_devices, NULL);
+      else
+	{
+	  (*callback->
+	   printf_filtered) (callback,
+			     "Seeing --cris-900000xx with memory defined there\n");
+	  goto abandon_chip;
+	}
+    }
+
+  /* Establish any remaining configuration options.  */
+  if (sim_config (sd) != SIM_RC_OK)
+    {
+    abandon_chip:
+      free_state (sd);
+      return 0;
+    }
+
+  if (sim_post_argv_init (sd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* Open a copy of the cpu descriptor table.  */
+  {
+    CGEN_CPU_DESC cd = cris_cgen_cpu_open_1 (STATE_ARCHITECTURE (sd)->printable_name,
+					     CGEN_ENDIAN_LITTLE);
+    for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+      {
+	SIM_CPU *cpu = STATE_CPU (sd, i);
+	CPU_CPU_DESC (cpu) = cd;
+	CPU_DISASSEMBLER (cpu) = cris_disassemble_insn;
+
+	/* See cris_option_handler for the reason why this is needed.  */
+	CPU_CRIS_MISC_PROFILE (cpu)->flags = STATE_TRACE_FLAGS (sd)[0];
+
+	/* Set SP to the stack we allocated above.  */
+	(* CPU_REG_STORE (cpu)) (cpu, H_GR_SP, (char *) sp_init, 4);
+
+	/* Set the simulator environment data.  */
+	cpu->highest_mmapped_page = NULL;
+	cpu->endmem = endmem;
+	cpu->endbrk = endbrk;
+	cpu->stack_low = stack_low;
+	cpu->syscalls = 0;
+	cpu->m1threads = 0;
+	cpu->threadno = 0;
+	cpu->max_threadid = 0;
+	cpu->thread_data = NULL;
+	memset (cpu->sighandler, 0, sizeof (cpu->sighandler));
+	cpu->make_thread_cpu_data = NULL;
+	cpu->thread_cpu_data_size = 0;
+      }
+  }
+
+  /* Initialize various cgen things not done by common framework.
+     Must be done after cris_cgen_cpu_open.  */
+  cgen_init (sd);
+
+  /* Store in a global so things like cris_dump_regs can be invoked
+     from the gdb command line.  */
+  current_state = sd;
+
+  cris_set_callbacks (callback);
+
+  return sd;
+}
+
+void
+sim_close (SIM_DESC sd, int quitting ATTRIBUTE_UNUSED)
+{
+  cris_cgen_cpu_close (CPU_CPU_DESC (STATE_CPU (sd, 0)));
+  sim_module_uninstall (sd);
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
+		     char **argv ATTRIBUTE_UNUSED,
+		     char **envp ATTRIBUTE_UNUSED)
+{
+  SIM_CPU *current_cpu = STATE_CPU (sd, 0);
+  SIM_ADDR addr;
+
+  if (abfd != NULL)
+    addr = bfd_get_start_address (abfd);
+  else
+    addr = 0;
+  sim_pc_set (current_cpu, addr);
+
+  /* Other simulators have #if 0:d code that says
+      STATE_ARGV (sd) = sim_copy_argv (argv);
+      STATE_ENVP (sd) = sim_copy_argv (envp);
+     Enabling that gives you not-found link-errors for sim_copy_argv.
+     FIXME: Do archaeology to find out more.  */
+
+  return SIM_RC_OK;
+}
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+  if (sim_args_command (sd, cmd) != SIM_RC_OK)
+    sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
+}
+
+/* Disassemble an instruction.  */
+
+static void
+cris_disassemble_insn (SIM_CPU *cpu,
+		       const CGEN_INSN *insn ATTRIBUTE_UNUSED,
+		       const ARGBUF *abuf ATTRIBUTE_UNUSED,
+		       IADDR pc, char *buf)
+{
+  disassembler_ftype pinsn;
+  struct disassemble_info disasm_info;
+  SFILE sfile;
+  SIM_DESC sd = CPU_STATE (cpu);
+
+  sfile.buffer = sfile.current = buf;
+  INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
+			 (fprintf_ftype) sim_disasm_sprintf);
+  disasm_info.endian =
+    (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG
+     : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE
+     : BFD_ENDIAN_UNKNOWN);
+  /* We live with the cast until the prototype is fixed, or else we get a
+     warning because the functions differ in the signedness of one parameter.  */
+  disasm_info.read_memory_func =
+    sim_disasm_read_memory;
+  disasm_info.memory_error_func = sim_disasm_perror_memory;
+  disasm_info.application_data = (PTR) cpu;
+  pinsn = cris_get_disassembler (STATE_PROG_BFD (sd));
+  (*pinsn) (pc, &disasm_info);
+}
diff -uprN none/sim-main.h cris/sim-main.h
--- none/sim-main.h	Thu Jan  1 01:00:00 1970
+++ cris/sim-main.h	Thu Dec 16 06:09:48 2004
@@ -0,0 +1,230 @@
+/* Main header for the CRIS simulator, based on the m32r header.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* All FIXME:s present in m32r apply here too; I just refuse to blindly
+   carry them over, as I don't know if they're really things that need
+   fixing.  */
+
+#ifndef SIM_MAIN_H
+#define SIM_MAIN_H
+
+#define USING_SIM_BASE_H
+
+struct _sim_cpu;
+typedef struct _sim_cpu SIM_CPU;
+
+#include "symcat.h"
+#include "sim-basics.h"
+#include "cgen-types.h"
+#include "cris-desc.h"
+#include "cris-opc.h"
+#include "arch.h"
+
+/* These must be defined before sim-base.h.  */
+typedef USI sim_cia;
+
+#define CIA_GET(cpu)     CPU_PC_GET (cpu)
+#define CIA_SET(cpu,val) CPU_PC_SET ((cpu), (val))
+
+#define SIM_ENGINE_HALT_HOOK(sd, cpu, cia) \
+do { \
+  if (cpu) /* Null if ctrl-c.  */ \
+    sim_pc_set ((cpu), (cia)); \
+} while (0)
+#define SIM_ENGINE_RESTART_HOOK(sd, cpu, cia) \
+do { \
+  sim_pc_set ((cpu), (cia)); \
+} while (0)
+
+#include "sim-base.h"
+#include "cgen-sim.h"
+#include "cris-sim.h"
+
+/* For occurrences of ANDIF in decodev32.c.  */
+#include "cgen-ops.h"
+
+struct cris_sim_mmapped_page {
+  USI addr;
+  struct cris_sim_mmapped_page *prev;
+};
+
+struct cris_thread_info {
+  /* Identifier for this thread.  */
+  unsigned int threadid;
+
+  /* Identifier for parent thread.  */
+  unsigned int parent_threadid;
+
+  /* Signal to send to parent at exit.  */
+  int exitsig;
+
+  /* Exit status.  */
+  int exitval;
+
+  /* Only as storage to return the "set" value to the "get" method.
+     I'm not sure whether this is useful per-thread.  */
+  USI priority;
+
+  struct
+  {
+    USI altstack;
+    USI options;
+
+    char action;
+    char pending;
+    char blocked;
+    char blocked_suspendsave;
+    /* The handler stub unblocks the signal, so we don't need a separate
+       "temporary save" for that.  */
+  } sigdata[64];
+
+  /* Register context, swapped with _sim_cpu.cpu_data.  */
+  void *cpu_context;
+
+  /* Similar, temporary copy for the state at a signal call.   */
+  void *cpu_context_atsignal;
+
+  /* The number of the reading and writing ends of a pipe if waiting for
+     the reader, else 0.  */
+  int pipe_read_fd;
+  int pipe_write_fd;
+
+  /* System time at last context switch when this thread ran.  */
+  USI last_execution;
+
+  /* Nonzero if we just executed a syscall.  */
+  char at_syscall;
+
+  /* Nonzero if any of sigaction[0..64].pending is true.  */
+  char sigpending;
+
+  /* Nonzero if in (rt_)sigsuspend call.  Cleared at every sighandler
+     call.  */
+  char sigsuspended;
+};
+
+struct _sim_cpu {
+  /* sim/common cpu base.  */
+  sim_cpu_base base;
+
+  /* Static parts of cgen.  */
+  CGEN_CPU cgen_cpu;
+
+  CRIS_MISC_PROFILE cris_misc_profile;
+#define CPU_CRIS_MISC_PROFILE(cpu) (& (cpu)->cris_misc_profile)
+
+  /* Copy of previous data; only valid when emitting trace-data after
+     each insn.  */
+  CRIS_MISC_PROFILE cris_prev_misc_profile;
+#define CPU_CRIS_PREV_MISC_PROFILE(cpu) (& (cpu)->cris_prev_misc_profile)
+
+  /* Simulator environment data.  */
+  USI endmem;
+  USI endbrk;
+  USI stack_low;
+  struct cris_sim_mmapped_page *highest_mmapped_page;
+
+  /* Number of syscalls performed or in progress, counting once extra
+     for every time a blocked thread (internally, when threading) polls
+     the (pipe) blockage.  By default, this is also a time counter: to
+     minimize performance noise from minor compiler changes,
+     instructions take no time and syscalls always take 1ms.  */
+  USI syscalls;
+
+  /* Number of execution contexts minus one.  */
+  int m1threads;
+
+  /* Current thread number; index into thread_data when m1threads != 0.  */
+  int threadno;
+
+  /* When a new thread is created, it gets a unique number, which we
+     count here.  */
+  int max_threadid;
+
+  /* Thread-specific info, for simulator thread support, created at
+     "clone" call.  Vector of [threads+1] when m1threads > 0.  */
+  struct cris_thread_info *thread_data;
+
+  /* "If CLONE_SIGHAND is set, the calling process and the child pro-
+     cesses share the same table of signal handlers." ... "However, the
+     calling process and child processes still have distinct signal
+     masks and sets of pending signals."  See struct cris_thread_info
+     for sigmasks and sigpendings. */
+  USI sighandler[64];
+
+  /* Function for initializing CPU thread context, which varies in size
+     with each CPU model.  They should be in some constant parts or
+     initialized in *_init_cpu, but we can't modify that for now.  */
+  void* (*make_thread_cpu_data) (SIM_CPU *, void *);
+  size_t thread_cpu_data_size;
+
+  /* CPU-model specific parts go here.
+     Note that in files that don't need to access these pieces WANT_CPU_FOO
+     won't be defined and thus these parts won't appear.  This is ok in the
+     sense that things work.  It is a source of bugs though.
+     One has to of course be careful to not take the size of this
+     struct and no structure members accessed in non-cpu specific files can
+     go after here.  */
+#if defined (WANT_CPU_CRISV0F)
+  CRISV0F_CPU_DATA cpu_data;
+#elif defined (WANT_CPU_CRISV3F)
+  CRISV3F_CPU_DATA cpu_data;
+#elif defined (WANT_CPU_CRISV8F)
+  CRISV8F_CPU_DATA cpu_data;
+#elif defined (WANT_CPU_CRISV10F)
+  CRISV10F_CPU_DATA cpu_data;
+#elif defined (WANT_CPU_CRISV32F)
+  CRISV32F_CPU_DATA cpu_data;
+#else
+  /* Let's assume all cpu_data have the same alignment requirements, so
+     they all are laid out at the same address.  Since we can't get the
+     exact definition, we also assume that it has no higher alignment
+     requirements than a vector of, say, 16 pointers.  (A single member
+     is often special-cased, and possibly two as well so we don't want
+     that).  */
+  union { void *dummy[16]; } cpu_data_placeholder;
+#endif
+};
+
+/* The sim_state struct.  */
+
+struct sim_state {
+  sim_cpu *cpu;
+#define STATE_CPU(sd, n) (/*&*/ (sd)->cpu)
+
+  CGEN_STATE cgen_state;
+
+  sim_state_base base;
+};
+
+/* Misc.  */
+
+/* Catch address exceptions.  */
+extern SIM_CORE_SIGNAL_FN cris_core_signal;
+#define SIM_CORE_SIGNAL(SD,CPU,CIA,MAP,NR_BYTES,ADDR,TRANSFER,ERROR) \
+cris_core_signal ((SD), (CPU), (CIA), (MAP), (NR_BYTES), (ADDR), \
+		  (TRANSFER), (ERROR))
+
+/* Default memory size.  */
+#define CRIS_DEFAULT_MEM_SIZE 0x800000 /* 8M */
+
+extern device cris_devices;
+
+#endif /* SIM_MAIN_H */
diff -uprN none/tconfig.in cris/tconfig.in
--- none/tconfig.in	Thu Jan  1 01:00:00 1970
+++ cris/tconfig.in	Sat Dec 18 02:13:09 2004
@@ -0,0 +1,56 @@
+/* CRIS target configuration file.  -*- C -*-
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef CRIS_TCONFIG_H
+#define CRIS_TCONFIG_H
+
+#include "ansidecl.h"
+#include "gdb/callback.h"
+#include "gdb/remote-sim.h"
+#include "sim-module.h"
+
+/* There's basically a a big ??? FIXME: CHECK THIS on everything in this
+   file.  I just copied it from m32r, pruned some stuff and added
+   HAVE_MODEL because it seemed useful.  */
+
+/* See sim-hload.c.  We properly handle LMA.  */
+#define SIM_HANDLES_LMA 1
+
+/* For MSPR support.  FIXME: revisit.  */
+#define WITH_DEVICES 1
+
+extern MODULE_INSTALL_FN cris_option_install;
+
+/* FIXME: Revisit.  */
+#ifdef HAVE_DV_SOCKSER
+extern MODULE_INSTALL_FN dv_sockser_install;
+#define MODULE_LIST dv_sockser_install, cris_option_install,
+#else
+#define MODULE_LIST cris_option_install,
+#endif
+
+#define SIM_HAVE_MODEL
+
+/* This is a global setting.  Different cpu families can't mix-n-match -scache
+   and -pbb.  However some cpu families may use -simple while others use
+   one of -scache/-pbb.  */
+#define WITH_SCACHE_PBB 1
+
+#endif /* CRIS_TCONFIG_H */
diff -uprN none/traps.c cris/traps.c
--- none/traps.c	Thu Jan  1 01:00:00 1970
+++ cris/traps.c	Thu Dec 16 06:09:24 2004
@@ -0,0 +1,2982 @@
+/* CRIS exception, interrupt, and trap (EIT) support
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, 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 "sim-options.h"
+#include "targ-vals.h"
+#include "bfd.h"
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+/* The verbatim values are from asm-cris/unistd.h.  */
+
+#define TARGET_SYS_exit 1
+#define TARGET_SYS_read 3
+#define TARGET_SYS_write 4
+#define TARGET_SYS_open 5
+#define TARGET_SYS_close 6
+#define TARGET_SYS_unlink 10
+#define TARGET_SYS_time 13
+#define TARGET_SYS_lseek 19
+#define TARGET_SYS_getpid 20
+#define TARGET_SYS_kill 37
+#define TARGET_SYS_rename 38
+#define TARGET_SYS_pipe 42
+#define TARGET_SYS_brk 45
+#define TARGET_SYS_ioctl 54
+#define TARGET_SYS_fcntl 55
+#define TARGET_SYS_getppid 64
+#define TARGET_SYS_setrlimit 75
+#define TARGET_SYS_gettimeofday	 78
+#define TARGET_SYS_readlink 85
+#define TARGET_SYS_munmap 91
+#define TARGET_SYS_truncate 92
+#define TARGET_SYS_ftruncate 93
+#define TARGET_SYS_socketcall 102
+#define TARGET_SYS_fstat 108
+#define TARGET_SYS_wait4 114
+#define TARGET_SYS_sigreturn 119
+#define TARGET_SYS_clone 120
+#define TARGET_SYS_uname 122
+#define TARGET_SYS_mprotect 125
+#define TARGET_SYS_llseek 140
+#define TARGET_SYS__sysctl 149
+#define TARGET_SYS_sched_setparam 154
+#define TARGET_SYS_sched_getparam 155
+#define TARGET_SYS_sched_setscheduler 156
+#define TARGET_SYS_sched_getscheduler 157
+#define TARGET_SYS_sched_yield 158
+#define TARGET_SYS_sched_get_priority_max 159
+#define TARGET_SYS_sched_get_priority_min 160
+#define TARGET_SYS_mremap 163
+#define TARGET_SYS_poll 168
+#define TARGET_SYS_rt_sigaction 174
+#define TARGET_SYS_rt_sigprocmask 175
+#define TARGET_SYS_rt_sigsuspend 179
+#define TARGET_SYS_getcwd 183
+#define TARGET_SYS_ugetrlimit 191
+#define TARGET_SYS_mmap2 192
+#define TARGET_SYS_stat64 195
+#define TARGET_SYS_lstat64 196
+#define TARGET_SYS_fstat64 197
+#define TARGET_SYS_geteuid32 201
+#define TARGET_SYS_getuid32 199
+#define TARGET_SYS_getegid32 202
+#define TARGET_SYS_getgid32 200
+#define TARGET_SYS_fcntl64 221
+
+#define TARGET_PROT_READ	0x1
+#define TARGET_PROT_WRITE	0x2
+#define TARGET_PROT_EXEC	0x4
+#define TARGET_PROT_NONE	0x0
+
+#define TARGET_MAP_SHARED	0x01
+#define TARGET_MAP_PRIVATE	0x02
+#define TARGET_MAP_TYPE		0x0f
+#define TARGET_MAP_FIXED	0x10
+#define TARGET_MAP_ANONYMOUS	0x20
+
+#define TARGET_CTL_KERN		1
+#define TARGET_CTL_VM		2
+#define TARGET_CTL_NET		3
+#define TARGET_CTL_PROC		4
+#define TARGET_CTL_FS		5
+#define TARGET_CTL_DEBUG	6
+#define TARGET_CTL_DEV		7
+#define TARGET_CTL_BUS		8
+#define TARGET_CTL_ABI		9
+
+#define TARGET_CTL_KERN_VERSION	4
+
+/* linux/mman.h */
+#define TARGET_MREMAP_MAYMOVE  1
+#define TARGET_MREMAP_FIXED    2
+
+#define TARGET_TCGETS 0x5401
+
+#define TARGET_UTSNAME "#38 Sun Apr 1 00:00:00 MET 2001"
+
+/* Seconds since the above date + 10 minutes.  */
+#define TARGET_EPOCH 986080200
+
+/* Milliseconds since start of run.  We use the number of syscalls to
+   avoid introducing noise in the execution time.  */
+#define TARGET_TIME_MS(cpu) ((cpu)->syscalls)
+
+/* Seconds as in time(2).  */
+#define TARGET_TIME(cpu) (TARGET_EPOCH + TARGET_TIME_MS (cpu) / 1000)
+
+#define TARGET_SCHED_OTHER 0
+
+#define TARGET_RLIMIT_STACK 3
+#define TARGET_RLIMIT_NOFILE 7
+
+#define SIM_TARGET_MAX_THREADS 64
+#define SIM_MAX_ALLOC_CHUNK (512*1024*1024)
+
+/* From linux/sched.h.  */
+#define TARGET_CSIGNAL 0x000000ff
+#define TARGET_CLONE_VM	0x00000100
+#define TARGET_CLONE_FS	0x00000200
+#define TARGET_CLONE_FILES 0x00000400
+#define TARGET_CLONE_SIGHAND 0x00000800
+#define TARGET_CLONE_PID 0x00001000
+#define TARGET_CLONE_PTRACE 0x00002000
+#define TARGET_CLONE_VFORK 0x00004000
+#define TARGET_CLONE_PARENT 0x00008000
+#define TARGET_CLONE_THREAD 0x00010000
+#define TARGET_CLONE_SIGNAL (TARGET_CLONE_SIGHAND | TARGET_CLONE_THREAD)
+
+/* From asm-cris/poll.h.  */
+#define TARGET_POLLIN 1
+
+/* From asm-cris/signal.h.  */
+#define TARGET_SIG_BLOCK 0
+#define TARGET_SIG_UNBLOCK 1
+#define TARGET_SIG_SETMASK 2
+
+#define TARGET_SIG_DFL 0
+#define TARGET_SIG_IGN 1
+#define TARGET_SIG_ERR ((USI)-1)
+
+#define TARGET_SIGHUP 1
+#define TARGET_SIGINT 2
+#define TARGET_SIGQUIT 3
+#define TARGET_SIGILL 4
+#define TARGET_SIGTRAP 5
+#define TARGET_SIGABRT 6
+#define TARGET_SIGIOT 6
+#define TARGET_SIGBUS 7
+#define TARGET_SIGFPE 8
+#define TARGET_SIGKILL 9
+#define TARGET_SIGUSR1 10
+#define TARGET_SIGSEGV 11
+#define TARGET_SIGUSR2 12
+#define TARGET_SIGPIPE 13
+#define TARGET_SIGALRM 14
+#define TARGET_SIGTERM 15
+#define TARGET_SIGSTKFLT 16
+#define TARGET_SIGCHLD 17
+#define TARGET_SIGCONT 18
+#define TARGET_SIGSTOP 19
+#define TARGET_SIGTSTP 20
+#define TARGET_SIGTTIN 21
+#define TARGET_SIGTTOU 22
+#define TARGET_SIGURG 23
+#define TARGET_SIGXCPU 24
+#define TARGET_SIGXFSZ 25
+#define TARGET_SIGVTALRM 26
+#define TARGET_SIGPROF 27
+#define TARGET_SIGWINCH 28
+#define TARGET_SIGIO 29
+#define TARGET_SIGPOLL SIGIO
+/* Actually commented out in the kernel header.  */
+#define TARGET_SIGLOST 29
+#define TARGET_SIGPWR 30
+#define TARGET_SIGSYS 31
+
+/* From include/asm-cris/signal.h.  */
+#define TARGET_SA_NOCLDSTOP 0x00000001
+#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
+#define TARGET_SA_SIGINFO 0x00000004
+#define TARGET_SA_ONSTACK 0x08000000
+#define TARGET_SA_RESTART 0x10000000
+#define TARGET_SA_NODEFER 0x40000000
+#define TARGET_SA_RESETHAND 0x80000000
+#define TARGET_SA_INTERRUPT 0x20000000 /* dummy -- ignored */
+#define TARGET_SA_RESTORER 0x04000000
+
+/* From linux/wait.h.  */
+#define TARGET_WNOHANG 1
+#define TARGET_WUNTRACED 2
+#define TARGET___WNOTHREAD 0x20000000
+#define TARGET___WALL 0x40000000
+#define TARGET___WCLONE 0x80000000
+
+static const char stat_map[] =
+"st_dev,2:space,10:space,4:st_mode,4:st_nlink,4:st_uid,4"
+":st_gid,4:st_rdev,2:space,10:st_size,8:st_blksize,4:st_blocks,4"
+":space,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,4"
+":st_ino,8";
+
+static const CB_TARGET_DEFS_MAP syscall_map[] =
+{
+  { CB_SYS_open, TARGET_SYS_open },
+  { CB_SYS_close, TARGET_SYS_close },
+  { CB_SYS_read, TARGET_SYS_read },
+  { CB_SYS_write, TARGET_SYS_write },
+  { CB_SYS_lseek, TARGET_SYS_lseek },
+  { CB_SYS_unlink, TARGET_SYS_unlink },
+  { CB_SYS_getpid, TARGET_SYS_getpid },
+  { CB_SYS_fstat, TARGET_SYS_fstat64 },
+  { CB_SYS_lstat, TARGET_SYS_lstat64 },
+  { CB_SYS_stat, TARGET_SYS_stat64 },
+  { CB_SYS_pipe, TARGET_SYS_pipe },
+  { CB_SYS_time, TARGET_SYS_time },
+  { CB_SYS_rename, TARGET_SYS_rename },
+  { CB_SYS_truncate, TARGET_SYS_truncate },
+  { CB_SYS_ftruncate, TARGET_SYS_ftruncate },
+  { 0, -1 }
+};
+
+/* An older, 32-bit-only stat mapping.  */
+static const char stat32_map[] =
+"st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2"
+":st_gid,2:st_rdev,2:space,2:st_size,4:st_blksize,4:st_blocks,4"
+":st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,12";
+
+/* Map for calls using the 32-bit struct stat.  Primarily used by the
+   newlib Linux mapping.  */
+static const CB_TARGET_DEFS_MAP syscall_stat32_map[] =
+{
+  { CB_SYS_fstat, TARGET_SYS_fstat },
+  { 0, -1 }
+};
+
+/* Giving the true value for the running sim process will lead to
+   non-time-invariant behavior.  */
+#define TARGET_PID 42
+
+/* Unfortunately, we don't get this from cris.cpu at the moment, and if
+   we did, we'd still don't get a register number with the "16" offset.  */
+#define TARGET_SRP_REGNUM (16+11)
+
+/* Extracted by applying
+   awk '/^#define/ { printf "#ifdef %s\n  { %s, %s },\n#endif\n", $2, $2, $3;}'
+   on .../include/asm/errno.h in a GNU/Linux/CRIS installation and
+   adjusting the synonyms.  */
+
+static const CB_TARGET_DEFS_MAP errno_map[] =
+{
+#ifdef EPERM
+  { EPERM, 1 },
+#endif
+#ifdef ENOENT
+  { ENOENT, 2 },
+#endif
+#ifdef ESRCH
+  { ESRCH, 3 },
+#endif
+#ifdef EINTR
+  { EINTR, 4 },
+#endif
+#ifdef EIO
+  { EIO, 5 },
+#endif
+#ifdef ENXIO
+  { ENXIO, 6 },
+#endif
+#ifdef E2BIG
+  { E2BIG, 7 },
+#endif
+#ifdef ENOEXEC
+  { ENOEXEC, 8 },
+#endif
+#ifdef EBADF
+  { EBADF, 9 },
+#endif
+#ifdef ECHILD
+  { ECHILD, 10 },
+#endif
+#ifdef EAGAIN
+  { EAGAIN, 11 },
+#endif
+#ifdef ENOMEM
+  { ENOMEM, 12 },
+#endif
+#ifdef EACCES
+  { EACCES, 13 },
+#endif
+#ifdef EFAULT
+  { EFAULT, 14 },
+#endif
+#ifdef ENOTBLK
+  { ENOTBLK, 15 },
+#endif
+#ifdef EBUSY
+  { EBUSY, 16 },
+#endif
+#ifdef EEXIST
+  { EEXIST, 17 },
+#endif
+#ifdef EXDEV
+  { EXDEV, 18 },
+#endif
+#ifdef ENODEV
+  { ENODEV, 19 },
+#endif
+#ifdef ENOTDIR
+  { ENOTDIR, 20 },
+#endif
+#ifdef EISDIR
+  { EISDIR, 21 },
+#endif
+#ifdef EINVAL
+  { EINVAL, 22 },
+#endif
+#ifdef ENFILE
+  { ENFILE, 23 },
+#endif
+#ifdef EMFILE
+  { EMFILE, 24 },
+#endif
+#ifdef ENOTTY
+  { ENOTTY, 25 },
+#endif
+#ifdef ETXTBSY
+  { ETXTBSY, 26 },
+#endif
+#ifdef EFBIG
+  { EFBIG, 27 },
+#endif
+#ifdef ENOSPC
+  { ENOSPC, 28 },
+#endif
+#ifdef ESPIPE
+  { ESPIPE, 29 },
+#endif
+#ifdef EROFS
+  { EROFS, 30 },
+#endif
+#ifdef EMLINK
+  { EMLINK, 31 },
+#endif
+#ifdef EPIPE
+  { EPIPE, 32 },
+#endif
+#ifdef EDOM
+  { EDOM, 33 },
+#endif
+#ifdef ERANGE
+  { ERANGE, 34 },
+#endif
+#ifdef EDEADLK
+  { EDEADLK, 35 },
+#endif
+#ifdef ENAMETOOLONG
+  { ENAMETOOLONG, 36 },
+#endif
+#ifdef ENOLCK
+  { ENOLCK, 37 },
+#endif
+#ifdef ENOSYS
+  { ENOSYS, 38 },
+#endif
+#ifdef ENOTEMPTY
+  { ENOTEMPTY, 39 },
+#endif
+#ifdef ELOOP
+  { ELOOP, 40 },
+#endif
+#ifdef EWOULDBLOCK
+  { EWOULDBLOCK, 11 },
+#endif
+#ifdef ENOMSG
+  { ENOMSG, 42 },
+#endif
+#ifdef EIDRM
+  { EIDRM, 43 },
+#endif
+#ifdef ECHRNG
+  { ECHRNG, 44 },
+#endif
+#ifdef EL2NSYNC
+  { EL2NSYNC, 45 },
+#endif
+#ifdef EL3HLT
+  { EL3HLT, 46 },
+#endif
+#ifdef EL3RST
+  { EL3RST, 47 },
+#endif
+#ifdef ELNRNG
+  { ELNRNG, 48 },
+#endif
+#ifdef EUNATCH
+  { EUNATCH, 49 },
+#endif
+#ifdef ENOCSI
+  { ENOCSI, 50 },
+#endif
+#ifdef EL2HLT
+  { EL2HLT, 51 },
+#endif
+#ifdef EBADE
+  { EBADE, 52 },
+#endif
+#ifdef EBADR
+  { EBADR, 53 },
+#endif
+#ifdef EXFULL
+  { EXFULL, 54 },
+#endif
+#ifdef ENOANO
+  { ENOANO, 55 },
+#endif
+#ifdef EBADRQC
+  { EBADRQC, 56 },
+#endif
+#ifdef EBADSLT
+  { EBADSLT, 57 },
+#endif
+#ifdef EDEADLOCK
+  { EDEADLOCK, 35 },
+#endif
+#ifdef EBFONT
+  { EBFONT, 59 },
+#endif
+#ifdef ENOSTR
+  { ENOSTR, 60 },
+#endif
+#ifdef ENODATA
+  { ENODATA, 61 },
+#endif
+#ifdef ETIME
+  { ETIME, 62 },
+#endif
+#ifdef ENOSR
+  { ENOSR, 63 },
+#endif
+#ifdef ENONET
+  { ENONET, 64 },
+#endif
+#ifdef ENOPKG
+  { ENOPKG, 65 },
+#endif
+#ifdef EREMOTE
+  { EREMOTE, 66 },
+#endif
+#ifdef ENOLINK
+  { ENOLINK, 67 },
+#endif
+#ifdef EADV
+  { EADV, 68 },
+#endif
+#ifdef ESRMNT
+  { ESRMNT, 69 },
+#endif
+#ifdef ECOMM
+  { ECOMM, 70 },
+#endif
+#ifdef EPROTO
+  { EPROTO, 71 },
+#endif
+#ifdef EMULTIHOP
+  { EMULTIHOP, 72 },
+#endif
+#ifdef EDOTDOT
+  { EDOTDOT, 73 },
+#endif
+#ifdef EBADMSG
+  { EBADMSG, 74 },
+#endif
+#ifdef EOVERFLOW
+  { EOVERFLOW, 75 },
+#endif
+#ifdef ENOTUNIQ
+  { ENOTUNIQ, 76 },
+#endif
+#ifdef EBADFD
+  { EBADFD, 77 },
+#endif
+#ifdef EREMCHG
+  { EREMCHG, 78 },
+#endif
+#ifdef ELIBACC
+  { ELIBACC, 79 },
+#endif
+#ifdef ELIBBAD
+  { ELIBBAD, 80 },
+#endif
+#ifdef ELIBSCN
+  { ELIBSCN, 81 },
+#endif
+#ifdef ELIBMAX
+  { ELIBMAX, 82 },
+#endif
+#ifdef ELIBEXEC
+  { ELIBEXEC, 83 },
+#endif
+#ifdef EILSEQ
+  { EILSEQ, 84 },
+#endif
+#ifdef ERESTART
+  { ERESTART, 85 },
+#endif
+#ifdef ESTRPIPE
+  { ESTRPIPE, 86 },
+#endif
+#ifdef EUSERS
+  { EUSERS, 87 },
+#endif
+#ifdef ENOTSOCK
+  { ENOTSOCK, 88 },
+#endif
+#ifdef EDESTADDRREQ
+  { EDESTADDRREQ, 89 },
+#endif
+#ifdef EMSGSIZE
+  { EMSGSIZE, 90 },
+#endif
+#ifdef EPROTOTYPE
+  { EPROTOTYPE, 91 },
+#endif
+#ifdef ENOPROTOOPT
+  { ENOPROTOOPT, 92 },
+#endif
+#ifdef EPROTONOSUPPORT
+  { EPROTONOSUPPORT, 93 },
+#endif
+#ifdef ESOCKTNOSUPPORT
+  { ESOCKTNOSUPPORT, 94 },
+#endif
+#ifdef EOPNOTSUPP
+  { EOPNOTSUPP, 95 },
+#endif
+#ifdef EPFNOSUPPORT
+  { EPFNOSUPPORT, 96 },
+#endif
+#ifdef EAFNOSUPPORT
+  { EAFNOSUPPORT, 97 },
+#endif
+#ifdef EADDRINUSE
+  { EADDRINUSE, 98 },
+#endif
+#ifdef EADDRNOTAVAIL
+  { EADDRNOTAVAIL, 99 },
+#endif
+#ifdef ENETDOWN
+  { ENETDOWN, 100 },
+#endif
+#ifdef ENETUNREACH
+  { ENETUNREACH, 101 },
+#endif
+#ifdef ENETRESET
+  { ENETRESET, 102 },
+#endif
+#ifdef ECONNABORTED
+  { ECONNABORTED, 103 },
+#endif
+#ifdef ECONNRESET
+  { ECONNRESET, 104 },
+#endif
+#ifdef ENOBUFS
+  { ENOBUFS, 105 },
+#endif
+#ifdef EISCONN
+  { EISCONN, 106 },
+#endif
+#ifdef ENOTCONN
+  { ENOTCONN, 107 },
+#endif
+#ifdef ESHUTDOWN
+  { ESHUTDOWN, 108 },
+#endif
+#ifdef ETOOMANYREFS
+  { ETOOMANYREFS, 109 },
+#endif
+#ifdef ETIMEDOUT
+  { ETIMEDOUT, 110 },
+#endif
+#ifdef ECONNREFUSED
+  { ECONNREFUSED, 111 },
+#endif
+#ifdef EHOSTDOWN
+  { EHOSTDOWN, 112 },
+#endif
+#ifdef EHOSTUNREACH
+  { EHOSTUNREACH, 113 },
+#endif
+#ifdef EALREADY
+  { EALREADY, 114 },
+#endif
+#ifdef EINPROGRESS
+  { EINPROGRESS, 115 },
+#endif
+#ifdef ESTALE
+  { ESTALE, 116 },
+#endif
+#ifdef EUCLEAN
+  { EUCLEAN, 117 },
+#endif
+#ifdef ENOTNAM
+  { ENOTNAM, 118 },
+#endif
+#ifdef ENAVAIL
+  { ENAVAIL, 119 },
+#endif
+#ifdef EISNAM
+  { EISNAM, 120 },
+#endif
+#ifdef EREMOTEIO
+  { EREMOTEIO, 121 },
+#endif
+#ifdef EDQUOT
+  { EDQUOT, 122 },
+#endif
+#ifdef ENOMEDIUM
+  { ENOMEDIUM, 123 },
+#endif
+#ifdef EMEDIUMTYPE
+  { EMEDIUMTYPE, 124 },
+#endif
+  { 0, -1 }
+};
+
+/* Extracted by applying
+   perl -ne 'if ($_ =~ /^#define/) { split;
+     printf "#ifdef $_[1]\n  { %s, 0x%x },\n#endif\n",
+             $_[1], $_[2] =~ /^0/ ? oct($_[2]) : $_[2];}'
+   on pertinent parts of .../include/asm/fcntl.h in a GNU/Linux/CRIS
+   installation and removing synonyms and unnecessary items.  Don't
+   forget the end-marker.  */
+
+static const CB_TARGET_DEFS_MAP open_map[] = {
+#ifdef O_ACCMODE
+  { O_ACCMODE, 0x3 },
+#endif
+#ifdef O_RDONLY
+  { O_RDONLY, 0x0 },
+#endif
+#ifdef O_WRONLY
+  { O_WRONLY, 0x1 },
+#endif
+#ifdef O_RDWR
+  { O_RDWR, 0x2 },
+#endif
+#ifdef O_CREAT
+  { O_CREAT, 0x40 },
+#endif
+#ifdef O_EXCL
+  { O_EXCL, 0x80 },
+#endif
+#ifdef O_NOCTTY
+  { O_NOCTTY, 0x100 },
+#endif
+#ifdef O_TRUNC
+  { O_TRUNC, 0x200 },
+#endif
+#ifdef O_APPEND
+  { O_APPEND, 0x400 },
+#endif
+#ifdef O_NONBLOCK
+  { O_NONBLOCK, 0x800 },
+#endif
+#ifdef O_NDELAY
+  { O_NDELAY, 0x0 },
+#endif
+#ifdef O_SYNC
+  { O_SYNC, 0x1000 },
+#endif
+#ifdef FASYNC
+  { FASYNC, 0x2000 },
+#endif
+#ifdef O_DIRECT
+  { O_DIRECT, 0x4000 },
+#endif
+#ifdef O_LARGEFILE
+  { O_LARGEFILE, 0x8000 },
+#endif
+#ifdef O_DIRECTORY
+  { O_DIRECTORY, 0x10000 },
+#endif
+#ifdef O_NOFOLLOW
+  { O_NOFOLLOW, 0x20000 },
+#endif
+  { -1, -1 }
+};
+
+/* Needed for the cris_pipe_nonempty and cris_pipe_empty syscalls.  */
+static SIM_CPU *current_cpu_for_cb_callback;
+
+static int syscall_read_mem (host_callback *, struct cb_syscall *,
+			     unsigned long, char *, int);
+static int syscall_write_mem (host_callback *, struct cb_syscall *,
+			      unsigned long, const char *, int);
+static USI create_map (SIM_DESC, struct cris_sim_mmapped_page **,
+		       USI addr, USI len);
+static USI unmap_pages (SIM_DESC, struct cris_sim_mmapped_page **,
+		       USI addr, USI len);
+static USI is_mapped (SIM_DESC, struct cris_sim_mmapped_page **,
+		       USI addr, USI len);
+static void dump_statistics (SIM_CPU *current_cpu);
+static void make_first_thread (SIM_CPU *current_cpu);
+
+/* Read/write functions for system call interface.  */
+
+static int
+syscall_read_mem (host_callback *cb ATTRIBUTE_UNUSED,
+		  struct cb_syscall *sc,
+		  unsigned long taddr, char *buf, int bytes)
+{
+  SIM_DESC sd = (SIM_DESC) sc->p1;
+  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
+
+  return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
+}
+
+static int
+syscall_write_mem (host_callback *cb ATTRIBUTE_UNUSED,
+		   struct cb_syscall *sc,
+		   unsigned long taddr, const char *buf, int bytes)
+{
+  SIM_DESC sd = (SIM_DESC) sc->p1;
+  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
+
+  return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
+}
+
+/* When we risk running self-modified code (as in trampolines), this is
+   called from special-case insns.  The silicon CRIS CPU:s have enough
+   cache snooping implemented making this a simulator-only issue.  Tests:
+   gcc.c-torture/execute/931002-1.c execution, -O3 -g
+   gcc.c-torture/execute/931002-1.c execution, -O3 -fomit-frame-pointer.  */
+
+void
+cris_flush_simulator_decode_cache (SIM_CPU *current_cpu,
+				   USI pc ATTRIBUTE_UNUSED)
+{
+  SIM_DESC sd = CPU_STATE (current_cpu);
+
+#if WITH_SCACHE
+  if (USING_SCACHE_P (sd))
+    scache_flush_cpu (current_cpu);
+#endif
+}
+
+/* Output statistics at the end of a run.  */
+static void
+dump_statistics (SIM_CPU *current_cpu)
+{
+  SIM_DESC sd = CPU_STATE (current_cpu);
+  CRIS_MISC_PROFILE *profp
+    = CPU_CRIS_MISC_PROFILE (current_cpu);
+  unsigned64 total = profp->basic_cycle_count;
+  const char *textmsg = "Basic clock cycles, total @: %llu\n";
+
+  /* The --cris-stats={basic|unaligned|schedulable|all} counts affect
+     what's included in the "total" count only.  */
+  switch (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
+	  & FLAG_CRIS_MISC_PROFILE_ALL)
+    {
+    case FLAG_CRIS_MISC_PROFILE_SIMPLE:
+      break;
+
+    case (FLAG_CRIS_MISC_PROFILE_UNALIGNED | FLAG_CRIS_MISC_PROFILE_SIMPLE):
+      textmsg
+	= "Clock cycles including stall cycles for unaligned accesses @: %llu\n";
+      total += profp->unaligned_mem_dword_count;
+      break;
+
+    case (FLAG_CRIS_MISC_PROFILE_SCHEDULABLE | FLAG_CRIS_MISC_PROFILE_SIMPLE):
+      textmsg = "Schedulable clock cycles, total @: %llu\n";
+      total
+	+= (profp->memsrc_stall_count
+	    + profp->memraw_stall_count
+	    + profp->movemsrc_stall_count
+	    + profp->movemdst_stall_count
+	    + profp->mulsrc_stall_count
+	    + profp->jumpsrc_stall_count
+	    + profp->unaligned_mem_dword_count);
+      break;
+
+    case FLAG_CRIS_MISC_PROFILE_ALL:
+      textmsg = "All accounted clock cycles, total @: %llu\n";
+      total
+	+= (profp->memsrc_stall_count
+	    + profp->memraw_stall_count
+	    + profp->movemsrc_stall_count
+	    + profp->movemdst_stall_count
+	    + profp->movemaddr_stall_count
+	    + profp->mulsrc_stall_count
+	    + profp->jumpsrc_stall_count
+	    + profp->branch_stall_count
+	    + profp->jumptarget_stall_count
+	    + profp->unaligned_mem_dword_count);
+      break;
+
+    default:
+      abort ();
+
+      sim_io_eprintf (sd,
+		      "Internal inconsistency at %s:%d",
+		      __FILE__, __LINE__);
+      sim_engine_halt (sd, current_cpu, NULL, 0,
+		       sim_stopped, SIM_SIGILL);
+    }
+
+  /* Historically, these messages have gone to stderr, so we'll keep it
+     that way.  It's also easier to then tell it from normal program
+     output.  FIXME: Add redirect option like "run -e file".  */
+  sim_io_eprintf (sd, textmsg, total);
+
+  /* For v32, unaligned_mem_dword_count should always be 0.  For
+     v10, memsrc_stall_count should always be 0.  */
+  sim_io_eprintf (sd, "Memory source stall cycles: %lld\n",
+		  profp->memsrc_stall_count
+		  + profp->unaligned_mem_dword_count);
+  sim_io_eprintf (sd, "Memory read-after-write stall cycles: %lld\n",
+		  profp->memraw_stall_count);
+  sim_io_eprintf (sd, "Movem source stall cycles: %lld\n",
+		  profp->movemsrc_stall_count);
+  sim_io_eprintf (sd, "Movem destination stall cycles: %lld\n",
+		  profp->movemdst_stall_count);
+  sim_io_eprintf (sd, "Movem address stall cycles: %lld\n",
+		  profp->movemaddr_stall_count);
+  sim_io_eprintf (sd, "Multiplication source stall cycles: %lld\n",
+		  profp->mulsrc_stall_count);
+  sim_io_eprintf (sd, "Jump source stall cycles: %lld\n",
+		  profp->jumpsrc_stall_count);
+  sim_io_eprintf (sd, "Branch misprediction stall cycles: %lld\n",
+		  profp->branch_stall_count);
+  sim_io_eprintf (sd, "Jump target stall cycles: %lld\n",
+		  profp->jumptarget_stall_count);
+}
+
+/* Check whether any part of [addr .. addr + len - 1] is already mapped.
+   Return 1 if a overlap detected, 0 otherwise.  */
+
+static USI
+is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED,
+	   struct cris_sim_mmapped_page **rootp,
+	   USI addr, USI len)
+{
+  struct cris_sim_mmapped_page *mapp;
+
+  if (len == 0 || (len & 8191))
+    abort ();
+
+  /* Iterate over the reverse-address sorted pages until we find a page in
+     or lower than the checked area.  */
+  for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
+    if (mapp->addr < addr + len && mapp->addr >= addr)
+      return 1;
+
+  return 0;
+}
+
+/* Create mmapped memory.  */
+
+static USI
+create_map (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
+	    USI len)
+{
+  struct cris_sim_mmapped_page *mapp;
+  struct cris_sim_mmapped_page **higher_prevp = rootp;
+  USI new_addr = 0x40000000;
+
+  if (addr != 0)
+    new_addr = addr;
+  else if (*rootp)
+    new_addr = rootp[0]->addr + 8192;
+
+  if (len != 8192)
+    {
+      USI page_addr;
+
+      if (len & 8191)
+	/* Which is better: return an error for this, or just round it up?  */
+	abort ();
+
+      /* Do a recursive call for each page in the request.  */
+      for (page_addr = new_addr; len != 0; page_addr += 8192, len -= 8192)
+	if (create_map (sd, rootp, page_addr, 8192) >= (USI) -8191)
+	  abort ();
+
+      return new_addr;
+    }
+
+  for (mapp = *rootp;
+       mapp != NULL && mapp->addr > new_addr;
+       mapp = mapp->prev)
+    higher_prevp = &mapp->prev;
+
+  /* Allocate the new page, on the next higher page from the last one
+     allocated, and link in the new descriptor before previous ones.  */
+  mapp = malloc (sizeof (*mapp));
+
+  if (mapp == NULL)
+    return (USI) -ENOMEM;
+
+  sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
+		   new_addr, len,
+		   0, NULL, NULL);
+
+  mapp->addr = new_addr;
+  mapp->prev = *higher_prevp;
+  *higher_prevp = mapp;
+
+  return new_addr;
+}
+
+/* Unmap one or more pages.  */
+
+static USI
+unmap_pages (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
+	    USI len)
+{
+  struct cris_sim_mmapped_page *mapp;
+  struct cris_sim_mmapped_page **higher_prevp = rootp;
+
+  if (len != 8192)
+    {
+      USI page_addr;
+
+      if (len & 8191)
+	/* Which is better: return an error for this, or just round it up?  */
+	abort ();
+
+      /* Loop backwards to make each call is O(1) over the number of pages
+	 allocated, if we're unmapping from the high end of the pages.  */
+      for (page_addr = addr + len - 8192;
+	   page_addr >= addr;
+	   page_addr -= 8192)
+	if (unmap_pages (sd, rootp, page_addr, 8192) != 0)
+	  abort ();
+
+      return 0;
+    }
+
+  for (mapp = *rootp; mapp != NULL && mapp->addr > addr; mapp = mapp->prev)
+    higher_prevp = &mapp->prev;
+
+  if (mapp == NULL || mapp->addr != addr)
+    return EINVAL;
+
+  *higher_prevp = mapp->prev;
+  sim_core_detach (sd, NULL, 0, 0, addr);
+  free (mapp);
+  return 0;
+}
+
+/* The semantic code invokes this for illegal (unrecognized) instructions.  */
+
+SEM_PC
+sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
+{
+  SIM_DESC sd = CPU_STATE (current_cpu);
+
+  sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
+  return vpc;
+}
+
+/* Handlers from the CGEN description that should not be called.  */
+
+USI
+cris_bmod_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+		   UINT srcreg ATTRIBUTE_UNUSED,
+		   USI dstreg ATTRIBUTE_UNUSED)
+{
+  abort ();
+}
+
+void
+h_supr_set_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+		    UINT index ATTRIBUTE_UNUSED,
+		    USI page ATTRIBUTE_UNUSED,
+		    USI newval ATTRIBUTE_UNUSED)
+{
+  abort ();
+}
+
+USI
+h_supr_get_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
+		    UINT index ATTRIBUTE_UNUSED,
+		    USI page ATTRIBUTE_UNUSED)
+{
+  abort ();
+}
+
+/* Swap one context for another.  */
+
+static void
+schedule (SIM_CPU *current_cpu, int next)
+{
+  /* Need to mark context-switches in the trace output.  */
+  if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags
+       & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE))
+    cris_trace_printf (CPU_STATE (current_cpu), current_cpu,
+		       "\t#:%d\n", next);
+
+  /* Copy the current context (if there is one) to its slot.  */
+  if (current_cpu->thread_data[current_cpu->threadno].cpu_context)
+    memcpy (current_cpu->thread_data[current_cpu->threadno].cpu_context,
+	    &current_cpu->cpu_data_placeholder,
+	    current_cpu->thread_cpu_data_size);
+
+  /* Copy the new context from its slot.  */
+  memcpy (&current_cpu->cpu_data_placeholder,
+	  current_cpu->thread_data[next].cpu_context,
+	  current_cpu->thread_cpu_data_size);
+
+  /* Update needed stuff to indicate the new context.  */
+  current_cpu->threadno = next;
+
+  /* Handle pending signals.  */
+  if (current_cpu->thread_data[next].sigpending
+      /* We don't run nested signal handlers.  This means that pause(2)
+	 and sigsuspend(2) do not work in sighandlers, but that
+	 shouldn't be too hard a restriction.  It also greatly
+	 simplifies the code.  */
+      && current_cpu->thread_data[next].cpu_context_atsignal == NULL)
+  {
+    int sig;
+
+    /* See if there's really a pending, non-blocked handler.  We don't
+       queue signals, so just use the first one in ascending order.  */
+    for (sig = 0; sig < 64; sig++)
+      if (current_cpu->thread_data[next].sigdata[sig].pending
+	  && !current_cpu->thread_data[next].sigdata[sig].blocked)
+      {
+	bfd_byte regbuf[4];
+	USI sp;
+	int i;
+	USI blocked;
+	USI pc = sim_pc_get (current_cpu);
+
+	/* It's simpler to save the CPU context inside the simulator
+	   than on the stack.  */
+	current_cpu->thread_data[next].cpu_context_atsignal
+	  = (*current_cpu
+	     ->make_thread_cpu_data) (current_cpu,
+				      current_cpu->thread_data[next]
+				      .cpu_context);
+
+	(*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
+	sp = bfd_getl32 (regbuf);
+
+	/* Make sure we have an aligned stack.  */
+	sp &= ~3;
+
+	/* Make room for the signal frame, aligned.  FIXME: Check that
+	   the memory exists, map it in if absent.  (BTW, should also
+	   implement on-access automatic stack allocation).  */
+	sp -= 20;
+
+	/* This isn't the same signal frame as the kernel uses, because
+           we don't want to bother getting all registers on and off the
+           stack.  */
+
+	/* First, we store the currently blocked signals.  */
+	blocked = 0;
+	for (i = 0; i < 32; i++)
+	  blocked
+	    |= current_cpu->thread_data[next].sigdata[i + 1].blocked << i;
+	sim_core_write_aligned_4 (current_cpu, pc, 0, sp, blocked);
+	blocked = 0;
+	for (i = 0; i < 31; i++)
+	  blocked
+	    |= current_cpu->thread_data[next].sigdata[i + 33].blocked << i;
+	sim_core_write_aligned_4 (current_cpu, pc, 0, sp + 4, blocked);
+
+	/* Then, the actual instructions.  This is CPU-specific, but we
+	   use instructions from the common subset for v10 and v32 which
+	   should be safe for the time being but could be parametrized
+	   if need be.  */
+	/* MOVU.W [PC+],R9.  */
+	sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 8, 0x9c5f);
+	/* .WORD TARGET_SYS_sigreturn.  */
+	sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 10,
+				  TARGET_SYS_sigreturn);
+	/* BREAK 13.  */
+	sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 12, 0xe93d);
+
+	/* NOP (on v32; it's SETF on v10, but is the correct compatible
+	   instruction.  Still, it doesn't matter because v10 has no
+	   delay slot for BREAK so it will not be executed).  */
+	sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 16, 0x05b0);
+
+	/* Modify registers to hold the right values for the sighandler
+	   context: updated stackpointer and return address pointing to
+	   the sigreturn stub.  */
+	bfd_putl32 (sp, regbuf);
+	(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
+	bfd_putl32 (sp + 8, regbuf);
+	(*CPU_REG_STORE (current_cpu)) (current_cpu, TARGET_SRP_REGNUM,
+					regbuf, 4);
+
+	current_cpu->thread_data[next].sigdata[sig].pending = 0;
+
+	/* Block this signal (for the duration of the sighandler).  */
+	current_cpu->thread_data[next].sigdata[sig].blocked = 1;
+
+	sim_pc_set (current_cpu, current_cpu->sighandler[sig]);
+	bfd_putl32 (sig, regbuf);
+	(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10,
+					regbuf, 4);
+
+	/* We ignore a SA_SIGINFO flag in the sigaction call; the code I
+	   needed all this for, specifies a SA_SIGINFO call but treats it
+	   like an ordinary sighandler; only the signal number argument is
+	   inspected.  To make future need to implement SA_SIGINFO
+	   correctly possible, we set the siginfo argument register to a
+	   magic (hopefully non-address) number.  (NB: then, you should
+	   just need to pass the siginfo argument; it seems you probably
+	   don't need to implement the specific rt_sigreturn.)  */
+	bfd_putl32 (0xbad5161f, regbuf);
+	(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R11,
+					regbuf, 4);
+
+	/* The third argument is unused and the kernel sets it to 0.  */
+	bfd_putl32 (0, regbuf);
+	(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R12,
+					regbuf, 4);
+	return;
+      }
+
+    /* No, there actually was no pending signal for this thread.  Reset
+       this flag.  */
+    current_cpu->thread_data[next].sigpending = 0;
+  }
+}
+
+/* Reschedule the simplest possible way until something else is absolutely
+   necessary:
+   - A. Find the next process (round-robin) that doesn't have at_syscall
+        set, schedule it.
+   - B. If there is none, just run the next process, round-robin.
+   - Clear at_syscall for the current process.  */
+
+static void
+reschedule (SIM_CPU *current_cpu)
+{
+  int i;
+
+  /* Iterate over all thread slots, because after a few thread creations
+     and exits, we don't know where the live ones are.  */
+  for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
+       i != current_cpu->threadno;
+       i = (i + 1) % SIM_TARGET_MAX_THREADS)
+    if (current_cpu->thread_data[i].cpu_context
+	&& current_cpu->thread_data[i].at_syscall == 0)
+      {
+	schedule (current_cpu, i);
+	return;
+      }
+
+  /* Pick any next live thread.  */
+  for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
+       i != current_cpu->threadno;
+       i = (i + 1) % SIM_TARGET_MAX_THREADS)
+    if (current_cpu->thread_data[i].cpu_context)
+      {
+	schedule (current_cpu, i);
+	return;
+      }
+
+  /* More than one live thread, but we couldn't find the next one?  */
+  abort ();
+}
+
+/* Set up everything to receive (or IGN) an incoming signal to the
+   current context.  */
+
+static int
+deliver_signal (SIM_CPU *current_cpu, int sig, unsigned int pid)
+{
+  int i;
+  USI pc = sim_pc_get (current_cpu);
+
+  /* Find the thread index of the pid. */
+  for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
+    /* Apparently it's ok to send signals to zombies (so a check for
+       current_cpu->thread_data[i].cpu_context != NULL would be
+       wrong). */
+    if (current_cpu->thread_data[i].threadid == pid - TARGET_PID)
+      {
+	if (sig < 64)
+	  switch (current_cpu->sighandler[sig])
+	    {
+	    case TARGET_SIG_DFL:
+	      switch (sig)
+		{
+		  /* The following according to the glibc
+		     documentation. (The kernel code has non-obvious
+		     execution paths.)  */
+		case TARGET_SIGFPE:
+		case TARGET_SIGILL:
+		case TARGET_SIGSEGV:
+		case TARGET_SIGBUS:
+		case TARGET_SIGABRT:
+		case TARGET_SIGTRAP:
+		case TARGET_SIGSYS:
+
+		case TARGET_SIGTERM:
+		case TARGET_SIGINT:
+		case TARGET_SIGQUIT:
+		case TARGET_SIGKILL:
+		case TARGET_SIGHUP:
+
+		case TARGET_SIGALRM:
+		case TARGET_SIGVTALRM:
+		case TARGET_SIGPROF:
+		case TARGET_SIGSTOP:
+
+		case TARGET_SIGPIPE:
+		case TARGET_SIGLOST:
+		case TARGET_SIGXCPU:
+		case TARGET_SIGXFSZ:
+		case TARGET_SIGUSR1:
+		case TARGET_SIGUSR2:
+		  sim_io_eprintf (CPU_STATE (current_cpu),
+				  "Exiting pid %d due to signal %d\n",
+				  pid, sig);
+		  sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
+				   NULL, pc, sim_stopped,
+				   sig == TARGET_SIGABRT
+				   ? SIM_SIGABRT : SIM_SIGILL);
+		  return 0;
+
+		  /* The default for all other signals is to be ignored.  */
+		default:
+		  return 0;
+		}
+
+	    case TARGET_SIG_IGN:
+	      switch (sig)
+		{
+		case TARGET_SIGKILL:
+		case TARGET_SIGSTOP:
+		  /* Can't ignore these signals.  */
+		  sim_io_eprintf (CPU_STATE (current_cpu),
+				  "Exiting pid %d due to signal %d\n",
+				  pid, sig);
+		  sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
+				   NULL, pc, sim_stopped, SIM_SIGILL);
+		  return 0;
+
+		default:
+		  return 0;
+		}
+	      break;
+
+	    default:
+	      /* Mark the signal as pending, making schedule () check
+		 closer.  The signal will be handled when the thread is
+		 scheduled and the signal is unblocked.  */
+	      current_cpu->thread_data[i].sigdata[sig].pending = 1;
+	      current_cpu->thread_data[i].sigpending = 1;
+	      return 0;
+	    }
+	else
+	  {
+	    sim_io_eprintf (CPU_STATE (current_cpu),
+			    "Unimplemented signal: %d\n", sig);
+	    sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc,
+			     sim_stopped, SIM_SIGILL);
+	  }
+      }
+
+  return
+    -cb_host_to_target_errno (STATE_CALLBACK (CPU_STATE (current_cpu)),
+			      ESRCH);
+}
+
+/* Make the vector and the first item, the main thread.  */
+
+static void
+make_first_thread (SIM_CPU *current_cpu)
+{
+  current_cpu->thread_data
+    = xcalloc (1,
+	       SIM_TARGET_MAX_THREADS
+	       * sizeof (current_cpu->thread_data[0]));
+  current_cpu->thread_data[0].cpu_context
+    = (*current_cpu->make_thread_cpu_data) (current_cpu,
+					    &current_cpu
+					    ->cpu_data_placeholder);
+  current_cpu->thread_data[0].parent_threadid = -1;
+
+  /* For good measure.  */
+  if (TARGET_SIG_DFL != 0)
+    abort ();
+}
+
+/* Main function: the handler of the "break 13" syscall insn.  */
+
+USI
+cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
+		       USI arg2, USI arg3, USI arg4, USI arg5, USI arg6,
+		       USI pc)
+{
+  CB_SYSCALL s;
+  SIM_DESC sd = CPU_STATE (current_cpu);
+  host_callback *cb = STATE_CALLBACK (sd);
+  int retval;
+  int threadno = current_cpu->threadno;
+
+  current_cpu->syscalls++;
+
+  CB_SYSCALL_INIT (&s);
+  s.func = callnum;
+  s.arg1 = arg1;
+  s.arg2 = arg2;
+  s.arg3 = arg3;
+
+  if (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0)
+    {
+      if (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
+	  & FLAG_CRIS_MISC_PROFILE_ALL)
+	dump_statistics (current_cpu);
+      sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
+    }
+
+  s.p1 = (PTR) sd;
+  s.p2 = (PTR) current_cpu;
+  s.read_mem = syscall_read_mem;
+  s.write_mem = syscall_write_mem;
+
+  current_cpu_for_cb_callback = current_cpu;
+
+  if (cb_syscall (cb, &s) != CB_RC_OK)
+    {
+      abort ();
+      sim_io_eprintf (sd, "Break 13: invalid %d?  Returned %ld\n", callnum,
+		      s.result);
+      sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
+    }
+
+  retval = s.result == -1 ? -s.errcode : s.result;
+
+  if (s.errcode != 0 && s.errcode == cb_host_to_target_errno (cb, ENOSYS))
+    {
+      /* If the generic simulator call said ENOSYS, then let's try the
+	 ones we know ourselves.
+
+	 The convention is to provide *very limited* functionality on an
+	 as-needed basis, only what's covered by the test-suite, tests
+	 added when functionality changes and abort with a descriptive
+	 message for *everything* else.  Where there's no test-case, we
+	 just abort.  */
+      switch (callnum)
+	{
+	case 0:
+	  /* It's a pretty safe bet that the "old setup() system call"
+	     number will not be re-used; we can't say the same for higher
+	     numbers.  We treat this simulator-generated call as "wait
+	     forever"; we re-run this insn.  The wait is ended by a
+	     callback.  Sanity check that this is the reason we got
+	     here. */
+	  if (current_cpu->thread_data == NULL
+	      || (current_cpu->thread_data[threadno].pipe_write_fd == 0))
+	    goto unimplemented_syscall;
+
+	  sim_pc_set (current_cpu, pc);
+	  retval = arg1;
+	  break;
+
+	case TARGET_SYS_fcntl64:
+	case TARGET_SYS_fcntl:
+	  if (arg2 == 1)
+	    {
+	      /* F_GETFD.
+		 Glibc checks stdin, stdout and stderr fd:s for
+		 close-on-exec security sanity.  We just need to provide a
+		 OK return value.  If we really need to have a
+		 close-on-exec flag true, we could just do a real fcntl
+		 here.  */
+	      retval = 0;
+	    }
+	  else if (arg2 == 2)
+	    {
+	      /* F_SETFD.  Just ignore attempts to set the close-on-exec
+		 flag.  */
+	      retval = 0;
+	    }
+	  break;
+
+	case TARGET_SYS_uname:
+	  {
+	    /* Fill in a few constants to appease glibc.  */
+	    static const char sim_utsname[6][65] =
+	    {
+	      "Linux",
+	      "sim-target",
+	      "2.4.5",
+	      TARGET_UTSNAME,
+	      "cris",
+	      "localdomain"
+	    };
+
+	    if ((s.write_mem) (cb, &s, arg1, (const char *) sim_utsname,
+			       sizeof (sim_utsname))
+		!= sizeof (sim_utsname))
+	      retval = -cb_host_to_target_errno (cb, EFAULT);
+	    else
+	      retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_geteuid32:
+	  /* We tell the truth with these.  Maybe we shouldn't, but it
+	     should match the "stat" information.  */
+	  retval = geteuid ();
+	  break;
+
+	case TARGET_SYS_getuid32:
+	  retval = getuid ();
+	  break;
+
+	case TARGET_SYS_getegid32:
+	  retval = getegid ();
+	  break;
+
+	case TARGET_SYS_getgid32:
+	  retval = getgid ();
+	  break;
+
+	case TARGET_SYS_brk:
+	  /* Most often, we just return the argument, like the Linux
+	     kernel.  */
+	  retval = arg1;
+
+	  if (arg1 == 0)
+	    retval = current_cpu->endbrk;
+	  else if (arg1 <= current_cpu->endmem)
+	    current_cpu->endbrk = arg1;
+	  else
+	    {
+	      USI new_end = (arg1 + 8191) & ~8191;
+
+	      /* If the simulator wants to brk more than a certain very
+		 large amount, something is wrong.  FIXME: Return an error
+		 or abort?  Have command-line selectable?  */
+	      if (new_end - current_cpu->endmem > SIM_MAX_ALLOC_CHUNK)
+		{
+		  current_cpu->endbrk = current_cpu->endmem;
+		  retval = current_cpu->endmem;
+		  break;
+		}
+
+	      sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
+			       current_cpu->endmem,
+			       new_end - current_cpu->endmem,
+			       0, NULL, NULL);
+	      current_cpu->endbrk = arg1;
+	      current_cpu->endmem = new_end;
+	    }
+	  break;
+
+	case TARGET_SYS_getpid:
+	  /* Correct until CLONE_THREAD is implemented.  */
+	  retval = current_cpu->thread_data == NULL
+	    ? TARGET_PID
+	    : TARGET_PID + current_cpu->thread_data[threadno].threadid;
+	  break;
+
+	case TARGET_SYS_getppid:
+	  /* Correct until CLONE_THREAD is implemented.  */
+	  retval = current_cpu->thread_data == NULL
+	    ? TARGET_PID - 1
+	    : (TARGET_PID
+	       + current_cpu->thread_data[threadno].parent_threadid);
+	  break;
+
+	case TARGET_SYS_mmap2:
+	  {
+	    USI addr = arg1;
+	    USI len = arg2;
+	    USI prot = arg3;
+	    USI flags = arg4;
+	    USI fd = arg5;
+	    USI pgoff = arg6;
+
+	    /* If the simulator wants to mmap more than the very large
+	       limit, something is wrong.  FIXME: Return an error or
+	       abort?  Have command-line selectable?  */
+	    if (len > SIM_MAX_ALLOC_CHUNK)
+	      {
+		retval = -cb_host_to_target_errno (cb, ENOMEM);
+		break;
+	      }
+
+	    if ((prot != (TARGET_PROT_READ | TARGET_PROT_WRITE)
+		 && (prot
+		     != (TARGET_PROT_READ
+			 | TARGET_PROT_WRITE
+			 | TARGET_PROT_EXEC))
+		 && prot != TARGET_PROT_READ)
+		|| (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
+		    && flags != TARGET_MAP_PRIVATE
+		    && flags != TARGET_MAP_SHARED)
+		|| (fd != (USI) -1 && prot != TARGET_PROT_READ)
+		|| pgoff != 0
+		|| ((len & 8191) != 0 && fd == (USI) -1))
+	      {
+		sim_io_eprintf (sd, "Unimplemented mmap2 call "
+				"(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+				(unsigned long) arg1,
+				(unsigned long) arg2,
+				(unsigned long) arg3,
+				(unsigned long) arg4,
+				(unsigned long) arg5,
+				(unsigned long) arg6);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+		break;
+	      }
+	    else if (fd != (USI) -1)
+	      {
+		/* Map a file.  */
+
+		USI newaddr;
+		USI pos;
+
+		/* A non-aligned argument is allowed for files.  */
+		USI newlen = (len + 8191) & ~8191;
+
+		/* We only support read, which we should already have
+		   checked.  Check again anyway.  */
+		if (prot != TARGET_PROT_READ)
+		  abort ();
+
+		newaddr
+		  = create_map (sd, &current_cpu->highest_mmapped_page, addr,
+				newlen);
+
+		if (newaddr >= (USI) -8191)
+		  {
+		    abort ();
+		    retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
+		    break;
+		  }
+
+		/* Find the current position in the file.  */
+		s.func = TARGET_SYS_lseek;
+		s.arg1 = fd;
+		s.arg2 = 0;
+		s.arg3 = SEEK_CUR;
+		if (cb_syscall (cb, &s) != CB_RC_OK)
+		  abort ();
+		pos = s.result;
+
+		if (s.result < 0)
+		  abort ();
+
+		/* Use the standard read callback to read in "len"
+		   bytes.  */
+		s.func = TARGET_SYS_read;
+		s.arg1 = fd;
+		s.arg2 = newaddr;
+		s.arg3 = len;
+		if (cb_syscall (cb, &s) != CB_RC_OK)
+		  abort ();
+
+		if ((USI) s.result != len)
+		  abort ();
+
+		/* After reading, we need to go back to the previous
+                   position in the file.  */
+		s.func = TARGET_SYS_lseek;
+		s.arg1 = fd;
+		s.arg2 = pos;
+		s.arg3 = SEEK_SET;
+		if (cb_syscall (cb, &s) != CB_RC_OK)
+		  abort ();
+		if (pos != (USI) s.result)
+		  abort ();
+
+		retval = newaddr;
+	      }
+	    else
+	      {
+		USI newaddr
+		  = create_map (sd, &current_cpu->highest_mmapped_page, addr, len);
+
+		if (newaddr >= (USI) -8191)
+		  retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
+		else
+		  retval = newaddr;
+	      }
+	    break;
+	  }
+
+	case TARGET_SYS_mprotect:
+	  {
+	    /* We only cover the case of linuxthreads mprotecting out its
+	       stack guard page.  */
+	    USI addr = arg1;
+	    USI len = arg2;
+	    USI prot = arg3;
+
+	    if ((addr & 8191) != 0
+		|| len != 8192
+		|| prot != TARGET_PROT_NONE
+		|| !is_mapped (sd, &current_cpu->highest_mmapped_page, addr,
+			       len))
+	      {
+		sim_io_eprintf (sd, "Unimplemented mprotect call "
+				"(0x%lx, 0x%lx, 0x%lx)\n",
+				(unsigned long) arg1,
+				(unsigned long) arg2,
+				(unsigned long) arg3);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+		break;
+	      }
+
+	    /* FIXME: We should account for pages like this that are
+	       "mprotected out".  For now, we just tell the simulator
+	       core to remove that page from its map.  */
+	    sim_core_detach (sd, NULL, 0, 0, addr);
+	    retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_ioctl:
+	  {
+	    /* We support only a very limited functionality: checking
+	       stdout with TCGETS to perform the isatty function.  The
+	       TCGETS ioctl isn't actually performed or the result used by
+	       an isatty () caller in a "hello, world" program; only the
+	       return value is then used.  Maybe we shouldn't care about
+	       the environment of the simulator regarding isatty, but
+	       that's been working before, in the xsim simulator.  */
+	    if (arg2 == TARGET_TCGETS && arg1 == 1)
+	      retval = isatty (1) ? 0 : cb_host_to_target_errno (cb, EINVAL);
+	    else
+	      retval = -cb_host_to_target_errno (cb, EINVAL);
+	    break;
+	  }
+
+	case TARGET_SYS_munmap:
+	  {
+	    USI addr = arg1;
+	    USI len = arg2;
+	    USI result
+	      = unmap_pages (sd, &current_cpu->highest_mmapped_page, addr,
+			     len);
+	    retval = result != 0 ? -cb_host_to_target_errno (cb, result) : 0;
+	    break;
+	  }
+
+	case TARGET_SYS_wait4:
+	  {
+	    int i;
+	    USI pid = arg1;
+	    USI saddr = arg2;
+	    USI options = arg3;
+	    USI rusagep = arg4;
+
+	    /* FIXME: We're not properly implementing __WCLONE, and we
+	       don't really need the special casing so we might as well
+	       make this general.  */
+	    if ((!(pid == (USI) -1
+		   && options == (TARGET___WCLONE | TARGET_WNOHANG)
+		   && saddr != 0)
+		 && !(pid > 0
+		      && (options == TARGET___WCLONE
+			  || options == TARGET___WALL)))
+		|| rusagep != 0
+		|| current_cpu->thread_data == NULL)
+	      {
+		sim_io_eprintf (sd, "Unimplemented wait4 call "
+				"(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+				(unsigned long) arg1,
+				(unsigned long) arg2,
+				(unsigned long) arg3,
+				(unsigned long) arg4);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+		break;
+	      }
+
+	    if (pid == (USI) -1)
+	      for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
+		{
+		  if (current_cpu->thread_data[threadno].threadid
+		      == current_cpu->thread_data[i].parent_threadid
+		      && current_cpu->thread_data[i].threadid != 0
+		      && current_cpu->thread_data[i].cpu_context == NULL)
+		    {
+		      /* A zombied child.  Get the exit value and clear the
+			 zombied entry so it will be reused.  */
+		      sim_core_write_unaligned_4 (current_cpu, pc, 0, saddr,
+						  current_cpu
+						  ->thread_data[i].exitval);
+		      retval
+			= current_cpu->thread_data[i].threadid + TARGET_PID;
+		      memset (&current_cpu->thread_data[i], 0,
+			      sizeof (current_cpu->thread_data[i]));
+		      goto outer_break;
+		    }
+		}
+	    else
+	      {
+		/* We're waiting for a specific PID.  If we don't find
+		   it zombied on this run, rerun the syscall.  */
+		for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
+		  if (pid == current_cpu->thread_data[i].threadid + TARGET_PID
+		      && current_cpu->thread_data[i].cpu_context == NULL)
+		    {
+		      if (saddr != 0)
+			/* Get the exit value if the caller wants it.  */
+			sim_core_write_unaligned_4 (current_cpu, pc, 0,
+						    saddr,
+						    current_cpu
+						    ->thread_data[i]
+						    .exitval);
+
+		      retval
+			= current_cpu->thread_data[i].threadid + TARGET_PID;
+		      memset (&current_cpu->thread_data[i], 0,
+			      sizeof (current_cpu->thread_data[i]));
+
+		      goto outer_break;
+		    }
+
+		sim_pc_set (current_cpu, pc);
+	      }
+
+	    retval = -cb_host_to_target_errno (cb, ECHILD);
+	  outer_break:
+	    break;
+	  }
+
+	case TARGET_SYS_rt_sigaction:
+	  {
+	    USI signum = arg1;
+	    USI old_sa = arg3;
+	    USI new_sa = arg2;
+
+	    /* The kernel says:
+	       struct sigaction {
+			__sighandler_t sa_handler;
+			unsigned long sa_flags;
+			void (*sa_restorer)(void);
+			sigset_t sa_mask;
+	       }; */
+
+	    if (old_sa != 0)
+	      {
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, old_sa + 0,
+					    current_cpu->sighandler[signum]);
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 4, 0);
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 8, 0);
+
+		/* We'll assume _NSIG_WORDS is 2 for the kernel.  */
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 12, 0);
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 16, 0);
+	      }
+	    if (new_sa != 0)
+	      {
+		USI sa_handler
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa);
+		USI sa_flags
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 4);
+		USI sa_restorer
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 8);
+		USI sa_mask_low
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 12);
+		USI sa_mask_high
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 16);
+
+		/* We won't interrupt a syscall so we won't restart it,
+		   but a signal(2) call ends up syscalling rt_sigaction
+		   with this flag, so we have to handle it.  The
+		   sa_restorer field contains garbage when not
+		   TARGET_SA_RESTORER, so don't look at it.  For the
+		   time being, we don't nest sighandlers, so we
+		   ignore the sa_mask, which simplifies things.  */
+		if ((sa_flags != 0
+		     && sa_flags != TARGET_SA_RESTART
+		     && sa_flags != (TARGET_SA_RESTART|TARGET_SA_SIGINFO))
+		    || sa_handler == 0)
+		  {
+		    sim_io_eprintf (sd, "Unimplemented rt_sigaction "
+				    "syscall (0x%lx, "
+				    "0x%lx: [0x%x, 0x%x, 0x%x, "
+				    "{0x%x, 0x%x}], "
+				    "0x%lx)\n",
+				    (unsigned long) arg1,
+				    (unsigned long) arg2,
+				    sa_handler, sa_flags, sa_restorer,
+				    sa_mask_low, sa_mask_high,
+				    (unsigned long) arg3);
+		    sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				     SIM_SIGILL);
+		  }
+
+		current_cpu->sighandler[signum] = sa_handler;
+
+		/* Because we may have unblocked signals, one may now be
+		   pending, if there are threads, that is.  */
+		if (current_cpu->thread_data)
+		  current_cpu->thread_data[threadno].sigpending = 1;
+	      }
+	    retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_mremap:
+	  {
+	    USI addr = arg1;
+	    USI old_len = arg2;
+	    USI new_len = arg3;
+	    USI flags = arg4;
+	    USI new_addr = arg5;
+	    USI mapped_addr;
+
+	    if (new_len == old_len)
+	      /* The program and/or library is possibly confused but
+		 this is a valid call.  Happens with ipps-1.40 on file
+		 svs_all.  */
+	      retval = addr;
+	    else if (new_len < old_len)
+	      {
+		/* Shrinking is easy.  */
+		if (unmap_pages (sd, &current_cpu->highest_mmapped_page,
+				 addr + new_len, old_len - new_len) != 0)
+		  retval = -cb_host_to_target_errno (cb, EINVAL);
+		else
+		  retval = addr;
+	      }
+	    else if (! is_mapped (sd, &current_cpu->highest_mmapped_page,
+				  addr + old_len, new_len - old_len))
+	      {
+		/* If the extension isn't mapped, we can just add it.  */
+		mapped_addr
+		  = create_map (sd, &current_cpu->highest_mmapped_page,
+				addr + old_len, new_len - old_len);
+
+		if (mapped_addr > (USI) -8192)
+		  retval = -cb_host_to_target_errno (cb, -(SI) mapped_addr);
+		else
+		  retval = addr;
+	      }
+	    else if (flags & TARGET_MREMAP_MAYMOVE)
+	      {
+		/* Create a whole new map and copy the contents
+		   block-by-block there.  We ignore the new_addr argument
+		   for now.  */
+		char buf[8192];
+		USI prev_addr = addr;
+		USI prev_len = old_len;
+
+		mapped_addr
+		  = create_map (sd, &current_cpu->highest_mmapped_page,
+				0, new_len);
+
+		if (mapped_addr > (USI) -8192)
+		  {
+		    retval = -cb_host_to_target_errno (cb, -(SI) new_addr);
+		    break;
+		  }
+
+		retval = mapped_addr;
+
+		for (; old_len > 0;
+		     old_len -= 8192, mapped_addr += 8192, addr += 8192)
+		  {
+		    if (sim_core_read_buffer (sd, current_cpu, read_map, buf,
+					      addr, 8192) != 8192
+			|| sim_core_write_buffer (sd, current_cpu, 0, buf,
+						  mapped_addr, 8192) != 8192)
+		      abort ();
+		  }
+
+		if (unmap_pages (sd, &current_cpu->highest_mmapped_page,
+				 prev_addr, prev_len) != 0)
+		  abort ();
+	      }
+	    else
+	      retval = -cb_host_to_target_errno (cb, -ENOMEM);
+	    break;
+	  }
+
+	case TARGET_SYS_poll:
+	  {
+	    int npollfds = arg2;
+	    int timeout = arg3;
+	    SI ufds = arg1;
+	    SI fd = -1;
+	    HI events = -1;
+	    HI revents = 0;
+	    struct stat buf;
+	    int i;
+
+	    /* The kernel says:
+		struct pollfd {
+		     int fd;
+		     short events;
+		     short revents;
+		}; */
+
+	    /* Check that this is the expected poll call from
+	       linuxthreads/manager.c; we don't support anything else.
+	       Remember, fd == 0 isn't supported.  */
+	    if (npollfds != 1
+		|| ((fd = sim_core_read_unaligned_4 (current_cpu, pc,
+						     0, ufds)) <= 0)
+		|| ((events = sim_core_read_unaligned_2 (current_cpu, pc,
+							 0, ufds + 4))
+		    != TARGET_POLLIN)
+		|| ((cb->fstat) (cb, fd, &buf) != 0
+		    || (buf.st_mode & S_IFIFO) == 0)
+		|| current_cpu->thread_data == NULL)
+	      {
+		sim_io_eprintf (sd, "Unimplemented poll syscall "
+				"(0x%lx: [0x%x, 0x%x, x], 0x%lx, 0x%lx)\n",
+				(unsigned long) arg1, fd, events,
+				(unsigned long) arg2, (unsigned long) arg3);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
+		break;
+	      }
+
+	    retval = 0;
+
+	    /* Iterate over threads; find a marker that a writer is
+	       sleeping, waiting for a reader.  */
+	    for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
+	      if (current_cpu->thread_data[i].cpu_context != NULL
+		  && current_cpu->thread_data[i].pipe_read_fd == fd)
+		{
+		  revents = TARGET_POLLIN;
+		  retval = 1;
+		  break;
+		}
+
+	    /* Timeout decreases with whatever time passed between the
+	       last syscall and this.  That's not exactly right for the
+	       first call, but it's close enough that it isn't
+	       worthwhile to complicate matters by making that a special
+	       case.  */
+	    timeout
+	      -= (TARGET_TIME_MS (current_cpu)
+		  - (current_cpu->thread_data[threadno].last_execution));
+
+	    /* Arrange to repeat this syscall until timeout or event,
+               decreasing timeout at each iteration.  */
+	    if (timeout > 0 && revents == 0)
+	      {
+		bfd_byte timeout_buf[4];
+
+		bfd_putl32 (timeout, timeout_buf);
+		(*CPU_REG_STORE (current_cpu)) (current_cpu,
+						H_GR_R12, timeout_buf, 4);
+		sim_pc_set (current_cpu, pc);
+		retval = arg1;
+		break;
+	      }
+
+	    sim_core_write_unaligned_2 (current_cpu, pc, 0, ufds + 4 + 2,
+					revents);
+	    break;
+	  }
+
+	case TARGET_SYS_gettimeofday:
+	  if (arg1 != 0)
+	    {
+	      USI ts = TARGET_TIME (current_cpu);
+	      USI tms = TARGET_TIME_MS (current_cpu);
+
+	      /* First dword is seconds since TARGET_EPOCH.  */
+	      sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, ts);
+
+	      /* Second dword is microseconds.  */
+	      sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1 + 4,
+					  (tms % 1000) * 1000);
+	    }
+	  if (arg2 != 0)
+	    {
+	      /* Time-zone info is always cleared.  */
+	      sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, 0);
+	      sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, 0);
+	    }
+	  retval = 0;
+	  break;
+
+	case TARGET_SYS_llseek:
+	  {
+	    /* If it fits, tweak parameters to fit the "generic" 32-bit
+	       lseek and use that.  */
+	    SI fd = arg1;
+	    SI offs_hi = arg2;
+	    SI offs_lo = arg3;
+	    SI resultp = arg4;
+	    SI whence = arg5;
+	    retval = 0;
+
+	    if (!((offs_hi == 0 && offs_lo >= 0)
+		  || (offs_hi == -1 &&  offs_lo < 0)))
+	      {
+		sim_io_eprintf (sd,
+				"Unimplemented llseek offset,"
+				" fd %d: 0x%x:0x%x\n",
+				fd, (unsigned) arg2, (unsigned) arg3);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+	      }
+
+	    s.func = TARGET_SYS_lseek;
+	    s.arg2 = offs_lo;
+	    s.arg3 = whence;
+	    if (cb_syscall (cb, &s) != CB_RC_OK)
+	      {
+		sim_io_eprintf (sd, "Break 13: invalid %d?  Returned %ld\n", callnum,
+				s.result);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
+	      }
+	    if (s.result < 0)
+	      retval = -s.errcode;
+	    else
+	      {
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp,
+					    s.result);
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp + 4,
+					    s.result < 0 ? -1 : 0);
+	      }
+	    break;
+	  }
+
+	/* This one does have a generic callback function, but at the time
+	   of this writing, cb_syscall does not have code for it, and we
+	   need target-specific code for the threads implementation
+	   anyway.  */
+	case TARGET_SYS_kill:
+	  {
+	    USI pid = arg1;
+	    USI sig = arg2;
+
+	    retval = 0;
+
+	    /* At kill(2), glibc sets signal masks such that the thread
+	       machinery is initialized.  Still, there is and was only
+	       one thread.  */
+	    if (current_cpu->max_threadid == 0)
+	      {
+		if (pid != TARGET_PID)
+		  {
+		    retval = -cb_host_to_target_errno (cb, EPERM);
+		    break;
+		  }
+
+		/* FIXME: Signal infrastructure (target-to-sim mapping).  */
+		if (sig == TARGET_SIGABRT)
+		  /* A call "abort ()", i.e. "kill (getpid(), SIGABRT)" is
+		     the end-point for failing GCC test-cases.  */
+		  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				   SIM_SIGABRT);
+		else
+		  {
+		    sim_io_eprintf (sd, "Unimplemented signal: %d\n", sig);
+		    sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				     SIM_SIGILL);
+		  }
+
+		/* This will not be reached.  */
+		abort ();
+	      }
+	    else
+	      retval = deliver_signal (current_cpu, sig, pid);
+	    break;
+	  }
+
+	case TARGET_SYS_rt_sigprocmask:
+	  {
+	    int i;
+	    USI how = arg1;
+	    USI newsetp = arg2;
+	    USI oldsetp = arg3;
+
+	    if (how != TARGET_SIG_BLOCK
+		&& how != TARGET_SIG_SETMASK
+		&& how != TARGET_SIG_UNBLOCK)
+	      {
+		sim_io_eprintf (sd, "Unimplemented rt_sigprocmask syscall "
+			       "(0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+		retval = 0;
+		break;
+	      }
+
+	    if (newsetp)
+	      {
+		USI set_low
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
+					       newsetp);
+		USI set_high
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
+					       newsetp + 4);
+
+		/* The sigmask is kept in the per-thread data, so we may
+		   need to create the first one.  */
+		if (current_cpu->thread_data == NULL)
+		  make_first_thread (current_cpu);
+
+		if (how == TARGET_SIG_SETMASK)
+		  for (i = 0; i < 64; i++)
+		    current_cpu->thread_data[threadno].sigdata[i].blocked = 0;
+
+		for (i = 0; i < 32; i++)
+		  if ((set_low & (1 << i)))
+		    current_cpu->thread_data[threadno].sigdata[i + 1].blocked
+		      = (how != TARGET_SIG_UNBLOCK);
+
+		for (i = 0; i < 31; i++)
+		  if ((set_high & (1 << i)))
+		    current_cpu->thread_data[threadno].sigdata[i + 33].blocked
+		      = (how != TARGET_SIG_UNBLOCK);
+
+		/* The mask changed, so a signal may be unblocked for
+                   execution.  */
+		current_cpu->thread_data[threadno].sigpending = 1;
+	      }
+
+	    if (oldsetp != 0)
+	      {
+		USI set_low = 0;
+		USI set_high = 0;
+
+		for (i = 0; i < 32; i++)
+		  if (current_cpu->thread_data[threadno]
+		      .sigdata[i + 1].blocked)
+		    set_low |= 1 << i;
+		for (i = 0; i < 31; i++)
+		  if (current_cpu->thread_data[threadno]
+		      .sigdata[i + 33].blocked)
+		    set_high |= 1 << i;
+
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 0, set_low);
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 4, set_high);
+	      }
+
+	    retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_sigreturn:
+	  {
+	    int i;
+	    bfd_byte regbuf[4];
+	    int was_sigsuspended;
+
+	    if (current_cpu->thread_data == NULL
+		/* The CPU context is saved with the simulator data, not
+		   on the stack as in the real world.  */
+		|| (current_cpu->thread_data[threadno].cpu_context_atsignal
+		    == NULL))
+	      {
+		sim_io_eprintf (sd, "Invalid sigreturn syscall: no signal"
+				" handler active "
+				"(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+				(unsigned long) arg1,
+				(unsigned long) arg2,
+				(unsigned long) arg3,
+				(unsigned long) arg4,
+				(unsigned long) arg5,
+				(unsigned long) arg6);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+	      }
+
+	    was_sigsuspended
+	      = current_cpu->thread_data[threadno].sigsuspended;
+
+	    /* Restore the sigmask, either from the stack copy made when
+	       the sighandler was called, or from the saved state
+	       specifically for sigsuspend(2).  */
+	    if (was_sigsuspended)
+	      {
+		current_cpu->thread_data[threadno].sigsuspended = 0;
+		for (i = 0; i < 64; i++)
+		  current_cpu->thread_data[threadno].sigdata[i].blocked
+		    = current_cpu->thread_data[threadno]
+		    .sigdata[i].blocked_suspendsave;
+	      }
+	    else
+	      {
+		USI sp;
+		USI set_low;
+		USI set_high;
+
+		(*CPU_REG_FETCH (current_cpu)) (current_cpu,
+					    H_GR_SP, regbuf, 4);
+		sp = bfd_getl32 (regbuf);
+		set_low
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp);
+		set_high
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp + 4);
+
+		for (i = 0; i < 32; i++)
+		  current_cpu->thread_data[threadno].sigdata[i + 1].blocked
+		    = (set_low & (1 << i)) != 0;
+		for (i = 0; i < 31; i++)
+		  current_cpu->thread_data[threadno].sigdata[i + 33].blocked
+		    = (set_high & (1 << i)) != 0;
+	      }
+
+	    /* The mask changed, so a signal may be unblocked for
+	       execution.  */
+	    current_cpu->thread_data[threadno].sigpending = 1;
+
+	    memcpy (&current_cpu->cpu_data_placeholder,
+		    current_cpu->thread_data[threadno].cpu_context_atsignal,
+		    current_cpu->thread_cpu_data_size);
+	    free (current_cpu->thread_data[threadno].cpu_context_atsignal);
+	    current_cpu->thread_data[threadno].cpu_context_atsignal = NULL;
+
+	    /* The return value must come from the saved R10.  */
+	    (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, regbuf, 4);
+	    retval = bfd_getl32 (regbuf);
+
+	    /* We must also break the "sigsuspension loop".  */
+	    if (was_sigsuspended)
+	      sim_pc_set (current_cpu, sim_pc_get (current_cpu) + 2);
+	    break;
+	  }
+
+	case TARGET_SYS_rt_sigsuspend:
+	  {
+	    USI newsetp = arg1;
+	    USI setsize = arg2;
+
+	    if (setsize != 8)
+	      {
+		sim_io_eprintf (sd, "Unimplemented rt_sigsuspend syscall"
+			       " arguments (0x%lx, 0x%lx)\n",
+				(unsigned long) arg1, (unsigned long) arg2);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+	      }
+
+	    /* Don't change the signal mask if we're already in
+	       sigsuspend state (i.e. this syscall is a rerun).  */
+	    else if (!current_cpu->thread_data[threadno].sigsuspended)
+	      {
+		USI set_low
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
+					       newsetp);
+		USI set_high
+		  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
+					       newsetp + 4);
+		int i;
+
+		/* Save the current sigmask and insert the user-supplied
+                   one.  */
+		for (i = 0; i < 32; i++)
+		  {
+		    current_cpu->thread_data[threadno]
+		      .sigdata[i + 1].blocked_suspendsave
+		      = current_cpu->thread_data[threadno]
+		      .sigdata[i + 1].blocked;
+
+		    current_cpu->thread_data[threadno]
+		      .sigdata[i + 1].blocked = (set_low & (1 << i)) != 0;
+		  }
+		for (i = 0; i < 31; i++)
+		  {
+		    current_cpu->thread_data[threadno]
+		      .sigdata[i + 33].blocked_suspendsave
+		      = current_cpu->thread_data[threadno]
+		      .sigdata[i + 33].blocked;
+		    current_cpu->thread_data[threadno]
+		      .sigdata[i + 33].blocked = (set_high & (1 << i)) != 0;
+		  }
+
+		current_cpu->thread_data[threadno].sigsuspended = 1;
+
+		/* The mask changed, so a signal may be unblocked for
+                   execution. */
+		current_cpu->thread_data[threadno].sigpending = 1;
+	      }
+
+	    /* Because we don't use arg1 (newsetp) when this syscall is
+	       rerun, it doesn't matter that we overwrite it with the
+	       (constant) return value.  */
+	    retval = -cb_host_to_target_errno (cb, EINTR);
+	    sim_pc_set (current_cpu, pc);
+	    break;
+	  }
+
+	  /* Add case labels here for other syscalls using the 32-bit
+	     "struct stat", provided they have a corresponding simulator
+	     function of course.  */
+	case TARGET_SYS_fstat:
+	  {
+	    /* As long as the infrastructure doesn't cache anything
+	       related to the stat mapping, this trick gets us a dual
+	       "struct stat"-type mapping in the least error-prone way.  */
+	    const char *saved_map = cb->stat_map;
+	    CB_TARGET_DEFS_MAP *saved_syscall_map = cb->syscall_map;
+
+	    cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_stat32_map;
+	    cb->stat_map = stat32_map;
+
+	    if (cb_syscall (cb, &s) != CB_RC_OK)
+	      {
+		abort ();
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+	      }
+	    retval = s.result == -1 ? -s.errcode : s.result;
+
+	    cb->stat_map = saved_map;
+	    cb->syscall_map = saved_syscall_map;
+	    break;
+	  }
+
+	case TARGET_SYS_getcwd:
+	  {
+	    USI buf = arg1;
+	    USI size = arg2;
+
+	    char *cwd = xmalloc (MAXPATHLEN);
+	    if (cwd != getcwd (cwd, MAXPATHLEN))
+	      abort ();
+
+	    /* FIXME: When and if we support chdir, we need something
+               a bit more elaborate.  */
+	    if (simulator_sysroot[0] != '\0')
+	      strcpy (cwd, "/");
+
+	    retval = -cb_host_to_target_errno (cb, ERANGE);
+	    if (strlen (cwd) + 1 <= size)
+	      {
+		retval = strlen (cwd) + 1;
+		if (sim_core_write_buffer (sd, current_cpu, 0, cwd,
+					   buf, retval)
+		    != (unsigned int) retval)
+		  retval = -cb_host_to_target_errno (cb, EFAULT);
+	      }
+	    free (cwd);
+	    break;
+	  }
+
+	case TARGET_SYS_readlink:
+	  {
+	    SI path = arg1;
+	    SI buf = arg2;
+	    SI bufsiz = arg3;
+	    char *pbuf = xmalloc (MAXPATHLEN);
+	    char *lbuf = xmalloc (MAXPATHLEN);
+	    char *lbuf_alloc = lbuf;
+	    int nchars = -1;
+	    int i;
+	    int o = 0;
+
+	    if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
+	      {
+		strcpy (pbuf, simulator_sysroot);
+		o += strlen (simulator_sysroot);
+	      }
+
+	    for (i = 0; i + o < MAXPATHLEN; i++)
+	      {
+		pbuf[i + o]
+		  = sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
+		if (pbuf[i + o] == 0)
+		  break;
+	      }
+
+	    if (i + o == MAXPATHLEN)
+	      {
+		retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
+		break;
+	      }
+
+	    /* Intervene calls for certain files expected in the target
+               proc file system.  */
+	    if (strcmp (pbuf + strlen (simulator_sysroot),
+			"/proc/" XSTRING (TARGET_PID) "/exe") == 0)
+	      {
+		char *argv0
+		  = (STATE_PROG_ARGV (sd) != NULL
+		     ? *STATE_PROG_ARGV (sd) : NULL);
+
+		if (argv0 == NULL || *argv0 == '.')
+		  {
+		    sim_io_eprintf (sd, "Unimplemented readlink syscall "
+				    "(0x%lx: [\"%s\"], 0x%lx)\n",
+				    (unsigned long) arg1, pbuf,
+				    (unsigned long) arg2);
+		    sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				     SIM_SIGILL);
+		    break;
+		  }
+		else if (*argv0 == '/')
+		  {
+		    if (strncmp (simulator_sysroot, argv0,
+				 strlen (simulator_sysroot)) == 0)
+		      argv0 += strlen (simulator_sysroot);
+
+		    strcpy (lbuf, argv0);
+		    nchars = strlen (argv0) + 1;
+		  }
+		else
+		  {
+		    if (getcwd (lbuf, MAXPATHLEN) != NULL
+			&& strlen (lbuf) + 2 + strlen (argv0) < MAXPATHLEN)
+		      {
+			if (strncmp (simulator_sysroot, lbuf,
+				     strlen (simulator_sysroot)) == 0)
+			  lbuf += strlen (simulator_sysroot);
+
+			strcat (lbuf, "/");
+			strcat (lbuf, argv0);
+			nchars = strlen (lbuf) + 1;
+		      }
+		    else
+		      abort ();
+		  }
+	      }
+	    else
+	      nchars = readlink (pbuf, lbuf, MAXPATHLEN);
+
+	    /* We trust that the readlink result returns a *relative*
+	       link, or one already adjusted for the file-path-prefix.
+	       (We can't generally tell the difference, so we go with
+	       the easiest decision; no adjustment.)  */
+
+	    if (nchars == -1)
+	      {
+		retval = -cb_host_to_target_errno (cb, errno);
+		break;
+	      }
+
+	    if (bufsiz < nchars)
+	      nchars = bufsiz;
+
+	    if (sim_core_write_buffer (sd, current_cpu, write_map, lbuf,
+				       buf, nchars) != (unsigned int) nchars)
+	      retval = -cb_host_to_target_errno (cb, EFAULT);
+	    else
+	      retval = nchars;
+
+	    free (pbuf);
+	    free (lbuf_alloc);
+	    break;
+	  }
+
+	case TARGET_SYS_sched_getscheduler:
+	  {
+	    USI pid = arg1;
+
+	    /* FIXME: Search (other) existing threads.  */
+	    if (pid != 0 && pid != TARGET_PID)
+	      retval = -cb_host_to_target_errno (cb, ESRCH);
+	    else
+	      retval = TARGET_SCHED_OTHER;
+	    break;
+	  }
+
+	case TARGET_SYS_sched_getparam:
+	  {
+	    USI pid = arg1;
+	    USI paramp = arg2;
+
+	    /* The kernel says:
+	       struct sched_param {
+			int sched_priority;
+	       }; */
+
+	    if (pid != 0 && pid != TARGET_PID)
+	      retval = -cb_host_to_target_errno (cb, ESRCH);
+	    else
+	      {
+		/* FIXME: Save scheduler setting before threads are
+		   created too.  */
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, paramp,
+					    current_cpu->thread_data != NULL
+					    ? (current_cpu
+					       ->thread_data[threadno]
+					       .priority)
+					    : 0);
+		retval = 0;
+	      }
+	    break;
+	  }
+
+	case TARGET_SYS_sched_setparam:
+	  {
+	    USI pid = arg1;
+	    USI paramp = arg2;
+
+	    if ((pid != 0 && pid != TARGET_PID)
+		|| sim_core_read_unaligned_4 (current_cpu, pc, 0,
+					      paramp) != 0)
+	      retval = -cb_host_to_target_errno (cb, EINVAL);
+	    else
+	      retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_sched_setscheduler:
+	  {
+	    USI pid = arg1;
+	    USI policy = arg2;
+	    USI paramp = arg3;
+
+	    if ((pid != 0 && pid != TARGET_PID)
+		|| policy != TARGET_SCHED_OTHER
+		|| sim_core_read_unaligned_4 (current_cpu, pc, 0,
+					      paramp) != 0)
+	      retval = -cb_host_to_target_errno (cb, EINVAL);
+	    else
+	      /* FIXME: Save scheduler setting to be read in later
+		 sched_getparam calls.  */
+	      retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_sched_yield:
+	  /* We reschedule to the next thread after a syscall anyway, so
+	     we don't have to do anything here than to set the return
+	     value.  */
+	  retval = 0;
+	  break;
+
+	case TARGET_SYS_sched_get_priority_min:
+	case TARGET_SYS_sched_get_priority_max:
+	  if (arg1 != 0)
+	    retval = -cb_host_to_target_errno (cb, EINVAL);
+	  else
+	    retval = 0;
+	  break;
+
+	case TARGET_SYS_ugetrlimit:
+	  {
+	    unsigned int curlim, maxlim;
+	    if (arg1 != TARGET_RLIMIT_STACK && arg1 != TARGET_RLIMIT_NOFILE)
+	      {
+		retval = -cb_host_to_target_errno (cb, EINVAL);
+		break;
+	      }
+
+	    /* The kernel says:
+	       struct rlimit {
+		       unsigned long   rlim_cur;
+		       unsigned long   rlim_max;
+	       }; */
+	    if (arg1 == TARGET_RLIMIT_NOFILE)
+	      {
+		/* Sadly a very low limit.  Better not lie, though.  */
+		maxlim = curlim = MAX_CALLBACK_FDS;
+	      }
+	    else /* arg1 == TARGET_RLIMIT_STACK */
+	      {
+		maxlim = 0xffffffff;
+		curlim = 0x800000;
+	      }
+	    sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, curlim);
+	    sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, maxlim);
+	    retval = 0;
+	    break;
+	  }
+
+	case TARGET_SYS_setrlimit:
+	  if (arg1 != TARGET_RLIMIT_STACK)
+	    {
+	      retval = -cb_host_to_target_errno (cb, EINVAL);
+	      break;
+	    }
+	  /* FIXME: Save values for future ugetrlimit calls.  */
+	  retval = 0;
+	  break;
+
+	/* Provide a very limited subset of the sysctl functions, and
+	   abort for the rest. */
+	case TARGET_SYS__sysctl:
+	  {
+	    /* The kernel says:
+	       struct __sysctl_args {
+		int *name;
+		int nlen;
+		void *oldval;
+		size_t *oldlenp;
+		void *newval;
+		size_t newlen;
+		unsigned long __unused[4];
+	       }; */
+	    SI name = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1);
+	    SI name0 = name == 0
+	      ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name);
+	    SI name1 = name == 0
+	      ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name + 4);
+	    SI nlen
+	      =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 4);
+	    SI oldval
+	      =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 8);
+	    SI oldlenp
+	      =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 12);
+	    SI oldlen = oldlenp == 0
+	      ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, oldlenp);
+	    SI newval
+	      =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 16);
+	    SI newlen
+	      = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 20);
+
+	    if (name0 == TARGET_CTL_KERN && name1 == TARGET_CTL_KERN_VERSION)
+	      {
+		SI to_write = oldlen < (SI) sizeof (TARGET_UTSNAME)
+		  ? oldlen : (SI) sizeof (TARGET_UTSNAME);
+
+		sim_core_write_unaligned_4 (current_cpu, pc, 0, oldlenp,
+					    sizeof (TARGET_UTSNAME));
+
+		if (sim_core_write_buffer (sd, current_cpu, write_map,
+					   TARGET_UTSNAME, oldval,
+					   to_write)
+		    != (unsigned int) to_write)
+		  retval = -cb_host_to_target_errno (cb, EFAULT);
+		else
+		  retval = 0;
+		break;
+	      }
+
+	    sim_io_eprintf (sd, "Unimplemented _sysctl syscall "
+			    "(0x%lx: [0x%lx, 0x%lx],"
+			    " 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+			    (unsigned long) name,
+			    (unsigned long) name0,
+			    (unsigned long) name1,
+			    (unsigned long) nlen,
+			    (unsigned long) oldval,
+			    (unsigned long) oldlenp,
+			    (unsigned long) newval,
+			    (unsigned long) newlen);
+	    sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+			     SIM_SIGILL);
+	    break;
+	  }
+
+	case TARGET_SYS_exit:
+	  {
+	    /* Here for all but the last thread.  */
+	    int i;
+	    int pid
+	      = current_cpu->thread_data[threadno].threadid + TARGET_PID;
+	    int ppid
+	      = (current_cpu->thread_data[threadno].parent_threadid
+		 + TARGET_PID);
+	    int exitsig = current_cpu->thread_data[threadno].exitsig;
+
+	    /* Any children are now all orphans.  */
+	    for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
+	      if (current_cpu->thread_data[i].parent_threadid
+		  == current_cpu->thread_data[threadno].threadid)
+		/* Make getppid(2) return 1 for them, poor little ones.  */
+		current_cpu->thread_data[i].parent_threadid = -TARGET_PID + 1;
+
+	    /* Free the cpu context data.  When the parent has received
+	       the exit status, we'll clear the entry too.  */
+	    free (current_cpu->thread_data[threadno].cpu_context);
+	    current_cpu->thread_data[threadno].cpu_context = NULL;
+	    current_cpu->m1threads--;
+	    if (arg1 != 0)
+	      {
+		sim_io_eprintf (sd, "Thread %d exited with status %d\n",
+				pid, arg1);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+	      }
+
+	    /* Still, we may want to support non-zero exit values.  */
+	    current_cpu->thread_data[threadno].exitval = arg1 << 8;
+
+	    if (exitsig)
+	      deliver_signal (current_cpu, exitsig, ppid);
+	    break;
+	  }
+
+	case TARGET_SYS_clone:
+	  {
+	    int nthreads = current_cpu->m1threads + 1;
+	    void *thread_cpu_data;
+	    bfd_byte old_sp_buf[4];
+	    bfd_byte sp_buf[4];
+	    const bfd_byte zeros[4] = { 0, 0, 0, 0 };
+	    int i;
+
+	    /* That's right, the syscall clone arguments are reversed
+	       compared to sys_clone notes in clone(2) and compared to
+	       other Linux ports (i.e. it's the same order as in the
+	       clone(2) libcall).  */
+	    USI flags = arg2;
+	    USI newsp = arg1;
+
+	    if (nthreads == SIM_TARGET_MAX_THREADS)
+	      {
+		retval = -cb_host_to_target_errno (cb, EAGAIN);
+		break;
+	      }
+
+	    /* FIXME: Implement the low byte.  */
+	    if ((flags & ~TARGET_CSIGNAL) !=
+		(TARGET_CLONE_VM
+		 | TARGET_CLONE_FS
+		 | TARGET_CLONE_FILES
+		 | TARGET_CLONE_SIGHAND)
+		|| newsp == 0)
+	      {
+		sim_io_eprintf (sd,
+				"Unimplemented clone syscall (0x%lx, 0x%lx)\n",
+				(unsigned long) arg1, (unsigned long) arg2);
+		sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+				 SIM_SIGILL);
+	      }
+
+	    if (current_cpu->thread_data == NULL)
+	      make_first_thread (current_cpu);
+
+	    /* The created thread will get the new SP and a cleared R10.
+	       Since it's created out of a copy of the old thread and we
+	       don't have a set-register-function that just take the
+	       cpu_data as a parameter, we set the childs values first,
+	       and write back or overwrite them in the parent after the
+	       copy.  */
+	    (*CPU_REG_FETCH (current_cpu)) (current_cpu,
+					    H_GR_SP, old_sp_buf, 4);
+	    bfd_putl32 (newsp, sp_buf);
+	    (*CPU_REG_STORE (current_cpu)) (current_cpu,
+					    H_GR_SP, sp_buf, 4);
+	    (*CPU_REG_STORE (current_cpu)) (current_cpu,
+					    H_GR_R10, (bfd_byte *) zeros, 4);
+	    thread_cpu_data
+	      = (*current_cpu
+		 ->make_thread_cpu_data) (current_cpu,
+					  &current_cpu->cpu_data_placeholder);
+	    (*CPU_REG_STORE (current_cpu)) (current_cpu,
+					    H_GR_SP, old_sp_buf, 4);
+
+	    retval = ++current_cpu->max_threadid + TARGET_PID;
+
+	    /* Find an unused slot.  After a few threads have been created
+	       and exited, the array is expected to be a bit fragmented.
+	       We don't reuse the first entry, though, that of the
+	       original thread.  */
+	    for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
+	      if (current_cpu->thread_data[i].cpu_context == NULL
+		  /* Don't reuse a zombied entry.  */
+		  && current_cpu->thread_data[i].threadid == 0)
+		break;
+
+	    memcpy (&current_cpu->thread_data[i],
+		    &current_cpu->thread_data[threadno],
+		    sizeof (current_cpu->thread_data[i]));
+	    current_cpu->thread_data[i].cpu_context = thread_cpu_data;
+	    current_cpu->thread_data[i].cpu_context_atsignal = NULL;
+	    current_cpu->thread_data[i].threadid = current_cpu->max_threadid;
+	    current_cpu->thread_data[i].parent_threadid
+	      = current_cpu->thread_data[threadno].threadid;
+	    current_cpu->thread_data[i].pipe_read_fd = 0;
+	    current_cpu->thread_data[i].pipe_write_fd = 0;
+	    current_cpu->thread_data[i].at_syscall = 0;
+	    current_cpu->thread_data[i].sigpending = 0;
+	    current_cpu->thread_data[i].sigsuspended = 0;
+	    current_cpu->thread_data[i].exitsig = flags & TARGET_CSIGNAL;
+	    current_cpu->m1threads = nthreads;
+	    break;
+	  }
+
+	/* Better watch these in case they do something necessary.  */
+	case TARGET_SYS_socketcall:
+	  retval = -cb_host_to_target_errno (cb, ENOSYS);
+	  break;
+
+	unimplemented_syscall:
+	default:
+	  sim_io_eprintf (sd, "Unimplemented syscall: %d "
+			  "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", callnum,
+			  arg1, arg2, arg3, arg4, arg5, arg6);
+	  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
+			   SIM_SIGILL);
+	}
+    }
+
+  /* A system call is a rescheduling point.  For the time being, we don't
+     reschedule anywhere else.  */
+  if (current_cpu->m1threads != 0
+      /* We need to schedule off from an exiting thread that is the
+	 second-last one.  */
+      || (current_cpu->thread_data != NULL
+	  && current_cpu->thread_data[threadno].cpu_context == NULL))
+    {
+      bfd_byte retval_buf[4];
+
+      current_cpu->thread_data[threadno].last_execution
+	= TARGET_TIME_MS (current_cpu);
+      bfd_putl32 (retval, retval_buf);
+      (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
+
+      current_cpu->thread_data[threadno].at_syscall = 1;
+      reschedule (current_cpu);
+
+      (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
+      retval = bfd_getl32 (retval_buf);
+    }
+
+  return retval;
+}
+
+/* Callback from simulator write saying that the pipe at (reader, writer)
+   is now non-empty (so the writer should wait until the pipe is empty, at
+   least not write to this or any other pipe).  Simplest is to just wait
+   until the pipe is empty.  */
+
+static void
+cris_pipe_nonempty (host_callback *cb ATTRIBUTE_UNUSED,
+		    int reader, int writer)
+{
+  SIM_CPU *cpu = current_cpu_for_cb_callback;
+  const bfd_byte zeros[4] = { 0, 0, 0, 0 };
+
+  /* It's the current thread: we just have to re-run the current
+     syscall instruction (presumably "break 13") and change the syscall
+     to the special simulator-wait code.  Oh, and set a marker that
+     we're waiting, so we can disambiguate the special call from a
+     program error.
+
+     This function may be called multiple times between cris_pipe_empty,
+     but we must avoid e.g. decreasing PC every time.  Check fd markers
+     to tell.  */
+  if (cpu->thread_data == NULL)
+    {
+      sim_io_eprintf (CPU_STATE (cpu),
+		      "Terminating simulation due to writing pipe rd:wr %d:%d"
+		      " from one single thread\n", reader, writer);
+      sim_engine_halt (CPU_STATE (cpu), cpu,
+		       NULL, sim_pc_get (cpu), sim_stopped, SIM_SIGILL);
+    }
+  else if (cpu->thread_data[cpu->threadno].pipe_write_fd == 0)
+    {
+      cpu->thread_data[cpu->threadno].pipe_write_fd = writer;
+      cpu->thread_data[cpu->threadno].pipe_read_fd = reader;
+      /* FIXME: We really shouldn't change registers other than R10 in
+	 syscalls (like R9), here or elsewhere.  */
+      (*CPU_REG_STORE (cpu)) (cpu, H_GR_R9, (bfd_byte *) zeros, 4);
+      sim_pc_set (cpu, sim_pc_get (cpu) - 2);
+    }
+}
+
+/* Callback from simulator close or read call saying that the pipe at
+   (reader, writer) is now empty (so the writer can write again, perhaps
+   leave a waiting state).  If there are bytes remaining, they couldn't be
+   consumed (perhaps due to the pipe closing).  */
+
+static void
+cris_pipe_empty (host_callback *cb,
+		 int reader ATTRIBUTE_UNUSED,
+		 int writer)
+{
+  int i;
+  SIM_CPU *cpu = current_cpu_for_cb_callback;
+  bfd_byte r10_buf[4];
+  int remaining = cb->pipe_buffer[writer].size;
+
+  /* We need to find the thread that waits for this pipe.  */
+  for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
+    if (cpu->thread_data[i].cpu_context
+	&& cpu->thread_data[i].pipe_write_fd == writer)
+      {
+	int retval;
+	/* Temporarily switch to this cpu context, so we can change the
+	   PC by ordinary calls.  */
+
+	memcpy (cpu->thread_data[cpu->threadno].cpu_context,
+		&cpu->cpu_data_placeholder,
+		cpu->thread_cpu_data_size);
+	memcpy (&cpu->cpu_data_placeholder,
+		cpu->thread_data[i].cpu_context,
+		cpu->thread_cpu_data_size);
+
+	/* The return value is supposed to contain the number of written
+	   bytes, which is the number of bytes requested and returned at
+	   the write call.  We subtract the remaining bytes from that,
+	   but making sure we still get a positive number.
+	   The return value may also be a negative number; an error
+	   value.  We cover this case by comparing against remaining,
+	   which is always >= 0.  */
+	(*CPU_REG_FETCH (cpu)) (cpu, H_GR_R10, r10_buf, 4);
+	retval = (int) bfd_getl_signed_32 (r10_buf);
+	if (retval >= remaining)
+	  bfd_putl32 (retval - remaining, r10_buf);
+	(*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
+
+	sim_pc_set (cpu, sim_pc_get (cpu) + 2);
+	memcpy (cpu->thread_data[i].cpu_context,
+		&cpu->cpu_data_placeholder,
+		cpu->thread_cpu_data_size);
+	memcpy (&cpu->cpu_data_placeholder,
+		cpu->thread_data[cpu->threadno].cpu_context,
+		cpu->thread_cpu_data_size);
+	cpu->thread_data[i].pipe_read_fd = 0;
+	cpu->thread_data[i].pipe_write_fd = 0;
+	return;
+      }
+
+  abort ();
+}
+
+/* We have a simulator-specific notion of time.  See TARGET_TIME.  */
+
+static long
+cris_time (host_callback *cb ATTRIBUTE_UNUSED, long *t)
+{
+  long retval = TARGET_TIME (current_cpu_for_cb_callback);
+  if (t)
+    *t = retval;
+  return retval;
+}
+
+/* Set target-specific callback data. */
+
+void
+cris_set_callbacks (host_callback *cb)
+{
+  /* Yeargh, have to cast away constness to avoid warnings.  */
+  cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_map;
+  cb->errno_map = (CB_TARGET_DEFS_MAP *) errno_map;
+
+  /* The kernel stat64 layout.  If we see a file > 2G, the "long"
+     parameter to cb_store_target_endian will make st_size negative.
+     Similarly for st_ino.  FIXME: Find a 64-bit type, and use it
+     *unsigned*, and/or add syntax for signed-ness.  */
+  cb->stat_map = stat_map;
+  cb->open_map = (CB_TARGET_DEFS_MAP *) open_map;
+  cb->pipe_nonempty = cris_pipe_nonempty;
+  cb->pipe_empty = cris_pipe_empty;
+  cb->time = cris_time;
+}
+
+/* Process an address exception.  */
+
+void
+cris_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
+		  unsigned int map, int nr_bytes, address_word addr,
+		  transfer_type transfer, sim_core_signals sig)
+{
+  sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
+		   transfer, sig);
+}

brgds, H-P


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]