diff --git a/sim/m32r/ChangeLog b/sim/m32r/ChangeLog
index f726c3e..09d2c05 100644
--- a/sim/m32r/ChangeLog
+++ b/sim/m32r/ChangeLog
@@ -1,5 +1,21 @@
 2015-12-25  Mike Frysinger  <vapier@gentoo.org>
 
+	* configure.ac (SIM_AC_OPTION_HARDWARE): Add m32r_cache & m32r_uart.
+	* configure: Regenerate.
+	* devices.c: Delete file.
+	* dv-m32r_cache.c, dv-m32r_cache.h: New cache model with logic from
+	devices.c.
+	* dv-m32r_uart.c, dv-m32r_uart.h: New uart model with logic from
+	devices.c.
+	* m32r-sim.h: Move cache defines to dv-m32r_cache.h and uart defines
+	to dv-m32r_uart.h.
+	* Makefile.in (SIM_OBJS): Delete devices.o.
+	* sim-if.c: Include dv-m32r_uart.h.
+	(sim_open): Replace sim_core_attach call with sim_hw_parse calls.
+	* tconfig.h: Delete file.
+
+2015-12-25  Mike Frysinger  <vapier@gentoo.org>
+
 	* Makefile.in (SIM_OBJS): Delete sim-model.o.
 
 2015-12-25  Mike Frysinger  <vapier@gentoo.org>
diff --git a/sim/m32r/Makefile.in b/sim/m32r/Makefile.in
index ca5c49d..d57a984 100644
--- a/sim/m32r/Makefile.in
+++ b/sim/m32r/Makefile.in
@@ -33,8 +33,7 @@ SIM_OBJS = \
 	$(M32R_OBJS) \
 	$(M32RX_OBJS) \
 	$(M32R2_OBJS) \
-	$(TRAPS_OBJ) \
-	devices.o
+	$(TRAPS_OBJ)
 
 # Extra headers included by sim-main.h.
 SIM_EXTRA_DEPS = \
diff --git a/sim/m32r/configure b/sim/m32r/configure
index 00d3316..6b9c76e 100755
--- a/sim/m32r/configure
+++ b/sim/m32r/configure
@@ -13400,12 +13400,12 @@ fi
 
 
 
-if test """"; then
-  hardware=""""
+if test ""; then
+  hardware=""
 else
   hardware="cfi core pal glue"
 fi
-hardware="$hardware """
+hardware="$hardware m32r_cache m32r_uart"
 
 sim_hw_cflags="-DWITH_HW=1"
 sim_hw="$hardware"
diff --git a/sim/m32r/configure.ac b/sim/m32r/configure.ac
index 56a7caa..d92e62b 100644
--- a/sim/m32r/configure.ac
+++ b/sim/m32r/configure.ac
@@ -27,6 +27,6 @@ SIM_AC_OPTION_CGEN_MAINT
 AC_SUBST(traps_obj)
 AC_SUBST(sim_extra_cflags)
 
-SIM_AC_OPTION_HARDWARE(yes,"","")
+SIM_AC_OPTION_HARDWARE(yes,,m32r_cache m32r_uart)
 
 SIM_AC_OUTPUT
