diff mbox

[RFC,22/23] prep: qdev'ify System I/O (WIP)

Message ID 1308019077-61957-23-git-send-email-andreas.faerber@web.de
State New
Headers show

Commit Message

Andreas Färber June 14, 2011, 2:37 a.m. UTC
PReP defines a number of 1-byte registers

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>

v1:
* Rebased: Fix I/O port types for ppc64 compatibility.
  Use Little Endian for parity error register.
* Drop iobase property. It was not being set to another value,
  ignored for reads and writes, and the spec makes no promises
  about register locations being en bloque.
* Generalize this as System I/O rather than I/O 0x800 and
  integrate Special Port 0x0092. It was implementing the parity
  error register at 0xBFFFEFF0 anyway.
* The v1.1 spec has parity read as 0x0840 rather than 0x841, so
  cover both.
* Turn board identification into a qdev property.
* Migrate remaining standard I/O ports from prep machine.
* Add some VMState support.

Add to 40p machine.

Cc: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.target    |    1 +
 hw/ppc_prep.c      |  165 ++++++--------------------
 hw/ppc_prep.h      |   24 ++++
 hw/prep_systemio.c |  335 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 399 insertions(+), 126 deletions(-)
 create mode 100644 hw/ppc_prep.h
 create mode 100644 hw/prep_systemio.c
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index b1a0f6d..b67b1f7 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -242,6 +242,7 @@  obj-ppc-y = ppc.o
 obj-ppc-y += vga.o
 # PREP target
 obj-ppc-y += i8259.o mc146818rtc.o
+obj-ppc-y += prep_systemio.o
 obj-ppc-y += ppc_prep.o
 # OldWorld PowerMac
 obj-ppc-y += ppc_oldworld.o
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 4759a03..6ae1635 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -21,6 +21,7 @@ 
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "ppc_prep.h"
 #include "hw.h"
 #include "nvram.h"
 #include "pc.h"
@@ -258,117 +259,55 @@  static CPUReadMemoryFunc * const PPC_XCSR_read[] = {
 #endif
 
 /* Fake super-io ports for PREP platform (Intel 82378ZB) */
-typedef struct sysctrl_t {
-    qemu_irq reset_irq;
-    M48t59State *nvram;
-    uint8_t state;
-    uint8_t syscontrol;
-    uint8_t fake_io[2];
-    int contiguous_map;
-    int endian;
-} sysctrl_t;
-
-enum {
-    STATE_HARDFILE = 0x01,
-};
-
-static sysctrl_t *sysctrl;
-
 static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val)
 {
-    sysctrl_t *sysctrl = opaque;
+    uint8_t *fake_io = opaque;
 
     PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE,
                    val);
-    sysctrl->fake_io[addr - 0x0398] = val;
+    fake_io[addr - 0x0398] = val;
 }
 
 static uint32_t PREP_io_read (void *opaque, uint32_t addr)
 {
-    sysctrl_t *sysctrl = opaque;
+    uint8_t *fake_io = opaque;
 
     PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", addr - PPC_IO_BASE,
-                   sysctrl->fake_io[addr - 0x0398]);
-    return sysctrl->fake_io[addr - 0x0398];
+                   fake_io[addr - 0x0398]);
+    return fake_io[addr - 0x0398];
 }
 
