Emulate non-native widths and optionally byte swap

From: Blue Swirl <blauwirbel@gmail.com>

Currently the devices handle non-native I/O accesses by themselves. Handle
them at higher level, so device code can be simplified.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---

 cpu-all.h |   18 ++
 exec.c    |  713 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 731 insertions(+), 0 deletions(-)


diff --git a/cpu-all.h b/cpu-all.h
index 0df54b6..d304296 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -918,6 +918,24 @@ int cpu_register_io_memory(int io_index,
                            void *opaque);
 void cpu_unregister_io_memory(int table_address);
 
+/* Register IO memory with optional emulation for other bus widths
+   than native, optionally byte swapped */
+int cpu_register_8bit_io_memory(int io_index,
+                                CPUReadMemoryFunc *mem_read,
+                                CPUWriteMemoryFunc *mem_write,
+                                void *opaque, int emulate_other_widths,
+                                int is_le);
+int cpu_register_16bit_io_memory(int io_index,
+                                 CPUReadMemoryFunc *mem_read,
+                                 CPUWriteMemoryFunc *mem_write,
+                                 void *opaque, int emulate_other_widths,
+                                 int is_le);
+int cpu_register_32bit_io_memory(int io_index,
+                                 CPUReadMemoryFunc *mem_read,
+                                 CPUWriteMemoryFunc *mem_write,
+                                 void *opaque, int emulate_other_widths,
+                                 int is_le);
+
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write);
 static inline void cpu_physical_memory_read(target_phys_addr_t addr,
diff --git a/exec.c b/exec.c
index c649381..2eae077 100644
--- a/exec.c
+++ b/exec.c
@@ -54,6 +54,7 @@
 
 //#define DEBUG_IOPORT
 //#define DEBUG_SUBPAGE
+//#define DEBUG_EMULATED_IO
 
 #if !defined(CONFIG_USER_ONLY)
 /* TB consistency checks only implemented for usermode emulation.  */
@@ -209,6 +210,12 @@ typedef struct subpage_t {
     ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
 } subpage_t;
 
+typedef struct emulated_io {
+    CPUReadMemoryFunc *mem_read;
+    CPUWriteMemoryFunc *mem_write;
+    void *opaque;
+} emulated_io;
+
 #ifdef _WIN32
 static void map_exec(void *addr, long size)
 {
@@ -2996,6 +3003,712 @@ static int get_free_io_mem_idx(void)
     return -1;
 }
 
+/* Emulation for non-native accesses for 8 bit devices */
+static uint32_t emulated_readb_b(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writeb_b(void *opaque, target_phys_addr_t addr,
+                              uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, val);
+}
+
+static uint32_t emulated_readw_b_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr);
+    ret |= s->mem_read(s->opaque, addr + 1) << 8;
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readw_b_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr) << 8;
+    ret |= s->mem_read(s->opaque, addr + 1);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writew_b_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, val);
+    s->mem_write(s->opaque, addr + 1, val >> 8);
+}
+
+static void emulated_writew_b_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, val >> 8);
+    s->mem_write(s->opaque, addr + 1, val);
+}
+
+static uint32_t emulated_readl_b_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr);
+    ret |= s->mem_read(s->opaque, addr + 1) << 8;
+    ret |= s->mem_read(s->opaque, addr + 2) << 16;
+    ret |= s->mem_read(s->opaque, addr + 3) << 24;
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readl_b_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr) << 24;
+    ret |= s->mem_read(s->opaque, addr + 1) << 16;
+    ret |= s->mem_read(s->opaque, addr + 2) << 8;
+    ret |= s->mem_read(s->opaque, addr + 3);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writel_b_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, val);
+    s->mem_write(s->opaque, addr + 1, val >> 8);
+    s->mem_write(s->opaque, addr + 2, val >> 16);
+    s->mem_write(s->opaque, addr + 3, val >> 24);
+}
+
+static void emulated_writel_b_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, val >> 24);
+    s->mem_write(s->opaque, addr + 1, val >> 16);
+    s->mem_write(s->opaque, addr + 2, val >> 8);
+    s->mem_write(s->opaque, addr + 3, val);
+}
+
+int cpu_register_8bit_io_memory(int io_index,
+                                CPUReadMemoryFunc *mem_read,
+                                CPUWriteMemoryFunc *mem_write,
+                                void *opaque, int emulate_other_widths,
+                                int is_le)
+{
+    if (io_index <= 0) {
+        io_index = get_free_io_mem_idx();
+        if (io_index == -1)
+            return io_index;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+
+    if (emulate_other_widths) {
+        emulated_io *s;
+
+        s = qemu_mallocz(sizeof(emulated_io));
+
+        io_mem_read[io_index][0] = emulated_readb_b;
+        io_mem_write[io_index][0] = emulated_writeb_b;
+
+        if (is_le) {
+            io_mem_read[io_index][1] = emulated_readw_b_le;
+            io_mem_write[io_index][1] = emulated_writew_b_le;
+            io_mem_read[io_index][2] = emulated_readl_b_le;
+            io_mem_write[io_index][2] = emulated_writel_b_le;
+        } else {
+            io_mem_read[io_index][1] = emulated_readw_b_be;
+            io_mem_write[io_index][1] = emulated_writew_b_be;
+            io_mem_read[io_index][2] = emulated_readl_b_be;
+            io_mem_write[io_index][2] = emulated_writel_b_be;
+        }
+        s->opaque = opaque;
+        s->mem_read = mem_read;
+        s->mem_write = mem_write;
+        io_mem_opaque[io_index] = s;
+    } else {
+        io_mem_read[io_index][0] = mem_read;
+        io_mem_write[io_index][0] = mem_write;
+        io_mem_opaque[io_index] = opaque;
+    }
+
+    return io_index << IO_MEM_SHIFT;
+}
+
+/* Emulation for non-native accesses for 16 bit devices */
+static uint32_t emulated_readb_w_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr & ~1);
+    switch (addr & 1) {
+    case 0:
+        break;
+    case 1:
+        ret >>= 8;
+        break;
+    }
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readb_w_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr & ~1);
+    switch (addr & 1) {
+    case 0:
+        ret >>= 8;
+        break;
+    case 1:
+        break;
+    }
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writeb_w_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+    uint32_t orig_val;
+
+    orig_val = s->mem_read(s->opaque, addr & ~1);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " orig_val %08x => val %08x\n", __func__,
+           addr, orig_val, val);
+#endif
+    switch (addr & 1) {
+    case 0:
+        orig_val &= 0xff00;
+        break;
+    case 1:
+        orig_val &= 0x00ff;
+        val <<= 8;
+        break;
+    }
+    val |= orig_val;
+    s->mem_write(s->opaque, addr & ~1, val);
+}
+
+static void emulated_writeb_w_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+    uint32_t orig_val;
+
+    orig_val = s->mem_read(s->opaque, addr & ~1);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " orig_val %08x => val %08x\n", __func__,
+           addr, orig_val, val);
+#endif
+    switch (addr & 1) {
+    case 0:
+        orig_val &= 0x00ff;
+        val <<= 8;
+        break;
+    case 1:
+        orig_val &= 0xff00;
+        break;
+    }
+    val |= orig_val;
+    s->mem_write(s->opaque, addr & ~1, val);
+}
+
+static uint32_t emulated_readw_w_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = cpu_to_le16(s->mem_read(s->opaque, addr & ~1));
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readw_w_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = cpu_to_be16(s->mem_read(s->opaque, addr & ~1));
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writew_w_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, le16_to_cpu(val));
+}
+
+static void emulated_writew_w_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, be16_to_cpu(val));
+}
+
+static uint32_t emulated_readl_w_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr & 1);
+    ret |= s->mem_read(s->opaque, (addr & 1) + 2) << 16;
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readl_w_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr & 1) << 16;
+    ret |= s->mem_read(s->opaque, (addr & 1) + 2);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writel_w_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, (addr & 1), val);
+    s->mem_write(s->opaque, (addr & 1) + 2, val >> 16);
+}
+
+static void emulated_writel_w_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, (addr & 1), val >> 16);
+    s->mem_write(s->opaque, (addr & 1) + 2, val);
+}
+
+int cpu_register_16bit_io_memory(int io_index,
+                                 CPUReadMemoryFunc *mem_read,
+                                 CPUWriteMemoryFunc *mem_write,
+                                 void *opaque, int emulate_other_widths,
+                                 int is_le)
+{
+    if (io_index <= 0) {
+        io_index = get_free_io_mem_idx();
+        if (io_index == -1)
+            return io_index;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+
+    if (emulate_other_widths) {
+        emulated_io *s;
+
+        s = qemu_mallocz(sizeof(emulated_io));
+
+        if (is_le) {
+            io_mem_read[io_index][0] = emulated_readb_w_le;
+            io_mem_write[io_index][0] = emulated_writeb_w_le;
+            io_mem_read[io_index][1] = emulated_readw_w_le;
+            io_mem_write[io_index][1] = emulated_writew_w_le;
+            io_mem_read[io_index][2] = emulated_readl_w_le;
+            io_mem_write[io_index][2] = emulated_writel_w_le;
+        } else {
+            io_mem_read[io_index][0] = emulated_readb_w_be;
+            io_mem_write[io_index][0] = emulated_writeb_w_be;
+            io_mem_read[io_index][1] = emulated_readw_w_be;
+            io_mem_write[io_index][1] = emulated_writew_w_be;
+            io_mem_read[io_index][2] = emulated_readl_w_be;
+            io_mem_write[io_index][2] = emulated_writel_w_be;
+        }
+        s->opaque = opaque;
+        s->mem_read = mem_read;
+        s->mem_write = mem_write;
+        io_mem_opaque[io_index] = s;
+    } else {
+        io_mem_read[io_index][1] = mem_read;
+        io_mem_write[io_index][1] = mem_write;
+        io_mem_opaque[io_index] = opaque;
+    }
+
+    return io_index << IO_MEM_SHIFT;
+}
+
+/* Emulation for non-native accesses for 32 bit devices */
+static uint32_t emulated_readb_l_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr & ~3);
+    switch (addr & 3) {
+    case 0:
+        break;
+    case 1:
+        ret >>= 8;
+        break;
+    case 2:
+        ret >>= 16;
+        break;
+    case 3:
+        ret >>= 24;
+        break;
+    }
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readb_l_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = s->mem_read(s->opaque, addr & ~3);
+    switch (addr & 3) {
+    case 0:
+        ret >>= 24;
+        break;
+    case 1:
+        ret >>= 16;
+        break;
+    case 2:
+        ret >>= 8;
+        break;
+    case 3:
+        break;
+    }
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writeb_l_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+    uint32_t orig_val;
+
+    orig_val = s->mem_read(s->opaque, addr & ~3);
+    switch (addr & 3) {
+    case 0:
+        orig_val &= 0xffffff00;
+        break;
+    case 1:
+        orig_val &= 0xffff00ff;
+        val <<= 8;
+        break;
+    case 2:
+        orig_val &= 0xff00ffff;
+        val <<= 16;
+        break;
+    case 3:
+        orig_val &= 0x00ffffff;
+        val <<= 24;
+        break;
+    }
+    val |= orig_val;
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " orig_val %08x => val %08x\n", __func__,
+           addr, orig_val, val);
+#endif
+    s->mem_write(s->opaque, addr & ~3, val);
+}
+
+static void emulated_writeb_l_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+    uint32_t orig_val;
+
+    orig_val = s->mem_read(s->opaque, addr & ~1);
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " orig_val %08x => val %08x\n", __func__,
+           addr, orig_val, val);
+#endif
+    switch (addr & 3) {
+    case 0:
+        orig_val &= 0x00ffffff;
+        val <<= 24;
+        break;
+    case 1:
+        orig_val &= 0xff00ffff;
+        val <<= 16;
+        break;
+    case 2:
+        orig_val &= 0xffff00ff;
+        val <<= 8;
+        break;
+    case 3:
+        orig_val &= 0xffffff00;
+        break;
+    }
+    val |= orig_val;
+    s->mem_write(s->opaque, addr & ~1, val);
+}
+
+static uint32_t emulated_readw_l_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = cpu_to_le32(s->mem_read(s->opaque, addr & ~3));
+    switch (addr & 2) {
+    case 0:
+        break;
+    case 2:
+        ret >>= 16;
+        break;
+    }
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readw_l_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = cpu_to_le32(s->mem_read(s->opaque, addr & ~3));
+    switch (addr & 2) {
+    case 0:
+        ret >>= 16;
+        break;
+    case 2:
+        break;
+    }
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writew_l_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+    uint32_t orig_val;
+
+    orig_val = s->mem_read(s->opaque, addr & ~3);
+    switch (addr & 2) {
+    case 0:
+        orig_val &= 0xffff0000;
+        break;
+    case 2:
+        orig_val &= 0x0000ffff;
+        val <<= 16;
+        break;
+    }
+    val |= orig_val;
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, le32_to_cpu(val));
+}
+
+static void emulated_writew_l_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+    uint32_t orig_val;
+
+    orig_val = s->mem_read(s->opaque, addr & ~3);
+    switch (addr & 2) {
+    case 0:
+        orig_val &= 0x0000ffff;
+        val <<= 16;
+        break;
+    case 2:
+        orig_val &= 0xffff0000;
+        break;
+    }
+    val |= orig_val;
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, addr, be32_to_cpu(val));
+}
+
+static uint32_t emulated_readl_l_le(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = cpu_to_le32(s->mem_read(s->opaque, addr & 3));
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static uint32_t emulated_readl_l_be(void *opaque, target_phys_addr_t addr)
+{
+    emulated_io *s = opaque;
+    uint32_t ret;
+
+    ret = cpu_to_be32(s->mem_read(s->opaque, addr & 3));
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, ret);
+#endif
+    return ret;
+}
+
+static void emulated_writel_l_le(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, (addr & 3), le32_to_cpu(val));
+}
+
+static void emulated_writel_l_be(void *opaque, target_phys_addr_t addr,
+                                 uint32_t val)
+{
+    emulated_io *s = opaque;
+
+#if defined(DEBUG_EMULATED_IO)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, val);
+#endif
+    s->mem_write(s->opaque, (addr & 3), be32_to_cpu(val));
+}
+
+int cpu_register_32bit_io_memory(int io_index,
+                                 CPUReadMemoryFunc *mem_read,
+                                 CPUWriteMemoryFunc *mem_write,
+                                 void *opaque, int emulate_other_widths,
+                                 int is_le)
+{
+    if (io_index <= 0) {
+        io_index = get_free_io_mem_idx();
+        if (io_index == -1)
+            return io_index;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+
+    if (emulate_other_widths) {
+        emulated_io *s;
+
+        s = qemu_mallocz(sizeof(emulated_io));
+
+        if (is_le) {
+            io_mem_read[io_index][0] = emulated_readb_l_le;
+            io_mem_write[io_index][0] = emulated_writeb_l_le;
+            io_mem_read[io_index][1] = emulated_readw_l_le;
+            io_mem_write[io_index][1] = emulated_writew_l_le;
+            io_mem_read[io_index][2] = emulated_readl_l_le;
+            io_mem_write[io_index][2] = emulated_writel_l_le;
+        } else {
+            io_mem_read[io_index][0] = emulated_readb_l_be;
+            io_mem_write[io_index][0] = emulated_writeb_l_be;
+            io_mem_read[io_index][1] = emulated_readw_l_be;
+            io_mem_write[io_index][1] = emulated_writew_l_be;
+            io_mem_read[io_index][2] = emulated_readl_l_be;
+            io_mem_write[io_index][2] = emulated_writel_l_be;
+        }
+        s->opaque = opaque;
+        s->mem_read = mem_read;
+        s->mem_write = mem_write;
+        io_mem_opaque[io_index] = s;
+    } else {
+        io_mem_read[io_index][2] = mem_read;
+        io_mem_write[io_index][2] = mem_write;
+        io_mem_opaque[io_index] = opaque;
+    }
+
+    return io_index << IO_MEM_SHIFT;
+}
+
 static void io_mem_init(void)
 {
     int i;