diff --git a/sim/m32r/devices.c b/sim/m32r/devices.c
deleted file mode 100644
index 62a9b6f..0000000
--- a/sim/m32r/devices.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* m32r device support
-   Copyright (C) 1997-2015 Free Software Foundation, Inc.
-   Contributed by Cygnus Solutions.
-
-This file is part of GDB, the GNU debugger.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include "sim-main.h"
-
-#ifdef HAVE_DV_SOCKSER
-#include "dv-sockser.h"
-#endif
-
-/* Handling the MSPR register is done by creating a device in the core
-   mapping that winds up here.  */
-
-device m32r_devices;
-
-int
-device_io_read_buffer (device *me, void *source, int space,
-		       address_word addr, unsigned nr_bytes,
-		       SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
-{
-  if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
-    return nr_bytes;
-
-#ifdef HAVE_DV_SOCKSER
-  if (addr == UART_INCHAR_ADDR)
-    {
-      int c = dv_sockser_read (sd);
-      if (c == -1)
-	return 0;
-      *(char *) source = c;
-      return 1;
-    }
-  if (addr == UART_STATUS_ADDR)
-    {
-      int status = dv_sockser_status (sd);
-      unsigned char *p = source;
-      p[0] = 0;
-      p[1] = (((status & DV_SOCKSER_INPUT_EMPTY)
-#ifdef UART_INPUT_READY0
-	       ? UART_INPUT_READY : 0)
-#else
-	       ? 0 : UART_INPUT_READY)
-#endif
-	      + ((status & DV_SOCKSER_OUTPUT_EMPTY) ? UART_OUTPUT_READY : 0));
-      return 2;
-    }
-#endif
-
-  return nr_bytes;
-}
-
-int
-device_io_write_buffer (device *me, const void *source, int space,
-			address_word addr, unsigned nr_bytes,
-			SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
-{
-#if WITH_SCACHE
-  /* MSPR support is deprecated but is kept in for upward compatibility
-     with existing overlay support.  */
-  if (addr == MSPR_ADDR)
-    {
-      if ((*(const char *) source & MSPR_PURGE) != 0)
-	scache_flush (sd);
-      return nr_bytes;
-    }
-  if (addr == MCCR_ADDR)
-    {
-      if ((*(const char *) source & MCCR_CP) != 0)
-	scache_flush (sd);
-      return nr_bytes;
-    }
-#endif
-
-  if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
-    return nr_bytes;
-
-#ifdef HAVE_DV_SOCKSER
-  if (addr == UART_OUTCHAR_ADDR)
-    {
-      int rc = dv_sockser_write (sd, *(char *) source);
-      return rc == 1;
-    }
-#endif
-
-  return nr_bytes;
-}
diff --git a/sim/m32r/dv-m32r_cache.c b/sim/m32r/dv-m32r_cache.c
new file mode 100644
index 0000000..dbef585
--- /dev/null
+++ b/sim/m32r/dv-m32r_cache.c
@@ -0,0 +1,96 @@
+/* Handle cache related addresses.
+
+   Copyright (C) 1996-2015 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions and Mike Frysinger.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+
+#include "sim-main.h"
+#include "hw-main.h"
+
+#include "dv-m32r_cache.h"
+
+struct m32r_cache_hw
+{
+};
+
+static unsigned
+cris_io_write_buffer (struct hw *me, const void *source,
+		      int space, address_word addr, unsigned nr_bytes)
+{
+  SIM_DESC sd = hw_system (me);
+
+#if WITH_SCACHE
+  /* MSPR support is deprecated but is kept in for upward compatibility
+     with existing overlay support.  */
+  switch (addr)
+    {
+    case MSPR_ADDR:
+      if ((*(const char *) source & MSPR_PURGE) != 0)
+	scache_flush (sd);
+      break;
+
+    case MCCR_ADDR:
+      if ((*(const char *) source & MCCR_CP) != 0)
+	scache_flush (sd);
+      break;
+    }
+#endif
+
+  return nr_bytes;
+}
+
+static void
+attach_regs (struct hw *me, struct m32r_cache_hw *hw)
+{
+  address_word attach_address;
+  int attach_space;
+  unsigned attach_size;
+  reg_property_spec reg;
+
+  if (hw_find_property (me, "reg") == NULL)
+    hw_abort (me, "Missing \"reg\" property");
+
+  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
+    hw_abort (me, "\"reg\" property must contain three addr/size entries");
+
+  hw_unit_address_to_attach_address (hw_parent (me),
+				     &reg.address,
+				     &attach_space, &attach_address, me);
+  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
+
+  hw_attach_address (hw_parent (me),
+		     0, attach_space, attach_address, attach_size, me);
+}
+
+static void
+m32r_cache_finish (struct hw *me)
+{
+  struct m32r_cache_hw *hw;
+
+  hw = HW_ZALLOC (me, struct m32r_cache_hw);
+  set_hw_data (me, hw);
+  set_hw_io_write_buffer (me, cris_io_write_buffer);
+
+  attach_regs (me, hw);
+}
+
+const struct hw_descriptor dv_m32r_cache_descriptor[] = {
+  { "m32r_cache", m32r_cache_finish, },
+  { NULL },
+};
diff --git a/sim/m32r/dv-m32r_cache.h b/sim/m32r/dv-m32r_cache.h
new file mode 100644
index 0000000..49d41c7
--- /dev/null
+++ b/sim/m32r/dv-m32r_cache.h
@@ -0,0 +1,48 @@
+/* Handle cache related addresses.
+
+   Copyright (C) 1996-2015 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions and Mike Frysinger.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef DV_M32R_CACHE_H
+#define DV_M32R_CACHE_H
+
+/* Support for the MSPR register (Cache Purge Control Register)
+   and the MCCR register (Cache Control Register) are needed in order for
+   overlays to work correctly with the scache.
+   MSPR no longer exists but is supported for upward compatibility with
+   early overlay support.  */
+
+/* Cache Purge Control (only exists on early versions of chips) */
+#define MSPR_ADDR 0xfffffff7
+#define MSPR_PURGE 1
+
+/* Lock Control Register (not supported) */
+#define MLCR_ADDR 0xfffffff7
+#define MLCR_LM 1
+
+/* Power Management Control Register (not supported) */
+#define MPMR_ADDR 0xfffffffb
+
+/* Cache Control Register */
+#define MCCR_ADDR 0xffffffff
+#define MCCR_CP 0x80
+/* not supported */
+#define MCCR_CM0 2
+#define MCCR_CM1 1
+
+#endif
diff --git a/sim/m32r/dv-m32r_uart.c b/sim/m32r/dv-m32r_uart.c
new file mode 100644
index 0000000..794280f
--- /dev/null
+++ b/sim/m32r/dv-m32r_uart.c
@@ -0,0 +1,143 @@
+/* UART model.
+
+   Copyright (C) 1996-2015 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions and Mike Frysinger.
+
+   This file is part of simulators.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+
+#include "sim-main.h"
+#include "hw-main.h"
+
+#include "dv-sockser.h"
+#include "dv-m32r_uart.h"
+
+struct m32r_uart
+{
+};
+
+static unsigned
+m32r_uart_io_write_buffer (struct hw *me, const void *source,
+			   int space, address_word addr, unsigned nr_bytes)
+{
+  SIM_DESC sd = hw_system (me);
+  struct m32r_uart *uart = hw_data (me);
+  int status = dv_sockser_status (sd);
+
+  switch (addr)
+    {
+    case UART_OUTCHAR_ADDR:
+      if (status & DV_SOCKSER_DISCONNECTED)
+	{
+	  sim_io_write_stdout (sd, source, nr_bytes);
+	  sim_io_flush_stdout (sd);
+	}
+      else
+	{
+	  /* Normalize errors to a value of 0.  */
+	  int ret = dv_sockser_write_buffer (sd, source, nr_bytes);
+	  if (ret < 0)
+	    nr_bytes = 0;
+	}
+      break;
+    }
+
+  return nr_bytes;
+}
+
+static unsigned
+m32r_uart_io_read_buffer (struct hw *me, void *dest,
+			  int space, address_word addr, unsigned nr_bytes)
+{
+  SIM_DESC sd = hw_system (me);
+  struct m32r_uart *uart = hw_data (me);
+  int status = dv_sockser_status (sd);
+
+  switch (addr)
+    {
+    case UART_INCHAR_ADDR:
+      if (status & DV_SOCKSER_DISCONNECTED)
+	{
+	  int ret = sim_io_poll_read (sd, 0/*STDIN*/, dest, 1);
+	  return (ret < 0) ? 0 : 1;
+        }
+      else
+	{
+	  char *buffer = dest;
+	  buffer[0] = dv_sockser_read (sd);
+	  return 1;
+	}
+    case UART_STATUS_ADDR:
+      {
+	unsigned char *p = dest;
+	p[0] = 0;
+	p[1] = (((status & DV_SOCKSER_INPUT_EMPTY)
+#ifdef UART_INPUT_READY0
+		 ? UART_INPUT_READY : 0)
+#else
+		 ? 0 : UART_INPUT_READY)
+#endif
+		+ ((status & DV_SOCKSER_OUTPUT_EMPTY) ? UART_OUTPUT_READY : 0));
+	return 2;
+      }
+    }
+
+  return nr_bytes;
+}
+
+static void
+attach_m32r_uart_regs (struct hw *me, struct m32r_uart *uart)
+{
+  address_word attach_address;
+  int attach_space;
+  unsigned attach_size;
+  reg_property_spec reg;
+
+  if (hw_find_property (me, "reg") == NULL)
+    hw_abort (me, "Missing \"reg\" property");
+
+  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
+    hw_abort (me, "\"reg\" property must contain three addr/size entries");
+
+  hw_unit_address_to_attach_address (hw_parent (me),
+				     &reg.address,
+				     &attach_space, &attach_address, me);
+  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
+
+  hw_attach_address (hw_parent (me),
+		     0, attach_space, attach_address, attach_size, me);
+}
+
+static void
+m32r_uart_finish (struct hw *me)
+{
+  struct m32r_uart *uart;
+
+  uart = HW_ZALLOC (me, struct m32r_uart);
+
+  set_hw_data (me, uart);
+  set_hw_io_read_buffer (me, m32r_uart_io_read_buffer);
+  set_hw_io_write_buffer (me, m32r_uart_io_write_buffer);
+
+  attach_m32r_uart_regs (me, uart);
+}
+
+const struct hw_descriptor dv_m32r_uart_descriptor[] =
+{
+  {"m32r_uart", m32r_uart_finish,},
+  {NULL, NULL},
+};
diff --git a/sim/m32r/dv-m32r_uart.h b/sim/m32r/dv-m32r_uart.h
new file mode 100644
index 0000000..c844c2a
--- /dev/null
+++ b/sim/m32r/dv-m32r_uart.h
@@ -0,0 +1,47 @@
+/* UART model.
+
+   Copyright (C) 1996-2015 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions and Mike Frysinger.
+
+   This file is part of simulators.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef DV_M32R_UART_H
+#define DV_M32R_UART_H
+
+/* Should move these settings to a flag to the uart device, and the adresses to
+   the sim-model framework.  */
+
+/* Serial device addresses.  */
+#ifdef M32R_EVA /* orig eva board, no longer supported */
+#define UART_BASE_ADDR		0xff102000
+#define UART_INCHAR_ADDR	0xff102013
+#define UART_OUTCHAR_ADDR	0xff10200f
+#define UART_STATUS_ADDR	0xff102006
+/* Indicate ready bit is inverted.  */
+#define UART_INPUT_READY0
+#else
+/* These are the values for the MSA2000 board.
+   ??? Will eventually need to move this to a config file.  */
+#define UART_BASE_ADDR		0xff004000
+#define UART_INCHAR_ADDR	0xff004009
+#define UART_OUTCHAR_ADDR	0xff004007
+#define UART_STATUS_ADDR	0xff004002
+#endif
+
+#define UART_INPUT_READY	0x4
+#define UART_OUTPUT_READY	0x1
+
+#endif
diff --git a/sim/m32r/m32r-sim.h b/sim/m32r/m32r-sim.h
index cb28e1d..14748b7 100644
--- a/sim/m32r/m32r-sim.h
+++ b/sim/m32r/m32r-sim.h
@@ -153,58 +153,6 @@ do { \
 #define TRAP_SYSCALL	0
 #define TRAP_BREAKPOINT	1
 
-/* Support for the MSPR register (Cache Purge Control Register)
-   and the MCCR register (Cache Control Register) are needed in order for
-   overlays to work correctly with the scache.
-   MSPR no longer exists but is supported for upward compatibility with
-   early overlay support.  */
-
-/* Cache Purge Control (only exists on early versions of chips) */
-#define MSPR_ADDR 0xfffffff7
-#define MSPR_PURGE 1
-
-/* Lock Control Register (not supported) */
-#define MLCR_ADDR 0xfffffff7
-#define MLCR_LM 1
-
-/* Power Management Control Register (not supported) */
-#define MPMR_ADDR 0xfffffffb
-
-/* Cache Control Register */
-#define MCCR_ADDR 0xffffffff
-#define MCCR_CP 0x80
-/* not supported */
-#define MCCR_CM0 2
-#define MCCR_CM1 1
-
-/* Serial device addresses.  */
-#ifdef M32R_EVA /* orig eva board, no longer supported */
-#define UART_INCHAR_ADDR	0xff102013
-#define UART_OUTCHAR_ADDR	0xff10200f
-#define UART_STATUS_ADDR	0xff102006
-/* Indicate ready bit is inverted.  */
-#define UART_INPUT_READY0
-#else
-/* These are the values for the MSA2000 board.
-   ??? Will eventually need to move this to a config file.  */
-#define UART_INCHAR_ADDR	0xff004009
-#define UART_OUTCHAR_ADDR	0xff004007
-#define UART_STATUS_ADDR	0xff004002
-#endif
-
-#define UART_INPUT_READY	0x4
-#define UART_OUTPUT_READY	0x1
-
-/* Start address and length of all device support.  */
-#define M32R_DEVICE_ADDR	0xff000000
-#define M32R_DEVICE_LEN		0x00ffffff
-
-/* sim_core_attach device argument.  */
-extern device m32r_devices;
-
-/* FIXME: Temporary, until device support ready.  */
-struct _device { int foo; };
-
 /* Handle the trap insn.  */
 USI m32r_trap (SIM_CPU *, PCADDR, int);
 
diff --git a/sim/m32r/sim-if.c b/sim/m32r/sim-if.c
index 5fd8de0..639976d 100644
--- a/sim/m32r/sim-if.c
+++ b/sim/m32r/sim-if.c
@@ -33,6 +33,8 @@
 #include <stdlib.h>
 #endif
 
+#include "dv-m32r_uart.h"
+
 static void free_state (SIM_DESC);
 static void print_m32r_misc_cpu (SIM_CPU *cpu, int verbose);
 
@@ -106,16 +108,10 @@ sim_open (kind, callback, abfd, argv)
   /* Allocate a handler for the control registers and other devices
      if no memory for that range has been allocated by the user.
      All are allocated in one chunk to keep things from being
-     unnecessarily complicated.  */
-  if (sim_core_read_buffer (sd, NULL, read_map, &c, M32R_DEVICE_ADDR, 1) == 0)
-    sim_core_attach (sd, NULL,
-		     0 /*level*/,
-		     access_read_write,
-		     0 /*space ???*/,
-		     M32R_DEVICE_ADDR, M32R_DEVICE_LEN /*nr_bytes*/,
-		     0 /*modulo*/,
-		     &m32r_devices,
-		     NULL /*buffer*/);
+     unnecessarily complicated.
+     TODO: Move these to the sim-model framework.  */
+  sim_hw_parse (sd, "/core/%s/reg %#x %i", "m32r_uart", UART_BASE_ADDR, 0x100);
+  sim_hw_parse (sd, "/core/%s/reg %#x %i", "m32r_cache", 0xfffffff0, 0x10);
 
   /* Allocate core managed memory if none specified by user.
      Use address 4 here in case the user wanted address 0 unmapped.  */
diff --git a/sim/m32r/tconfig.h b/sim/m32r/tconfig.h
deleted file mode 100644
index 42c538c..0000000
--- a/sim/m32r/tconfig.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* M32R target configuration file.  -*- C -*- */
-
-#ifndef M32R_TCONFIG_H
-#define M32R_TCONFIG_H
-
-/* For MSPR support.  FIXME: revisit.  */
-#define WITH_DEVICES 1
-
-#endif /* M32R_TCONFIG_H */