+#if 0
 static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
 {
-    sysctrl_t *sysctrl = opaque;
-
     PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n",
                    addr - PPC_IO_BASE, val);
     switch (addr) {
-    case 0x0092:
-        /* Special port 92 */
-        /* Check soft reset asked */
-        if (val & 0x01) {
-            qemu_irq_raise(sysctrl->reset_irq);
-        } else {
-            qemu_irq_lower(sysctrl->reset_irq);
-        }
-        /* Check LE mode */
-        if (val & 0x02) {
-            sysctrl->endian = 1;
-        } else {
-            sysctrl->endian = 0;
-        }
-        break;
-    case 0x0800:
-        /* Motorola CPU configuration register : read-only */
-        break;
-    case 0x0802:
-        /* Motorola base module feature register : read-only */
-        break;
-    case 0x0803:
-        /* Motorola base module status register : read-only */
-        break;
-    case 0x0808:
-        /* Hardfile light register */
-        if (val & 1)
-            sysctrl->state |= STATE_HARDFILE;
-        else
-            sysctrl->state &= ~STATE_HARDFILE;
-        break;
     case 0x0810:
         /* Password protect 1 register */
-        if (sysctrl->nvram != NULL)
-            m48t59_toggle_lock(sysctrl->nvram, 1);
+        // TODO   m48t59_toggle_lock(sysctrl->nvram, 1);
         break;
     case 0x0812:
         /* Password protect 2 register */
-        if (sysctrl->nvram != NULL)
-            m48t59_toggle_lock(sysctrl->nvram, 2);
+        // TODO   m48t59_toggle_lock(sysctrl->nvram, 2);
         break;
     case 0x0814:
         /* L2 invalidate register */
         //        tlb_flush(first_cpu, 1);
         break;
-    case 0x081C:
-        /* system control register */
-        sysctrl->syscontrol = val & 0x0F;
-        break;
-    case 0x0850:
-        /* I/O map type register */
-        sysctrl->contiguous_map = val & 0x01;
-        break;
     default:
         printf("ERROR: unaffected IO port write: %04" PRIx32
                " => %02" PRIx32"\n", addr, val);
         break;
     }
 }
+#endif
 
 static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
 {
-    sysctrl_t *sysctrl = opaque;
     uint32_t retval = 0xFF;
 
     switch (addr) {
-    case 0x0092:
-        /* Special port 92 */
-        retval = 0x00;
-        break;
     case 0x0800:
         /* Motorola CPU configuration register */
         retval = 0xEF; /* MPC750 */
@@ -377,44 +316,14 @@  static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
         /* Motorola Base module feature register */
         retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
         break;
-    case 0x0803:
-        /* Motorola base module status register */
-        retval = 0xE0; /* Standard MPC750 */
-        break;
-    case 0x080C:
-        /* Equipment present register:
-         *  no L2 cache
-         *  no upgrade processor
-         *  no cards in PCI slots
-         *  SCSI fuse is bad
-         */
-        retval = 0x3C;
-        break;
     case 0x0810:
         /* Motorola base module extended feature register */
         retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
         break;
-    case 0x0814:
-        /* L2 invalidate: don't care */
-        break;
-    case 0x0818:
-        /* Keylock */
-        retval = 0x00;
-        break;
-    case 0x081C:
-        /* system control register
-         * 7 - 6 / 1 - 0: L2 cache enable
-         */
-        retval = sysctrl->syscontrol;
-        break;
     case 0x0823:
         /* */
         retval = 0x03; /* no L2 cache */
         break;
-    case 0x0850:
-        /* I/O map type register */
-        retval = sysctrl->contiguous_map;
-        break;
     default:
         printf("ERROR: unaffected IO port: %04" PRIx32 " read\n", addr);
         break;
@@ -425,10 +334,10 @@  static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
     return retval;
 }
 
-static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl,
+static inline target_phys_addr_t prep_IO_address(ISAPrepSystemIo800State *state,
                                                  target_phys_addr_t addr)
 {
-    if (sysctrl->contiguous_map == 0) {
+    if (prep_is_iomap_contiguous(state)) {
         /* 64 KB contiguous space for IOs */
         addr &= 0xFFFF;
     } else {
@@ -442,18 +351,18 @@  static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl,
 static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr,
                                 uint32_t value)
 {
-    sysctrl_t *sysctrl = opaque;
+    ISAPrepSystemIo800State *dev = opaque;
 
-    addr = prep_IO_address(sysctrl, addr);
+    addr = prep_IO_address(dev, addr);
     cpu_outb(addr, value);
 }
 
 static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr)
 {
-    sysctrl_t *sysctrl = opaque;
+    ISAPrepSystemIo800State *dev = opaque;
     uint32_t ret;
 
-    addr = prep_IO_address(sysctrl, addr);
+    addr = prep_IO_address(dev, addr);
     ret = cpu_inb(addr);
 
     return ret;
@@ -462,19 +371,19 @@  static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr)
 static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr,
                                 uint32_t value)
 {
-    sysctrl_t *sysctrl = opaque;
+    ISAPrepSystemIo800State *dev = opaque;
 
-    addr = prep_IO_address(sysctrl, addr);
+    addr = prep_IO_address(dev, addr);
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
     cpu_outw(addr, value);
 }
 
 static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
 {
-    sysctrl_t *sysctrl = opaque;
+    ISAPrepSystemIo800State *dev = opaque;
     uint32_t ret;
 
-    addr = prep_IO_address(sysctrl, addr);
+    addr = prep_IO_address(dev, addr);
     ret = cpu_inw(addr);
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
 
@@ -484,19 +393,19 @@  static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
 static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr,
                                 uint32_t value)
 {
-    sysctrl_t *sysctrl = opaque;
+    ISAPrepSystemIo800State *dev = opaque;
 
-    addr = prep_IO_address(sysctrl, addr);
+    addr = prep_IO_address(dev, addr);
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
     cpu_outl(addr, value);
 }
 
 static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
 {
-    sysctrl_t *sysctrl = opaque;
+    ISAPrepSystemIo800State *dev = opaque;
     uint32_t ret;
 
-    addr = prep_IO_address(sysctrl, addr);
+    addr = prep_IO_address(dev, addr);
     ret = cpu_inl(addr);
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
 
@@ -566,6 +475,8 @@  static void ppc_prep_init (ram_addr_t ram_size,
 {
     CPUState *env = NULL;
     char *filename;
+    ISADevice *systemio;
+    uint8_t *fake_io;
     nvram_t nvram;
     M48t59State *m48t59;
     int PPC_io_memory;
@@ -580,8 +491,6 @@  static void ppc_prep_init (ram_addr_t ram_size,
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     DriveInfo *fd[MAX_FD];
 
-    sysctrl = qemu_mallocz(sizeof(sysctrl_t));
-
     linux_boot = (kernel_filename != NULL);
 
     /* init CPUs */
@@ -668,10 +577,11 @@  static void ppc_prep_init (ram_addr_t ram_size,
     /* Hmm, prep has no pci-isa bridge ??? */
     isa_bus_new(NULL);
     isa_bus_irqs(i8259);
+    systemio = isa_create_simple("prep-systemio800");
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
     PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read,
-                                           PPC_prep_io_write, sysctrl,
+                                           PPC_prep_io_write, systemio,
                                            DEVICE_LITTLE_ENDIAN);
     cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
 
@@ -719,14 +629,13 @@  static void ppc_prep_init (ram_addr_t ram_size,
     register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
     register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
     /* Register fake IO ports for PREP */
-    sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET];
-    register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
-    register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl);
+    fake_io = qemu_mallocz(2);
+    register_ioport_read(0x398, 2, 1, &PREP_io_read, fake_io);
+    register_ioport_write(0x398, 2, 1, &PREP_io_write, fake_io);
     /* System control ports */
-    register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl);
-    register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl);
-    register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
-    register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
+    register_ioport_read(0x0800, 2/*3*/, 1, &PREP_io_800_readb, systemio);
+    //register_ioport_read(0x0810, 1, 1, PREP_io_800_readb, systemio);
+    register_ioport_read(0x0823, 1, 1, PREP_io_800_readb, systemio);
     /* PCI intack location */
     PPC_io_memory = cpu_register_io_memory(PPC_intack_read,
                                            PPC_intack_write, NULL,
@@ -746,7 +655,6 @@  static void ppc_prep_init (ram_addr_t ram_size,
     m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
     if (m48t59 == NULL)
         return;
-    sysctrl->nvram = m48t59;
 
     /* Initialise NVRAM */
     nvram.opaque = m48t59;
@@ -834,6 +742,11 @@  static void ibm_40p_init(ram_addr_t ram_size,
     qdev_connect_gpio_out(&pci->qdev, 0, env->irq_inputs[PPC6xx_INPUT_INT]);
     qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
 
+    /* PReP System I/O */
+    isa = isa_create("prep-systemio800");
+    qdev_prop_set_uint8(&isa->qdev, "board-identification", 0xfc);
+    qdev_init_nofail(&isa->qdev);
+
     /* Super I/O (parallel + serial ports) */
     isa = isa_create("isa-pc87312");
     qdev_prop_set_chr(&isa->qdev, "parallel", parallel_hds[0]);
diff --git a/hw/ppc_prep.h b/hw/ppc_prep.h
new file mode 100644
index 0000000..ad74c29
--- /dev/null
+++ b/hw/ppc_prep.h
@@ -0,0 +1,24 @@ 
+#ifndef PPC_PREP_H
+#define PPC_PREP_H
+
+#include "isa.h"
+
+
+typedef struct PrepIo800State {
+    uint8_t system_control; /* 0x081c */
+    uint8_t iomap_type; /* 0x0850 */
+    uint32_t mem_parity_error_address;
+    qemu_irq softreset_irq;
+} PrepIo800State;
+
+typedef struct ISAPrepSystemIo800State {
+    ISADevice dev;
+    uint8_t board_identification; /* 0x0852 */
+    PrepIo800State state;
+} ISAPrepSystemIo800State;
+
+
+int prep_is_iomap_contiguous(ISAPrepSystemIo800State *s);
+
+
+#endif
diff --git a/hw/prep_systemio.c b/hw/prep_systemio.c
new file mode 100644
index 0000000..edfcfcc
--- /dev/null
+++ b/hw/prep_systemio.c
@@ -0,0 +1,335 @@ 
+/*
+ * QEMU PReP System I/O emulation
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ * Copyright (c) 2010 Herve Poussineau
+ * Copyright (c) 2010-2011 Andreas Faerber
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ppc_prep.h"
+
+//#define DEBUG_PREPIO
+
+#ifdef DEBUG_PREPIO
+#define DPRINTF(fmt, ...) \
+do { \
+    fprintf(stderr, "io800: " fmt , ## __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "io800 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+/* Bit as defined in PowerPC Reference Plaform v1.1, sect. 6.1.5, p. 132 */
+#define BIT(n) (1 << (7 - (n)))
+
+
+/* PORT 0092 -- Special Port 92 (Read/Write) */
+
+enum {
+    PORT0092_SOFTRESET  = BIT(7),
+    PORT0092_LE_MODE    = BIT(6),
+};
+
+static void prep_port0092_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PrepIo800State *s = opaque;
+
+    if ((val & PORT0092_SOFTRESET) != 0) {
+        qemu_irq_raise(s->softreset_irq);
+    } else {
+        qemu_irq_lower(s->softreset_irq);
+    }
+    
+    if ((val & PORT0092_LE_MODE) != 0) {
+        /* XXX Not supported yet */
+    } else {
+        /* Nothing to do */
+    }
+}
+
+static uint32_t prep_port0092_read(void *opaque, uint32_t addr)
+{
+    /* XXX LE mode unsupported */
+    return 0;
+}
+
+/* SIMM ID (32/8 MB) */
+
+static uint32_t prep_port0803_read(void *opaque, uint32_t addr)
+{
+    return 3; // XXX or 0xe0
+}
+
+/* SIMM Presence */
+
+static uint32_t prep_port0804_read(void *opaque, uint32_t addr)
+{
+    return 0;
+}
+
+/* PORT 0808 -- Hardfile Light Register (Write Only) */
+
+enum {
+    PORT0808_HARDFILE_LIGHT_ON  = BIT(7),
+};
+
+static void prep_port0808_write(void *opaque, uint32_t addr, uint32_t val)
+{
+}
+
+/* PORT 080C -- Equipment Present Register (Read Only) */
+
+enum {
+    PORT080C_L2_CACHE_ABSENT                = BIT(7),
+    PORT080C_UPGRADE_PROCESSOR_ABSENT       = BIT(6),
+    PORT080C_L2_CACHE_256KB_OR_ABSENT       = BIT(5),
+    PORT080C_L2_CACHE_COPYBACK_OR_ABSENT    = BIT(4),
+    PORT080C_PCI_SLOT1_CARD_ABSENT          = BIT(3),
+    PORT080C_PCI_SLOT2_CARD_ABSENT          = BIT(2),
+    PORT080C_SCSI_FUSE_OK                   = BIT(1),
+};
+
+static uint32_t prep_port080c_read(void *opaque, uint32_t addr)
+{
+    /* no L2 cache
+     * no upgrade processor
+     * no cards in PCI slots
+     * SCSI fuse is bad
+     */
+    return PORT080C_L2_CACHE_ABSENT |
+           PORT080C_L2_CACHE_256KB_OR_ABSENT |
+           PORT080C_L2_CACHE_COPYBACK_OR_ABSENT |
+           PORT080C_UPGRADE_PROCESSOR_ABSENT |
+           PORT080C_PCI_SLOT1_CARD_ABSENT |
+           PORT080C_PCI_SLOT2_CARD_ABSENT;
+}
+
+/* PORT 0810 -- Password Protect 1 Register (Write Only) */
+
+/* reset by port 0x4D in the SIO */
+static void prep_port0810_write(void *opaque, uint32_t addr, uint32_t val)
+{
+}
+
+/* PORT 0812 -- Password Protect 2 Register (Write Only) */
+
+/* reset by port 0x4D in the SIO */
+static void prep_port0812_write(void *opaque, uint32_t addr, uint32_t val)
+{
+}
+
+/* PORT 0814 -- L2 Invalidate Register (Write Only) */
+
+static void prep_port0814_write(void *opaque, uint32_t addr, uint32_t val)
+{
+}
+
+/* PORT 0818 -- Reserved for Keylock (Read Only) */
+
+enum {
+    PORT0818_KEYLOCK_SIGNAL_HIGH    = BIT(7),
+};
+
+static uint32_t prep_port0818_read(void *opaque, uint32_t addr)
+{
+    return 0;
+}
+
+/* PORT 081C -- System Control Register (Read/Write) */
+
+enum {
+    PORT081C_FLOPPY_MOTOR_INHIBIT   = BIT(3),
+    PORT081C_MASK_TEA               = BIT(2),
+    PORT081C_L2_UPDATE_INHIBIT      = BIT(1),
+    PORT081C_L2_CACHEMISS_INHIBIT   = BIT(0),
+};
+
+static void prep_port081c_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PrepIo800State *s = opaque;
+    s->system_control = val;
+}
+
+static uint32_t prep_port081c_read(void *opaque, uint32_t addr)
+{
+    PrepIo800State *s = opaque;
+    return s->system_control;
+}
+
+/* Memory Controller Size Programming Register */
+
+static void prep_port0820_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PrepIo800State *s = opaque;
+    if (val == 0xe3) {
+        s->mem_parity_error_address = 1; /* HACK */
+    }
+}
+
+/* Read Memory Parity Error */
+
+static uint32_t prep_port0840_read(void *opaque, uint32_t addr)
+{
+    PrepIo800State *s = opaque;
+    return s->mem_parity_error_address != 0 ? 1 : 0;
+}
+
+/* System Board Identification */
+
+static uint32_t prep_port0852_read(void *opaque, uint32_t addr)
+{
+    ISAPrepSystemIo800State *s = opaque;
+    return s->board_identification;
+}
+
+/* PORT 0850 -- I/O Map Type Register (Read/Write) */
+
+enum {
+    PORT0850_IOMAP_NONCONTIGUOUS    = BIT(7),
+};
+
+static uint32_t prep_port0850_read(void *opaque, uint32_t addr)
+{
+    PrepIo800State *s = opaque;
+    return s->iomap_type;
+}
+
+static void prep_port0850_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PrepIo800State *s = opaque;
+    s->iomap_type = val;
+}
+
+int prep_is_iomap_contiguous(ISAPrepSystemIo800State *s)
+{
+    return (s->state.iomap_type & PORT0850_IOMAP_NONCONTIGUOUS) == 0;
+}
+
+
+static uint32_t ppc_parity_error_readl(void *opaque, target_phys_addr_t addr)
+{
+    PrepIo800State* s = opaque;
+    uint32_t val = s->mem_parity_error_address;
+
+    DPRINTF("%s: read 0x%08x at [" TARGET_FMT_plx "]\n", __func__, val, addr);
+
+    return val;
+}
+
+static CPUReadMemoryFunc * const ppc_parity_error_read[] = {
+    NULL,
+    NULL,
+    ppc_parity_error_readl,
+};
+
+static CPUWriteMemoryFunc * const ppc_parity_error_write[] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static void prep_register_ioport(uint16_t start, int length,
+                                 IOPortReadFunc *read_func,
+                                 IOPortWriteFunc *write_func,
+                                 void *opaque)
+{
+    if (read_func != NULL) {
+        register_ioport_read(start, length, 1, read_func, opaque);
+    }
+    if (write_func != NULL) {
+        register_ioport_write(start, length, 1, write_func, opaque);
+    }
+}
+
+static int prep_systemio_isa_init(ISADevice *dev)
+{
+    ISAPrepSystemIo800State *isa = DO_UPCAST(ISAPrepSystemIo800State, dev, dev);
+    PrepIo800State *s = &isa->state;
+    int io;
+
+    s->iomap_type = 0; /* contiguous mode  CHECKME 0x1? */
+    s->softreset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET];
+
+    prep_register_ioport(0x0092, 1, prep_port0092_read,
+                                    prep_port0092_write, s);
+
+    prep_register_ioport(0x0803, 1, prep_port0803_read, NULL, s);
+    prep_register_ioport(0x0804, 1, prep_port0804_read, NULL, s);
+    prep_register_ioport(0x0808, 4, NULL,
+                                    prep_port0808_write, s);
+    prep_register_ioport(0x080c, 4, prep_port080c_read, NULL, s);
+    prep_register_ioport(0x0810, 2, NULL,
+                                    prep_port0810_write, s);
+    prep_register_ioport(0x0812, 2, NULL,
+                                    prep_port0812_write, s);
+    prep_register_ioport(0x0814, 4, NULL,
+                                    prep_port0814_write, s);
+    prep_register_ioport(0x0818, 1, prep_port0818_read, NULL, s);
+    prep_register_ioport(0x081c, 4, prep_port081c_read,
+                                    prep_port081c_write, s);
+    prep_register_ioport(0x0820, 1, NULL,
+                                    prep_port0820_write, s);
+    prep_register_ioport(0x0840, 2, prep_port0840_read, NULL, s);
+    /* Reference Implementation supposedly uses 0x0850 - 0x0853 */
+    prep_register_ioport(0x0850, 2, prep_port0850_read,
+                                    prep_port0850_write, s);
+    prep_register_ioport(0x0852, 1, prep_port0852_read, NULL, isa);
+
+    io = cpu_register_io_memory(ppc_parity_error_read,
+                                ppc_parity_error_write, s,
+                                DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0xBFFFEFF0, 0x4, io);
+    return 0;
+}
+
+static const VMStateDescription vmstate_prep_systemio = {
+    .name = "prep_systemio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(state.system_control, ISAPrepSystemIo800State),
+        VMSTATE_UINT8(state.iomap_type, ISAPrepSystemIo800State),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static ISADeviceInfo prep_systemio800_info = {
+    .init = prep_systemio_isa_init,
+    .qdev.name = "prep-systemio800",
+    .qdev.size = sizeof(ISAPrepSystemIo800State),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("board-identification", ISAPrepSystemIo800State,
+                          board_identification, 0),
+        DEFINE_PROP_END_OF_LIST()
+    },
+    .qdev.vmsd = &vmstate_prep_systemio,
+    .qdev.no_user = 1,
+};
+
+static void prep_systemio_register_devices(void)
+{
+    isa_qdev_register(&prep_systemio800_info);
+}
+
+device_init(prep_systemio_register_devices)