All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC 00/23] PReP 40P emulation
@ 2011-06-14  2:37 Andreas Färber
  2011-06-14  2:37 ` [Qemu-devel] [PATCH RFC 01/23] prep: Refactor CPU initialization Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

Hi,

Based mostly on earlier work by Hervé Poussineau, this RFC series adds
emulation of a real '40p' IBM PReP machine as an addition to the existing
'prep' machine. It does some general cleanups and qdev'ification
that will benefit further PReP machines, such as the BeBox.

This series supersedes my preparatory "ISA reconfigurability" series,
by adding the i82378 PCI-ISA bridge on which it is to be used. The qdev and
ISA device patches up to pc87312 should allow for cherry-picking.

The state of -M prep (on Darwin/ppc64 and OSol/amd64) is that my
2.4.36.1 Linux kernel hardly gets to the root prompt
("INIT: Id "n" respawning too fast: disabled for 5 minutes"),
both before and after.

Firmware for -M 40p can be downloaded here:
ftp://ftp.boulder.ibm.com/rs6000/firmware/7020-40p/P12H0456.IMG

With some additional patches on top of this series (memory-forced
I/O, a PCI BAR issue and a parallel ioport conflict) after about
one and a half minutes it gets to the graphical boot screen with
keyboard icon, after about seven and a half minutes to the floppy icon
and after a really looong time gets to a third, memory(?) icon.

TODOs:
* improve ISA ioport vs. IORange handling and naming
* fix a few -M prep System I/O ports broken by qdev'ification
* possibly make -M prep use i82378, too (broke Linux boot)
* IBM8514/A cleanup, RAMDAC support for colors
* 7020 had max. 6x 32 MB = 192 MB RAM

Regards,
Andreas

Cc: Hervé Poussineau <hpoussin@reactos.org>


Andreas Färber (21):
  prep: Refactor CPU initialization
  prep: qdev'ify PCI
  prep: Prepare emulation of an IBM RS/6000 6015 / 7020 (40p)
  40p: Add PCI host
  prep: Add i82374 DMA emulation
  prep: Add i82378 PCI-to-ISA bridge emulation
  40p: Add a PCI to ISA bridge (i82378)
  qdev: Add support for property type bool
  qdev: Add helpers for reading properties
  isa: Provide enable and disable callbacks
  isa: Allow to un-assign I/O ports
  isa: Allow to un-associate an IRQ
  parallel: Implement ISA state callbacks
  serial: Implement ISA state callbacks
  fdc: Implement ISA state callbacks
  ide: Allow to discard I/O ports
  ide: Implement ISA state callbacks
  prep: Add pc87312 Super I/O emulation
  40p: Add the Super I/O chip (pc87312)
  prep: qdev'ify System I/O (WIP)
  40p: Add an 8514/A graphics card

Hervé Poussineau (2):
  fdc: Parametrize ISA base, IRQ and DMA
  40p: Add an audio card and a keyboard

 Makefile.objs                   |    4 +
 Makefile.target                 |    1 +
 default-configs/ppc-softmmu.mak |    7 +
 hw/fdc.c                        |  118 ++++++-
 hw/hw.h                         |   15 +
 hw/i82374.c                     |  133 ++++++++
 hw/i82378.c                     |  298 +++++++++++++++++
 hw/ide/core.c                   |    8 +
 hw/ide/internal.h               |    1 +
 hw/ide/isa.c                    |   98 ++++++-
 hw/isa-bus.c                    |   71 ++++
 hw/isa.h                        |    8 +
 hw/parallel.c                   |   75 +++--
 hw/pc87312.c                    |  495 ++++++++++++++++++++++++++++
 hw/pci_ids.h                    |    4 +
 hw/ppc_prep.c                   |  316 ++++++++++--------
 hw/ppc_prep.h                   |   24 ++
 hw/prep_pci.c                   |  126 ++++++--
 hw/prep_systemio.c              |  335 +++++++++++++++++++
 hw/qdev-properties.c            |   96 ++++++-
 hw/qdev.h                       |   13 +
 hw/serial.c                     |   91 +++++-
 hw/vga-s3.c                     |  694 +++++++++++++++++++++++++++++++++++++++
 23 files changed, 2812 insertions(+), 219 deletions(-)
 create mode 100644 hw/i82374.c
 create mode 100644 hw/i82378.c
 create mode 100644 hw/pc87312.c
 create mode 100644 hw/ppc_prep.h
 create mode 100644 hw/prep_systemio.c
 create mode 100644 hw/vga-s3.c

-- 
1.7.5.3

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [Qemu-devel] [PATCH RFC 01/23] prep: Refactor CPU initialization
  2011-06-14  2:37 [Qemu-devel] [RFC 00/23] PReP 40P emulation Andreas Färber
@ 2011-06-14  2:37 ` Andreas Färber
  2011-06-14  2:37   ` [Qemu-devel] [RFC 02/23] prep: qdev'ify PCI Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

To cope with upcoming PReP machines and as a first step towards
pending qdev'ification of the ppc CPU, move CPU initialization
to a helper function, similar to pc_new_cpu().

Cc: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/ppc_prep.c |   47 +++++++++++++++++++++++++++++++----------------
 1 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 0e9cfc2..b3efd3c 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -525,6 +525,36 @@ static void cpu_request_exit(void *opaque, int irq, int level)
     }
 }
 
+static void prep_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+}
+
+static CPUState *ppc_prep_new_cpu(const char *cpu_model)
+{
+    CPUState *env;
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+        exit(1);
+    }
+    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+        hw_error("Only 6xx bus is supported on PREP machine\n");
+    }
+    if (env->flags & POWERPC_FLAG_RTC_CLK) {
+        /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
+        cpu_ppc_tb_init(env, 7812500UL);
+    } else {
+        /* Set time-base frequency to 100 Mhz */
+        cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+    }
+    qemu_register_reset(prep_cpu_reset, env);
+    return env;
+}
+
 /* PowerPC PREP hardware initialisation */
 static void ppc_prep_init (ram_addr_t ram_size,
                            const char *boot_device,
@@ -557,19 +587,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
     if (cpu_model == NULL)
         cpu_model = "602";
     for (i = 0; i < smp_cpus; i++) {
-        env = cpu_init(cpu_model);
-        if (!env) {
-            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
-            exit(1);
-        }
-        if (env->flags & POWERPC_FLAG_RTC_CLK) {
-            /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
-            cpu_ppc_tb_init(env, 7812500UL);
-        } else {
-            /* Set time-base frequency to 100 Mhz */
-            cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-        }
-        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
+        env = ppc_prep_new_cpu(cpu_model);
     }
 
     /* allocate RAM */
@@ -644,9 +662,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
     }
 
     isa_mem_base = 0xc0000000;
-    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
-        hw_error("Only 6xx bus is supported on PREP machine\n");
-    }
     i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
     pci_bus = pci_prep_init(i8259);
     /* Hmm, prep has no pci-isa bridge ??? */
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 02/23] prep: qdev'ify PCI
  2011-06-14  2:37 ` [Qemu-devel] [PATCH RFC 01/23] prep: Refactor CPU initialization Andreas Färber
@ 2011-06-14  2:37   ` Andreas Färber
  2011-06-14  2:37     ` [Qemu-devel] [RFC 03/23] prep: Prepare emulation of an IBM RS/6000 6015 / 7020 (40p) Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: Andreas Färber, Hervé Poussineau, Alexander Graf,
	Michael S. Tsirkin

Don't always keep pointer to PIC, but keep only references
to required IRQs. Add a PCI host.

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

Avoid adding qemu_irq state by reusing SysBus facilities.
This allows to qdev'ify the PCIDevice, too, by banning
hardcoded IRQ numbers into pci_prep_init() wrapper.

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/prep_pci.c |  126 ++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 97 insertions(+), 29 deletions(-)

diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index f88b825..2554d86 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -2,6 +2,8 @@
  * QEMU PREP PCI host
  *
  * Copyright (c) 2006 Fabrice Bellard
+ * 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
@@ -27,7 +29,14 @@
 #include "pci_host.h"
 #include "prep_pci.h"
 
-typedef PCIHostState PREPPCIState;
+typedef struct PREPPCIState {
+    PCIHostState host_state;
+} PREPPCIState;
+
+typedef struct PRePPCIBusState {
+    SysBusDevice busdev;
+    PREPPCIState state;
+} PRePPCIBusState;
 
 static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
 {
@@ -43,28 +52,28 @@ static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
 static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     PREPPCIState *s = opaque;
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
+    pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, 1);
 }
 
 static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     PREPPCIState *s = opaque;
     val = bswap16(val);
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
+    pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, 2);
 }
 
 static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     PREPPCIState *s = opaque;
     val = bswap32(val);
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
+    pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, 4);
 }
 
 static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
 {
     PREPPCIState *s = opaque;
     uint32_t val;
-    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
+    val = pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), 1);
     return val;
 }
 
@@ -72,7 +81,7 @@ static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
 {
     PREPPCIState *s = opaque;
     uint32_t val;
-    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
+    val = pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), 2);
     val = bswap16(val);
     return val;
 }
@@ -81,7 +90,7 @@ static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
 {
     PREPPCIState *s = opaque;
     uint32_t val;
-    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
+    val = pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), 4);
     val = bswap32(val);
     return val;
 }
@@ -105,40 +114,99 @@ static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
 
 static void prep_set_irq(void *opaque, int irq_num, int level)
 {
-    qemu_irq *pic = opaque;
+    PRePPCIBusState *s = opaque;
+    SysBusDevice *sysbus = &s->busdev;
 
-    qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
+    if (sysbus->irqp[irq_num] != NULL) {
+        qemu_set_irq(*sysbus->irqp[irq_num], level);
+    }
 }
 
+static int prep_pci_host_init(PCIDevice *d)
+{
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
+    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
+    d->config[0x08] = 0x00; // revision
+    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+
+    return 0;
+}
+
+/* Motorola Raven */
+static PCIDeviceInfo prep_pci_host_info = {
+    .qdev.name = "prep-pci",
+    .qdev.size = sizeof(PCIDevice),
+    .init = prep_pci_host_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
 PCIBus *pci_prep_init(qemu_irq *pic)
 {
-    PREPPCIState *s;
-    PCIDevice *d;
-    int PPC_io_memory;
+    DeviceState *dev;
+    SysBusDevice *sysbus;
+
+    /* PReP PCI bus */
+    dev = qdev_create(NULL, "prep-pci");
+    sysbus = sysbus_from_qdev(dev);
 
-    s = qemu_mallocz(sizeof(PREPPCIState));
-    s->bus = pci_register_bus(NULL, "pci",
-                              prep_set_irq, prep_map_irq, pic, 0, 4);
+    /* Allocate and initialize both IRQs before init */
+    sysbus_init_irq(sysbus, &pic[9]);
+    sysbus_init_irq(sysbus, &pic[11]);
 
-    pci_host_conf_register_ioport(0xcf8, s);
+    qdev_init_nofail(dev);
 
-    pci_host_data_register_ioport(0xcfc, s);
+    sysbus_mmio_map(sysbus, 0, 0x80800000);
+
+    return (PCIBus *)qdev_get_child_bus(dev, "pci");
+}
+
+static int prep_pci_sysbus_init(SysBusDevice *dev)
+{
+    PRePPCIBusState *sysbus = FROM_SYSBUS(PRePPCIBusState, dev);
+    PREPPCIState *s = &sysbus->state;
+    PCIDevice *d;
+    int PPC_io_memory;
+
+    /* Allocate two IRQs if necessary and NULL-initialize */
+    while (sysbus->busdev.num_irq < 2) {
+        sysbus_init_irq(&sysbus->busdev, NULL);
+    }
 
     PPC_io_memory = cpu_register_io_memory(PPC_PCIIO_read,
                                            PPC_PCIIO_write, s,
                                            DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
+    sysbus_init_mmio(dev, 0x00400000, PPC_io_memory);
 
-    /* PCI host bridge */
-    d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
-                            sizeof(PCIDevice), 0, NULL, NULL);
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x34] = 0x00; // capabilities_pointer
+    s->host_state.bus = pci_register_bus(&sysbus->busdev.qdev, "pci",
+                                         prep_set_irq,
+                                         prep_map_irq, sysbus, 0, 2);
+
+    pci_host_conf_register_ioport(0xcf8, &s->host_state);
+    pci_host_data_register_ioport(0xcfc, &s->host_state);
+
+    d = pci_create_simple(s->host_state.bus, 0, "prep-pci");
+
+    return 0;
+}
+
+static SysBusDeviceInfo prep_pci_sysbus_info = {
+    .qdev.name = "prep-pci",
+    .qdev.size = sizeof(PRePPCIBusState),
+    .init = prep_pci_sysbus_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
 
-    return s->bus;
+static void prep_pci_register_devices(void)
+{
+    sysbus_register_withprop(&prep_pci_sysbus_info);
+    pci_qdev_register(&prep_pci_host_info);
 }
+
+device_init(prep_pci_register_devices)
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 03/23] prep: Prepare emulation of an IBM RS/6000 6015 / 7020 (40p)
  2011-06-14  2:37   ` [Qemu-devel] [RFC 02/23] prep: qdev'ify PCI Andreas Färber
@ 2011-06-14  2:37     ` Andreas Färber
  2011-06-14  2:37       ` [Qemu-devel] [RFC 04/23] 40p: Add PCI host Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/ppc_prep.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index b3efd3c..071c149 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -763,6 +763,61 @@ static void ppc_prep_init (ram_addr_t ram_size,
     register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
 }
 
+static void ibm_40p_init(ram_addr_t ram_size,
+                         const char *boot_device,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename,
+                         const char *cpu_model)
+{
+    CPUState *env;
+    char *filename;
+    int bios_size;
+    ram_addr_t ram_offset, bios_offset;
+
+    // IBM E15 graphic adapter (S3 Vision864)
+    // PowerPC 601
+    // PCI, ISA
+    // 16 MB RAM
+    // Audio Crystal 4231
+    // SCSI-2
+    // Parallel ECP / 2 Serials 16550 (on Super I/O)
+
+    /* init CPU */
+    if (cpu_model == NULL)
+        cpu_model = "601";
+    env = ppc_prep_new_cpu(cpu_model);
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "ppc_prep.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* allocate and load BIOS */
+    bios_offset = qemu_ram_alloc(NULL, "ppc_prep.bios", BIOS_SIZE);
+    if (bios_name == NULL)
+        bios_name = "P12H0456.IMG";
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size > 0 && bios_size <= BIOS_SIZE) {
+        target_phys_addr_t bios_addr;
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        bios_addr = (uint32_t)(-BIOS_SIZE);
+        cpu_register_physical_memory(bios_addr, bios_size,
+                                     bios_offset | IO_MEM_ROM);
+        bios_size = load_image_targphys(filename, bios_addr, bios_size);
+    }
+    if (bios_size < 0 || bios_size > BIOS_SIZE) {
+        hw_error("qemu: could not load PPC PReP bios '%s'\n", bios_name);
+    }
+    if (filename) {
+        qemu_free(filename);
+    }
+}
+
 static QEMUMachine prep_machine = {
     .name = "prep",
     .desc = "PowerPC PREP platform",
@@ -770,9 +825,16 @@ static QEMUMachine prep_machine = {
     .max_cpus = MAX_CPUS,
 };
 
+static QEMUMachine ibm_40p_machine = {
+    .name = "40p",
+    .desc = "IBM RS/6000 7020 (40p)",
+    .init = ibm_40p_init,
+};
+
 static void prep_machine_init(void)
 {
     qemu_register_machine(&prep_machine);
+    qemu_register_machine(&ibm_40p_machine);
 }
 
 machine_init(prep_machine_init);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 04/23] 40p: Add PCI host
  2011-06-14  2:37     ` [Qemu-devel] [RFC 03/23] prep: Prepare emulation of an IBM RS/6000 6015 / 7020 (40p) Andreas Färber
@ 2011-06-14  2:37       ` Andreas Färber
  2011-06-14  2:37         ` [Qemu-devel] [RFC 05/23] prep: Add i82374 DMA emulation Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

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

Avoid global variable for PCIBus. Inline PCI bus creation.
Suppress potential gcc 4.6 write-only variable warning.

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/ppc_prep.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 071c149..50cb6c7 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -38,6 +38,7 @@
 #include "loader.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "sysbus.h"
 
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
@@ -774,6 +775,8 @@ static void ibm_40p_init(ram_addr_t ram_size,
     char *filename;
     int bios_size;
     ram_addr_t ram_offset, bios_offset;
+    DeviceState *dev;
+    PCIBus *pci_bus;
 
     // IBM E15 graphic adapter (S3 Vision864)
     // PowerPC 601
@@ -816,6 +819,11 @@ static void ibm_40p_init(ram_addr_t ram_size,
     if (filename) {
         qemu_free(filename);
     }
+
+    /* PCI host */
+    dev = sysbus_create_simple("prep-pci", 0x80800000, NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+    (void)pci_bus;
 }
 
 static QEMUMachine prep_machine = {
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 05/23] prep: Add i82374 DMA emulation
  2011-06-14  2:37       ` [Qemu-devel] [RFC 04/23] 40p: Add PCI host Andreas Färber
@ 2011-06-14  2:37         ` Andreas Färber
  2011-06-14  2:37           ` [Qemu-devel] [RFC 06/23] prep: Add i82378 PCI-to-ISA bridge emulation Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

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

Confine to CONFIG_I82374.

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.objs                   |    1 +
 default-configs/ppc-softmmu.mak |    1 +
 hw/i82374.c                     |  133 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 135 insertions(+), 0 deletions(-)
 create mode 100644 hw/i82374.c

diff --git a/Makefile.objs b/Makefile.objs
index 509ab39..b0e4c09 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -201,6 +201,7 @@ hw-obj-$(CONFIG_FDC) += fdc.o
 hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
 hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
 hw-obj-$(CONFIG_DMA) += dma.o
+hw-obj-$(CONFIG_I82374) += i82374.o
 hw-obj-$(CONFIG_HPET) += hpet.o
 hw-obj-$(CONFIG_APPLESMC) += applesmc.o
 hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 4563742..1d1a7c2 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -11,6 +11,7 @@ CONFIG_I8254=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_DMA=y
+CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
 CONFIG_MACIO=y
diff --git a/hw/i82374.c b/hw/i82374.c
new file mode 100644
index 0000000..383cf1b
--- /dev/null
+++ b/hw/i82374.c
@@ -0,0 +1,133 @@
+/*
+ * QEMU Intel 82374 emulation (Enhanced DMA controller)
+ *
+ * Copyright (c) 2010 Herve Poussineau
+ *
+ * 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 "isa.h"
+
+//#define DEBUG_I82374
+
+#ifdef DEBUG_I82374
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82374: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82374State {
+    uint8_t commands[8];
+} I82374State;
+
+static uint32_t i82374_read_isr(void *opaque, uint32_t nport)
+{
+    uint32_t val = 0;
+
+    BADF("%s: %08x\n", __func__, nport);
+
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+    return val;
+}
+
+static void i82374_write_command(void *opaque, uint32_t nport, uint32_t data)
+{
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+    if (data != 0x42) {
+        /* Not Stop S/G command */
+        BADF("%s: %08x=%08x\n", __func__, nport, data);
+    }
+}
+
+static uint32_t i82374_read_status(void *opaque, uint32_t nport)
+{
+    uint32_t val = 0;
+
+    BADF("%s: %08x\n", __func__, nport);
+
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+    return val;
+}
+
+static void i82374_write_descriptor(void *opaque, uint32_t nport, uint32_t data)
+{
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+    BADF("%s: %08x=%08x\n", __func__, nport, data);
+}
+
+static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport)
+{
+    uint32_t val = 0;
+
+    BADF("%s: %08x\n", __func__, nport);
+
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+    return val;
+}
+
+static void i82374_init(I82374State *s)
+{
+    DMA_init(1, NULL);
+    memset(s->commands, 0, sizeof(s->commands));
+}
+
+typedef struct ISAi82374State {
+    ISADevice dev;
+    uint32_t iobase;
+    I82374State state;
+} ISAi82374State;
+
+static int i82374_isa_init(ISADevice *dev)
+{
+    ISAi82374State *isa = DO_UPCAST(ISAi82374State, dev, dev);
+    I82374State *s = &isa->state;
+
+    register_ioport_read(isa->iobase + 0x0A, 1, 1, i82374_read_isr, s);
+    register_ioport_write(isa->iobase + 0x10, 8, 1, i82374_write_command, s);
+    register_ioport_read(isa->iobase + 0x18, 8, 1, i82374_read_status, s);
+    register_ioport_write(isa->iobase + 0x20, 0x20, 1, i82374_write_descriptor, s);
+    register_ioport_read(isa->iobase + 0x20, 0x20, 1, i82374_read_descriptor, s);
+
+    i82374_init(s);
+
+    return 0;
+}
+
+static ISADeviceInfo i82374_isa_info = {
+    .qdev.name  = "i82374",
+    .qdev.size  = sizeof(ISAi82374State),
+    .init       = i82374_isa_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void i82374_register_devices(void)
+{
+    isa_qdev_register(&i82374_isa_info);
+}
+
+device_init(i82374_register_devices)
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 06/23] prep: Add i82378 PCI-to-ISA bridge emulation
  2011-06-14  2:37         ` [Qemu-devel] [RFC 05/23] prep: Add i82374 DMA emulation Andreas Färber
@ 2011-06-14  2:37           ` Andreas Färber
  2011-06-14  2:37             ` [Qemu-devel] [RFC 07/23] 40p: Add a PCI to ISA bridge (i82378) Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau, Markus Armbruster

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

Inverse endianness in order to work on x86 and ppc host.
Create ISA bus in this device (suggested by Markus).

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.objs                   |    1 +
 default-configs/ppc-softmmu.mak |    2 +
 hw/i82378.c                     |  298 +++++++++++++++++++++++++++++++++++++++
 hw/pci_ids.h                    |    1 +
 4 files changed, 302 insertions(+), 0 deletions(-)
 create mode 100644 hw/i82378.c

diff --git a/Makefile.objs b/Makefile.objs
index b0e4c09..fb57bbf 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -210,6 +210,7 @@ hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 # PPC devices
 hw-obj-$(CONFIG_OPENPIC) += openpic.o
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
+hw-obj-$(CONFIG_I82378) += i82378.o
 # Mac shared devices
 hw-obj-$(CONFIG_MACIO) += macio.o
 hw-obj-$(CONFIG_CUDA) += cuda.o
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 1d1a7c2..df64ee6 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -14,7 +14,9 @@ CONFIG_DMA=y
 CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
+CONFIG_I82378=y
 CONFIG_MACIO=y
+CONFIG_PCSPK=y
 CONFIG_CUDA=y
 CONFIG_ADB=y
 CONFIG_MAC_NVRAM=y
diff --git a/hw/i82378.c b/hw/i82378.c
new file mode 100644
index 0000000..181e441
--- /dev/null
+++ b/hw/i82378.c
@@ -0,0 +1,298 @@
+/*
+ * QEMU Intel i82378 emulation (PCI to ISA bridge)
+ *
+ * Copyright (c) 2010-2011 Herve Poussineau
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ * Copyright (c) 2010 Andreas Faerber
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci.h"
+#include "pc.h"
+
+//#define DEBUG_I82378
+
+#ifdef DEBUG_I82378
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define DEVICE_INVERSE_ENDIAN DEVICE_LITTLE_ENDIAN
+#else
+#define DEVICE_INVERSE_ENDIAN DEVICE_BIG_ENDIAN
+#endif
+
+typedef struct I82378State {
+    qemu_irq out[2];
+    int s_io;
+    int s_mem;
+} I82378State;
+
+typedef struct PCIi82378State {
+    PCIDevice pci_dev;
+    uint32_t isa_io_base;
+    uint32_t isa_mem_base;
+    I82378State state;
+} PCIi82378State;
+
+static inline target_phys_addr_t i82378_io_address(I82378State *state,
+                                                   target_phys_addr_t addr)
+{
+    if (true) {
+        return addr & 0xFFFF;
+    } else {
+        return (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
+    }
+}
+
+static void i82378_io_writeb(void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
+{
+    I82378State *s = opaque;
+    DPRINTF("%s: " TARGET_FMT_plx "=%02x\n", __func__, addr, value);
+    addr = i82378_io_address(s, addr);
+    cpu_outb(addr, value);
+}
+
+static void i82378_io_writew(void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
+{
+    I82378State *s = opaque;
+    DPRINTF("%s: " TARGET_FMT_plx "=%04x\n", __func__, addr, value);
+    addr = i82378_io_address(s, addr);
+    cpu_outw(addr, value);
+}
+
+static void i82378_io_writel(void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
+{
+    I82378State *s = opaque;
+    DPRINTF("%s: " TARGET_FMT_plx "=%08x\n", __func__, addr, value);
+    addr = i82378_io_address(s, addr);
+    cpu_outl(addr, value);
+}
+
+static uint32_t i82378_io_readb(void *opaque, target_phys_addr_t addr)
+{
+    I82378State *s = opaque;
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    addr = i82378_io_address(s, addr);
+    return cpu_inb(addr);
+}
+
+static uint32_t i82378_io_readw(void *opaque, target_phys_addr_t addr)
+{
+    I82378State *s = opaque;
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    addr = i82378_io_address(s, addr);
+    return cpu_inw(addr);
+}
+
+static uint32_t i82378_io_readl(void *opaque, target_phys_addr_t addr)
+{
+    I82378State *s = opaque;
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    addr = i82378_io_address(s, addr);
+    return cpu_inl(addr);
+}
+
+static CPUWriteMemoryFunc * const i82378_io_write[] = {
+    i82378_io_writeb,
+    i82378_io_writew,
+    i82378_io_writel,
+};
+
+static CPUReadMemoryFunc * const i82378_io_read[] = {
+    i82378_io_readb,
+    i82378_io_readw,
+    i82378_io_readl,
+};
+
+static void i82378_mem_writeb(void *opaque,
+                              target_phys_addr_t addr, uint32_t value)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "=%02x\n", __func__, addr, value);
+    cpu_outb(addr, value);
+}
+
+static void i82378_mem_writew(void *opaque,
+                              target_phys_addr_t addr, uint32_t value)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "=%04x\n", __func__, addr, value);
+    cpu_outw(addr, value);
+}
+
+static void i82378_mem_writel(void *opaque,
+                              target_phys_addr_t addr, uint32_t value)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "=%08x\n", __func__, addr, value);
+    cpu_outl(addr, value);
+}
+
+static uint32_t i82378_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    return cpu_inb(addr);
+}
+
+static uint32_t i82378_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    return cpu_inw(addr);
+}
+
+static uint32_t i82378_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    return cpu_inl(addr);
+}
+
+static CPUWriteMemoryFunc * const i82378_mem_write[] = {
+    i82378_mem_writeb,
+    i82378_mem_writew,
+    i82378_mem_writel,
+};
+
+static CPUReadMemoryFunc * const i82378_mem_read[] = {
+    i82378_mem_readb,
+    i82378_mem_readw,
+    i82378_mem_readl,
+};
+
+static void i82378_init(DeviceState *dev, I82378State *s)
+{
+    ISADevice *pit;
+
+    isa_bus_new(dev);
+
+    /* This device has:
+       2 82C59 (irq)
+       1 82C54 (pit)
+       2 82C37 (dma)
+       NMI
+       Utility Bus Support Registers
+
+       All devices accept byte access only, except timer
+    */
+
+    /* 2 82C59 (irq) */
+    qdev_init_gpio_out(dev, s->out, 2);
+    isa_bus_irqs(i8259_init(s->out[0]));
+
+    /* 1 82C54 (pit) */
+    pit = pit_init(0x40, 0);
+
+    /* speaker */
+    pcspk_init(pit);
+
+    /* 2 82C37 (dma) */
+    DMA_init(1, &s->out[1]);
+    isa_create_simple("i82374");
+
+    /* timer */
+    isa_create_simple("mc146818rtc");
+
+    s->s_io = cpu_register_io_memory(i82378_io_read,
+                                     i82378_io_write, s, DEVICE_INVERSE_ENDIAN);
+    s->s_mem = cpu_register_io_memory(i82378_mem_read,
+                                      i82378_mem_write, s, DEVICE_INVERSE_ENDIAN);
+}
+
+static void pci_i82378_ioport_map(PCIDevice *pci_dev, int region_num,
+                                  pcibus_t addr, pcibus_t size, int type)
+{
+    I82378State *s = &DO_UPCAST(PCIi82378State, pci_dev, pci_dev)->state;
+
+    DPRINTF("%s: %s addr=0x%" FMT_PCIBUS " size=0x%" FMT_PCIBUS "\n",
+            __func__, pci_dev->name, addr, size);
+
+    cpu_register_physical_memory(addr, size, s->s_io);
+}
+
+static void pci_i82378_mmio_map(PCIDevice *pci_dev, int region_num,
+                                pcibus_t addr, pcibus_t size, int type)
+{
+    I82378State *s = &DO_UPCAST(PCIi82378State, pci_dev, pci_dev)->state;
+
+    DPRINTF("%s: %s addr=0x%" FMT_PCIBUS " size=0x%" FMT_PCIBUS "\n",
+            __func__, pci_dev->name, addr, size);
+
+    cpu_register_physical_memory(addr, size, s->s_mem);
+    qemu_register_coalesced_mmio(addr, size);
+}
+
+static int pci_i82378_init(PCIDevice *pci_dev)
+{
+    PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, pci_dev);
+    I82378State *s = &pci->state;
+    uint8_t *pci_conf;
+
+    pci_conf = pci_dev->config;
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82378);
+    pci_set_word(pci_conf + PCI_COMMAND,
+                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    pci_conf[PCI_REVISION_ID] = 0x03;
+    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
+
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
+
+    pci_register_bar(pci_dev, 0, 0x00010000,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, pci_i82378_ioport_map);
+
+    pci_register_bar(pci_dev, 1, 0x01000000,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, pci_i82378_mmio_map);
+
+    /* Make addresses read only */
+    pci_set_word(pci_dev->wmask + PCI_COMMAND,
+                 PCI_COMMAND_SPECIAL);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0 + 0 * 4, pci->isa_io_base);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0 + 1 * 4, pci->isa_mem_base);
+
+    isa_mem_base = pci->isa_mem_base;
+    i82378_init(&pci_dev->qdev, s);
+
+    return 0;
+}
+
+static PCIDeviceInfo pci_i82378_info = {
+    .init = pci_i82378_init,
+    .qdev.name = "i82378",
+    .qdev.size = sizeof(PCIi82378State),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
+        DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void i82378_register_devices(void)
+{
+    pci_qdev_register(&pci_i82378_info);
+}
+
+device_init(i82378_register_devices)
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index d9457ed..d3bef0e 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -98,6 +98,7 @@
 #define PCI_DEVICE_ID_MPC8533E           0x0030
 
 #define PCI_VENDOR_ID_INTEL              0x8086
+#define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
 #define PCI_DEVICE_ID_INTEL_82801AA_5    0x2415
 #define PCI_DEVICE_ID_INTEL_82801D       0x24CD
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 07/23] 40p: Add a PCI to ISA bridge (i82378)
  2011-06-14  2:37           ` [Qemu-devel] [RFC 06/23] prep: Add i82378 PCI-to-ISA bridge emulation Andreas Färber
@ 2011-06-14  2:37             ` Andreas Färber
  2011-06-14  2:37               ` [Qemu-devel] [PATCH v5 08/23] qdev: Add support for property type bool Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau, Markus Armbruster

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

Don't create an ISA bus at machine level, the i82378 does that.

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/ppc_prep.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 50cb6c7..27e1d14 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -775,8 +775,10 @@ static void ibm_40p_init(ram_addr_t ram_size,
     char *filename;
     int bios_size;
     ram_addr_t ram_offset, bios_offset;
+    qemu_irq *cpu_exit_irq;
     DeviceState *dev;
     PCIBus *pci_bus;
+    PCIDevice *pci;
 
     // IBM E15 graphic adapter (S3 Vision864)
     // PowerPC 601
@@ -823,7 +825,12 @@ static void ibm_40p_init(ram_addr_t ram_size,
     /* PCI host */
     dev = sysbus_create_simple("prep-pci", 0x80800000, NULL);
     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
-    (void)pci_bus;
+
+    /* PCI -> ISA bridge */
+    pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    qdev_connect_gpio_out(&pci->qdev, 0, env->irq_inputs[PPC6xx_INPUT_INT]);
+    qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
 }
 
 static QEMUMachine prep_machine = {
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [PATCH v5 08/23] qdev: Add support for property type bool
  2011-06-14  2:37             ` [Qemu-devel] [RFC 07/23] 40p: Add a PCI to ISA bridge (i82378) Andreas Färber
@ 2011-06-14  2:37               ` Andreas Färber
  2011-06-14  2:37                 ` [Qemu-devel] [PATCH v5 09/23] qdev: Add helpers for reading properties Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Markus Armbruster, Juan Quintela

VMState supports the type bool but qdev instead supports bit, backed by
uint32_t. Therefore let's add DEFINE_PROP_BOOL() and qdev_prop_set_bool().

Since, e.g., enabled=on does not look nice, parse/print "yes" and "no".
Also support on/off as secondary values and vice versa.

Cc: Juan Quintela <quintela@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/qdev-properties.c |   43 +++++++++++++++++++++++++++++++++++++++++--
 hw/qdev.h            |    5 +++++
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index eff2d24..3ad6f93 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -40,9 +40,11 @@ static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
 /* Bit */
 static int parse_bit(DeviceState *dev, Property *prop, const char *str)
 {
-    if (!strncasecmp(str, "on", 2))
+    if (!strncasecmp(str, "on", 2) ||
+        !strncasecmp(str, "yes", 3))
         bit_prop_set(dev, prop, true);
-    else if (!strncasecmp(str, "off", 3))
+    else if (!strncasecmp(str, "off", 3) ||
+             !strncasecmp(str, "no", 2))
         bit_prop_set(dev, prop, false);
     else
         return -EINVAL;
@@ -63,6 +65,38 @@ PropertyInfo qdev_prop_bit = {
     .print = print_bit,
 };
 
+/* --- bool --- */
+
+static int parse_bool(DeviceState *dev, Property *prop, const char *str)
+{
+    bool *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (strncasecmp(str, "yes", 3) == 0 ||
+        strncasecmp(str, "on", 2) == 0) {
+        *ptr = true;
+    } else if (strncasecmp(str, "no", 2) == 0 ||
+               strncasecmp(str, "off", 3) == 0) {
+        *ptr = false;
+    } else {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int print_bool(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    bool *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, (*ptr) ? "yes" : "no");
+}
+
+PropertyInfo qdev_prop_bool = {
+    .name = "yes/no",
+    .type = PROP_TYPE_BOOL,
+    .size = sizeof(bool),
+    .parse = parse_bool,
+    .print = print_bool,
+};
+
 /* --- 8bit integer --- */
 
 static int parse_uint8(DeviceState *dev, Property *prop, const char *str)
@@ -644,6 +678,11 @@ void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
     qdev_prop_set(dev, name, &value, PROP_TYPE_BIT);
 }
 
+void qdev_prop_set_bool(DeviceState *dev, const char *name, bool value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_BOOL);
+}
+
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8);
diff --git a/hw/qdev.h b/hw/qdev.h
index 8a13ec9..f05166d 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -101,6 +101,7 @@ enum PropertyType {
     PROP_TYPE_VLAN,
     PROP_TYPE_PTR,
     PROP_TYPE_BIT,
+    PROP_TYPE_BOOL,
 };
 
 struct PropertyInfo {
@@ -219,6 +220,7 @@ int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 /*** qdev-properties.c ***/
 
 extern PropertyInfo qdev_prop_bit;
+extern PropertyInfo qdev_prop_bool;
 extern PropertyInfo qdev_prop_uint8;
 extern PropertyInfo qdev_prop_uint16;
 extern PropertyInfo qdev_prop_uint32;
@@ -257,6 +259,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
         .defval    = (bool[]) { (_defval) },                     \
         }
 
+#define DEFINE_PROP_BOOL(_n, _s, _f, _d)                        \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bool, bool)
 #define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
     DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
 #define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
@@ -298,6 +302,7 @@ int qdev_prop_exists(DeviceState *dev, const char *name);
 int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
 void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type);
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
+void qdev_prop_set_bool(DeviceState *dev, const char *name, bool value);
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [PATCH v5 09/23] qdev: Add helpers for reading properties
  2011-06-14  2:37               ` [Qemu-devel] [PATCH v5 08/23] qdev: Add support for property type bool Andreas Färber
@ 2011-06-14  2:37                 ` Andreas Färber
  2011-06-14  2:37                   ` [Qemu-devel] [RFC v5 10/23] isa: Provide enable and disable callbacks Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber

Add helpers qdev_prop_get_*() to access all integer qdev properties
as well as string properties.

This effectively turns qdev properties from write-only to read/write,
allowing to inspect a private DeviceState.

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/qdev-properties.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/qdev.h            |    8 +++++++
 2 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 3ad6f93..92bc095 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -673,6 +673,24 @@ void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyT
     qdev_prop_cpy(dev, prop, src);
 }
 
+void *qdev_prop_get(DeviceState *dev, const char *name, enum PropertyType type)
+{
+    Property *prop;
+
+    prop = qdev_prop_find(dev, name);
+    if (!prop) {
+        fprintf(stderr, "%s: property \"%s.%s\" not found\n",
+                __FUNCTION__, dev->info->name, name);
+        abort();
+    }
+    if (prop->info->type != type) {
+        fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
+                __FUNCTION__, dev->info->name, name);
+        abort();
+    }
+    return qdev_get_prop_ptr(dev, prop);
+}
+
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_BIT);
@@ -683,36 +701,71 @@ void qdev_prop_set_bool(DeviceState *dev, const char *name, bool value)
     qdev_prop_set(dev, name, &value, PROP_TYPE_BOOL);
 }
 
+bool qdev_prop_get_bool(DeviceState *dev, const char *name)
+{
+    return *(bool *)qdev_prop_get(dev, name, PROP_TYPE_BOOL);
+}
+
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8);
 }
 
+uint8_t qdev_prop_get_uint8(DeviceState *dev, const char *name)
+{
+    return *(uint8_t *)qdev_prop_get(dev, name, PROP_TYPE_UINT8);
+}
+
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16);
 }
 
+uint16_t qdev_prop_get_uint16(DeviceState *dev, const char *name)
+{
+    return *(uint16_t *)qdev_prop_get(dev, name, PROP_TYPE_UINT16);
+}
+
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32);
 }
 
+uint32_t qdev_prop_get_uint32(DeviceState *dev, const char *name)
+{
+    return *(uint32_t *)qdev_prop_get(dev, name, PROP_TYPE_UINT32);
+}
+
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_INT32);
 }
 
+int32_t qdev_prop_get_int32(DeviceState *dev, const char *name)
+{
+    return *(int32_t *)qdev_prop_get(dev, name, PROP_TYPE_INT32);
+}
+
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64);
 }
 
+uint64_t qdev_prop_get_uint64(DeviceState *dev, const char *name)
+{
+    return *(uint64_t *)qdev_prop_get(dev, name, PROP_TYPE_UINT64);
+}
+
 void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_STRING);
 }
 
+char *qdev_prop_get_string(DeviceState *dev, const char *name)
+{
+    return (char *)qdev_prop_get(dev, name, PROP_TYPE_STRING);
+}
+
 int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
 {
     int res;
diff --git a/hw/qdev.h b/hw/qdev.h
index f05166d..71bd230 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -301,14 +301,22 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
 int qdev_prop_exists(DeviceState *dev, const char *name);
 int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
 void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type);
+void *qdev_prop_get(DeviceState *dev, const char *name, enum PropertyType type);
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
 void qdev_prop_set_bool(DeviceState *dev, const char *name, bool value);
+bool qdev_prop_get_bool(DeviceState *dev, const char *name);
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
+uint8_t qdev_prop_get_uint8(DeviceState *dev, const char *name);
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
+uint16_t qdev_prop_get_uint16(DeviceState *dev, const char *name);
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
+uint32_t qdev_prop_get_uint32(DeviceState *dev, const char *name);
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
+int32_t qdev_prop_get_int32(DeviceState *dev, const char *name);
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
+uint64_t qdev_prop_get_uint64(DeviceState *dev, const char *name);
 void qdev_prop_set_string(DeviceState *dev, const char *name, char *value);
+char *qdev_prop_get_string(DeviceState *dev, const char *name);
 void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value);
 void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 10/23] isa: Provide enable and disable callbacks
  2011-06-14  2:37                 ` [Qemu-devel] [PATCH v5 09/23] qdev: Add helpers for reading properties Andreas Färber
@ 2011-06-14  2:37                   ` Andreas Färber
  2011-06-14  2:37                     ` [Qemu-devel] [RFC v5 11/23] isa: Allow to un-assign I/O ports Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: Andreas Färber, Juan Quintela, Gerd Hoffmann, Markus Armbruster

To allow enabling/disabling present ISA devices without hotplug,
keep track of state and add a helper to avoid enabling twice.
Since the properties to be configured are defined at device level,
delegate the actual work to callback functions. Use separate ones
for enable and disable, otherwise the functions ended up as a big
"if" statement.

If no callback is supplied, the device can't be disabled.

Prepare VMSTATE_ISA_DEVICE for devices that support disabling.
Legacy devices never change their state and won't need this yet.
For those that do, supply a "needed" callback.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/hw.h      |   15 +++++++++++++++
 hw/isa-bus.c |   39 +++++++++++++++++++++++++++++++++++++++
 hw/isa.h     |    6 ++++++
 3 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/hw/hw.h b/hw/hw.h
index 56447a7..32226b1 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -628,6 +628,21 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .info         = &vmstate_info_unused_buffer,                     \
     .flags        = VMS_BUFFER,                                      \
 }
+
+extern const VMStateDescription vmstate_isa_device;
+
+#define VMSTATE_ISA_DEVICE_V(_field, _state, _version) {             \
+    .name       = (stringify(_field)),                               \
+    .version_id   = (_version),                                      \
+    .size       = sizeof(ISADevice),                                 \
+    .vmsd       = &vmstate_isa_device,                               \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, ISADevice),   \
+}
+
+#define VMSTATE_ISA_DEVICE(_field, _state)                           \
+    VMSTATE_ISA_DEVICE_V(_field, _state, 0)
+
 extern const VMStateDescription vmstate_pci_device;
 
 #define VMSTATE_PCI_DEVICE(_field, _state) {                         \
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 2765543..bbafb75 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -112,6 +112,9 @@ static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
 
     dev->isairq[0] = -1;
     dev->isairq[1] = -1;
+    dev->enabled = true; /* XXX for legacy devices without qdev property */
+
+    dev->initially_enabled = dev->enabled;
 
     return info->init(dev);
 }
@@ -156,6 +159,42 @@ ISADevice *isa_create_simple(const char *name)
     return dev;
 }
 
+const VMStateDescription vmstate_isa_device = {
+    .name = "ISADevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_BOOL(enabled, ISADevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int isa_set_state(ISADevice *dev, bool enabled)
+{
+    ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, dev->qdev.info);
+    isa_qdev_initfn statefn = enabled ? info->enable : info->disable;
+    int err;
+
+    if (dev->enabled == enabled) {
+        return 0;
+    } else if (statefn == NULL) {
+        return -1;
+    }
+    err = statefn(dev);
+    if (err < 0) {
+        return err;
+    }
+    dev->enabled = enabled;
+    return err;
+}
+
+bool isa_vmstate_needed(void *opaque)
+{
+    ISADevice *s = opaque;
+
+    return s->initially_enabled != s->enabled;
+}
+
 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
 {
     ISADevice *d = DO_UPCAST(ISADevice, qdev, dev);
diff --git a/hw/isa.h b/hw/isa.h
index d2b6126..1eefd17 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -16,12 +16,16 @@ struct ISADevice {
     int nirqs;
     uint16_t ioports[32];
     int nioports;
+    bool enabled;
+    bool initially_enabled;
 };
 
 typedef int (*isa_qdev_initfn)(ISADevice *dev);
 struct ISADeviceInfo {
     DeviceInfo qdev;
     isa_qdev_initfn init;
+    isa_qdev_initfn enable;
+    isa_qdev_initfn disable;
 };
 
 ISABus *isa_bus_new(DeviceState *dev);
@@ -34,6 +38,8 @@ void isa_qdev_register(ISADeviceInfo *info);
 ISADevice *isa_create(const char *name);
 ISADevice *isa_try_create(const char *name);
 ISADevice *isa_create_simple(const char *name);
+int isa_set_state(ISADevice *dev, bool enabled);
+bool isa_vmstate_needed(void *opaque);
 
 extern target_phys_addr_t isa_mem_base;
 
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 11/23] isa: Allow to un-assign I/O ports
  2011-06-14  2:37                   ` [Qemu-devel] [RFC v5 10/23] isa: Provide enable and disable callbacks Andreas Färber
@ 2011-06-14  2:37                     ` Andreas Färber
  2011-06-14  2:37                       ` [Qemu-devel] [RFC v5 12/23] isa: Allow to un-associate an IRQ Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/isa-bus.c |   15 +++++++++++++++
 hw/isa.h     |    1 +
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index bbafb75..6e33d80 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -105,6 +105,21 @@ void isa_init_ioport(ISADevice *dev, uint16_t ioport)
     isa_init_ioport_range(dev, ioport, 1);
 }
 
+void isa_discard_ioport_range(ISADevice *dev, uint16_t start, uint16_t length)
+{
+    int i, j;
+    for (i = 0; i < dev->nioports; i++) {
+        if (dev->ioports[i] == start) {
+            for (j = 0; j < dev->nioports - i; j++) {
+                dev->ioports[i + j] = dev->ioports[i + length + j];
+            }
+            dev->nioports -= length;
+            break;
+        }
+    }
+    assert(dev->nioports >= 0);
+}
+
 static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
diff --git a/hw/isa.h b/hw/isa.h
index 1eefd17..fe1a20c 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -34,6 +34,7 @@ qemu_irq isa_get_irq(int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
 void isa_init_ioport(ISADevice *dev, uint16_t ioport);
 void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
+void isa_discard_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
 void isa_qdev_register(ISADeviceInfo *info);
 ISADevice *isa_create(const char *name);
 ISADevice *isa_try_create(const char *name);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 12/23] isa: Allow to un-associate an IRQ
  2011-06-14  2:37                     ` [Qemu-devel] [RFC v5 11/23] isa: Allow to un-assign I/O ports Andreas Färber
@ 2011-06-14  2:37                       ` Andreas Färber
  2011-06-14  2:37                         ` [Qemu-devel] [RFC v5 13/23] parallel: Implement ISA state callbacks Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Gerd Hoffmann, Markus Armbruster

ISADevices keep a list of numeric IRQs. Remove one from that list.
Also optionally NULL the qemu_irq, calling it "uninit" for symmetry.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/isa-bus.c |   17 +++++++++++++++++
 hw/isa.h     |    1 +
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 6e33d80..d037ed3 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -80,6 +80,23 @@ void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
     dev->nirqs++;
 }
 
+void isa_uninit_irq(ISADevice *dev, qemu_irq *p, int isairq)
+{
+    int i, j;
+    for (i = 0; i < dev->nirqs; i++) {
+        if (dev->isairq[i] == isairq) {
+            for (j = i + 1; j < dev->nirqs; j++) {
+                dev->isairq[j - 1] = dev->isairq[j];
+            }
+            dev->nirqs--;
+            break;
+        }
+    }
+    if (p != NULL) {
+        *p = NULL;
+    }
+}
+
 static void isa_init_ioport_one(ISADevice *dev, uint16_t ioport)
 {
     assert(dev->nioports < ARRAY_SIZE(dev->ioports));
diff --git a/hw/isa.h b/hw/isa.h
index fe1a20c..72829bb 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -32,6 +32,7 @@ ISABus *isa_bus_new(DeviceState *dev);
 void isa_bus_irqs(qemu_irq *irqs);
 qemu_irq isa_get_irq(int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
+void isa_uninit_irq(ISADevice *dev, qemu_irq *p, int isairq);
 void isa_init_ioport(ISADevice *dev, uint16_t ioport);
 void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
 void isa_discard_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 13/23] parallel: Implement ISA state callbacks
  2011-06-14  2:37                       ` [Qemu-devel] [RFC v5 12/23] isa: Allow to un-associate an IRQ Andreas Färber
@ 2011-06-14  2:37                         ` Andreas Färber
  2011-06-14  2:37                           ` [Qemu-devel] [RFC v5 14/23] serial: " Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Gerd Hoffmann, Markus Armbruster

Add "enabled" qdev property, and implement enable and disable callbacks.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/parallel.c |   75 +++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 54 insertions(+), 21 deletions(-)

diff --git a/hw/parallel.c b/hw/parallel.c
index cc853a5..8315894 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -446,6 +446,55 @@ static void parallel_reset(void *opaque)
     s->last_read_offset = ~0U;
 }
 
+static int parallel_isa_enable(ISADevice *dev)
+{
+    ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
+    ParallelState *s = &isa->state;
+    int base;
+
+    isa_init_irq(dev, &s->irq, isa->isairq);
+
+    base = isa->iobase;
+    if (s->hw_driver) {
+        register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
+        register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
+        isa_init_ioport_range(dev, base, 8);
+
+        register_ioport_write(base + 4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
+        register_ioport_read(base + 4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
+        register_ioport_write(base + 4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
+        register_ioport_read(base + 4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
+        isa_init_ioport(dev, base + 4);
+        register_ioport_write(base + 0x400, 8, 1, parallel_ioport_ecp_write, s);
+        register_ioport_read(base + 0x400, 8, 1, parallel_ioport_ecp_read, s);
+        isa_init_ioport_range(dev, base + 0x400, 8);
+    }
+    else {
+        register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
+        register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
+        isa_init_ioport_range(dev, base, 8);
+    }
+    return 0;
+}
+
+static int parallel_isa_disable(ISADevice *dev)
+{
+    ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
+    ParallelState *s = &isa->state;
+
+    isa_uninit_irq(dev, &s->irq, isa->isairq);
+
+    isa_discard_ioport_range(dev, isa->iobase, 8);
+    isa_unassign_ioport(isa->iobase, 8);
+    if (s->hw_driver) {
+        isa_discard_ioport_range(dev, isa->iobase + 4, 1);
+        isa_unassign_ioport(isa->iobase + 4, 1);
+        isa_discard_ioport_range(dev, isa->iobase + 0x400, 8);
+        isa_unassign_ioport(isa->iobase + 0x400, 8);
+    }
+    return 0;
+}
+
 static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
 
 static int parallel_isa_initfn(ISADevice *dev)
@@ -453,7 +502,6 @@ static int parallel_isa_initfn(ISADevice *dev)
     static int index;
     ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
     ParallelState *s = &isa->state;
-    int base;
     uint8_t dummy;
 
     if (!s->chr) {
@@ -469,8 +517,6 @@ static int parallel_isa_initfn(ISADevice *dev)
         isa->iobase = isa_parallel_io[isa->index];
     index++;
 
-    base = isa->iobase;
-    isa_init_irq(dev, &s->irq, isa->isairq);
     qemu_register_reset(parallel_reset, s);
 
     if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
@@ -478,24 +524,8 @@ static int parallel_isa_initfn(ISADevice *dev)
         s->status = dummy;
     }
 
-    if (s->hw_driver) {
-        register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
-        register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
-        isa_init_ioport_range(dev, base, 8);
-
-        register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
-        register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
-        register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
-        register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
-        isa_init_ioport(dev, base+4);
-        register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
-        register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
-        isa_init_ioport_range(dev, base+0x400, 8);
-    }
-    else {
-        register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
-        register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
-        isa_init_ioport_range(dev, base, 8);
+    if (dev->enabled) {
+        parallel_isa_enable(dev);
     }
     return 0;
 }
@@ -581,11 +611,14 @@ static ISADeviceInfo parallel_isa_info = {
     .qdev.name  = "isa-parallel",
     .qdev.size  = sizeof(ISAParallelState),
     .init       = parallel_isa_initfn,
+    .enable     = parallel_isa_enable,
+    .disable    = parallel_isa_disable,
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
         DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
         DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
         DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
+        DEFINE_PROP_BOOL("enabled", ISAParallelState, dev.enabled, true),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 14/23] serial: Implement ISA state callbacks
  2011-06-14  2:37                         ` [Qemu-devel] [RFC v5 13/23] parallel: Implement ISA state callbacks Andreas Färber
@ 2011-06-14  2:37                           ` Andreas Färber
  2011-06-14  2:37                             ` [Qemu-devel] [PATCH v5 15/23] fdc: Parametrize ISA base, IRQ and DMA Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: Andreas Färber, Juan Quintela, Gerd Hoffmann, Markus Armbruster

Add "enabled" qdev property, and implement enable and disable callbacks.

Incorporate ISA VMState as well as I/O base and IRQ as subsection, and
implement pre_load and post_load callbacks.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/serial.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/hw/serial.c b/hw/serial.c
index 0ee61dd..7a63b7d 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -161,6 +161,8 @@ typedef struct ISASerialState {
     uint32_t iobase;
     uint32_t isairq;
     SerialState state;
+    uint32_t initial_iobase;
+    uint32_t initial_isairq;
 } ISASerialState;
 
 static void serial_receive1(void *opaque, const uint8_t *buf, int size);
@@ -752,6 +754,31 @@ void serial_set_frequency(SerialState *s, uint32_t frequency)
     serial_update_parameters(s);
 }
 
+static int serial_isa_enable(ISADevice *dev)
+{
+    ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev);
+    SerialState *s = &isa->state;
+
+    isa_init_irq(dev, &s->irq, isa->isairq);
+
+    register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s);
+    register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s);
+    isa_init_ioport_range(dev, isa->iobase, 8);
+    return 0;
+}
+
+static int serial_isa_disable(ISADevice *dev)
+{
+    ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev);
+    SerialState *s = &isa->state;
+
+    isa_uninit_irq(dev, &s->irq, isa->isairq);
+
+    isa_discard_ioport_range(dev, isa->iobase, 8);
+    isa_unassign_ioport(isa->iobase, 8);
+    return 0;
+}
+
 static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
 static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
 
@@ -771,25 +798,76 @@ static int serial_isa_initfn(ISADevice *dev)
         isa->isairq = isa_serial_irq[isa->index];
     index++;
 
+    isa->initial_iobase = isa->iobase;
+    isa->initial_isairq = isa->isairq;
+
     s->baudbase = 115200;
-    isa_init_irq(dev, &s->irq, isa->isairq);
     serial_init_core(s);
     qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
 
-    register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s);
-    register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s);
-    isa_init_ioport_range(dev, isa->iobase, 8);
+    if (dev->enabled) {
+        serial_isa_enable(dev);
+    }
     return 0;
 }
 
+static int serial_isa_pre_load(void *opaque)
+{
+    ISASerialState *s = opaque;
+
+    isa_set_state(&s->dev, false);
+    return 0;
+}
+
+static int serial_isa_post_load(void *opaque, int version_id)
+{
+    ISASerialState *s = opaque;
+    ISADevice *dev = &s->dev;
+
+    if (dev->enabled) {
+        serial_isa_enable(dev);
+    }
+    return 0;
+}
+
+static bool serial_isa_config_needed(void *opaque)
+{
+    ISASerialState *s = opaque;
+
+    return isa_vmstate_needed(&s->dev) ||
+        s->initial_iobase != s->iobase ||
+        s->initial_isairq != s->isairq;
+}
+
+static const VMStateDescription vmstate_isa_serial_isaconfig = {
+    .name = "serial/isa-config",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_ISA_DEVICE(dev, ISASerialState),
+        VMSTATE_UINT32(iobase, ISASerialState),
+        VMSTATE_UINT32(isairq, ISASerialState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_isa_serial = {
     .name = "serial",
     .version_id = 3,
     .minimum_version_id = 2,
+    .pre_load  = serial_isa_pre_load,
+    .post_load = serial_isa_post_load,
     .fields      = (VMStateField []) {
         VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
         VMSTATE_END_OF_LIST()
-    }
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_isa_serial_isaconfig,
+            .needed = serial_isa_config_needed,
+        }, {
+        }
+    },
 };
 
 SerialState *serial_init(int base, qemu_irq irq, int baudbase,
@@ -962,11 +1040,14 @@ static ISADeviceInfo serial_isa_info = {
     .qdev.size  = sizeof(ISASerialState),
     .qdev.vmsd  = &vmstate_isa_serial,
     .init       = serial_isa_initfn,
+    .enable     = serial_isa_enable,
+    .disable    = serial_isa_disable,
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("index", ISASerialState, index,   -1),
         DEFINE_PROP_HEX32("iobase", ISASerialState, iobase,  -1),
         DEFINE_PROP_UINT32("irq",   ISASerialState, isairq,  -1),
         DEFINE_PROP_CHR("chardev",  ISASerialState, state.chr),
+        DEFINE_PROP_BOOL("enabled", ISASerialState, dev.enabled, true),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [PATCH v5 15/23] fdc: Parametrize ISA base, IRQ and DMA
  2011-06-14  2:37                           ` [Qemu-devel] [RFC v5 14/23] serial: " Andreas Färber
@ 2011-06-14  2:37                             ` Andreas Färber
  2011-06-14  2:37                               ` [Qemu-devel] [RFC v5 16/23] fdc: Implement ISA state callbacks Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau, Markus Armbruster

From: Hervé Poussineau <hpoussin@reactos.org>

Keep the PC values as defaults but allow to override them for PReP.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/fdc.c |   27 +++++++++++++++------------
 1 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/hw/fdc.c b/hw/fdc.c
index edf0360..f4e3e0d 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -425,6 +425,9 @@ typedef struct FDCtrlSysBus {
 
 typedef struct FDCtrlISABus {
     ISADevice busdev;
+    uint32_t iobase;
+    uint32_t irq;
+    uint32_t dma;
     struct FDCtrl state;
     int32_t bootindexA;
     int32_t bootindexB;
@@ -1895,26 +1898,23 @@ static int isabus_fdc_init1(ISADevice *dev)
 {
     FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
     FDCtrl *fdctrl = &isa->state;
-    int iobase = 0x3f0;
-    int isairq = 6;
-    int dma_chann = 2;
     int ret;
 
-    register_ioport_read(iobase + 0x01, 5, 1,
+    register_ioport_read(isa->iobase + 0x01, 5, 1,
                          &fdctrl_read_port, fdctrl);
-    register_ioport_read(iobase + 0x07, 1, 1,
+    register_ioport_read(isa->iobase + 0x07, 1, 1,
                          &fdctrl_read_port, fdctrl);
-    register_ioport_write(iobase + 0x01, 5, 1,
+    register_ioport_write(isa->iobase + 0x01, 5, 1,
                           &fdctrl_write_port, fdctrl);
-    register_ioport_write(iobase + 0x07, 1, 1,
+    register_ioport_write(isa->iobase + 0x07, 1, 1,
                           &fdctrl_write_port, fdctrl);
-    isa_init_ioport_range(dev, iobase, 6);
-    isa_init_ioport(dev, iobase + 7);
+    isa_init_ioport_range(dev, isa->iobase, 6);
+    isa_init_ioport(dev, isa->iobase + 7);
 
-    isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
-    fdctrl->dma_chann = dma_chann;
+    isa_init_irq(&isa->busdev, &fdctrl->irq, isa->irq);
+    fdctrl->dma_chann = isa->dma;
 
-    qdev_set_legacy_instance_id(&dev->qdev, iobase, 2);
+    qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 2);
     ret = fdctrl_init_common(fdctrl);
 
     add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy@0");
@@ -1979,6 +1979,9 @@ static ISADeviceInfo isa_fdc_info = {
     .qdev.vmsd  = &vmstate_isa_fdc,
     .qdev.reset = fdctrl_external_reset_isa,
     .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", FDCtrlISABus, iobase, 0x3f0),
+        DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
+        DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
         DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
         DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
         DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 16/23] fdc: Implement ISA state callbacks
  2011-06-14  2:37                             ` [Qemu-devel] [PATCH v5 15/23] fdc: Parametrize ISA base, IRQ and DMA Andreas Färber
@ 2011-06-14  2:37                               ` Andreas Färber
  2011-06-14  2:37                                 ` [Qemu-devel] [RFC v5 17/23] ide: Allow to discard I/O ports Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: Andreas Färber, Juan Quintela, Gerd Hoffmann, Markus Armbruster

Add "enabled" qdev property, and implement enable and disable callbacks.

Incorporate ISA VMState as well as I/O base and IRQ as subsection,
and implement pre_load and post_load callbacks.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/fdc.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/hw/fdc.c b/hw/fdc.c
index f4e3e0d..778fb58 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -431,6 +431,8 @@ typedef struct FDCtrlISABus {
     struct FDCtrl state;
     int32_t bootindexA;
     int32_t bootindexB;
+    uint32_t initial_iobase;
+    uint32_t initial_irq;
 } FDCtrlISABus;
 
 static uint32_t fdctrl_read (void *opaque, uint32_t reg)
@@ -1894,11 +1896,10 @@ static int fdctrl_init_common(FDCtrl *fdctrl)
     return fdctrl_connect_drives(fdctrl);
 }
 
-static int isabus_fdc_init1(ISADevice *dev)
+static int isabus_fdc_enable(ISADevice *dev)
 {
     FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
     FDCtrl *fdctrl = &isa->state;
-    int ret;
 
     register_ioport_read(isa->iobase + 0x01, 5, 1,
                          &fdctrl_read_port, fdctrl);
@@ -1912,7 +1913,58 @@ static int isabus_fdc_init1(ISADevice *dev)
     isa_init_ioport(dev, isa->iobase + 7);
 
     isa_init_irq(&isa->busdev, &fdctrl->irq, isa->irq);
+
+    return 0;
+}
+
+static int isabus_fdc_disable(ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+
+    isa_discard_ioport_range(dev, isa->iobase + 0x07, 1);
+    isa_discard_ioport_range(dev, isa->iobase + 0x01, 5);
+    isa_unassign_ioport(isa->iobase + 7, 1);
+    isa_unassign_ioport(isa->iobase, 6);
+
+    isa_uninit_irq(&isa->busdev, &fdctrl->irq, isa->irq);
+    fdctrl->irq = NULL;
+
+    return 0;
+}
+
+static int isabus_fdc_pre_load(void *opaque)
+{
+    FDCtrlISABus *s = opaque;
+
+    isa_set_state(&s->busdev, false);
+    return 0;
+}
+
+static int isabus_fdc_post_load(void *opaque, int version_id)
+{
+    FDCtrlISABus *s = opaque;
+    ISADevice *dev = &s->busdev;
+
+    if (dev->enabled) {
+        isabus_fdc_enable(dev);
+    }
+    return 0;
+}
+
+static int isabus_fdc_init1(ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+    int ret;
+
+    isa->initial_iobase = isa->iobase;
+    isa->initial_irq = isa->irq;
+
     fdctrl->dma_chann = isa->dma;
+    if (dev->enabled) {
+        isabus_fdc_enable(dev);
+    }
 
     qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 2);
     ret = fdctrl_init_common(fdctrl);
@@ -1960,18 +2012,50 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
     return fdctrl_init_common(fdctrl);
 }
 
+static bool isabus_fdc_isaconfig_needed(void *opaque)
+{
+    FDCtrlISABus *s = opaque;
+
+    return isa_vmstate_needed(&s->busdev) ||
+        s->initial_iobase != s->iobase ||
+        s->initial_irq != s->irq;
+}
+
+static const VMStateDescription vmstate_isa_fdc_isaconfig = {
+    .name = "fdc/isa-config",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_ISA_DEVICE(busdev, FDCtrlISABus),
+        VMSTATE_UINT32(iobase, FDCtrlISABus),
+        VMSTATE_UINT32(irq, FDCtrlISABus),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_isa_fdc ={
     .name = "fdc",
     .version_id = 2,
     .minimum_version_id = 2,
+    .pre_load  = isabus_fdc_pre_load,
+    .post_load = isabus_fdc_post_load,
     .fields = (VMStateField []) {
         VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
         VMSTATE_END_OF_LIST()
-    }
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_isa_fdc_isaconfig,
+            .needed = isabus_fdc_isaconfig_needed,
+        }, {
+        }
+    },
 };
 
 static ISADeviceInfo isa_fdc_info = {
     .init = isabus_fdc_init1,
+    .enable = isabus_fdc_enable,
+    .disable = isabus_fdc_disable,
     .qdev.name  = "isa-fdc",
     .qdev.fw_name  = "fdc",
     .qdev.size  = sizeof(FDCtrlISABus),
@@ -1986,6 +2070,7 @@ static ISADeviceInfo isa_fdc_info = {
         DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
         DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
         DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
+        DEFINE_PROP_BOOL("enabled", FDCtrlISABus, busdev.enabled, true),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 17/23] ide: Allow to discard I/O ports
  2011-06-14  2:37                               ` [Qemu-devel] [RFC v5 16/23] fdc: Implement ISA state callbacks Andreas Färber
@ 2011-06-14  2:37                                 ` Andreas Färber
  2011-06-14  2:37                                   ` [Qemu-devel] [RFC v5 18/23] ide: Implement ISA state callbacks Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/ide/core.c     |    8 ++++++++
 hw/ide/internal.h |    1 +
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 95beb17..8fa2201 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1761,6 +1761,14 @@ void ide_init_ioport(IDEBus *bus, int iobase, int iobase2)
     register_ioport_read(iobase, 4, 4, ide_data_readl, bus);
 }
 
+void ide_discard_ioport(int iobase, int iobase2)
+{
+    isa_unassign_ioport(iobase, 8);
+    if (iobase2 != 0) {
+        isa_unassign_ioport(iobase2, 1);
+    }
+}
+
 static bool is_identify_set(void *opaque, int version_id)
 {
     IDEState *s = opaque;
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index c2b35ec..dc0a2c9 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -564,6 +564,7 @@ void ide_init2(IDEBus *bus, qemu_irq irq);
 void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
                                     DriveInfo *hd1, qemu_irq irq);
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
+void ide_discard_ioport(int iobase, int iobase2);
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val);
 void ide_dma_cb(void *opaque, int ret);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 18/23] ide: Implement ISA state callbacks
  2011-06-14  2:37                                 ` [Qemu-devel] [RFC v5 17/23] ide: Allow to discard I/O ports Andreas Färber
@ 2011-06-14  2:37                                   ` Andreas Färber
  2011-06-14  2:37                                     ` [Qemu-devel] [RFC v5 19/23] prep: Add pc87312 Super I/O emulation Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: Andreas Färber, Juan Quintela, Gerd Hoffmann, Markus Armbruster

Add "enabled" qdev property, and implement enable and disable callbacks.

Incorporate ISA VMState as well as I/O bases and IRQ as subsection,
and implement pre_load and post_load callbacks.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 hw/ide/isa.c |   98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 4ac7453..de8b949 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -41,6 +41,9 @@ typedef struct ISAIDEState {
     uint32_t  iobase2;
     uint32_t  isairq;
     qemu_irq  irq;
+    uint32_t  initial_iobase;
+    uint32_t  initial_iobase2;
+    uint32_t  initial_isairq;
 } ISAIDEState;
 
 static void isa_ide_reset(DeviceState *d)
@@ -50,27 +53,109 @@ static void isa_ide_reset(DeviceState *d)
     ide_bus_reset(&s->bus);
 }
 
+static int isa_ide_enable(ISADevice *dev)
+{
+    ISAIDEState *s = DO_UPCAST(ISAIDEState, dev, dev);
+
+    ide_init_ioport(&s->bus, s->iobase, s->iobase2);
+
+    isa_init_ioport_range(dev, s->iobase, 8);
+    isa_init_ioport(dev, s->iobase2);
+
+    isa_init_irq(dev, &s->irq, s->isairq);
+
+    return 0;
+}
+
+static int isa_ide_disable(ISADevice *dev)
+{
+    ISAIDEState *s = DO_UPCAST(ISAIDEState, dev, dev);
+
+    ide_discard_ioport(s->iobase, s->iobase2);
+
+    isa_discard_ioport_range(dev, s->iobase2, 1);
+    isa_discard_ioport_range(dev, s->iobase, 8);
+
+    isa_uninit_irq(dev, &s->irq, s->isairq);
+
+    return 0;
+}
+
+static int isa_ide_pre_load(void *opaque)
+{
+    ISAIDEState *s = opaque;
+
+    isa_set_state(&s->dev, false);
+    return 0;
+}
+
+static int isa_ide_post_load(void *opaque, int version_id)
+{
+    ISAIDEState *s = opaque;
+    ISADevice *dev = &s->dev;
+
+    if (dev->enabled) {
+        isa_ide_enable(dev);
+    }
+    return 0;
+}
+
+static bool isa_ide_isaconfig_needed(void *opaque)
+{
+    ISAIDEState *s = opaque;
+
+    return isa_vmstate_needed(&s->dev) ||
+        s->initial_iobase != s->iobase ||
+        s->initial_iobase2 != s->iobase2 ||
+        s->initial_isairq != s->isairq;
+}
+
+static const VMStateDescription vmstate_ide_isa_config = {
+    .name = "isa-ide/isa-config",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_ISA_DEVICE(dev, ISAIDEState),
+        VMSTATE_UINT32(iobase, ISAIDEState),
+        VMSTATE_UINT32(iobase2, ISAIDEState),
+        VMSTATE_UINT32(isairq, ISAIDEState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_ide_isa = {
     .name = "isa-ide",
     .version_id = 3,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
+    .pre_load = isa_ide_pre_load,
+    .post_load = isa_ide_post_load,
     .fields      = (VMStateField []) {
         VMSTATE_IDE_BUS(bus, ISAIDEState),
         VMSTATE_IDE_DRIVES(bus.ifs, ISAIDEState),
         VMSTATE_END_OF_LIST()
-    }
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ide_isa_config,
+            .needed = isa_ide_isaconfig_needed,
+        }, {
+        }
+    },
 };
 
 static int isa_ide_initfn(ISADevice *dev)
 {
     ISAIDEState *s = DO_UPCAST(ISAIDEState, dev, dev);
 
+    s->initial_iobase = s->iobase;
+    s->initial_iobase2 = s->iobase2;
+    s->initial_isairq = s->isairq;
+
     ide_bus_new(&s->bus, &s->dev.qdev, 0);
-    ide_init_ioport(&s->bus, s->iobase, s->iobase2);
-    isa_init_irq(dev, &s->irq, s->isairq);
-    isa_init_ioport_range(dev, s->iobase, 8);
-    isa_init_ioport(dev, s->iobase2);
+    if (dev->enabled) {
+        isa_ide_enable(dev);
+    }
     ide_init2(&s->bus, s->irq);
     vmstate_register(&dev->qdev, 0, &vmstate_ide_isa, s);
     return 0;
@@ -102,11 +187,14 @@ static ISADeviceInfo isa_ide_info = {
     .qdev.fw_name  = "ide",
     .qdev.size  = sizeof(ISAIDEState),
     .init       = isa_ide_initfn,
+    .enable     = isa_ide_enable,
+    .disable     = isa_ide_disable,
     .qdev.reset = isa_ide_reset,
     .qdev.props = (Property[]) {
         DEFINE_PROP_HEX32("iobase",  ISAIDEState, iobase,  0x1f0),
         DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
         DEFINE_PROP_UINT32("irq",    ISAIDEState, isairq,  14),
+        DEFINE_PROP_BOOL("enabled",  ISAIDEState, dev.enabled, true),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v5 19/23] prep: Add pc87312 Super I/O emulation
  2011-06-14  2:37                                   ` [Qemu-devel] [RFC v5 18/23] ide: Implement ISA state callbacks Andreas Färber
@ 2011-06-14  2:37                                     ` Andreas Färber
  2011-06-14  2:37                                       ` [Qemu-devel] [RFC 20/23] 40p: Add the Super I/O chip (pc87312) Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

This provides floppy and IDE controllers as well as
serial and parallel ports.

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

Create all devices ahead of time and enable/disable as needed.
Check the qdev properties for whether a change is necessary.

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.objs                   |    1 +
 default-configs/ppc-softmmu.mak |    2 +
 hw/pc87312.c                    |  495 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 498 insertions(+), 0 deletions(-)
 create mode 100644 hw/pc87312.c

diff --git a/Makefile.objs b/Makefile.objs
index fb57bbf..7bb6b1a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -211,6 +211,7 @@ hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 hw-obj-$(CONFIG_OPENPIC) += openpic.o
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
 hw-obj-$(CONFIG_I82378) += i82378.o
+hw-obj-$(CONFIG_PC87312) += pc87312.o
 # Mac shared devices
 hw-obj-$(CONFIG_MACIO) += macio.o
 hw-obj-$(CONFIG_CUDA) += cuda.o
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index df64ee6..0999008 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -7,6 +7,7 @@ CONFIG_ESCC=y
 CONFIG_M48T59=y
 CONFIG_VGA_PCI=y
 CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
@@ -15,6 +16,7 @@ CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
 CONFIG_I82378=y
+CONFIG_PC87312=y
 CONFIG_MACIO=y
 CONFIG_PCSPK=y
 CONFIG_CUDA=y
diff --git a/hw/pc87312.c b/hw/pc87312.c
new file mode 100644
index 0000000..14b58ed
--- /dev/null
+++ b/hw/pc87312.c
@@ -0,0 +1,495 @@
+/*
+ * QEMU National Semiconductor PC87312 (Super I/O)
+ *
+ * Copyright (c) 2010 Herve Poussineau
+ *
+ * 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 "isa.h"
+#include "fdc.h"
+#include "ide.h"
+
+//#define DEBUG_PC87312
+
+#ifdef DEBUG_PC87312
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "pc87312: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pc87312 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+#define REG_FER 0
+#define REG_FAR 1
+#define REG_PTR 2
+
+#define FER regs[REG_FER]
+#define FAR regs[REG_FAR]
+#define PTR regs[REG_PTR]
+
+#define FER_PARALLEL_EN   0x01
+#define FER_UART1_EN      0x02
+#define FER_UART2_EN      0x04
+#define FER_FDC_EN        0x08
+#define FER_FDC_4         0x10
+#define FER_FDC_ADDR      0x20
+#define FER_IDE_EN        0x40
+#define FER_IDE_ADDR      0x80
+
+#define FAR_PARALLEL_ADDR 0x03
+#define FAR_UART1_ADDR    0x0C
+#define FAR_UART2_ADDR    0x30
+#define FAR_UART_3_4      0xC0
+
+#define PTR_POWER_DOWN    0x01
+#define PTR_CLOCK_DOWN    0x02
+#define PTR_PWDN          0x04
+#define PTR_IRQ_5_7       0x08
+#define PTR_UART1_TEST    0x10
+#define PTR_UART2_TEST    0x20
+#define PTR_LOCK_CONF     0x40
+#define PTR_EPP_MODE      0x80
+
+typedef struct PC87312State {
+    uint8_t config; /* initial configuration */
+
+    struct {
+        DeviceState *dev;
+        CharDriverState *chr;
+    } parallel;
+
+    struct {
+        DeviceState *dev;
+        CharDriverState *chr;
+    } uart[2];
+
+    struct {
+        DeviceState *dev;
+        BlockDriverState *drive[2];
+        uint32_t base;
+    } fdc;
+
+    struct {
+        DeviceState *dev;
+        uint32_t base;
+    } ide;
+
+    uint8_t read_id_step;
+    uint8_t selected_index;
+
+    uint8_t regs[3];
+} PC87312State;
+
+
+/* Parallel port */
+
+static inline bool is_parallel_enabled(PC87312State *s)
+{
+    return s->FER & FER_PARALLEL_EN;
+}
+
+static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
+
+static inline uint32_t get_parallel_iobase(PC87312State *s)
+{
+    return parallel_base[s->FAR & FAR_PARALLEL_ADDR];
+}
+
+static const uint32_t parallel_irq[] = { 5, 7, 5, 0 };
+
+static inline uint32_t get_parallel_irq(PC87312State *s)
+{
+    int idx;
+    idx = (s->FAR & FAR_PARALLEL_ADDR);
+    if (idx == 0) {
+        return (s->PTR & PTR_IRQ_5_7) ? 7 : 5;
+    } else {
+        return parallel_irq[idx];
+    }
+}
+
+static inline bool is_parallel_epp(PC87312State *s)
+{
+    return (s->PTR & PTR_EPP_MODE);
+}
+
+static void update_parallel(PC87312State *s)
+{
+    ISADevice *isa;
+    uint32_t base, isairq;
+    bool enabled;
+
+    if (s->parallel.dev != NULL) {
+        isa = DO_UPCAST(ISADevice, qdev, s->parallel.dev);
+        base = get_parallel_iobase(s);
+        isairq = get_parallel_irq(s);
+        enabled = is_parallel_enabled(s);
+        if (qdev_prop_get_bool(&isa->qdev, "enabled") != enabled ||
+            qdev_prop_get_uint32(&isa->qdev, "iobase") != base ||
+            qdev_prop_get_uint32(&isa->qdev, "irq") != isairq) {
+            DPRINTF("updating parallel: base 0x%x, enabled? %s\n",
+                    base, enabled ? "yes" : "no");
+            isa_set_state(isa, false);
+            qdev_prop_set_uint32(&isa->qdev, "iobase", base);
+            qdev_prop_set_uint32(&isa->qdev, "irq", isairq);
+            if (enabled) {
+                isa_set_state(isa, true);
+            }
+        }
+    }
+}
+
+
+/* UARTs */
+
+static const uint32_t uart_base[2][4] = {
+    { 0x3e8, 0x338, 0x2e8, 0x220 },
+    { 0x2e8, 0x238, 0x2e0, 0x228 }
+};
+
+static inline uint32_t get_uart_iobase(PC87312State *s, int i)
+{
+    int idx;
+    idx = (s->FAR >> (2 * i + 2)) & 0x3;
+    if (idx == 0) {
+        return 0x3f8;
+    } else if (idx == 1) {
+        return 0x2f8;
+    } else {
+        return uart_base[idx & 1][(s->FAR & FAR_UART_3_4) >> 6];
+    }
+}
+
+static inline uint32_t get_uart_irq(PC87312State *s, int i)
+{
+    int idx;
+    idx = (s->FAR >> (2 * i + 2)) & 0x3;
+    return (idx & 1) ? 3 : 4;
+}
+
+static inline bool is_uart_enabled(PC87312State *s, int i)
+{
+    return s->FER & (FER_UART1_EN << i);
+}
+
+static void update_uarts(PC87312State *s)
+{
+    ISADevice *isa;
+    uint32_t base, isairq;
+    bool enabled;
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        if (s->uart[i].dev != NULL) {
+            isa = DO_UPCAST(ISADevice, qdev, s->uart[i].dev);
+            base = get_uart_iobase(s, i);
+            isairq = get_uart_irq(s, i);
+            enabled = is_uart_enabled(s, i);
+            if (qdev_prop_get_bool(&isa->qdev, "enabled") != enabled ||
+                qdev_prop_get_uint32(&isa->qdev, "iobase") != base ||
+                qdev_prop_get_uint32(&isa->qdev, "irq") != isairq) {
+                DPRINTF("updating uart%d: base 0x%x, irq %u, enabled? %s\n", i,
+                        base, isairq, enabled ? "yes" : "no");
+                isa_set_state(isa, false);
+                qdev_prop_set_uint32(&isa->qdev, "iobase", base);
+                qdev_prop_set_uint32(&isa->qdev, "irq", isairq);
+                if (enabled) {
+                    isa_set_state(isa, true);
+                }
+            }
+        }
+    }
+}
+
+
+/* Floppy controller */
+
+static inline bool is_fdc_enabled(PC87312State *s)
+{
+    return (s->FER & FER_FDC_EN);
+}
+
+static inline uint32_t get_fdc_iobase(PC87312State *s)
+{
+    return (s->FER & FER_FDC_ADDR) ? 0x370 : 0x3f0;
+}
+
+static void update_fdc(PC87312State *s)
+{
+    ISADevice *isa = DO_UPCAST(ISADevice, qdev, s->fdc.dev);
+    uint32_t base;
+    bool enabled;
+
+    base = get_fdc_iobase(s);
+    enabled = is_fdc_enabled(s);
+    if (qdev_prop_get_bool(&isa->qdev, "enabled") != enabled ||
+        qdev_prop_get_uint32(&isa->qdev, "iobase") != base) {
+        DPRINTF("updating fdc: base 0x%x, enabled? %s\n",
+                base, enabled ? "yes" : "no");
+        isa_set_state(isa, false);
+        qdev_prop_set_uint32(&isa->qdev, "iobase", base);
+        if (enabled) {
+            isa_set_state(isa, true);
+        }
+    }
+}
+
+
+/* IDE controller */
+
+static inline bool is_ide_enabled(PC87312State *s)
+{
+    return (s->FER & FER_IDE_EN);
+}
+
+static inline uint32_t get_ide_iobase(PC87312State *s)
+{
+    return (s->FER & FER_IDE_ADDR) ? 0x170 : 0x1f0;
+}
+
+static void update_ide(PC87312State *s)
+{
+    ISADevice *isa = DO_UPCAST(ISADevice, qdev, s->ide.dev);
+    uint32_t base;
+    bool enabled;
+
+    base = get_ide_iobase(s);
+    enabled = is_ide_enabled(s);
+    if (qdev_prop_get_bool(&isa->qdev, "enabled") != enabled ||
+        qdev_prop_get_uint32(&isa->qdev, "iobase") != base) {
+        DPRINTF("updating ide: base 0x%x, enabled? %s\n",
+                base, enabled ? "yes" : "no");
+        isa_set_state(isa, false);
+        qdev_prop_set_uint32(&isa->qdev, "iobase", base);
+        qdev_prop_set_uint32(&isa->qdev, "iobase2", base + 0x206);
+        if (enabled) {
+            isa_set_state(isa, true);
+        }
+    }
+}
+
+
+static void update_mappings(PC87312State *s)
+{
+    update_parallel(s);
+    update_uarts(s);
+    update_fdc(s);
+    update_ide(s);
+}
+
+static void pc87312_soft_reset(PC87312State *s)
+{
+    static const uint8_t fer_init[] = {
+        0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b,
+        0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f,
+        0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07,
+        0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00,
+    };
+    static const uint8_t far_init[] = {
+        0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01,
+        0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24,
+        0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24,
+        0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10,
+    };
+    static const uint8_t ptr_init[] = {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    };
+
+    s->read_id_step = 0;
+    s->selected_index = REG_FER;
+
+    s->FER = fer_init[s->config & 0x1f];
+    s->FAR = far_init[s->config & 0x1f];
+    s->PTR = ptr_init[s->config & 0x1f];
+}
+
+static void pc87312_hard_reset(PC87312State *s)
+{
+    pc87312_soft_reset(s);
+}
+
+static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PC87312State *s = opaque;
+
+    DPRINTF("%s: write %x at %x\n", __func__, val, addr);
+
+    if ((addr & 1) == 0) {
+        /* Index register */
+        s->read_id_step = 2;
+        s->selected_index = val;
+    } else {
+        /* Data register */
+        if (s->selected_index < 3) {
+            s->regs[s->selected_index] = val;
+            update_mappings(s);
+        }
+    }
+}
+
+static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr)
+{
+    PC87312State *s = opaque;
+    uint32_t val;
+
+    if ((addr & 1) == 0) {
+        /* Index register */
+        if (s->read_id_step++ == 0) {
+            val = 0x88;
+        } else if (s->read_id_step++ == 1) {
+            val = 0;
+        } else {
+            val = s->selected_index;
+        }
+    } else {
+        /* Data register */
+        if (s->selected_index < 3) {
+            val = s->regs[s->selected_index];
+        } else {
+            /* Invalid selected index */
+            val = 0;
+        }
+    }
+
+    DPRINTF("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static void pc87312_init_core(PC87312State *s)
+{
+    ISADevice *isa;
+    int i;
+
+    pc87312_hard_reset(s);
+
+    if (s->parallel.chr != NULL) {
+        isa = isa_create("isa-parallel");
+        qdev_prop_set_uint32(&isa->qdev, "index", 0);
+        qdev_prop_set_uint32(&isa->qdev, "iobase", get_parallel_iobase(s));
+        qdev_prop_set_uint32(&isa->qdev, "irq", get_parallel_irq(s));
+        qdev_prop_set_chr(&isa->qdev, "chardev", s->parallel.chr);
+        qdev_prop_set_bool(&isa->qdev, "enabled", is_parallel_enabled(s));
+        qdev_init_nofail(&isa->qdev);
+        s->parallel.dev = &isa->qdev;
+        DPRINTF("parallel: base 0x%x, irq %u, enabled? %s\n",
+                get_parallel_iobase(s), get_parallel_irq(s),
+                is_parallel_enabled(s) ? "yes" : "no");
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (s->uart[i].chr != NULL) {
+            isa = isa_create("isa-serial");
+            qdev_prop_set_uint32(&isa->qdev, "index", i);
+            qdev_prop_set_uint32(&isa->qdev, "iobase", get_uart_iobase(s, i));
+            qdev_prop_set_uint32(&isa->qdev, "irq", get_uart_irq(s, i));
+            qdev_prop_set_chr(&isa->qdev, "chardev", s->uart[i].chr);
+            qdev_prop_set_bool(&isa->qdev, "enabled", is_uart_enabled(s, i));
+            qdev_init_nofail(&isa->qdev);
+            s->uart[i].dev = &isa->qdev;
+            DPRINTF("uart%d: base 0x%x, irq %u, enabled? %s\n", i,
+                    get_uart_iobase(s, i),
+                    get_uart_irq(s, i),
+                    is_uart_enabled(s, i) ? "yes" : "no");
+        }
+    }
+
+    isa = isa_create("isa-fdc");
+    qdev_prop_set_uint32(&isa->qdev, "iobase", get_fdc_iobase(s));
+    qdev_prop_set_uint32(&isa->qdev, "irq", 6);
+    if (s->fdc.drive[0] != NULL) {
+        qdev_prop_set_drive_nofail(&isa->qdev, "driveA", s->fdc.drive[0]);
+    }
+    if (s->fdc.drive[1] != NULL) {
+        qdev_prop_set_drive_nofail(&isa->qdev, "driveB", s->fdc.drive[1]);
+    }
+    qdev_prop_set_bool(&isa->qdev, "enabled", is_fdc_enabled(s));
+    qdev_init_nofail(&isa->qdev);
+    s->fdc.dev = &isa->qdev;
+    DPRINTF("fdc: base 0x%x, enabled? %s\n",
+            get_fdc_iobase(s),
+            is_fdc_enabled(s) ? "yes" : "no");
+
+    isa = isa_create("isa-ide");
+    qdev_prop_set_uint32(&isa->qdev, "iobase", get_ide_iobase(s));
+    qdev_prop_set_uint32(&isa->qdev, "iobase2", get_ide_iobase(s) + 0x206);
+    qdev_prop_set_uint32(&isa->qdev, "irq", 14);
+    qdev_prop_set_bool(&isa->qdev, "enabled", is_ide_enabled(s));
+    qdev_init_nofail(&isa->qdev);
+    s->ide.dev = &isa->qdev;
+    DPRINTF("ide: base 0x%x, enabled? %s\n",
+            get_ide_iobase(s),
+            is_ide_enabled(s) ? "yes" : "no");
+
+    update_mappings(s);
+}
+
+typedef struct ISAPC87312State {
+    ISADevice dev;
+    uint32_t iobase;
+    PC87312State state;
+} ISAPC87312State;
+
+static void isa_pc87312_reset(DeviceState *d)
+{
+    PC87312State *s = &container_of(d, ISAPC87312State, dev.qdev)->state;
+    pc87312_soft_reset(s);
+}
+
+static int isa_pc87312_init(ISADevice *dev)
+{
+    ISAPC87312State *isa = DO_UPCAST(ISAPC87312State, dev, dev);
+    PC87312State *s = &isa->state;
+
+    pc87312_init_core(s);
+
+    register_ioport_write(isa->iobase, 2, 1, pc87312_ioport_write, s);
+    register_ioport_read(isa->iobase, 2, 1, pc87312_ioport_read, s);
+    return 0;
+}
+
+static ISADeviceInfo pc87312_isa_info = {
+    .qdev.name = "isa-pc87312",
+    .qdev.size = sizeof(ISAPC87312State),
+    .qdev.reset = isa_pc87312_reset,
+    .init = isa_pc87312_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", ISAPC87312State, iobase, 0x398),
+        DEFINE_PROP_UINT8("config", ISAPC87312State, state.config, 1),
+        DEFINE_PROP_CHR("parallel", ISAPC87312State, state.parallel.chr),
+        DEFINE_PROP_CHR("uart1", ISAPC87312State, state.uart[0].chr),
+        DEFINE_PROP_CHR("uart2", ISAPC87312State, state.uart[1].chr),
+        DEFINE_PROP_DRIVE("floppyA", ISAPC87312State, state.fdc.drive[0]),
+        DEFINE_PROP_DRIVE("floppyB", ISAPC87312State, state.fdc.drive[1]),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void pc87312_register_devices(void)
+{
+    isa_qdev_register(&pc87312_isa_info);
+}
+
+device_init(pc87312_register_devices)
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 20/23] 40p: Add the Super I/O chip (pc87312)
  2011-06-14  2:37                                     ` [Qemu-devel] [RFC v5 19/23] prep: Add pc87312 Super I/O emulation Andreas Färber
@ 2011-06-14  2:37                                       ` Andreas Färber
  2011-06-14  2:37                                         ` [Qemu-devel] [RFC 21/23] 40p: Add an audio card and a keyboard Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

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

Set the floppy properties with raw qdev_prop_set() for now because
qdev_prop_set_drive() also calls bdrv_attach(), which can't be called
twice for a drive. Having it attached to the isa-fdc seems nicer.

Signed-off-by: Andreas Färber <andreas.faerber@web.de>

prep: Manually set floppy properties
---
 hw/ppc_prep.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 27e1d14..935d1e9 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -779,6 +779,8 @@ static void ibm_40p_init(ram_addr_t ram_size,
     DeviceState *dev;
     PCIBus *pci_bus;
     PCIDevice *pci;
+    ISADevice *isa;
+    DriveInfo *drive;
 
     // IBM E15 graphic adapter (S3 Vision864)
     // PowerPC 601
@@ -831,6 +833,21 @@ static void ibm_40p_init(ram_addr_t ram_size,
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     qdev_connect_gpio_out(&pci->qdev, 0, env->irq_inputs[PPC6xx_INPUT_INT]);
     qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
+
+    /* Super I/O (parallel + serial ports) */
+    isa = isa_create("isa-pc87312");
+    qdev_prop_set_chr(&isa->qdev, "parallel", parallel_hds[0]);
+    qdev_prop_set_chr(&isa->qdev, "uart1", serial_hds[0]);
+    qdev_prop_set_chr(&isa->qdev, "uart2", serial_hds[1]);
+    drive = drive_get(IF_FLOPPY, 0, 0);
+    if (drive) {
+        qdev_prop_set(&isa->qdev, "floppyA", drive->bdrv, PROP_TYPE_DRIVE);
+    }
+    drive = drive_get(IF_FLOPPY, 0, 1);
+    if (drive) {
+        qdev_prop_set(&isa->qdev, "floppyB", drive->bdrv, PROP_TYPE_DRIVE);
+    }
+    qdev_init_nofail(&isa->qdev);
 }
 
 static QEMUMachine prep_machine = {
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 21/23] 40p: Add an audio card and a keyboard
  2011-06-14  2:37                                       ` [Qemu-devel] [RFC 20/23] 40p: Add the Super I/O chip (pc87312) Andreas Färber
@ 2011-06-14  2:37                                         ` Andreas Färber
  2011-06-14  2:37                                           ` [Qemu-devel] [RFC 22/23] prep: qdev'ify System I/O (WIP) Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

From: Hervé Poussineau <hpoussin@reactos.org>

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 default-configs/ppc-softmmu.mak |    1 +
 hw/ppc_prep.c                   |    8 ++++++++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 0999008..303929f 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -19,6 +19,7 @@ CONFIG_I82378=y
 CONFIG_PC87312=y
 CONFIG_MACIO=y
 CONFIG_PCSPK=y
+CONFIG_CS4231A=y
 CONFIG_CUDA=y
 CONFIG_ADB=y
 CONFIG_MAC_NVRAM=y
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 935d1e9..4759a03 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -848,6 +848,14 @@ static void ibm_40p_init(ram_addr_t ram_size,
         qdev_prop_set(&isa->qdev, "floppyB", drive->bdrv, PROP_TYPE_DRIVE);
     }
     qdev_init_nofail(&isa->qdev);
+
+    /* Audio */
+    isa = isa_create("cs4231a");
+    qdev_prop_set_uint32(&isa->qdev, "iobase", 0x830);
+    qdev_prop_set_uint32(&isa->qdev, "irq", 10);
+    qdev_init_nofail(&isa->qdev);
+
+    isa_create_simple("i8042");
 }
 
 static QEMUMachine prep_machine = {
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 22/23] prep: qdev'ify System I/O (WIP)
  2011-06-14  2:37                                         ` [Qemu-devel] [RFC 21/23] 40p: Add an audio card and a keyboard Andreas Färber
@ 2011-06-14  2:37                                           ` Andreas Färber
  2011-06-14  2:37                                             ` [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau, Alexander Graf

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 --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)
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card
  2011-06-14  2:37                                           ` [Qemu-devel] [RFC 22/23] prep: qdev'ify System I/O (WIP) Andreas Färber
@ 2011-06-14  2:37                                             ` Andreas Färber
  2011-06-15  4:33                                               ` Roy Tam
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-14  2:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau

The IBM E15 is equivalent to an S3 Vision864.

Lacking S3 SDAC (86C716) support, the DAC indizes are translated
to greyscale colors. This works sufficiently to observe firmware
boot progress.

Cc: Hervé Poussineau <hpoussin@reactos.org>

Fixed off-by-one drawing issue.
Replaced hardcoded color for RECT.
Separate I/O debug output for readability.

Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.objs                   |    1 +
 default-configs/ppc-softmmu.mak |    1 +
 hw/pci_ids.h                    |    3 +
 hw/ppc_prep.c                   |    2 +
 hw/vga-s3.c                     |  694 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 701 insertions(+), 0 deletions(-)
 create mode 100644 hw/vga-s3.c

diff --git a/Makefile.objs b/Makefile.objs
index 7bb6b1a..0893c85 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -270,6 +270,7 @@ hw-obj-y += qdev-addr.o
 hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
 hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
+hw-obj-$(CONFIG_VGA_S3) += vga-s3.o
 hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
 hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 303929f..ab74392 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -6,6 +6,7 @@ CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
 CONFIG_VGA_PCI=y
+CONFIG_VGA_S3=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index d3bef0e..821421c 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -97,6 +97,9 @@
 #define PCI_VENDOR_ID_FREESCALE          0x1957
 #define PCI_DEVICE_ID_MPC8533E           0x0030
 
+#define PCI_VENDOR_ID_S3                 0x5333
+#define PCI_DEVICE_ID_S3_864             0x88c0
+
 #define PCI_VENDOR_ID_INTEL              0x8086
 #define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 6ae1635..9085f89 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -747,6 +747,8 @@ static void ibm_40p_init(ram_addr_t ram_size,
     qdev_prop_set_uint8(&isa->qdev, "board-identification", 0xfc);
     qdev_init_nofail(&isa->qdev);
 
+    pci_create_simple(pci_bus, PCI_DEVFN(2, 0), "S3-864");
+
     /* 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/vga-s3.c b/hw/vga-s3.c
new file mode 100644
index 0000000..9b0bc13
--- /dev/null
+++ b/hw/vga-s3.c
@@ -0,0 +1,694 @@
+/*
+ * QEMU PCI IBM 8514/A Emulator.
+ *
+ * Copyright (c) 2010 Hervé Poussineau
+ * Copyright (c) 2010-2011 Andreas Färber
+ *
+ * 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.
+ */
+
+/* Documentation available at
+ * http://www.datasheetarchive.com/Indexer/Datasheet-06/DSA0091551.html
+ */
+
+#include "console.h"
+#include "pci.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+
+//#define DEBUG_8514
+//#define DEBUG_8514_IO
+
+#ifdef DEBUG_8514
+#define DPRINTF(fmt, ...) \
+do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#ifdef DEBUG_8514_IO
+#define DPRINTF_IO(fmt, ...) \
+do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_IO(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "8514 ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
+enum {
+    REG_CMD = 0x9AE8,
+    REG_PIX_TRANS = 0xE2E8,
+};
+
+#define GP_STAT_BUSY     0x0200
+
+#define CMD_WRTDATA      0x0001
+#define CMD_PLANAR       0x0002
+#define CMD_LASTPIX      0x0004
+#define CMD_LINETYPE     0x0008
+#define CMD_DRAW         0x0010
+#define CMD_INC_X        0x0020
+#define CMD_YMAJAXIS     0x0040
+#define CMD_INC_Y        0x0080
+#define CMD_PCDATA       0x0100
+#define CMD_16BIT        0x0200
+#define CMD_BYTSEQ       0x1000
+#define CMD_CMD_MASK     0xE000
+
+#define CMD_CMD_NOP    0x0000
+#define CMD_CMD_LINE   0x2000
+#define CMD_CMD_RECT   0x4000
+#define CMD_CMD_RECTV1 0x6000
+#define CMD_CMD_RECTV2 0x8000
+#define CMD_CMD_LINEAF 0xA000
+#define CMD_CMD_BITBLT 0xC000
+
+#define BKGD_MIX_BSS_MASK 0x0060
+enum {
+    BKGD_MIX_BSS_BKGD = 0x0000,
+    BKGD_MIX_BSS_FRGD = 0x0020,
+    BKGD_MIX_BSS_PIX  = 0x0040,
+    BKGD_MIX_BSS_BMP  = 0x0060,
+};
+
+#define FRGD_MIX_FSS_MASK 0x0060
+enum {
+    FRGD_MIX_FSS_BKGD = 0x0000,
+    FRGD_MIX_FSS_FRGD = 0x0020,
+    FRGD_MIX_FSS_PIX  = 0x0040,
+    FRGD_MIX_FSS_BMP  = 0x0060,
+};
+
+#define PIX_CNTL_MIXSEL_MASK    0x00C0
+enum {
+    PIX_CNTL_MIXSEL_FOREMIX = 0x0000,
+    PIX_CNTL_MIXSEL_PATTERN = 0x0040,
+    PIX_CNTL_MIXSEL_VAR     = 0x0080,
+    PIX_CNTL_MIXSEL_TRANS   = 0x00C0,
+};
+
+// 40f3 = CMD_CMD_RECT | CMD_INC_Y | CMD_YMAJAXIS | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
+// 4331 = CMD_CMD_RECT | CMD_16BIT | CMD_PCDATA | CMD_INC_X | CMD_DRAW | CMD_WRTDATA
+// c0b3 = CMD_CMD_BITBLT | CMD_INC_Y | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
+
+typedef struct IBM8514State {
+    VGACommonState vga;
+    uint16_t maj_axis, min_axis;
+
+    uint16_t disp_stat; /* 02e8 */
+    uint16_t h_disp; /* 06e8 */
+    uint16_t h_sync_strt; /* 0ae8 */
+    uint16_t h_sync_wid; /* 0ee8 */
+    uint16_t v_total; /* 12e8 */
+    uint16_t v_disp; /* 16e8 */
+    uint16_t v_sync_strt; /* 1ae8 */
+    uint16_t v_sync_wid; /* 1ee8 */
+    uint16_t disp_cntl; /* 22e8 */
+    uint16_t h_total; /* 26e8 */
+    uint16_t subsys_cntl; /* 42e8 (W) */
+    uint16_t subsys_stat; /* 42e8 (R) */
+    uint16_t rom_page_sel; /* 46e8 */
+    uint16_t advfunc_cntl; /* 4ae8 */
+    uint16_t cur_y; /* 82e8 */
+    uint16_t cur_x; /* 86e8 */
+    uint16_t desty_axstep; /* 8ae8 */
+    uint16_t destx_diastp; /* 8ee8 */
+    uint16_t err_term; /* 92e8 */
+    uint16_t maj_axis_pcnt; /* 96e8 */
+    uint16_t gp_stat; /* 9ae8 (R) */
+    uint16_t cmd; /* 9ae8 (W) */
+    uint16_t short_stroke; /* 9ee8 */
+    uint16_t bkgd_color; /* a2e8 */
+    uint16_t frgd_color; /* a6e8 */
+    uint16_t wrt_mask; /* aae8 */
+    uint16_t rd_mask; /* aee8 */
+    uint16_t color_cmp; /* b2e8 */
+    uint16_t bkgd_mix; /* b6e8 */
+    uint16_t frgd_mix; /* bae8 */
+    uint16_t mfc[16]; /* bee8 */
+    uint16_t pix_trans; /* e2e8 */
+} IBM8514State;
+
+#define min_axis_pcnt mfc[0]
+#define scissors_t    mfc[1]
+#define scissors_l    mfc[2]
+#define scissors_b    mfc[3]
+#define scissors_r    mfc[4]
+#define mem_cntl      mfc[5]
+#define pattern_l     mfc[8]
+#define pattern_h     mfc[9]
+#define pix_cntl      mfc[10]
+
+static inline void do_cmd_done(IBM8514State *s)
+{
+    s->gp_stat &= ~GP_STAT_BUSY;
+}
+
+static void do_cmd_write_pixel(IBM8514State *s, uint16_t value)
+{
+    uint16_t maj_axis_pcnt = s->maj_axis_pcnt + 1;
+    uint8_t* p8 = s->vga.vram_ptr + (s->cur_y * 640 + s->cur_x) * 4;
+    int dx = s->cmd & CMD_INC_X ? 1 : -1;
+    int dy = s->cmd & CMD_INC_Y ? 1 : -1;
+
+    if (!(s->gp_stat & GP_STAT_BUSY)) {
+        return;
+    }
+
+    ++s->maj_axis;
+    if ((s->maj_axis < maj_axis_pcnt) ||
+        (s->maj_axis == maj_axis_pcnt && !(s->cmd & CMD_LASTPIX))) {
+        p8[0] = p8[1] = p8[2] = p8[3] = value;
+    }
+    if (s->maj_axis < maj_axis_pcnt) {
+        s->cur_x += dx;
+    } else if (s->maj_axis == maj_axis_pcnt) {
+        if ((maj_axis_pcnt % 2 == 0) || !(s->cmd & CMD_16BIT)) {
+            s->maj_axis = 0;
+        }
+        s->cur_x -= (s->maj_axis_pcnt) * dx;
+        s->cur_y += dy;
+        s->min_axis++;
+        if (s->min_axis == s->min_axis_pcnt + 1) {
+            do_cmd_done(s);
+        }
+    } else {
+        //DPRINTF("%s: (skip - maj_axis = %u, maj_axis_pcnt = %u)\n",
+        //    __func__, s->maj_axis, maj_axis_pcnt);
+        s->maj_axis = 0;
+    }
+}
+
+static uint16_t get_source_operand(IBM8514State *s)
+{
+    switch (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) {
+        case PIX_CNTL_MIXSEL_FOREMIX:
+            switch (s->frgd_mix & FRGD_MIX_FSS_MASK) {
+                case FRGD_MIX_FSS_BKGD:
+                    return s->bkgd_color & 0xff;
+                case FRGD_MIX_FSS_FRGD:
+                    return s->frgd_color & 0xff;
+                default:
+                    BADF("%s: Unimplemented FSS %x\n",
+                         __func__, (s->frgd_mix & FRGD_MIX_FSS_MASK) >> 5);
+                    return 0;
+            }
+        default:
+            BADF("%s: Unimplemented MIXSEL %x\n",
+                 __func__, (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) >> 6);
+            return 0;
+    }
+}
+
+static void do_cmd_init(IBM8514State *s)
+{
+    s->gp_stat |= GP_STAT_BUSY;
+    s->maj_axis = 0;
+    s->min_axis = 0;
+
+    if ((s->cmd & CMD_CMD_MASK) == CMD_CMD_RECT) {
+        DPRINTF("cmd RECT: cur_x=%d cur_y=%d inc_x=%d inc_y=%d width=%d height=%d\n",
+            s->cur_x, s->cur_y,
+            s->cmd & CMD_INC_X ? 1 : -1, s->cmd & CMD_INC_Y ? 1 : -1,
+            s->maj_axis_pcnt, s->min_axis_pcnt);
+
+        if (!(s->cmd & CMD_PCDATA)) {
+            while (s->gp_stat & GP_STAT_BUSY) {
+                do_cmd_write_pixel(s, get_source_operand(s));
+            }
+        }
+    }
+}
+
+static void do_cmd(IBM8514State *s)
+{
+    DPRINTF("%s: execute cmd %04x\n", __func__, s->cmd);
+
+    do_cmd_init(s);
+}
+
+static uint16_t* ibm8514_get_register(IBM8514State *s, uint32_t addr, int is_write, uint32_t* val_if_write)
+{
+    uint16_t *p;
+
+    switch (addr) {
+        case 0x02e8:
+            p = is_write ? &s->h_total : &s->disp_stat;
+            break;
+        case 0x06e8:
+            p = is_write ? &s->h_disp : NULL;
+            break;
+        case 0x0ae8:
+            p = is_write ? &s->h_sync_strt : NULL;
+            break;
+        case 0x0ee8:
+            p = is_write ? &s->h_sync_wid : NULL;
+            break;
+        case 0x12e8:
+            p = is_write ? &s->v_total : NULL;
+            break;
+        case 0x16e8:
+            p = is_write ? &s->v_disp : NULL;
+            break;
+        case 0x1ae8:
+            p = is_write ? &s->v_sync_strt : NULL;
+            break;
+        case 0x1ee8:
+            p = is_write ? &s->v_sync_wid : NULL;
+            break;
+        case 0x22e8:
+            p = is_write ? &s->disp_cntl : NULL;
+            break;
+        case 0x26e8:
+            p = is_write ? NULL: &s->h_total;
+            break;
+        case 0x42e8:
+            p = is_write ? &s->subsys_cntl : &s->subsys_stat;
+            break;
+        case 0x46e8:
+            p = is_write ? &s->rom_page_sel : NULL;
+            break;
+        case 0x4ae8:
+            p = is_write ? &s->advfunc_cntl : NULL;
+            break;
+        case 0x82e8:
+            p = &s->cur_y;
+            break;
+        case 0x86e8:
+            p = &s->cur_x;
+            break;
+        case 0x8ae8:
+            p = is_write ? &s->desty_axstep : NULL;
+            break;
+        case 0x8ee8:
+            p = is_write ? &s->destx_diastp : NULL;
+            break;
+        case 0x92e8:
+            p = &s->err_term;
+            break;
+        case 0x96e8:
+            p = is_write ? &s->maj_axis_pcnt : NULL;
+            break;
+        case 0x9ae8:
+            p = is_write ? &s->cmd : &s->gp_stat;
+            break;
+        case 0x9ee8:
+            p = is_write ? &s->short_stroke : NULL;
+            break;
+        case 0xa2e8:
+            p = is_write ? &s->bkgd_color : NULL;
+            break;
+        case 0xa6e8:
+            p = is_write ? &s->frgd_color : NULL;
+            break;
+        case 0xaae8:
+            p = is_write ? &s->wrt_mask : NULL;
+            break;
+        case 0xaee8:
+            p = is_write ? &s->rd_mask : NULL;
+            break;
+        case 0xb2e8:
+            p = is_write ? &s->color_cmp : NULL;
+            break;
+        case 0xb6e8:
+            p = is_write ? &s->bkgd_mix : NULL;
+            break;
+        case 0xbae8:
+            p = is_write ? &s->frgd_mix : NULL;
+            break;
+        case 0xbee8:
+            if (is_write) {
+                p = &s->mfc[(*val_if_write >> 12) & 0xf];
+                *val_if_write &= 0x0fff;
+            } else {
+                p = NULL;
+            }
+            break;
+        case 0xe2e8:
+            p = &s->pix_trans;
+            break;
+        default:
+            BADF("%s: invalid register at 0x%x\n", __func__, addr);
+            p = NULL;
+            break;
+    }
+
+    return p;
+}
+
+static uint32_t ibm8514_ioport_readb(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+    uint16_t *p;
+
+    p = ibm8514_get_register(s, addr & ~0x1, 0, NULL);
+
+    if (p) {
+        val = (be16_to_cpu(*p) >> ((~addr & 1) * 8)) & 0xff;
+    } else {
+        val = 0;
+    }
+
+    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static uint32_t ibm8514_ioport_readw(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+    uint16_t *p;
+
+    p = ibm8514_get_register(s, addr, 0, NULL);
+
+    if (p) {
+        val = be16_to_cpu(*p);
+    } else {
+        val = 0;
+    }
+
+    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static void ibm8514_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+    uint16_t *p;
+    uint8_t *c;
+
+    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
+    p = ibm8514_get_register(s, addr & ~0x1, 1, &val);
+
+    if (p) {
+        c = (uint8_t*)p;
+        c[~addr & 1] = val;
+    }
+    if ((addr & ~0x1) == REG_CMD) {
+        do_cmd(s);
+    } else if ((addr & ~0x1) == REG_PIX_TRANS) {
+        BADF("%s: ibm8514: 8-byte PIX_TRANS access (0x%08" PRIx32 ")\n",
+            __func__, addr);
+    }
+}
+
+static void ibm8514_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+    uint16_t *p;
+
+    val = cpu_to_be16(val);
+    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
+    p = ibm8514_get_register(s, addr, 1, &val);
+
+    if (p) {
+        *p = val & 0xffff;
+    }
+    if (addr == REG_CMD) {
+        do_cmd(s);
+    } else if (addr == REG_PIX_TRANS) {
+        if (!(s->cmd & CMD_16BIT)) {
+            do_cmd_write_pixel(s, val & 0xff);
+        } else if (s->cmd & CMD_BYTSEQ) {
+            do_cmd_write_pixel(s, val & 0xff);
+            do_cmd_write_pixel(s, val >> 8);
+        } else {
+            do_cmd_write_pixel(s, val >> 8);
+            do_cmd_write_pixel(s, val & 0xff);
+        }
+    }
+}
+
+static void ibm8514_register_port_one(IBM8514State *s, uint32_t addr)
+{
+    register_ioport_read(addr, 1, 1, ibm8514_ioport_readb, s);
+    register_ioport_write(addr, 1, 1, ibm8514_ioport_writeb, s);
+}
+
+static void ibm8514_register_port(IBM8514State *s, uint32_t addr)
+{
+    register_ioport_read(addr, 2, 1, ibm8514_ioport_readb, s);
+    register_ioport_read(addr, 1, 2, ibm8514_ioport_readw, s);
+    register_ioport_write(addr, 2, 1, ibm8514_ioport_writeb, s);
+    register_ioport_write(addr, 1, 2, ibm8514_ioport_writew, s);
+}
+
+static void my_update_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+    int w;
+    uint8_t *vram;
+    uint8_t *data_display, *dd;
+    int x, y;
+    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
+
+    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) != 480) {
+        qemu_console_resize(s->ds, 640, 480);
+    }
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            rgb_to_pixel = rgb_to_pixel8;
+            w = 1;
+            break;
+        case 15:
+            rgb_to_pixel = rgb_to_pixel15;
+            w = 2;
+            break;
+        case 16:
+            rgb_to_pixel = rgb_to_pixel16;
+            w = 2;
+            break;
+        case 32:
+            rgb_to_pixel = rgb_to_pixel32;
+            w = 4;
+            break;
+        default:
+            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
+            return;
+    }
+
+    vram = s->vram_ptr;
+    /* XXX: out of range in vram? */
+    data_display = dd = ds_get_data(s->ds);
+    for (y = 0; y < 480; y++) {
+        for (x = 0; x < 640; x++) {
+            unsigned int color;
+            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
+            memcpy(dd, &color, w);
+            dd += w;
+            vram += 4;
+        }
+        data_display = dd = data_display + ds_get_linesize(s->ds);
+    }
+
+    dpy_update(s->ds, 0, 0, 640, 480);
+}
+
+static void ibm8514_init(IBM8514State *s)
+{
+    VGACommonState *vga = &s->vga;
+
+    vga->vram_size = 0x200000;
+
+    /* vga + console init */
+    vga_common_init(vga, vga->vram_size);
+    vga_init(vga);
+
+    vga->ds = graphic_console_init(/*vga->update*/my_update_display, vga->invalidate,
+                                   vga->screen_dump, vga->text_update,
+                                   vga);
+
+    ibm8514_register_port(s, 0x02e8);
+    ibm8514_register_port_one(s, 0x02ea);
+    ibm8514_register_port_one(s, 0x02eb);
+    ibm8514_register_port_one(s, 0x02ec);
+    ibm8514_register_port_one(s, 0x02ed);
+    ibm8514_register_port(s, 0x06e8);
+    ibm8514_register_port(s, 0x0ae8);
+    ibm8514_register_port(s, 0x0ee8);
+    ibm8514_register_port(s, 0x12e8);
+    ibm8514_register_port(s, 0x16e8);
+    ibm8514_register_port(s, 0x1ae8);
+    ibm8514_register_port(s, 0x1ee8);
+    ibm8514_register_port(s, 0x22e8);
+    ibm8514_register_port(s, 0x26e8);
+    ibm8514_register_port(s, 0x42e8);
+    ibm8514_register_port(s, 0x46e8);
+    ibm8514_register_port(s, 0x4ae8);
+    ibm8514_register_port(s, 0x82e8);
+    ibm8514_register_port(s, 0x86e8);
+    ibm8514_register_port(s, 0x8ae8);
+    ibm8514_register_port(s, 0x8ee8);
+    ibm8514_register_port(s, 0x92e8);
+    ibm8514_register_port(s, 0x96e8);
+    ibm8514_register_port(s, 0x9ae8);
+    ibm8514_register_port(s, 0x9ae8);
+    ibm8514_register_port(s, 0x9ee8);
+    ibm8514_register_port(s, 0xa2e8);
+    ibm8514_register_port(s, 0xa6e8);
+    ibm8514_register_port(s, 0xaae8);
+    ibm8514_register_port(s, 0xaee8);
+    ibm8514_register_port(s, 0xb2e8);
+    ibm8514_register_port(s, 0xb6e8);
+    ibm8514_register_port(s, 0xbae8);
+    ibm8514_register_port(s, 0xbee8);
+    ibm8514_register_port(s, 0xe2e8);
+
+    cpu_register_physical_memory(isa_mem_base + 0x02800000, vga->vram_size, vga->vram_offset);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x02800000, vga->vram_size);
+}
+
+typedef struct PCIIBM8514State {
+    PCIDevice dev;
+    IBM8514State state;
+} PCIIBM8514State;
+
+static void pci_ibm8514_write_config(PCIDevice *d,
+                                     uint32_t address, uint32_t val, int len)
+{
+    BADF("%s: 0x%08" PRIx32 "\n", __func__, address);
+}
+
+static int pci_ibm8514_init(PCIDevice *dev)
+{
+    PCIIBM8514State *pci = DO_UPCAST(PCIIBM8514State, dev, dev);
+    IBM8514State *s = &pci->state;
+    uint8_t *pci_conf = dev->config;
+
+    DPRINTF("%s\n", __func__);
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_S3);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_S3_864);
+    pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
+
+    ibm8514_init(s);
+
+    return 0;
+}
+
+static PCIDeviceInfo ibm8514_info = {
+    .qdev.name    = "S3-864",
+    .qdev.size    = sizeof(PCIIBM8514State),
+    //.qdev.vmsd    = &vmstate_ibm8514_pci,
+    .init         = pci_ibm8514_init,
+    .config_write = pci_ibm8514_write_config,
+    .qdev.props   = (Property[]) {
+        //DEFINE_PROP_HEX32("bios-offset", PCIVGAState, state.bios_offset, 0),
+        //DEFINE_PROP_HEX32("bios-size",   PCIVGAState, state.bios_size,   0),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void ibm8514_register(void)
+{
+    pci_qdev_register(&ibm8514_info);
+}
+
+device_init(ibm8514_register);
+
+/*
+21:
+  DEVICE_ID
+    BusId = PCI
+    DevId = 0x41d00909 (PNP0909)
+    SerialNum = 0x00000000
+    Flags = 0x000061c5
+      : Output
+      : ConsoleOut
+      : PowerManaged
+      : Disableable
+      : Configurable
+      : Integrated
+      : Enabled
+    BaseType = DisplayController (3)
+    SubType = SVGAController (1)
+    Interface = GeneralSVGA (0)
+  BUS_ACCESS
+    info0 = 0
+    info1 = 112
+  AllocatedOffset  = 0x00000767
+    IRQ: 15
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x102 size 0x1 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3b4 size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3b8 size 0x4 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3bf size 0xc bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3cc size 0x1 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3ce size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3d4 size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3d8 size 0x5 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x42e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x46e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x4ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x82e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x86e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x8ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x8ee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x92e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x96e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x9ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x9ee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xa2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xa6e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xaae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xaee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xb2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xb6e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xbae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xbee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xe2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xe2ea size 0x1 bytes
+    LargeVendorItem: Generic Address
+      Memory address (32 bits), at 0x2800000 size 0x200000 bytes	ok
+    LargeVendorItem: Display
+      01 00 80 02 e0 01 80 02 00 00 80 c2 00 00 00 00 
+      00 00 20 00 00 00 00 00 78 
+  PossibleOffset   = 0x00000a58
+  CompatibleOffset = 0x00000a59
+
+*/
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card
  2011-06-14  2:37                                             ` [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card Andreas Färber
@ 2011-06-15  4:33                                               ` Roy Tam
  2011-06-15 18:11                                                 ` Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Roy Tam @ 2011-06-15  4:33 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Hervé Poussineau, qemu-devel

Hi all,

2011/6/14 Andreas Färber <andreas.faerber@web.de>:
> The IBM E15 is equivalent to an S3 Vision864.
>
> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
> to greyscale colors. This works sufficiently to observe firmware
> boot progress.
>

IMO we can generalize it as a generic S3 Vision864 and use it in x86 guest too.
http://wiki.qemu.org/Google_Summer_of_Code_2011#Add_a_S3_Trio_or_S3_Virge
CC: Natalia Portillo <claunia@claunia.com>

> Cc: Hervé Poussineau <hpoussin@reactos.org>
>
> Fixed off-by-one drawing issue.
> Replaced hardcoded color for RECT.
> Separate I/O debug output for readability.
>
> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
> ---
>  Makefile.objs                   |    1 +
>  default-configs/ppc-softmmu.mak |    1 +
>  hw/pci_ids.h                    |    3 +
>  hw/ppc_prep.c                   |    2 +
>  hw/vga-s3.c                     |  694 +++++++++++++++++++++++++++++++++++++++
>  5 files changed, 701 insertions(+), 0 deletions(-)
>  create mode 100644 hw/vga-s3.c
>
[snip]

IMO using vga-s3-864.c as the file name may be better as S3 produced
many display chips.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card
  2011-06-15  4:33                                               ` Roy Tam
@ 2011-06-15 18:11                                                 ` Andreas Färber
  2011-06-16  0:02                                                   ` [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM " Andreas Färber
                                                                     ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: Andreas Färber @ 2011-06-15 18:11 UTC (permalink / raw)
  To: Roy Tam; +Cc: Hervé Poussineau, qemu-devel Developers, Michael S. Tsirkin

Am 15.06.2011 um 06:33 schrieb Roy Tam:

> 2011/6/14 Andreas Färber <andreas.faerber@web.de>:
>> The IBM E15 is equivalent to an S3 Vision864.
>>
>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>> to greyscale colors. This works sufficiently to observe firmware
>> boot progress.
>>
>
> IMO we can generalize it as a generic S3 Vision864 and use it in x86  
> guest too.

What in particular would we need to generalize? It's qdev'ified; I  
don't remember seeing anything PReP-specific in there.
It still needs VMState of course.

> http://wiki.qemu.org/Google_Summer_of_Code_2011#Add_a_S3_Trio_or_S3_Virge
> CC: Natalia Portillo <claunia@claunia.com>
>
>> Cc: Hervé Poussineau <hpoussin@reactos.org>
>>
>> Fixed off-by-one drawing issue.
>> Replaced hardcoded color for RECT.
>> Separate I/O debug output for readability.
>>
>> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
>> ---
>>  Makefile.objs                   |    1 +
>>  default-configs/ppc-softmmu.mak |    1 +
>>  hw/pci_ids.h                    |    3 +
>>  hw/ppc_prep.c                   |    2 +
>>  hw/vga-s3.c                     |  694 ++++++++++++++++++++++++++++ 
>> +++++++++++
>>  5 files changed, 701 insertions(+), 0 deletions(-)
>>  create mode 100644 hw/vga-s3.c
>>
> [snip]
>
> IMO using vga-s3-864.c as the file name may be better as S3 produced
> many display chips.

Actually in the meantime I've already renamed the file to vga- 
ibm8514a.c (better: vga-ibm8514.c) and renamed the registration  
functions to reflect the s3_vision864.

I agree that rather than bundling different graphics cards by one  
vendor we should bundle different implementations of the same chipset.  
I was assuming that the IBM E15 uses a different vendor_id at least  
but could share the initialization with other cards, once mst's  
declarative PCI initialization reaches master (prepared that locally).
Supposedly the Miro 20SD is compatible with the S3 Vision864, and the  
ATI Mach8 was based on IBM 8514/A, too. Not sure about the Weitek  
P9100-based IBM S15.

Any suggestions what to do about the RAMDAC would be appreciated. The  
firmware only accesses the DAC_MASK register but does not write to the  
DAC itself, so for colors the card needs a reset handler that  
initializes the 256-color palette to the right RGB values.

Andreas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-15 18:11                                                 ` Andreas Färber
@ 2011-06-16  0:02                                                   ` Andreas Färber
  2011-06-18 20:42                                                     ` Blue Swirl
  2011-06-16  0:05                                                   ` [Qemu-devel] [RFC 23/23] 40p: Add an " Andreas Färber
  2011-06-16  1:22                                                   ` Roy Tam
  2 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-16  0:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, Hervé Poussineau, Roy Tam

The IBM E15 is equivalent to an S3 Vision864.

Lacking S3 SDAC (86C716) support, the DAC indizes are translated
to greyscale colors. This works sufficiently to observe firmware
boot progress.

Cc: Hervé Poussineau <hpoussin@reactos.org>

Fixed off-by-one drawing issue.
Replaced hardcoded color for RECT.
Separate I/O debug output for readability.
Start cleaning up the naming s3 vs. ibm8514.
Prepare support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA regs.

Cc: Roy Tam <roytam@gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.objs                   |    1 +
 default-configs/ppc-softmmu.mak |    1 +
 hw/pci_ids.h                    |    3 +
 hw/ppc_prep.c                   |    2 +
 hw/vga-ibm8514.c                |  780 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 787 insertions(+), 0 deletions(-)
 create mode 100644 hw/vga-ibm8514.c

diff --git a/Makefile.objs b/Makefile.objs
index 7ceeee5..95dcd91 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -270,6 +270,7 @@ hw-obj-y += qdev-addr.o
 hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
 hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
+hw-obj-$(CONFIG_VGA_IBM8514) += vga-ibm8514.o
 hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
 hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 303929f..f9c97b7 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -6,6 +6,7 @@ CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
 CONFIG_VGA_PCI=y
+CONFIG_VGA_IBM8514=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index d3bef0e..821421c 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -97,6 +97,9 @@
 #define PCI_VENDOR_ID_FREESCALE          0x1957
 #define PCI_DEVICE_ID_MPC8533E           0x0030
 
+#define PCI_VENDOR_ID_S3                 0x5333
+#define PCI_DEVICE_ID_S3_864             0x88c0
+
 #define PCI_VENDOR_ID_INTEL              0x8086
 #define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 6ae1635..c215b0f 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -747,6 +747,8 @@ static void ibm_40p_init(ram_addr_t ram_size,
     qdev_prop_set_uint8(&isa->qdev, "board-identification", 0xfc);
     qdev_init_nofail(&isa->qdev);
 
+    pci_create_simple(pci_bus, PCI_DEVFN(2, 0), "s3-vision864");
+
     /* 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/vga-ibm8514.c b/hw/vga-ibm8514.c
new file mode 100644
index 0000000..a87afe1
--- /dev/null
+++ b/hw/vga-ibm8514.c
@@ -0,0 +1,780 @@
+/*
+ * QEMU PCI IBM 8514/A Emulator.
+ *
+ * Copyright (c) 2010 Hervé Poussineau
+ * Copyright (c) 2010-2011 Andreas Färber
+ *
+ * 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.
+ */
+
+/* Documentation available at
+ * http://www.datasheetarchive.com/Indexer/Datasheet-06/DSA0091551.html
+ */
+
+#include "console.h"
+#include "pci.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+
+//#define DEBUG_8514
+//#define DEBUG_8514_IO
+
+#ifdef DEBUG_8514
+#define DPRINTF(fmt, ...) \
+do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#ifdef DEBUG_8514_IO
+#define DPRINTF_IO(fmt, ...) \
+do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_IO(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "8514 ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
+enum {
+    REG_CMD = 0x9AE8,
+    REG_PIX_TRANS = 0xE2E8,
+};
+
+#define GP_STAT_BUSY     0x0200
+
+#define CMD_WRTDATA      0x0001
+#define CMD_PLANAR       0x0002
+#define CMD_LASTPIX      0x0004
+#define CMD_LINETYPE     0x0008
+#define CMD_DRAW         0x0010
+#define CMD_INC_X        0x0020
+#define CMD_YMAJAXIS     0x0040
+#define CMD_INC_Y        0x0080
+#define CMD_PCDATA       0x0100
+#define CMD_16BIT        0x0200
+#define CMD_BYTSEQ       0x1000
+#define CMD_CMD_MASK     0xE000
+
+#define CMD_CMD_NOP    0x0000
+#define CMD_CMD_LINE   0x2000
+#define CMD_CMD_RECT   0x4000
+#define CMD_CMD_RECTV1 0x6000
+#define CMD_CMD_RECTV2 0x8000
+#define CMD_CMD_LINEAF 0xA000
+#define CMD_CMD_BITBLT 0xC000
+
+#define BKGD_MIX_BSS_MASK 0x0060
+enum {
+    BKGD_MIX_BSS_BKGD = 0x0000,
+    BKGD_MIX_BSS_FRGD = 0x0020,
+    BKGD_MIX_BSS_PIX  = 0x0040,
+    BKGD_MIX_BSS_BMP  = 0x0060,
+};
+
+#define FRGD_MIX_FSS_MASK 0x0060
+enum {
+    FRGD_MIX_FSS_BKGD = 0x0000,
+    FRGD_MIX_FSS_FRGD = 0x0020,
+    FRGD_MIX_FSS_PIX  = 0x0040,
+    FRGD_MIX_FSS_BMP  = 0x0060,
+};
+
+#define PIX_CNTL_MIXSEL_MASK    0x00C0
+enum {
+    PIX_CNTL_MIXSEL_FOREMIX = 0x0000,
+    PIX_CNTL_MIXSEL_PATTERN = 0x0040,
+    PIX_CNTL_MIXSEL_VAR     = 0x0080,
+    PIX_CNTL_MIXSEL_TRANS   = 0x00C0,
+};
+
+// 40f3 = CMD_CMD_RECT | CMD_INC_Y | CMD_YMAJAXIS | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
+// 4331 = CMD_CMD_RECT | CMD_16BIT | CMD_PCDATA | CMD_INC_X | CMD_DRAW | CMD_WRTDATA
+// c0b3 = CMD_CMD_BITBLT | CMD_INC_Y | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
+
+typedef struct IBM8514State {
+    VGACommonState vga;
+    uint16_t maj_axis, min_axis;
+
+    uint8_t dac_mask; /* 02ea */
+    uint8_t dac_r_index; /* 02eb */
+    uint8_t dac_w_index; /* 02ec */
+    uint8_t dac_state[4];
+
+    uint16_t disp_stat; /* 02e8 */
+    uint16_t h_disp; /* 06e8 */
+    uint16_t h_sync_strt; /* 0ae8 */
+    uint16_t h_sync_wid; /* 0ee8 */
+    uint16_t v_total; /* 12e8 */
+    uint16_t v_disp; /* 16e8 */
+    uint16_t v_sync_strt; /* 1ae8 */
+    uint16_t v_sync_wid; /* 1ee8 */
+    uint16_t disp_cntl; /* 22e8 */
+    uint16_t h_total; /* 26e8 */
+    uint16_t subsys_cntl; /* 42e8 (W) */
+    uint16_t subsys_stat; /* 42e8 (R) */
+    uint16_t rom_page_sel; /* 46e8 */
+    uint16_t advfunc_cntl; /* 4ae8 */
+    uint16_t cur_y; /* 82e8 */
+    uint16_t cur_x; /* 86e8 */
+    uint16_t desty_axstep; /* 8ae8 */
+    uint16_t destx_diastp; /* 8ee8 */
+    uint16_t err_term; /* 92e8 */
+    uint16_t maj_axis_pcnt; /* 96e8 */
+    uint16_t gp_stat; /* 9ae8 (R) */
+    uint16_t cmd; /* 9ae8 (W) */
+    uint16_t short_stroke; /* 9ee8 */
+    uint16_t bkgd_color; /* a2e8 */
+    uint16_t frgd_color; /* a6e8 */
+    uint16_t wrt_mask; /* aae8 */
+    uint16_t rd_mask; /* aee8 */
+    uint16_t color_cmp; /* b2e8 */
+    uint16_t bkgd_mix; /* b6e8 */
+    uint16_t frgd_mix; /* bae8 */
+    uint16_t mfc[16]; /* bee8 */
+    uint16_t pix_trans; /* e2e8 */
+} IBM8514State;
+
+#define dac_byte dac_state[3]
+
+#define min_axis_pcnt mfc[0]
+#define scissors_t    mfc[1]
+#define scissors_l    mfc[2]
+#define scissors_b    mfc[3]
+#define scissors_r    mfc[4]
+#define mem_cntl      mfc[5]
+#define pattern_l     mfc[8]
+#define pattern_h     mfc[9]
+#define pix_cntl      mfc[10]
+
+static VMStateDescription vmstate_ibm8514 = {
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static inline void do_cmd_done(IBM8514State *s)
+{
+    s->gp_stat &= ~GP_STAT_BUSY;
+}
+
+static void do_cmd_write_pixel(IBM8514State *s, uint16_t value)
+{
+    uint16_t maj_axis_pcnt = s->maj_axis_pcnt + 1;
+    uint8_t* p8 = s->vga.vram_ptr + (s->cur_y * 640 + s->cur_x) * 4;
+    int dx = s->cmd & CMD_INC_X ? 1 : -1;
+    int dy = s->cmd & CMD_INC_Y ? 1 : -1;
+
+    if (!(s->gp_stat & GP_STAT_BUSY)) {
+        return;
+    }
+
+    ++s->maj_axis;
+    if ((s->maj_axis < maj_axis_pcnt) ||
+        (s->maj_axis == maj_axis_pcnt && !(s->cmd & CMD_LASTPIX))) {
+        p8[0] = p8[1] = p8[2] = p8[3] = value;
+    }
+    if (s->maj_axis < maj_axis_pcnt) {
+        s->cur_x += dx;
+    } else if (s->maj_axis == maj_axis_pcnt) {
+        if ((maj_axis_pcnt % 2 == 0) || !(s->cmd & CMD_16BIT)) {
+            s->maj_axis = 0;
+        }
+        s->cur_x -= (s->maj_axis_pcnt) * dx;
+        s->cur_y += dy;
+        s->min_axis++;
+        if (s->min_axis == s->min_axis_pcnt + 1) {
+            do_cmd_done(s);
+        }
+    } else {
+        //DPRINTF("%s: (skip - maj_axis = %u, maj_axis_pcnt = %u)\n",
+        //    __func__, s->maj_axis, maj_axis_pcnt);
+        s->maj_axis = 0;
+    }
+}
+
+static uint16_t get_source_operand(IBM8514State *s)
+{
+    switch (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) {
+        case PIX_CNTL_MIXSEL_FOREMIX:
+            switch (s->frgd_mix & FRGD_MIX_FSS_MASK) {
+                case FRGD_MIX_FSS_BKGD:
+                    return s->bkgd_color & 0xff;
+                case FRGD_MIX_FSS_FRGD:
+                    return s->frgd_color & 0xff;
+                default:
+                    BADF("%s: Unimplemented FSS %x\n",
+                         __func__, (s->frgd_mix & FRGD_MIX_FSS_MASK) >> 5);
+                    return 0;
+            }
+        default:
+            BADF("%s: Unimplemented MIXSEL %x\n",
+                 __func__, (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) >> 6);
+            return 0;
+    }
+}
+
+static void do_cmd_init(IBM8514State *s)
+{
+    s->gp_stat |= GP_STAT_BUSY;
+    s->maj_axis = 0;
+    s->min_axis = 0;
+
+    if ((s->cmd & CMD_CMD_MASK) == CMD_CMD_RECT) {
+        DPRINTF("cmd RECT: cur_x=%d cur_y=%d inc_x=%d inc_y=%d width=%d height=%d\n",
+            s->cur_x, s->cur_y,
+            s->cmd & CMD_INC_X ? 1 : -1, s->cmd & CMD_INC_Y ? 1 : -1,
+            s->maj_axis_pcnt, s->min_axis_pcnt);
+
+        if (!(s->cmd & CMD_PCDATA)) {
+            while (s->gp_stat & GP_STAT_BUSY) {
+                do_cmd_write_pixel(s, get_source_operand(s));
+            }
+        }
+    }
+}
+
+static void do_cmd(IBM8514State *s)
+{
+    DPRINTF("%s: execute cmd %04x\n", __func__, s->cmd);
+
+    do_cmd_init(s);
+}
+
+static uint32_t ibm8514_ramdac_ioport_readb(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+
+    switch (addr) {
+        case 0x02ea:
+            val = s->dac_mask;
+            break;
+        case 0x02eb:
+            val = s->dac_r_index;
+            break;
+        case 0x02ec:
+            val = s->dac_w_index;
+            break;
+        case 0x02ed:
+            if (s->dac_byte == 0) {
+                // XXX load dac_state[0-2] from palette
+            }
+            val = s->dac_state[s->dac_byte];
+            s->dac_byte = (s->dac_byte + 1) % 3;
+            if (s->dac_byte == 0) {
+                s->dac_r_index++;
+                s->dac_w_index++;
+            }
+            break;
+        default:
+            BADF("%s: invalid register at 0x%04x\n", __func__, addr);
+            val = 0;
+            break;
+    }
+    DPRINTF_IO("%s: read %02x at %04x\n", __func__, val, addr);
+    return val;
+}
+
+static void ibm8514_ramdac_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+
+    DPRINTF_IO("%s: write %02x at %04x\n", __func__, val, addr);
+    switch (addr) {
+        case 0x02ea:
+            s->dac_mask = val & 0xff;
+            break;
+        case 0x02eb:
+            s->dac_r_index = val & 0xff;
+            s->dac_byte = 0;
+            break;
+        case 0x02ec:
+            s->dac_w_index = val & 0xff;
+            s->dac_byte = 0;
+            break;
+        case 0x02ed:
+            s->dac_state[s->dac_byte] = val & 0xff;
+            s->dac_byte = (s->dac_byte + 1) % 3;
+            if (s->dac_byte == 0) {
+                // XXX store s->dac_state[0-2] to palette
+                s->dac_r_index++;
+                s->dac_w_index++;
+            }
+            break;
+        default:
+            BADF("%s: invalid register at 0x%04x\n", __func__, addr);
+            break;
+    }
+}
+
+static uint16_t* ibm8514_get_register(IBM8514State *s, uint32_t addr, int is_write, uint32_t* val_if_write)
+{
+    uint16_t *p;
+
+    switch (addr) {
+        case 0x02e8:
+            p = is_write ? &s->h_total : &s->disp_stat;
+            break;
+        case 0x06e8:
+            p = is_write ? &s->h_disp : NULL;
+            break;
+        case 0x0ae8:
+            p = is_write ? &s->h_sync_strt : NULL;
+            break;
+        case 0x0ee8:
+            p = is_write ? &s->h_sync_wid : NULL;
+            break;
+        case 0x12e8:
+            p = is_write ? &s->v_total : NULL;
+            break;
+        case 0x16e8:
+            p = is_write ? &s->v_disp : NULL;
+            break;
+        case 0x1ae8:
+            p = is_write ? &s->v_sync_strt : NULL;
+            break;
+        case 0x1ee8:
+            p = is_write ? &s->v_sync_wid : NULL;
+            break;
+        case 0x22e8:
+            p = is_write ? &s->disp_cntl : NULL;
+            break;
+        case 0x26e8:
+            p = is_write ? NULL: &s->h_total;
+            break;
+        case 0x42e8:
+            p = is_write ? &s->subsys_cntl : &s->subsys_stat;
+            break;
+        case 0x46e8:
+            p = is_write ? &s->rom_page_sel : NULL;
+            break;
+        case 0x4ae8:
+            p = is_write ? &s->advfunc_cntl : NULL;
+            break;
+        case 0x82e8:
+            p = &s->cur_y;
+            break;
+        case 0x86e8:
+            p = &s->cur_x;
+            break;
+        case 0x8ae8:
+            p = is_write ? &s->desty_axstep : NULL;
+            break;
+        case 0x8ee8:
+            p = is_write ? &s->destx_diastp : NULL;
+            break;
+        case 0x92e8:
+            p = &s->err_term;
+            break;
+        case 0x96e8:
+            p = is_write ? &s->maj_axis_pcnt : NULL;
+            break;
+        case 0x9ae8:
+            p = is_write ? &s->cmd : &s->gp_stat;
+            break;
+        case 0x9ee8:
+            p = is_write ? &s->short_stroke : NULL;
+            break;
+        case 0xa2e8:
+            p = is_write ? &s->bkgd_color : NULL;
+            break;
+        case 0xa6e8:
+            p = is_write ? &s->frgd_color : NULL;
+            break;
+        case 0xaae8:
+            p = is_write ? &s->wrt_mask : NULL;
+            break;
+        case 0xaee8:
+            p = is_write ? &s->rd_mask : NULL;
+            break;
+        case 0xb2e8:
+            p = is_write ? &s->color_cmp : NULL;
+            break;
+        case 0xb6e8:
+            p = is_write ? &s->bkgd_mix : NULL;
+            break;
+        case 0xbae8:
+            p = is_write ? &s->frgd_mix : NULL;
+            break;
+        case 0xbee8:
+            if (is_write) {
+                p = &s->mfc[(*val_if_write >> 12) & 0xf];
+                *val_if_write &= 0x0fff;
+            } else {
+                p = NULL;
+            }
+            break;
+        case 0xe2e8:
+            p = &s->pix_trans;
+            break;
+        default:
+            BADF("%s: invalid register at 0x%x\n", __func__, addr);
+            p = NULL;
+            break;
+    }
+
+    return p;
+}
+
+static uint32_t ibm8514_ioport_readb(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+    uint16_t *p;
+
+    p = ibm8514_get_register(s, addr & ~0x1, 0, NULL);
+
+    if (p) {
+        val = (be16_to_cpu(*p) >> ((~addr & 1) * 8)) & 0xff;
+    } else {
+        val = 0;
+    }
+
+    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static uint32_t ibm8514_ioport_readw(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+    uint16_t *p;
+
+    p = ibm8514_get_register(s, addr, 0, NULL);
+
+    if (p) {
+        val = be16_to_cpu(*p);
+    } else {
+        val = 0;
+    }
+
+    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static void ibm8514_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+    uint16_t *p;
+    uint8_t *c;
+
+    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
+    p = ibm8514_get_register(s, addr & ~0x1, 1, &val);
+
+    if (p) {
+        c = (uint8_t*)p;
+        c[~addr & 1] = val;
+    }
+    if ((addr & ~0x1) == REG_CMD) {
+        do_cmd(s);
+    } else if ((addr & ~0x1) == REG_PIX_TRANS) {
+        BADF("%s: ibm8514: 8-byte PIX_TRANS access (0x%08" PRIx32 ")\n",
+            __func__, addr);
+    }
+}
+
+static void ibm8514_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+    uint16_t *p;
+
+    val = cpu_to_be16(val);
+    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
+    p = ibm8514_get_register(s, addr, 1, &val);
+
+    if (p) {
+        *p = val & 0xffff;
+    }
+    if (addr == REG_CMD) {
+        do_cmd(s);
+    } else if (addr == REG_PIX_TRANS) {
+        if (!(s->cmd & CMD_16BIT)) {
+            do_cmd_write_pixel(s, val & 0xff);
+        } else if (s->cmd & CMD_BYTSEQ) {
+            do_cmd_write_pixel(s, val & 0xff);
+            do_cmd_write_pixel(s, val >> 8);
+        } else {
+            do_cmd_write_pixel(s, val >> 8);
+            do_cmd_write_pixel(s, val & 0xff);
+        }
+    }
+}
+
+static void ibm8514_register_ramdac_port(IBM8514State *s, uint32_t addr)
+{
+    register_ioport_read(addr, 1, 1, ibm8514_ramdac_ioport_readb, s);
+    register_ioport_write(addr, 1, 1, ibm8514_ramdac_ioport_writeb, s);
+}
+
+static void ibm8514_register_port(IBM8514State *s, uint32_t addr)
+{
+    register_ioport_read(addr, 2, 1, ibm8514_ioport_readb, s);
+    register_ioport_read(addr, 1, 2, ibm8514_ioport_readw, s);
+    register_ioport_write(addr, 2, 1, ibm8514_ioport_writeb, s);
+    register_ioport_write(addr, 1, 2, ibm8514_ioport_writew, s);
+}
+
+static void my_update_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+    int w;
+    uint8_t *vram;
+    uint8_t *data_display, *dd;
+    int x, y;
+    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
+
+    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) != 480) {
+        qemu_console_resize(s->ds, 640, 480);
+    }
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            rgb_to_pixel = rgb_to_pixel8;
+            w = 1;
+            break;
+        case 15:
+            rgb_to_pixel = rgb_to_pixel15;
+            w = 2;
+            break;
+        case 16:
+            rgb_to_pixel = rgb_to_pixel16;
+            w = 2;
+            break;
+        case 32:
+            rgb_to_pixel = rgb_to_pixel32;
+            w = 4;
+            break;
+        default:
+            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
+            return;
+    }
+
+    vram = s->vram_ptr;
+    /* XXX: out of range in vram? */
+    data_display = dd = ds_get_data(s->ds);
+    for (y = 0; y < 480; y++) {
+        for (x = 0; x < 640; x++) {
+            unsigned int color;
+            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
+            memcpy(dd, &color, w);
+            dd += w;
+            vram += 4;
+        }
+        data_display = dd = data_display + ds_get_linesize(s->ds);
+    }
+
+    dpy_update(s->ds, 0, 0, 640, 480);
+}
+
+static void ibm8514_init(IBM8514State *s)
+{
+    VGACommonState *vga = &s->vga;
+
+    vga->vram_size = 0x200000;
+
+    /* vga + console init */
+    vga_common_init(vga, vga->vram_size);
+    vga_init(vga);
+
+    vga->ds = graphic_console_init(/*vga->update*/my_update_display, vga->invalidate,
+                                   vga->screen_dump, vga->text_update,
+                                   vga);
+
+    ibm8514_register_port(s, 0x02e8);
+    ibm8514_register_ramdac_port(s, 0x02ea);
+    ibm8514_register_ramdac_port(s, 0x02eb);
+    ibm8514_register_ramdac_port(s, 0x02ec);
+    ibm8514_register_ramdac_port(s, 0x02ed);
+    ibm8514_register_port(s, 0x06e8);
+    ibm8514_register_port(s, 0x0ae8);
+    ibm8514_register_port(s, 0x0ee8);
+    ibm8514_register_port(s, 0x12e8);
+    ibm8514_register_port(s, 0x16e8);
+    ibm8514_register_port(s, 0x1ae8);
+    ibm8514_register_port(s, 0x1ee8);
+    ibm8514_register_port(s, 0x22e8);
+    ibm8514_register_port(s, 0x26e8);
+    ibm8514_register_port(s, 0x42e8);
+    ibm8514_register_port(s, 0x46e8);
+    ibm8514_register_port(s, 0x4ae8);
+    ibm8514_register_port(s, 0x82e8);
+    ibm8514_register_port(s, 0x86e8);
+    ibm8514_register_port(s, 0x8ae8);
+    ibm8514_register_port(s, 0x8ee8);
+    ibm8514_register_port(s, 0x92e8);
+    ibm8514_register_port(s, 0x96e8);
+    ibm8514_register_port(s, 0x9ae8);
+    ibm8514_register_port(s, 0x9ae8);
+    ibm8514_register_port(s, 0x9ee8);
+    ibm8514_register_port(s, 0xa2e8);
+    ibm8514_register_port(s, 0xa6e8);
+    ibm8514_register_port(s, 0xaae8);
+    ibm8514_register_port(s, 0xaee8);
+    ibm8514_register_port(s, 0xb2e8);
+    ibm8514_register_port(s, 0xb6e8);
+    ibm8514_register_port(s, 0xbae8);
+    ibm8514_register_port(s, 0xbee8);
+    ibm8514_register_port(s, 0xe2e8);
+
+    cpu_register_physical_memory(isa_mem_base + 0x02800000, vga->vram_size, vga->vram_offset);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x02800000, vga->vram_size);
+}
+
+typedef struct PCIIBM8514State {
+    PCIDevice dev;
+    IBM8514State state;
+} PCIIBM8514State;
+
+static void s3_vision864_write_config(PCIDevice *d,
+                                      uint32_t address, uint32_t val, int len)
+{
+    BADF("%s: 0x%08" PRIx32 "\n", __func__, address);
+}
+
+static int s3_vision864_init(PCIDevice *dev)
+{
+    PCIIBM8514State *pci = DO_UPCAST(PCIIBM8514State, dev, dev);
+    IBM8514State *s = &pci->state;
+    uint8_t *pci_conf = dev->config;
+
+    DPRINTF("%s\n", __func__);
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_S3);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_S3_864);
+    pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
+
+    ibm8514_init(s);
+
+    return 0;
+}
+
+static PCIDeviceInfo s3_vision864_info = {
+    .qdev.name    = "s3-vision864",
+    .qdev.size    = sizeof(PCIIBM8514State),
+    .qdev.vmsd    = &vmstate_ibm8514,
+    // XXX these depend on mst's PCI tree
+#if 0
+    .vendor_id    = PCI_VENDOR_ID_S3,
+    .device_id    = PCI_DEVICE_ID_S3_864,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+#endif
+    .init         = s3_vision864_init,
+    .config_write = s3_vision864_write_config,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void ibm8514_register(void)
+{
+    pci_qdev_register(&s3_vision864_info);
+}
+
+device_init(ibm8514_register);
+
+/*
+21:
+  DEVICE_ID
+    BusId = PCI
+    DevId = 0x41d00909 (PNP0909)
+    SerialNum = 0x00000000
+    Flags = 0x000061c5
+      : Output
+      : ConsoleOut
+      : PowerManaged
+      : Disableable
+      : Configurable
+      : Integrated
+      : Enabled
+    BaseType = DisplayController (3)
+    SubType = SVGAController (1)
+    Interface = GeneralSVGA (0)
+  BUS_ACCESS
+    info0 = 0
+    info1 = 112
+  AllocatedOffset  = 0x00000767
+    IRQ: 15
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x102 size 0x1 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3b4 size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3b8 size 0x4 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3bf size 0xc bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3cc size 0x1 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3ce size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3d4 size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3d8 size 0x5 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x42e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x46e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x4ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x82e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x86e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x8ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x8ee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x92e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x96e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x9ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x9ee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xa2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xa6e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xaae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xaee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xb2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xb6e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xbae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xbee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xe2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xe2ea size 0x1 bytes
+    LargeVendorItem: Generic Address
+      Memory address (32 bits), at 0x2800000 size 0x200000 bytes	ok
+    LargeVendorItem: Display
+      01 00 80 02 e0 01 80 02 00 00 80 c2 00 00 00 00 
+      00 00 20 00 00 00 00 00 78 
+  PossibleOffset   = 0x00000a58
+  CompatibleOffset = 0x00000a59
+
+*/
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card
  2011-06-15 18:11                                                 ` Andreas Färber
  2011-06-16  0:02                                                   ` [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM " Andreas Färber
@ 2011-06-16  0:05                                                   ` Andreas Färber
  2011-06-16  1:22                                                   ` Roy Tam
  2 siblings, 0 replies; 37+ messages in thread
From: Andreas Färber @ 2011-06-16  0:05 UTC (permalink / raw)
  To: Roy Tam; +Cc: Hervé Poussineau, qemu-devel Developers, Michael S. Tsirkin

Am 15.06.2011 um 20:11 schrieb Andreas Färber:

> Am 15.06.2011 um 06:33 schrieb Roy Tam:
>
>> 2011/6/14 Andreas Färber <andreas.faerber@web.de>:
>>> The IBM E15 is equivalent to an S3 Vision864.
>>>
>>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>>> to greyscale colors. This works sufficiently to observe firmware
>>> boot progress.
>>>
>>
>> IMO we can generalize it as a generic S3 Vision864 and use it in  
>> x86 guest too.
>
> What in particular would we need to generalize? It's qdev'ified; I  
> don't remember seeing anything PReP-specific in there.

Err, be16_to_cpu()?

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card
  2011-06-15 18:11                                                 ` Andreas Färber
  2011-06-16  0:02                                                   ` [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM " Andreas Färber
  2011-06-16  0:05                                                   ` [Qemu-devel] [RFC 23/23] 40p: Add an " Andreas Färber
@ 2011-06-16  1:22                                                   ` Roy Tam
  2 siblings, 0 replies; 37+ messages in thread
From: Roy Tam @ 2011-06-16  1:22 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Hervé Poussineau, qemu-devel Developers, Michael S. Tsirkin

2011/6/16 Andreas Färber <andreas.faerber@web.de>:
> Am 15.06.2011 um 06:33 schrieb Roy Tam:
>
>> 2011/6/14 Andreas Färber <andreas.faerber@web.de>:
>>>
>>> The IBM E15 is equivalent to an S3 Vision864.
>>>
>>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>>> to greyscale colors. This works sufficiently to observe firmware
>>> boot progress.
>>>
>>
>> IMO we can generalize it as a generic S3 Vision864 and use it in x86 guest
>> too.
>
> What in particular would we need to generalize? It's qdev'ified; I don't
> remember seeing anything PReP-specific in there.
> It still needs VMState of course.
>
>> http://wiki.qemu.org/Google_Summer_of_Code_2011#Add_a_S3_Trio_or_S3_Virge
>> CC: Natalia Portillo <claunia@claunia.com>
>>
>>> Cc: Hervé Poussineau <hpoussin@reactos.org>
>>>
>>> Fixed off-by-one drawing issue.
>>> Replaced hardcoded color for RECT.
>>> Separate I/O debug output for readability.
>>>
>>> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
>>> ---
>>>  Makefile.objs                   |    1 +
>>>  default-configs/ppc-softmmu.mak |    1 +
>>>  hw/pci_ids.h                    |    3 +
>>>  hw/ppc_prep.c                   |    2 +
>>>  hw/vga-s3.c                     |  694
>>> +++++++++++++++++++++++++++++++++++++++
>>>  5 files changed, 701 insertions(+), 0 deletions(-)
>>>  create mode 100644 hw/vga-s3.c
>>>
>> [snip]
>>
>> IMO using vga-s3-864.c as the file name may be better as S3 produced
>> many display chips.
>
> Actually in the meantime I've already renamed the file to vga-ibm8514a.c
> (better: vga-ibm8514.c) and renamed the registration functions to reflect
> the s3_vision864.
>

Actually what I mean is that, you may make the code to be more S3
Vision864-ish because S3 Vision864 extends its display capability, not
only 1024*768 4/8bpp.

> I agree that rather than bundling different graphics cards by one vendor we
> should bundle different implementations of the same chipset. I was assuming
> that the IBM E15 uses a different vendor_id at least but could share the
> initialization with other cards, once mst's declarative PCI initialization
> reaches master (prepared that locally).
> Supposedly the Miro 20SD is compatible with the S3 Vision864, and the ATI
> Mach8 was based on IBM 8514/A, too. Not sure about the Weitek P9100-based
> IBM S15.
>
> Any suggestions what to do about the RAMDAC would be appreciated. The
> firmware only accesses the DAC_MASK register but does not write to the DAC
> itself, so for colors the card needs a reset handler that initializes the
> 256-color palette to the right RGB values.
>
> Andreas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-16  0:02                                                   ` [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM " Andreas Färber
@ 2011-06-18 20:42                                                     ` Blue Swirl
  2011-06-19 10:04                                                       ` Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Blue Swirl @ 2011-06-18 20:42 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Hervé Poussineau, qemu-devel, Roy Tam

On Thu, Jun 16, 2011 at 3:02 AM, Andreas Färber <andreas.faerber@web.de> wrote:
> The IBM E15 is equivalent to an S3 Vision864.
>
> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
> to greyscale colors. This works sufficiently to observe firmware
> boot progress.
>
> Cc: Hervé Poussineau <hpoussin@reactos.org>
>
> Fixed off-by-one drawing issue.
> Replaced hardcoded color for RECT.
> Separate I/O debug output for readability.
> Start cleaning up the naming s3 vs. ibm8514.
> Prepare support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA regs.
>
> Cc: Roy Tam <roytam@gmail.com>
> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
> ---
>  Makefile.objs                   |    1 +
>  default-configs/ppc-softmmu.mak |    1 +
>  hw/pci_ids.h                    |    3 +
>  hw/ppc_prep.c                   |    2 +
>  hw/vga-ibm8514.c                |  780 +++++++++++++++++++++++++++++++++++++++
>  5 files changed, 787 insertions(+), 0 deletions(-)
>  create mode 100644 hw/vga-ibm8514.c
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 7ceeee5..95dcd91 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -270,6 +270,7 @@ hw-obj-y += qdev-addr.o
>  hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
>  hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
>  hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
> +hw-obj-$(CONFIG_VGA_IBM8514) += vga-ibm8514.o
>  hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
>  hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
>
> diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
> index 303929f..f9c97b7 100644
> --- a/default-configs/ppc-softmmu.mak
> +++ b/default-configs/ppc-softmmu.mak
> @@ -6,6 +6,7 @@ CONFIG_ISA_MMIO=y
>  CONFIG_ESCC=y
>  CONFIG_M48T59=y
>  CONFIG_VGA_PCI=y
> +CONFIG_VGA_IBM8514=y
>  CONFIG_SERIAL=y
>  CONFIG_PARALLEL=y
>  CONFIG_I8254=y
> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index d3bef0e..821421c 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -97,6 +97,9 @@
>  #define PCI_VENDOR_ID_FREESCALE          0x1957
>  #define PCI_DEVICE_ID_MPC8533E           0x0030
>
> +#define PCI_VENDOR_ID_S3                 0x5333
> +#define PCI_DEVICE_ID_S3_864             0x88c0
> +
>  #define PCI_VENDOR_ID_INTEL              0x8086
>  #define PCI_DEVICE_ID_INTEL_82378        0x0484
>  #define PCI_DEVICE_ID_INTEL_82441        0x1237
> diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
> index 6ae1635..c215b0f 100644
> --- a/hw/ppc_prep.c
> +++ b/hw/ppc_prep.c
> @@ -747,6 +747,8 @@ static void ibm_40p_init(ram_addr_t ram_size,
>     qdev_prop_set_uint8(&isa->qdev, "board-identification", 0xfc);
>     qdev_init_nofail(&isa->qdev);
>
> +    pci_create_simple(pci_bus, PCI_DEVFN(2, 0), "s3-vision864");
> +
>     /* 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/vga-ibm8514.c b/hw/vga-ibm8514.c
> new file mode 100644
> index 0000000..a87afe1
> --- /dev/null
> +++ b/hw/vga-ibm8514.c
> @@ -0,0 +1,780 @@
> +/*
> + * QEMU PCI IBM 8514/A Emulator.
> + *
> + * Copyright (c) 2010 Hervé Poussineau
> + * Copyright (c) 2010-2011 Andreas Färber
> + *
> + * 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.
> + */
> +
> +/* Documentation available at
> + * http://www.datasheetarchive.com/Indexer/Datasheet-06/DSA0091551.html
> + */
> +
> +#include "console.h"
> +#include "pci.h"
> +#include "vga_int.h"
> +#include "pixel_ops.h"
> +
> +//#define DEBUG_8514
> +//#define DEBUG_8514_IO
> +
> +#ifdef DEBUG_8514
> +#define DPRINTF(fmt, ...) \
> +do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) do {} while (0)
> +#endif
> +#ifdef DEBUG_8514_IO
> +#define DPRINTF_IO(fmt, ...) \
> +do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF_IO(fmt, ...) do {} while (0)
> +#endif
> +#define BADF(fmt, ...) \
> +do { fprintf(stderr, "8514 ERROR: " fmt , ## __VA_ARGS__);} while (0)
> +
> +enum {
> +    REG_CMD = 0x9AE8,
> +    REG_PIX_TRANS = 0xE2E8,
> +};
> +
> +#define GP_STAT_BUSY     0x0200
> +
> +#define CMD_WRTDATA      0x0001
> +#define CMD_PLANAR       0x0002
> +#define CMD_LASTPIX      0x0004
> +#define CMD_LINETYPE     0x0008
> +#define CMD_DRAW         0x0010
> +#define CMD_INC_X        0x0020
> +#define CMD_YMAJAXIS     0x0040
> +#define CMD_INC_Y        0x0080
> +#define CMD_PCDATA       0x0100
> +#define CMD_16BIT        0x0200
> +#define CMD_BYTSEQ       0x1000
> +#define CMD_CMD_MASK     0xE000
> +
> +#define CMD_CMD_NOP    0x0000
> +#define CMD_CMD_LINE   0x2000
> +#define CMD_CMD_RECT   0x4000
> +#define CMD_CMD_RECTV1 0x6000
> +#define CMD_CMD_RECTV2 0x8000
> +#define CMD_CMD_LINEAF 0xA000
> +#define CMD_CMD_BITBLT 0xC000
> +
> +#define BKGD_MIX_BSS_MASK 0x0060
> +enum {
> +    BKGD_MIX_BSS_BKGD = 0x0000,
> +    BKGD_MIX_BSS_FRGD = 0x0020,
> +    BKGD_MIX_BSS_PIX  = 0x0040,
> +    BKGD_MIX_BSS_BMP  = 0x0060,
> +};
> +
> +#define FRGD_MIX_FSS_MASK 0x0060
> +enum {
> +    FRGD_MIX_FSS_BKGD = 0x0000,
> +    FRGD_MIX_FSS_FRGD = 0x0020,
> +    FRGD_MIX_FSS_PIX  = 0x0040,
> +    FRGD_MIX_FSS_BMP  = 0x0060,
> +};
> +
> +#define PIX_CNTL_MIXSEL_MASK    0x00C0
> +enum {
> +    PIX_CNTL_MIXSEL_FOREMIX = 0x0000,
> +    PIX_CNTL_MIXSEL_PATTERN = 0x0040,
> +    PIX_CNTL_MIXSEL_VAR     = 0x0080,
> +    PIX_CNTL_MIXSEL_TRANS   = 0x00C0,
> +};
> +
> +// 40f3 = CMD_CMD_RECT | CMD_INC_Y | CMD_YMAJAXIS | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
> +// 4331 = CMD_CMD_RECT | CMD_16BIT | CMD_PCDATA | CMD_INC_X | CMD_DRAW | CMD_WRTDATA
> +// c0b3 = CMD_CMD_BITBLT | CMD_INC_Y | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA

C89 comments?

> +
> +typedef struct IBM8514State {
> +    VGACommonState vga;
> +    uint16_t maj_axis, min_axis;
> +
> +    uint8_t dac_mask; /* 02ea */
> +    uint8_t dac_r_index; /* 02eb */
> +    uint8_t dac_w_index; /* 02ec */
> +    uint8_t dac_state[4];
> +
> +    uint16_t disp_stat; /* 02e8 */
> +    uint16_t h_disp; /* 06e8 */
> +    uint16_t h_sync_strt; /* 0ae8 */
> +    uint16_t h_sync_wid; /* 0ee8 */
> +    uint16_t v_total; /* 12e8 */
> +    uint16_t v_disp; /* 16e8 */
> +    uint16_t v_sync_strt; /* 1ae8 */
> +    uint16_t v_sync_wid; /* 1ee8 */
> +    uint16_t disp_cntl; /* 22e8 */
> +    uint16_t h_total; /* 26e8 */
> +    uint16_t subsys_cntl; /* 42e8 (W) */
> +    uint16_t subsys_stat; /* 42e8 (R) */
> +    uint16_t rom_page_sel; /* 46e8 */
> +    uint16_t advfunc_cntl; /* 4ae8 */
> +    uint16_t cur_y; /* 82e8 */
> +    uint16_t cur_x; /* 86e8 */
> +    uint16_t desty_axstep; /* 8ae8 */
> +    uint16_t destx_diastp; /* 8ee8 */
> +    uint16_t err_term; /* 92e8 */
> +    uint16_t maj_axis_pcnt; /* 96e8 */
> +    uint16_t gp_stat; /* 9ae8 (R) */
> +    uint16_t cmd; /* 9ae8 (W) */
> +    uint16_t short_stroke; /* 9ee8 */
> +    uint16_t bkgd_color; /* a2e8 */
> +    uint16_t frgd_color; /* a6e8 */
> +    uint16_t wrt_mask; /* aae8 */
> +    uint16_t rd_mask; /* aee8 */
> +    uint16_t color_cmp; /* b2e8 */
> +    uint16_t bkgd_mix; /* b6e8 */
> +    uint16_t frgd_mix; /* bae8 */
> +    uint16_t mfc[16]; /* bee8 */
> +    uint16_t pix_trans; /* e2e8 */
> +} IBM8514State;
> +
> +#define dac_byte dac_state[3]
> +
> +#define min_axis_pcnt mfc[0]
> +#define scissors_t    mfc[1]
> +#define scissors_l    mfc[2]
> +#define scissors_b    mfc[3]
> +#define scissors_r    mfc[4]
> +#define mem_cntl      mfc[5]
> +#define pattern_l     mfc[8]
> +#define pattern_h     mfc[9]
> +#define pix_cntl      mfc[10]
> +
> +static VMStateDescription vmstate_ibm8514 = {
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField []) {
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static inline void do_cmd_done(IBM8514State *s)
> +{
> +    s->gp_stat &= ~GP_STAT_BUSY;
> +}
> +
> +static void do_cmd_write_pixel(IBM8514State *s, uint16_t value)
> +{
> +    uint16_t maj_axis_pcnt = s->maj_axis_pcnt + 1;
> +    uint8_t* p8 = s->vga.vram_ptr + (s->cur_y * 640 + s->cur_x) * 4;
> +    int dx = s->cmd & CMD_INC_X ? 1 : -1;
> +    int dy = s->cmd & CMD_INC_Y ? 1 : -1;
> +
> +    if (!(s->gp_stat & GP_STAT_BUSY)) {
> +        return;
> +    }
> +
> +    ++s->maj_axis;
> +    if ((s->maj_axis < maj_axis_pcnt) ||
> +        (s->maj_axis == maj_axis_pcnt && !(s->cmd & CMD_LASTPIX))) {
> +        p8[0] = p8[1] = p8[2] = p8[3] = value;
> +    }
> +    if (s->maj_axis < maj_axis_pcnt) {
> +        s->cur_x += dx;
> +    } else if (s->maj_axis == maj_axis_pcnt) {
> +        if ((maj_axis_pcnt % 2 == 0) || !(s->cmd & CMD_16BIT)) {
> +            s->maj_axis = 0;
> +        }
> +        s->cur_x -= (s->maj_axis_pcnt) * dx;
> +        s->cur_y += dy;
> +        s->min_axis++;
> +        if (s->min_axis == s->min_axis_pcnt + 1) {
> +            do_cmd_done(s);
> +        }
> +    } else {
> +        //DPRINTF("%s: (skip - maj_axis = %u, maj_axis_pcnt = %u)\n",
> +        //    __func__, s->maj_axis, maj_axis_pcnt);
> +        s->maj_axis = 0;
> +    }
> +}
> +
> +static uint16_t get_source_operand(IBM8514State *s)
> +{
> +    switch (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) {
> +        case PIX_CNTL_MIXSEL_FOREMIX:
> +            switch (s->frgd_mix & FRGD_MIX_FSS_MASK) {
> +                case FRGD_MIX_FSS_BKGD:
> +                    return s->bkgd_color & 0xff;
> +                case FRGD_MIX_FSS_FRGD:
> +                    return s->frgd_color & 0xff;
> +                default:
> +                    BADF("%s: Unimplemented FSS %x\n",
> +                         __func__, (s->frgd_mix & FRGD_MIX_FSS_MASK) >> 5);
> +                    return 0;
> +            }
> +        default:
> +            BADF("%s: Unimplemented MIXSEL %x\n",
> +                 __func__, (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) >> 6);
> +            return 0;
> +    }
> +}
> +
> +static void do_cmd_init(IBM8514State *s)
> +{
> +    s->gp_stat |= GP_STAT_BUSY;
> +    s->maj_axis = 0;
> +    s->min_axis = 0;
> +
> +    if ((s->cmd & CMD_CMD_MASK) == CMD_CMD_RECT) {
> +        DPRINTF("cmd RECT: cur_x=%d cur_y=%d inc_x=%d inc_y=%d width=%d height=%d\n",
> +            s->cur_x, s->cur_y,
> +            s->cmd & CMD_INC_X ? 1 : -1, s->cmd & CMD_INC_Y ? 1 : -1,
> +            s->maj_axis_pcnt, s->min_axis_pcnt);
> +
> +        if (!(s->cmd & CMD_PCDATA)) {
> +            while (s->gp_stat & GP_STAT_BUSY) {
> +                do_cmd_write_pixel(s, get_source_operand(s));
> +            }
> +        }
> +    }
> +}
> +
> +static void do_cmd(IBM8514State *s)
> +{
> +    DPRINTF("%s: execute cmd %04x\n", __func__, s->cmd);
> +
> +    do_cmd_init(s);
> +}
> +
> +static uint32_t ibm8514_ramdac_ioport_readb(void *opaque, uint32_t addr)
> +{
> +    IBM8514State *s = opaque;
> +    uint32_t val;
> +
> +    switch (addr) {
> +        case 0x02ea:
> +            val = s->dac_mask;
> +            break;
> +        case 0x02eb:
> +            val = s->dac_r_index;
> +            break;
> +        case 0x02ec:
> +            val = s->dac_w_index;
> +            break;
> +        case 0x02ed:
> +            if (s->dac_byte == 0) {
> +                // XXX load dac_state[0-2] from palette
> +            }
> +            val = s->dac_state[s->dac_byte];
> +            s->dac_byte = (s->dac_byte + 1) % 3;
> +            if (s->dac_byte == 0) {
> +                s->dac_r_index++;
> +                s->dac_w_index++;
> +            }
> +            break;
> +        default:
> +            BADF("%s: invalid register at 0x%04x\n", __func__, addr);
> +            val = 0;
> +            break;
> +    }
> +    DPRINTF_IO("%s: read %02x at %04x\n", __func__, val, addr);
> +    return val;
> +}
> +
> +static void ibm8514_ramdac_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    IBM8514State *s = opaque;
> +
> +    DPRINTF_IO("%s: write %02x at %04x\n", __func__, val, addr);
> +    switch (addr) {
> +        case 0x02ea:
> +            s->dac_mask = val & 0xff;
> +            break;
> +        case 0x02eb:
> +            s->dac_r_index = val & 0xff;
> +            s->dac_byte = 0;
> +            break;
> +        case 0x02ec:
> +            s->dac_w_index = val & 0xff;
> +            s->dac_byte = 0;
> +            break;
> +        case 0x02ed:
> +            s->dac_state[s->dac_byte] = val & 0xff;
> +            s->dac_byte = (s->dac_byte + 1) % 3;
> +            if (s->dac_byte == 0) {
> +                // XXX store s->dac_state[0-2] to palette
> +                s->dac_r_index++;
> +                s->dac_w_index++;
> +            }
> +            break;
> +        default:
> +            BADF("%s: invalid register at 0x%04x\n", __func__, addr);
> +            break;
> +    }
> +}
> +
> +static uint16_t* ibm8514_get_register(IBM8514State *s, uint32_t addr, int is_write, uint32_t* val_if_write)
> +{
> +    uint16_t *p;
> +
> +    switch (addr) {
> +        case 0x02e8:
> +            p = is_write ? &s->h_total : &s->disp_stat;
> +            break;
> +        case 0x06e8:
> +            p = is_write ? &s->h_disp : NULL;
> +            break;
> +        case 0x0ae8:
> +            p = is_write ? &s->h_sync_strt : NULL;
> +            break;
> +        case 0x0ee8:
> +            p = is_write ? &s->h_sync_wid : NULL;
> +            break;
> +        case 0x12e8:
> +            p = is_write ? &s->v_total : NULL;
> +            break;
> +        case 0x16e8:
> +            p = is_write ? &s->v_disp : NULL;
> +            break;
> +        case 0x1ae8:
> +            p = is_write ? &s->v_sync_strt : NULL;
> +            break;
> +        case 0x1ee8:
> +            p = is_write ? &s->v_sync_wid : NULL;
> +            break;
> +        case 0x22e8:
> +            p = is_write ? &s->disp_cntl : NULL;
> +            break;
> +        case 0x26e8:
> +            p = is_write ? NULL: &s->h_total;
> +            break;
> +        case 0x42e8:
> +            p = is_write ? &s->subsys_cntl : &s->subsys_stat;
> +            break;
> +        case 0x46e8:
> +            p = is_write ? &s->rom_page_sel : NULL;
> +            break;
> +        case 0x4ae8:
> +            p = is_write ? &s->advfunc_cntl : NULL;
> +            break;
> +        case 0x82e8:
> +            p = &s->cur_y;
> +            break;
> +        case 0x86e8:
> +            p = &s->cur_x;
> +            break;
> +        case 0x8ae8:
> +            p = is_write ? &s->desty_axstep : NULL;
> +            break;
> +        case 0x8ee8:
> +            p = is_write ? &s->destx_diastp : NULL;
> +            break;
> +        case 0x92e8:
> +            p = &s->err_term;
> +            break;
> +        case 0x96e8:
> +            p = is_write ? &s->maj_axis_pcnt : NULL;
> +            break;
> +        case 0x9ae8:
> +            p = is_write ? &s->cmd : &s->gp_stat;
> +            break;
> +        case 0x9ee8:
> +            p = is_write ? &s->short_stroke : NULL;
> +            break;
> +        case 0xa2e8:
> +            p = is_write ? &s->bkgd_color : NULL;
> +            break;
> +        case 0xa6e8:
> +            p = is_write ? &s->frgd_color : NULL;
> +            break;
> +        case 0xaae8:
> +            p = is_write ? &s->wrt_mask : NULL;
> +            break;
> +        case 0xaee8:
> +            p = is_write ? &s->rd_mask : NULL;
> +            break;
> +        case 0xb2e8:
> +            p = is_write ? &s->color_cmp : NULL;
> +            break;
> +        case 0xb6e8:
> +            p = is_write ? &s->bkgd_mix : NULL;
> +            break;
> +        case 0xbae8:
> +            p = is_write ? &s->frgd_mix : NULL;
> +            break;
> +        case 0xbee8:
> +            if (is_write) {
> +                p = &s->mfc[(*val_if_write >> 12) & 0xf];
> +                *val_if_write &= 0x0fff;
> +            } else {
> +                p = NULL;
> +            }
> +            break;
> +        case 0xe2e8:
> +            p = &s->pix_trans;
> +            break;
> +        default:
> +            BADF("%s: invalid register at 0x%x\n", __func__, addr);
> +            p = NULL;
> +            break;
> +    }
> +
> +    return p;
> +}
> +
> +static uint32_t ibm8514_ioport_readb(void *opaque, uint32_t addr)
> +{
> +    IBM8514State *s = opaque;
> +    uint32_t val;
> +    uint16_t *p;
> +
> +    p = ibm8514_get_register(s, addr & ~0x1, 0, NULL);
> +
> +    if (p) {
> +        val = (be16_to_cpu(*p) >> ((~addr & 1) * 8)) & 0xff;
> +    } else {
> +        val = 0;
> +    }
> +
> +    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
> +    return val;
> +}
> +
> +static uint32_t ibm8514_ioport_readw(void *opaque, uint32_t addr)
> +{
> +    IBM8514State *s = opaque;
> +    uint32_t val;
> +    uint16_t *p;
> +
> +    p = ibm8514_get_register(s, addr, 0, NULL);
> +
> +    if (p) {
> +        val = be16_to_cpu(*p);
> +    } else {
> +        val = 0;
> +    }
> +
> +    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
> +    return val;
> +}
> +
> +static void ibm8514_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    IBM8514State *s = opaque;
> +    uint16_t *p;
> +    uint8_t *c;
> +
> +    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
> +    p = ibm8514_get_register(s, addr & ~0x1, 1, &val);
> +
> +    if (p) {
> +        c = (uint8_t*)p;
> +        c[~addr & 1] = val;
> +    }
> +    if ((addr & ~0x1) == REG_CMD) {
> +        do_cmd(s);
> +    } else if ((addr & ~0x1) == REG_PIX_TRANS) {
> +        BADF("%s: ibm8514: 8-byte PIX_TRANS access (0x%08" PRIx32 ")\n",
> +            __func__, addr);
> +    }
> +}
> +
> +static void ibm8514_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    IBM8514State *s = opaque;
> +    uint16_t *p;
> +
> +    val = cpu_to_be16(val);
> +    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
> +    p = ibm8514_get_register(s, addr, 1, &val);
> +
> +    if (p) {
> +        *p = val & 0xffff;
> +    }
> +    if (addr == REG_CMD) {
> +        do_cmd(s);
> +    } else if (addr == REG_PIX_TRANS) {
> +        if (!(s->cmd & CMD_16BIT)) {
> +            do_cmd_write_pixel(s, val & 0xff);
> +        } else if (s->cmd & CMD_BYTSEQ) {
> +            do_cmd_write_pixel(s, val & 0xff);
> +            do_cmd_write_pixel(s, val >> 8);
> +        } else {
> +            do_cmd_write_pixel(s, val >> 8);
> +            do_cmd_write_pixel(s, val & 0xff);
> +        }
> +    }
> +}
> +
> +static void ibm8514_register_ramdac_port(IBM8514State *s, uint32_t addr)
> +{
> +    register_ioport_read(addr, 1, 1, ibm8514_ramdac_ioport_readb, s);
> +    register_ioport_write(addr, 1, 1, ibm8514_ramdac_ioport_writeb, s);
> +}
> +
> +static void ibm8514_register_port(IBM8514State *s, uint32_t addr)
> +{
> +    register_ioport_read(addr, 2, 1, ibm8514_ioport_readb, s);
> +    register_ioport_read(addr, 1, 2, ibm8514_ioport_readw, s);
> +    register_ioport_write(addr, 2, 1, ibm8514_ioport_writeb, s);
> +    register_ioport_write(addr, 1, 2, ibm8514_ioport_writew, s);
> +}
> +
> +static void my_update_display(void *opaque)
> +{
> +    VGACommonState *s = opaque;
> +    int w;
> +    uint8_t *vram;
> +    uint8_t *data_display, *dd;
> +    int x, y;
> +    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
> +
> +    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) != 480) {
> +        qemu_console_resize(s->ds, 640, 480);
> +    }
> +
> +    switch (ds_get_bits_per_pixel(s->ds)) {
> +        case 8:
> +            rgb_to_pixel = rgb_to_pixel8;
> +            w = 1;
> +            break;
> +        case 15:
> +            rgb_to_pixel = rgb_to_pixel15;
> +            w = 2;
> +            break;
> +        case 16:
> +            rgb_to_pixel = rgb_to_pixel16;
> +            w = 2;
> +            break;
> +        case 32:
> +            rgb_to_pixel = rgb_to_pixel32;
> +            w = 4;
> +            break;
> +        default:
> +            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
> +            return;
> +    }
> +
> +    vram = s->vram_ptr;
> +    /* XXX: out of range in vram? */
> +    data_display = dd = ds_get_data(s->ds);
> +    for (y = 0; y < 480; y++) {
> +        for (x = 0; x < 640; x++) {
> +            unsigned int color;
> +            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
> +            memcpy(dd, &color, w);

Please take a look at tcx.c for a 8 bit mode frame buffer with palette
translation. Also VGA_DIRTY bit handling should be added to this loop
to speed it up.

> +            dd += w;
> +            vram += 4;
> +        }
> +        data_display = dd = data_display + ds_get_linesize(s->ds);
> +    }
> +
> +    dpy_update(s->ds, 0, 0, 640, 480);
> +}
> +
> +static void ibm8514_init(IBM8514State *s)
> +{
> +    VGACommonState *vga = &s->vga;
> +
> +    vga->vram_size = 0x200000;
> +
> +    /* vga + console init */
> +    vga_common_init(vga, vga->vram_size);
> +    vga_init(vga);
> +
> +    vga->ds = graphic_console_init(/*vga->update*/my_update_display, vga->invalidate,
> +                                   vga->screen_dump, vga->text_update,
> +                                   vga);
> +
> +    ibm8514_register_port(s, 0x02e8);
> +    ibm8514_register_ramdac_port(s, 0x02ea);
> +    ibm8514_register_ramdac_port(s, 0x02eb);
> +    ibm8514_register_ramdac_port(s, 0x02ec);
> +    ibm8514_register_ramdac_port(s, 0x02ed);
> +    ibm8514_register_port(s, 0x06e8);
> +    ibm8514_register_port(s, 0x0ae8);
> +    ibm8514_register_port(s, 0x0ee8);
> +    ibm8514_register_port(s, 0x12e8);
> +    ibm8514_register_port(s, 0x16e8);
> +    ibm8514_register_port(s, 0x1ae8);
> +    ibm8514_register_port(s, 0x1ee8);
> +    ibm8514_register_port(s, 0x22e8);
> +    ibm8514_register_port(s, 0x26e8);
> +    ibm8514_register_port(s, 0x42e8);
> +    ibm8514_register_port(s, 0x46e8);
> +    ibm8514_register_port(s, 0x4ae8);
> +    ibm8514_register_port(s, 0x82e8);
> +    ibm8514_register_port(s, 0x86e8);
> +    ibm8514_register_port(s, 0x8ae8);
> +    ibm8514_register_port(s, 0x8ee8);
> +    ibm8514_register_port(s, 0x92e8);
> +    ibm8514_register_port(s, 0x96e8);
> +    ibm8514_register_port(s, 0x9ae8);
> +    ibm8514_register_port(s, 0x9ae8);
> +    ibm8514_register_port(s, 0x9ee8);
> +    ibm8514_register_port(s, 0xa2e8);
> +    ibm8514_register_port(s, 0xa6e8);
> +    ibm8514_register_port(s, 0xaae8);
> +    ibm8514_register_port(s, 0xaee8);
> +    ibm8514_register_port(s, 0xb2e8);
> +    ibm8514_register_port(s, 0xb6e8);
> +    ibm8514_register_port(s, 0xbae8);
> +    ibm8514_register_port(s, 0xbee8);
> +    ibm8514_register_port(s, 0xe2e8);
> +
> +    cpu_register_physical_memory(isa_mem_base + 0x02800000, vga->vram_size, vga->vram_offset);
> +    qemu_register_coalesced_mmio(isa_mem_base + 0x02800000, vga->vram_size);
> +}
> +
> +typedef struct PCIIBM8514State {
> +    PCIDevice dev;
> +    IBM8514State state;
> +} PCIIBM8514State;
> +
> +static void s3_vision864_write_config(PCIDevice *d,
> +                                      uint32_t address, uint32_t val, int len)
> +{
> +    BADF("%s: 0x%08" PRIx32 "\n", __func__, address);
> +}
> +
> +static int s3_vision864_init(PCIDevice *dev)
> +{
> +    PCIIBM8514State *pci = DO_UPCAST(PCIIBM8514State, dev, dev);
> +    IBM8514State *s = &pci->state;
> +    uint8_t *pci_conf = dev->config;
> +
> +    DPRINTF("%s\n", __func__);
> +
> +    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_S3);
> +    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_S3_864);
> +    pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
> +
> +    ibm8514_init(s);
> +
> +    return 0;
> +}
> +
> +static PCIDeviceInfo s3_vision864_info = {
> +    .qdev.name    = "s3-vision864",
> +    .qdev.size    = sizeof(PCIIBM8514State),
> +    .qdev.vmsd    = &vmstate_ibm8514,
> +    // XXX these depend on mst's PCI tree
> +#if 0
> +    .vendor_id    = PCI_VENDOR_ID_S3,
> +    .device_id    = PCI_DEVICE_ID_S3_864,
> +    .class_id     = PCI_CLASS_DISPLAY_VGA,
> +#endif
> +    .init         = s3_vision864_init,
> +    .config_write = s3_vision864_write_config,
> +    .qdev.props   = (Property[]) {
> +        DEFINE_PROP_END_OF_LIST()
> +    },
> +};
> +
> +static void ibm8514_register(void)
> +{
> +    pci_qdev_register(&s3_vision864_info);
> +}
> +
> +device_init(ibm8514_register);
> +
> +/*
> +21:
> +  DEVICE_ID
> +    BusId = PCI
> +    DevId = 0x41d00909 (PNP0909)
> +    SerialNum = 0x00000000
> +    Flags = 0x000061c5
> +      : Output
> +      : ConsoleOut
> +      : PowerManaged
> +      : Disableable
> +      : Configurable
> +      : Integrated
> +      : Enabled
> +    BaseType = DisplayController (3)
> +    SubType = SVGAController (1)
> +    Interface = GeneralSVGA (0)
> +  BUS_ACCESS
> +    info0 = 0
> +    info1 = 112
> +  AllocatedOffset  = 0x00000767
> +    IRQ: 15
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x102 size 0x1 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3b4 size 0x2 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3b8 size 0x4 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3bf size 0xc bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3cc size 0x1 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3ce size 0x2 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3d4 size 0x2 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x3d8 size 0x5 bytes
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x42e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x46e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x4ae8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x82e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x86e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x8ae8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x8ee8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x92e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x96e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x9ae8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0x9ee8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xa2e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xa6e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xaae8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xaee8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xb2e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xb6e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xbae8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xbee8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xe2e8 size 0x1 bytes                          ok
> +    LargeVendorItem: Generic Address
> +      I/O address (32 bits), at 0xe2ea size 0x1 bytes
> +    LargeVendorItem: Generic Address
> +      Memory address (32 bits), at 0x2800000 size 0x200000 bytes       ok
> +    LargeVendorItem: Display
> +      01 00 80 02 e0 01 80 02 00 00 80 c2 00 00 00 00
> +      00 00 20 00 00 00 00 00 78
> +  PossibleOffset   = 0x00000a58
> +  CompatibleOffset = 0x00000a59
> +
> +*/
> --
> 1.7.5.3
>
>
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-18 20:42                                                     ` Blue Swirl
@ 2011-06-19 10:04                                                       ` Andreas Färber
  2011-06-19 12:10                                                         ` Hervé Poussineau
  2011-06-19 13:27                                                         ` Blue Swirl
  0 siblings, 2 replies; 37+ messages in thread
From: Andreas Färber @ 2011-06-19 10:04 UTC (permalink / raw)
  To: Blue Swirl
  Cc: Juan Quintela, Hervé Poussineau,
	qemu-devel@nongnu.org Developers, Roy Tam

Am 18.06.2011 um 22:42 schrieb Blue Swirl:

> On Thu, Jun 16, 2011 at 3:02 AM, Andreas Färber <andreas.faerber@web.de 
> > wrote:
>> The IBM E15 is equivalent to an S3 Vision864.
>>
>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>> to greyscale colors. This works sufficiently to observe firmware
>> boot progress.
>>
>> Cc: Hervé Poussineau <hpoussin@reactos.org>
>>
>> Fixed off-by-one drawing issue.
>> Replaced hardcoded color for RECT.
>> Separate I/O debug output for readability.
>> Start cleaning up the naming s3 vs. ibm8514.
>> Prepare support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA  
>> regs.
>>
>> Cc: Roy Tam <roytam@gmail.com>
>> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
>> ---
>>  Makefile.objs                   |    1 +
>>  default-configs/ppc-softmmu.mak |    1 +
>>  hw/pci_ids.h                    |    3 +
>>  hw/ppc_prep.c                   |    2 +
>>  hw/vga-ibm8514.c                |  780 ++++++++++++++++++++++++++++ 
>> +++++++++++
>>  5 files changed, 787 insertions(+), 0 deletions(-)
>>  create mode 100644 hw/vga-ibm8514.c

>> diff --git a/hw/vga-ibm8514.c b/hw/vga-ibm8514.c
>> new file mode 100644
>> index 0000000..a87afe1
>> --- /dev/null
>> +++ b/hw/vga-ibm8514.c

>> +// 40f3 = CMD_CMD_RECT | CMD_INC_Y | CMD_YMAJAXIS | CMD_INC_X |  
>> CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
>> +// 4331 = CMD_CMD_RECT | CMD_16BIT | CMD_PCDATA | CMD_INC_X |  
>> CMD_DRAW | CMD_WRTDATA
>> +// c0b3 = CMD_CMD_BITBLT | CMD_INC_Y | CMD_INC_X | CMD_DRAW |  
>> CMD_PLANAR | CMD_WRTDATA
>
> C89 comments?

Yeah, and it could use an explanation: It's a decode table for debug  
output from the command register.

>> +static VMStateDescription vmstate_ibm8514 = {

Missing .name - crashes in some pstrcpy() without it. Better error  
handling would be nice.

>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField []) {
>> +        VMSTATE_END_OF_LIST()
>> +    },
>> +};

>> +static void my_update_display(void *opaque)
>> +{
>> +    VGACommonState *s = opaque;
>> +    int w;
>> +    uint8_t *vram;
>> +    uint8_t *data_display, *dd;
>> +    int x, y;
>> +    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g,  
>> unsigned int b);
>> +
>> +    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) != 480) {
>> +        qemu_console_resize(s->ds, 640, 480);
>> +    }
>> +
>> +    switch (ds_get_bits_per_pixel(s->ds)) {
>> +        case 8:
>> +            rgb_to_pixel = rgb_to_pixel8;
>> +            w = 1;
>> +            break;
>> +        case 15:
>> +            rgb_to_pixel = rgb_to_pixel15;
>> +            w = 2;
>> +            break;
>> +        case 16:
>> +            rgb_to_pixel = rgb_to_pixel16;
>> +            w = 2;
>> +            break;
>> +        case 32:
>> +            rgb_to_pixel = rgb_to_pixel32;
>> +            w = 4;
>> +            break;
>> +        default:
>> +            BADF("unknown host depth %d\n",  
>> ds_get_bits_per_pixel(s->ds));
>> +            return;
>> +    }
>> +
>> +    vram = s->vram_ptr;
>> +    /* XXX: out of range in vram? */
>> +    data_display = dd = ds_get_data(s->ds);
>> +    for (y = 0; y < 480; y++) {
>> +        for (x = 0; x < 640; x++) {
>> +            unsigned int color;
>> +            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
>> +            memcpy(dd, &color, w);
>
> Please take a look at tcx.c for a 8 bit mode frame buffer with palette
> translation. Also VGA_DIRTY bit handling should be added to this loop
> to speed it up.

Will look into it.

I doubt this is causing the long delays though.
* There's an unhandled write to the PCI card's config address 0x4, for  
which I have no documentation.
* Generally, there are some unhandled writel to 0x680, which look like  
IBM progress codes (but I didn't find a manual to decode them -  
Hervé?), and
* a frequent writeb to 0x690 with value 0x1 or 0x3 (some activity LED  
maybe?).
I thought it might be trying to access the missing NCR 53C810 SCSI but  
saw no indication of that.

Andreas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-19 10:04                                                       ` Andreas Färber
@ 2011-06-19 12:10                                                         ` Hervé Poussineau
  2011-06-19 13:27                                                         ` Blue Swirl
  1 sibling, 0 replies; 37+ messages in thread
From: Hervé Poussineau @ 2011-06-19 12:10 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Blue Swirl, Juan Quintela, Hervé Poussineau,
	qemu-devel@nongnu.org Developers, Roy Tam

Andreas Färber a écrit :
> Am 18.06.2011 um 22:42 schrieb Blue Swirl:
>> Please take a look at tcx.c for a 8 bit mode frame buffer with palette
>> translation. Also VGA_DIRTY bit handling should be added to this loop
>> to speed it up.
>
> Will look into it.
>
> I doubt this is causing the long delays though.
> * There's an unhandled write to the PCI card's config address 0x4, for 
> which I have no documentation.
I don't have any documentation either for this graphic card :(

> * Generally, there are some unhandled writel to 0x680, which look like 
> IBM progress codes (but I didn't find a manual to decode them - 
> Hervé?), and
Port 0x680 is a diagnostic port, related to what appears in the 
"operator display".
32 bit values are written to this port, and first byte meaning can be 
found in this document : http://ps-2.kev009.com:8081/rsinfo/Fcodes.htm
With that, you can see that first long step is 0x09, ie "Copy CRC 
verification code to RAM"

> * a frequent writeb to 0x690 with value 0x1 or 0x3 (some activity LED 
> maybe?).
> I thought it might be trying to access the missing NCR 53C810 SCSI but 
> saw no indication of that.
The operator display/operator panel also contains 2 LEDs: one for Power 
On, and the other one for Disk Drive Activity. You might indeed have 
found the I/O port to control them.

Hervé

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-19 10:04                                                       ` Andreas Färber
  2011-06-19 12:10                                                         ` Hervé Poussineau
@ 2011-06-19 13:27                                                         ` Blue Swirl
  2011-06-19 18:40                                                           ` Andreas Färber
  1 sibling, 1 reply; 37+ messages in thread
From: Blue Swirl @ 2011-06-19 13:27 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Juan Quintela, Hervé Poussineau,
	qemu-devel@nongnu.org Developers, Roy Tam

On Sun, Jun 19, 2011 at 1:04 PM, Andreas Färber <andreas.faerber@web.de> wrote:
> Am 18.06.2011 um 22:42 schrieb Blue Swirl:
>
>> On Thu, Jun 16, 2011 at 3:02 AM, Andreas Färber <andreas.faerber@web.de>
>> wrote:
>>>
>>> The IBM E15 is equivalent to an S3 Vision864.
>>>
>>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>>> to greyscale colors. This works sufficiently to observe firmware
>>> boot progress.
>>>
>>> Cc: Hervé Poussineau <hpoussin@reactos.org>
>>>
>>> Fixed off-by-one drawing issue.
>>> Replaced hardcoded color for RECT.
>>> Separate I/O debug output for readability.
>>> Start cleaning up the naming s3 vs. ibm8514.
>>> Prepare support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA regs.
>>>
>>> Cc: Roy Tam <roytam@gmail.com>
>>> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
>>> ---
>>>  Makefile.objs                   |    1 +
>>>  default-configs/ppc-softmmu.mak |    1 +
>>>  hw/pci_ids.h                    |    3 +
>>>  hw/ppc_prep.c                   |    2 +
>>>  hw/vga-ibm8514.c                |  780
>>> +++++++++++++++++++++++++++++++++++++++
>>>  5 files changed, 787 insertions(+), 0 deletions(-)
>>>  create mode 100644 hw/vga-ibm8514.c
>
>>> diff --git a/hw/vga-ibm8514.c b/hw/vga-ibm8514.c
>>> new file mode 100644
>>> index 0000000..a87afe1
>>> --- /dev/null
>>> +++ b/hw/vga-ibm8514.c
>
>>> +// 40f3 = CMD_CMD_RECT | CMD_INC_Y | CMD_YMAJAXIS | CMD_INC_X | CMD_DRAW
>>> | CMD_PLANAR | CMD_WRTDATA
>>> +// 4331 = CMD_CMD_RECT | CMD_16BIT | CMD_PCDATA | CMD_INC_X | CMD_DRAW |
>>> CMD_WRTDATA
>>> +// c0b3 = CMD_CMD_BITBLT | CMD_INC_Y | CMD_INC_X | CMD_DRAW | CMD_PLANAR
>>> | CMD_WRTDATA
>>
>> C89 comments?
>
> Yeah, and it could use an explanation: It's a decode table for debug output
> from the command register.
>
>>> +static VMStateDescription vmstate_ibm8514 = {
>
> Missing .name - crashes in some pstrcpy() without it. Better error handling
> would be nice.
>
>>> +    .version_id = 1,
>>> +    .minimum_version_id = 1,
>>> +    .fields = (VMStateField []) {
>>> +        VMSTATE_END_OF_LIST()
>>> +    },
>>> +};
>
>>> +static void my_update_display(void *opaque)
>>> +{
>>> +    VGACommonState *s = opaque;
>>> +    int w;
>>> +    uint8_t *vram;
>>> +    uint8_t *data_display, *dd;
>>> +    int x, y;
>>> +    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g,
>>> unsigned int b);
>>> +
>>> +    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) != 480) {
>>> +        qemu_console_resize(s->ds, 640, 480);
>>> +    }
>>> +
>>> +    switch (ds_get_bits_per_pixel(s->ds)) {
>>> +        case 8:
>>> +            rgb_to_pixel = rgb_to_pixel8;
>>> +            w = 1;
>>> +            break;
>>> +        case 15:
>>> +            rgb_to_pixel = rgb_to_pixel15;
>>> +            w = 2;
>>> +            break;
>>> +        case 16:
>>> +            rgb_to_pixel = rgb_to_pixel16;
>>> +            w = 2;
>>> +            break;
>>> +        case 32:
>>> +            rgb_to_pixel = rgb_to_pixel32;
>>> +            w = 4;
>>> +            break;
>>> +        default:
>>> +            BADF("unknown host depth %d\n",
>>> ds_get_bits_per_pixel(s->ds));
>>> +            return;
>>> +    }
>>> +
>>> +    vram = s->vram_ptr;
>>> +    /* XXX: out of range in vram? */
>>> +    data_display = dd = ds_get_data(s->ds);
>>> +    for (y = 0; y < 480; y++) {
>>> +        for (x = 0; x < 640; x++) {
>>> +            unsigned int color;
>>> +            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
>>> +            memcpy(dd, &color, w);
>>
>> Please take a look at tcx.c for a 8 bit mode frame buffer with palette
>> translation. Also VGA_DIRTY bit handling should be added to this loop
>> to speed it up.
>
> Will look into it.
>
> I doubt this is causing the long delays though.

The difference is that only areas which have been written after last
update are copied to display instead of updating the whole screen
every time. IIRC for TCX it was a major speedup.

> * There's an unhandled write to the PCI card's config address 0x4, for which
> I have no documentation.
> * Generally, there are some unhandled writel to 0x680, which look like IBM
> progress codes (but I didn't find a manual to decode them - Hervé?), and
> * a frequent writeb to 0x690 with value 0x1 or 0x3 (some activity LED
> maybe?).
> I thought it might be trying to access the missing NCR 53C810 SCSI but saw
> no indication of that.
>
> Andreas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-19 13:27                                                         ` Blue Swirl
@ 2011-06-19 18:40                                                           ` Andreas Färber
  2011-06-19 19:03                                                             ` Blue Swirl
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-19 18:40 UTC (permalink / raw)
  To: Blue Swirl
  Cc: Hervé Poussineau, qemu-devel@nongnu.org Developers, Roy Tam

Am 19.06.2011 um 15:27 schrieb Blue Swirl:

> On Sun, Jun 19, 2011 at 1:04 PM, Andreas Färber <andreas.faerber@web.de 
> > wrote:
>> Am 18.06.2011 um 22:42 schrieb Blue Swirl:
>>
>>> On Thu, Jun 16, 2011 at 3:02 AM, Andreas Färber <andreas.faerber@web.de 
>>> >
>>> wrote:
>>>>
>>>> The IBM E15 is equivalent to an S3 Vision864.
>>>>
>>>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>>>> to greyscale colors. This works sufficiently to observe firmware
>>>> boot progress.
>>>>
>>>> Cc: Hervé Poussineau <hpoussin@reactos.org>
>>>>
>>>> Fixed off-by-one drawing issue.
>>>> Replaced hardcoded color for RECT.
>>>> Separate I/O debug output for readability.
>>>> Start cleaning up the naming s3 vs. ibm8514.
>>>> Prepare support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA  
>>>> regs.
>>>>
>>>> Cc: Roy Tam <roytam@gmail.com>
>>>> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
>>>> ---
>>>>  Makefile.objs                   |    1 +
>>>>  default-configs/ppc-softmmu.mak |    1 +
>>>>  hw/pci_ids.h                    |    3 +
>>>>  hw/ppc_prep.c                   |    2 +
>>>>  hw/vga-ibm8514.c                |  780
>>>> +++++++++++++++++++++++++++++++++++++++
>>>>  5 files changed, 787 insertions(+), 0 deletions(-)
>>>>  create mode 100644 hw/vga-ibm8514.c
>>
>>>> diff --git a/hw/vga-ibm8514.c b/hw/vga-ibm8514.c
>>>> new file mode 100644
>>>> index 0000000..a87afe1
>>>> --- /dev/null
>>>> +++ b/hw/vga-ibm8514.c

>>>> +static void my_update_display(void *opaque)
>>>> +{
>>>> +    VGACommonState *s = opaque;
>>>> +    int w;
>>>> +    uint8_t *vram;
>>>> +    uint8_t *data_display, *dd;
>>>> +    int x, y;
>>>> +    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g,
>>>> unsigned int b);
>>>> +
>>>> +    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) !=  
>>>> 480) {
>>>> +        qemu_console_resize(s->ds, 640, 480);
>>>> +    }
>>>> +
>>>> +    switch (ds_get_bits_per_pixel(s->ds)) {
>>>> +        case 8:
>>>> +            rgb_to_pixel = rgb_to_pixel8;
>>>> +            w = 1;
>>>> +            break;
>>>> +        case 15:
>>>> +            rgb_to_pixel = rgb_to_pixel15;
>>>> +            w = 2;
>>>> +            break;
>>>> +        case 16:
>>>> +            rgb_to_pixel = rgb_to_pixel16;
>>>> +            w = 2;
>>>> +            break;
>>>> +        case 32:
>>>> +            rgb_to_pixel = rgb_to_pixel32;
>>>> +            w = 4;
>>>> +            break;
>>>> +        default:
>>>> +            BADF("unknown host depth %d\n",
>>>> ds_get_bits_per_pixel(s->ds));
>>>> +            return;
>>>> +    }
>>>> +
>>>> +    vram = s->vram_ptr;
>>>> +    /* XXX: out of range in vram? */
>>>> +    data_display = dd = ds_get_data(s->ds);
>>>> +    for (y = 0; y < 480; y++) {
>>>> +        for (x = 0; x < 640; x++) {
>>>> +            unsigned int color;
>>>> +            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
>>>> +            memcpy(dd, &color, w);
>>>
>>> Please take a look at tcx.c for a 8 bit mode frame buffer with  
>>> palette
>>> translation. Also VGA_DIRTY bit handling should be added to this  
>>> loop
>>> to speed it up.
>>
>> Will look into it.
>>
>> I doubt this is causing the long delays though.
>
> The difference is that only areas which have been written after last
> update are copied to display instead of updating the whole screen
> every time. IIRC for TCX it was a major speedup.

Some remarks:

* TCX seems to assume that TARGET_HOST_PAGE == 4 * 1024 in the  
unrolled loop in tcx_update_display(). You might want to assert that.

* The check page < page_min with page_min == -1 seems unintended in  
tcx_update_display() and would have undesired effects on resetting the  
dirty bit. I used page_min < 0 instead.

* The reset code seems wrong wrt dirty bit: after zero-ing VRAM the  
dirty bit should be set, not reset. Otherwise the screen is not redrawn.

Andreas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-19 18:40                                                           ` Andreas Färber
@ 2011-06-19 19:03                                                             ` Blue Swirl
  2011-06-19 21:38                                                               ` Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Blue Swirl @ 2011-06-19 19:03 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Hervé Poussineau, qemu-devel@nongnu.org Developers, Roy Tam

On Sun, Jun 19, 2011 at 9:40 PM, Andreas Färber <andreas.faerber@web.de> wrote:
> Am 19.06.2011 um 15:27 schrieb Blue Swirl:
>
>> On Sun, Jun 19, 2011 at 1:04 PM, Andreas Färber <andreas.faerber@web.de>
>> wrote:
>>>
>>> Am 18.06.2011 um 22:42 schrieb Blue Swirl:
>>>
>>>> On Thu, Jun 16, 2011 at 3:02 AM, Andreas Färber <andreas.faerber@web.de>
>>>> wrote:
>>>>>
>>>>> The IBM E15 is equivalent to an S3 Vision864.
>>>>>
>>>>> Lacking S3 SDAC (86C716) support, the DAC indizes are translated
>>>>> to greyscale colors. This works sufficiently to observe firmware
>>>>> boot progress.
>>>>>
>>>>> Cc: Hervé Poussineau <hpoussin@reactos.org>
>>>>>
>>>>> Fixed off-by-one drawing issue.
>>>>> Replaced hardcoded color for RECT.
>>>>> Separate I/O debug output for readability.
>>>>> Start cleaning up the naming s3 vs. ibm8514.
>>>>> Prepare support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA regs.
>>>>>
>>>>> Cc: Roy Tam <roytam@gmail.com>
>>>>> Signed-off-by: Andreas Färber <andreas.faerber@web.de>
>>>>> ---
>>>>>  Makefile.objs                   |    1 +
>>>>>  default-configs/ppc-softmmu.mak |    1 +
>>>>>  hw/pci_ids.h                    |    3 +
>>>>>  hw/ppc_prep.c                   |    2 +
>>>>>  hw/vga-ibm8514.c                |  780
>>>>> +++++++++++++++++++++++++++++++++++++++
>>>>>  5 files changed, 787 insertions(+), 0 deletions(-)
>>>>>  create mode 100644 hw/vga-ibm8514.c
>>>
>>>>> diff --git a/hw/vga-ibm8514.c b/hw/vga-ibm8514.c
>>>>> new file mode 100644
>>>>> index 0000000..a87afe1
>>>>> --- /dev/null
>>>>> +++ b/hw/vga-ibm8514.c
>
>>>>> +static void my_update_display(void *opaque)
>>>>> +{
>>>>> +    VGACommonState *s = opaque;
>>>>> +    int w;
>>>>> +    uint8_t *vram;
>>>>> +    uint8_t *data_display, *dd;
>>>>> +    int x, y;
>>>>> +    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g,
>>>>> unsigned int b);
>>>>> +
>>>>> +    if (ds_get_width(s->ds) != 640 || ds_get_height(s->ds) != 480) {
>>>>> +        qemu_console_resize(s->ds, 640, 480);
>>>>> +    }
>>>>> +
>>>>> +    switch (ds_get_bits_per_pixel(s->ds)) {
>>>>> +        case 8:
>>>>> +            rgb_to_pixel = rgb_to_pixel8;
>>>>> +            w = 1;
>>>>> +            break;
>>>>> +        case 15:
>>>>> +            rgb_to_pixel = rgb_to_pixel15;
>>>>> +            w = 2;
>>>>> +            break;
>>>>> +        case 16:
>>>>> +            rgb_to_pixel = rgb_to_pixel16;
>>>>> +            w = 2;
>>>>> +            break;
>>>>> +        case 32:
>>>>> +            rgb_to_pixel = rgb_to_pixel32;
>>>>> +            w = 4;
>>>>> +            break;
>>>>> +        default:
>>>>> +            BADF("unknown host depth %d\n",
>>>>> ds_get_bits_per_pixel(s->ds));
>>>>> +            return;
>>>>> +    }
>>>>> +
>>>>> +    vram = s->vram_ptr;
>>>>> +    /* XXX: out of range in vram? */
>>>>> +    data_display = dd = ds_get_data(s->ds);
>>>>> +    for (y = 0; y < 480; y++) {
>>>>> +        for (x = 0; x < 640; x++) {
>>>>> +            unsigned int color;
>>>>> +            color = (*rgb_to_pixel)(vram[0], vram[1], vram[2]);
>>>>> +            memcpy(dd, &color, w);
>>>>
>>>> Please take a look at tcx.c for a 8 bit mode frame buffer with palette
>>>> translation. Also VGA_DIRTY bit handling should be added to this loop
>>>> to speed it up.
>>>
>>> Will look into it.
>>>
>>> I doubt this is causing the long delays though.
>>
>> The difference is that only areas which have been written after last
>> update are copied to display instead of updating the whole screen
>> every time. IIRC for TCX it was a major speedup.
>
> Some remarks:
>
> * TCX seems to assume that TARGET_HOST_PAGE == 4 * 1024 in the unrolled loop
> in tcx_update_display(). You might want to assert that.

TCX was only used on Sparc32. Though some Ultra machines had SBus,
there the page size would be 8k (also bigger pages, but that is what
QEMU uses for TARGET_PAGE_SIZE).

> * The check page < page_min with page_min == -1 seems unintended in
> tcx_update_display() and would have undesired effects on resetting the dirty
> bit. I used page_min < 0 instead.

No, the check is correct since the type of page_min is ram_addr_t
(unsigned long).

> * The reset code seems wrong wrt dirty bit: after zero-ing VRAM the dirty
> bit should be set, not reset. Otherwise the screen is not redrawn.

Actually reset should not touch VRAM, the screen is cleared by OpenBIOS.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-19 19:03                                                             ` Blue Swirl
@ 2011-06-19 21:38                                                               ` Andreas Färber
  2011-06-19 21:43                                                                 ` [Qemu-devel] [RFC v3 " Andreas Färber
  0 siblings, 1 reply; 37+ messages in thread
From: Andreas Färber @ 2011-06-19 21:38 UTC (permalink / raw)
  To: Blue Swirl
  Cc: Hervé Poussineau, qemu-devel@nongnu.org Developers, Roy Tam

Am 19.06.2011 um 21:03 schrieb Blue Swirl:

> On Sun, Jun 19, 2011 at 9:40 PM, Andreas Färber <andreas.faerber@web.de 
> > wrote:
>> Some remarks:
>>
>> * TCX seems to assume that TARGET_HOST_PAGE == 4 * 1024 in the  
>> unrolled loop
>> in tcx_update_display(). You might want to assert that.
>
> TCX was only used on Sparc32. Though some Ultra machines had SBus,
> there the page size would be 8k (also bigger pages, but that is what
> QEMU uses for TARGET_PAGE_SIZE).

Well, I wasn't saying it doesn't work presently, just pointing out  
that a qdev device might be instantiated by someone under  
circumstances not envisioned.

>> * The check page < page_min with page_min == -1 seems unintended in
>> tcx_update_display() and would have undesired effects on resetting  
>> the dirty
>> bit. I used page_min < 0 instead.
>
> No, the check is correct since the type of page_min is ram_addr_t
> (unsigned long).

OK

>> * The reset code seems wrong wrt dirty bit: after zero-ing VRAM the  
>> dirty
>> bit should be set, not reset. Otherwise the screen is not redrawn.
>
> Actually reset should not touch VRAM, the screen is cleared by  
> OpenBIOS.

tcx_reset() does do a memset on the VRAM.

In my case, I like sharing code, so I'm calling ibm8514_reset() on  
init to initialize registers and palette - I personally prefer a black  
screen during the one and a half minutes before the screen gets  
updated the first time.

Andreas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC v3 23/23] 40p: Add an IBM 8514/A graphics card
  2011-06-19 21:38                                                               ` Andreas Färber
@ 2011-06-19 21:43                                                                 ` Andreas Färber
  0 siblings, 0 replies; 37+ messages in thread
From: Andreas Färber @ 2011-06-19 21:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Blue Swirl, Andreas Färber, Hervé Poussineau, Roy Tam

The IBM E15 is equivalent to an S3 Vision864.

Lacking S3 SDAC (86C716) support, the DAC indizes are translated
to greyscale colors. This works sufficiently to observe firmware
boot progress.

Cc: Hervé Poussineau <hpoussin@reactos.org>

Fixed off-by-one drawing issue.
Replaced hardcoded color for RECT.
Separate I/O debug output for readability.
Start cleaning up the naming s3 vs. ibm8514.
Add support for DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA regs.
Decouple from VGA. Implement dirty bit handling inspired by TCX.

Cc: Roy Tam <roytam@gmail.com>
Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
---
 Makefile.target |    1 +
 hw/ibm8514.c    |  961 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pci_ids.h    |    3 +
 hw/ppc_prep.c   |    2 +
 4 files changed, 967 insertions(+), 0 deletions(-)
 create mode 100644 hw/ibm8514.c

diff --git a/Makefile.target b/Makefile.target
index b67b1f7..629ca35 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -244,6 +244,7 @@ obj-ppc-y += vga.o
 obj-ppc-y += i8259.o mc146818rtc.o
 obj-ppc-y += prep_systemio.o
 obj-ppc-y += ppc_prep.o
+obj-ppc-y += ibm8514.o
 # OldWorld PowerMac
 obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
diff --git a/hw/ibm8514.c b/hw/ibm8514.c
new file mode 100644
index 0000000..05bd07e
--- /dev/null
+++ b/hw/ibm8514.c
@@ -0,0 +1,961 @@
+/*
+ * QEMU PCI IBM 8514/A Emulator.
+ *
+ * Copyright (c) 2010 Hervé Poussineau
+ * Copyright (c) 2010-2011 Andreas Färber
+ *
+ * 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.
+ */
+
+/* Documentation available at
+ * http://www.datasheetarchive.com/Indexer/Datasheet-06/DSA0091551.html
+ */
+
+#include "console.h"
+#include "pci.h"
+#include "pixel_ops.h"
+
+//#define DEBUG_8514
+//#define DEBUG_8514_IO
+
+#ifdef DEBUG_8514
+#define DPRINTF(fmt, ...) \
+do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#ifdef DEBUG_8514_IO
+#define DPRINTF_IO(fmt, ...) \
+do { printf("8514: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_IO(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "8514 ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
+enum {
+    REG_CMD       = 0x9AE8,
+    REG_PIX_TRANS = 0xE2E8,
+};
+
+enum {
+    GP_STAT_BUSY = 0x0200,
+};
+
+enum {
+    CMD_WRTDATA  = 0x0001,
+    CMD_PLANAR   = 0x0002,
+    CMD_LASTPIX  = 0x0004,
+    CMD_LINETYPE = 0x0008,
+    CMD_DRAW     = 0x0010,
+    CMD_INC_X    = 0x0020,
+    CMD_YMAJAXIS = 0x0040,
+    CMD_INC_Y    = 0x0080,
+    CMD_PCDATA   = 0x0100,
+    CMD_16BIT    = 0x0200,
+    CMD_BYTSEQ   = 0x1000,
+};
+
+#define CMD_CMD_MASK 0xE000
+enum {
+    CMD_CMD_NOP    = 0x0000,
+    CMD_CMD_LINE   = 0x2000,
+    CMD_CMD_RECT   = 0x4000,
+    CMD_CMD_RECTV1 = 0x6000,
+    CMD_CMD_RECTV2 = 0x8000,
+    CMD_CMD_LINEAF = 0xA000,
+    CMD_CMD_BITBLT = 0xC000,
+};
+
+#define BKGD_MIX_BSS_MASK 0x0060
+enum {
+    BKGD_MIX_BSS_BKGD = 0x0000,
+    BKGD_MIX_BSS_FRGD = 0x0020,
+    BKGD_MIX_BSS_PIX  = 0x0040,
+    BKGD_MIX_BSS_BMP  = 0x0060,
+};
+
+#define FRGD_MIX_FSS_MASK 0x0060
+enum {
+    FRGD_MIX_FSS_BKGD = 0x0000,
+    FRGD_MIX_FSS_FRGD = 0x0020,
+    FRGD_MIX_FSS_PIX  = 0x0040,
+    FRGD_MIX_FSS_BMP  = 0x0060,
+};
+
+#define PIX_CNTL_MIXSEL_MASK 0x00C0
+enum {
+    PIX_CNTL_MIXSEL_FOREMIX = 0x0000,
+    PIX_CNTL_MIXSEL_PATTERN = 0x0040,
+    PIX_CNTL_MIXSEL_VAR     = 0x0080,
+    PIX_CNTL_MIXSEL_TRANS   = 0x00C0,
+};
+
+/*
+ * CMD values used by IBM firmware:
+ * 40f3 = CMD_CMD_RECT | CMD_INC_Y | CMD_YMAJAXIS | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
+ * 4331 = CMD_CMD_RECT | CMD_16BIT | CMD_PCDATA | CMD_INC_X | CMD_DRAW | CMD_WRTDATA
+ * c0b3 = CMD_CMD_BITBLT | CMD_INC_Y | CMD_INC_X | CMD_DRAW | CMD_PLANAR | CMD_WRTDATA
+ */
+
+typedef struct IBM8514State {
+    DisplayState *ds;
+    uint8_t *vram_ptr;
+    ram_addr_t vram_offset;
+    uint32_t vram_size;
+    uint8_t r[256], g[256], b[256];
+    uint32_t palette[256];
+    uint16_t maj_axis, min_axis;
+
+    uint8_t dac_mask; /* 02ea */
+    uint8_t dac_r_index; /* 02eb */
+    uint8_t dac_w_index; /* 02ec */
+    uint8_t dac_r_temp[3];
+    uint8_t dac_r_state;
+    uint8_t dac_w_temp[3];
+    uint8_t dac_w_state;
+
+    uint16_t disp_stat; /* 02e8 */
+    uint16_t h_disp; /* 06e8 */
+    uint16_t h_sync_strt; /* 0ae8 */
+    uint16_t h_sync_wid; /* 0ee8 */
+    uint16_t v_total; /* 12e8 */
+    uint16_t v_disp; /* 16e8 */
+    uint16_t v_sync_strt; /* 1ae8 */
+    uint16_t v_sync_wid; /* 1ee8 */
+    uint16_t disp_cntl; /* 22e8 */
+    uint16_t h_total; /* 26e8 */
+    uint16_t subsys_cntl; /* 42e8 (W) */
+    uint16_t subsys_stat; /* 42e8 (R) */
+    uint16_t rom_page_sel; /* 46e8 */
+    uint16_t advfunc_cntl; /* 4ae8 */
+    uint16_t cur_y; /* 82e8 */
+    uint16_t cur_x; /* 86e8 */
+    uint16_t desty_axstep; /* 8ae8 */
+    uint16_t destx_diastp; /* 8ee8 */
+    uint16_t err_term; /* 92e8 */
+    uint16_t maj_axis_pcnt; /* 96e8 */
+    uint16_t gp_stat; /* 9ae8 (R) */
+    uint16_t cmd; /* 9ae8 (W) */
+    uint16_t short_stroke; /* 9ee8 */
+    uint16_t bkgd_color; /* a2e8 */
+    uint16_t frgd_color; /* a6e8 */
+    uint16_t wrt_mask; /* aae8 */
+    uint16_t rd_mask; /* aee8 */
+    uint16_t color_cmp; /* b2e8 */
+    uint16_t bkgd_mix; /* b6e8 */
+    uint16_t frgd_mix; /* bae8 */
+    uint16_t mfc[16]; /* bee8 */
+    uint16_t pix_trans; /* e2e8 */
+} IBM8514State;
+
+#define min_axis_pcnt mfc[0]
+#define scissors_t    mfc[1]
+#define scissors_l    mfc[2]
+#define scissors_b    mfc[3]
+#define scissors_r    mfc[4]
+#define mem_cntl      mfc[5]
+#define pattern_l     mfc[8]
+#define pattern_h     mfc[9]
+#define pix_cntl      mfc[10]
+
+static inline void do_cmd_done(IBM8514State *s)
+{
+    s->gp_stat &= ~GP_STAT_BUSY;
+}
+
+static void do_cmd_write_pixel(IBM8514State *s, uint16_t value)
+{
+    uint16_t maj_axis_pcnt;
+    uint32_t offset;
+    uint8_t* p8;
+    int dx;
+    int dy;
+
+    if (!(s->gp_stat & GP_STAT_BUSY)) {
+        return;
+    }
+
+    maj_axis_pcnt = s->maj_axis_pcnt + 1;
+    offset = s->cur_y * 640 + s->cur_x;
+    p8 = s->vram_ptr + offset;
+    dx = s->cmd & CMD_INC_X ? 1 : -1;
+    dy = s->cmd & CMD_INC_Y ? 1 : -1;
+    ++s->maj_axis;
+    if ((s->maj_axis < maj_axis_pcnt) ||
+        (s->maj_axis == maj_axis_pcnt && !(s->cmd & CMD_LASTPIX))) {
+        p8[0] = value;
+        cpu_physical_memory_set_dirty_flags((s->vram_offset + offset) &
+            TARGET_PAGE_MASK, VGA_DIRTY_FLAG);
+    }
+    if (s->maj_axis < maj_axis_pcnt) {
+        s->cur_x += dx;
+    } else if (s->maj_axis == maj_axis_pcnt) {
+        if ((maj_axis_pcnt % 2 == 0) || !(s->cmd & CMD_16BIT)) {
+            s->maj_axis = 0;
+        }
+        s->cur_x -= (s->maj_axis_pcnt) * dx;
+        s->cur_y += dy;
+        s->min_axis++;
+        if (s->min_axis == s->min_axis_pcnt + 1) {
+            do_cmd_done(s);
+        }
+    } else {
+        s->maj_axis = 0;
+    }
+}
+
+static uint16_t get_source_operand(IBM8514State *s)
+{
+    switch (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) {
+        case PIX_CNTL_MIXSEL_FOREMIX:
+            switch (s->frgd_mix & FRGD_MIX_FSS_MASK) {
+                case FRGD_MIX_FSS_BKGD:
+                    return s->bkgd_color & 0xff;
+                case FRGD_MIX_FSS_FRGD:
+                    return s->frgd_color & 0xff;
+                default:
+                    BADF("%s: Unimplemented FSS %x\n",
+                         __func__, (s->frgd_mix & FRGD_MIX_FSS_MASK) >> 5);
+                    return 0;
+            }
+        default:
+            BADF("%s: Unimplemented MIXSEL %x\n",
+                 __func__, (s->pix_cntl & PIX_CNTL_MIXSEL_MASK) >> 6);
+            return 0;
+    }
+}
+
+static inline void do_cmd_init(IBM8514State *s)
+{
+    s->gp_stat |= GP_STAT_BUSY;
+    s->maj_axis = 0;
+    s->min_axis = 0;
+}
+
+static void do_cmd(IBM8514State *s)
+{
+    DPRINTF("%s: execute cmd %04x\n", __func__, s->cmd);
+
+    do_cmd_init(s);
+
+    if ((s->cmd & CMD_CMD_MASK) == CMD_CMD_RECT) {
+        DPRINTF("cmd RECT: cur_x=%d cur_y=%d inc_x=%d inc_y=%d width=%d height=%d\n",
+            s->cur_x, s->cur_y,
+            s->cmd & CMD_INC_X ? 1 : -1, s->cmd & CMD_INC_Y ? 1 : -1,
+            s->maj_axis_pcnt, s->min_axis_pcnt);
+
+        if (!(s->cmd & CMD_PCDATA)) {
+            while (s->gp_stat & GP_STAT_BUSY) {
+                do_cmd_write_pixel(s, get_source_operand(s));
+            }
+        }
+    }
+}
+
+static void ibm8514_set_dirty(IBM8514State *s)
+{
+    unsigned int i;
+
+    for (i = 0; i < 640 * 480; i += TARGET_PAGE_SIZE) {
+        cpu_physical_memory_set_dirty(s->vram_offset + i);
+    }
+}
+
+static void update_palette_entries(IBM8514State *s, int start, int end)
+{
+    int i;
+
+    for (i = start; i < end; i++) {
+        switch (ds_get_bits_per_pixel(s->ds)) {
+            default:
+            case 8:
+                s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
+                break;
+            case 15:
+                s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
+                break;
+            case 16:
+                s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
+                break;
+            case 32:
+                if (is_surface_bgr(s->ds->surface)) {
+                    s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
+                } else {
+                    s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
+                }
+                break;
+        }
+    }
+    ibm8514_set_dirty(s);
+}
+
+static uint32_t ibm8514_dac_ioport_readb(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+
+    switch (addr) {
+        case 0x02ea:
+            val = s->dac_mask;
+            break;
+        case 0x02eb:
+            val = s->dac_r_index;
+            break;
+        case 0x02ec:
+            val = s->dac_w_index;
+            break;
+        case 0x02ed:
+            if (s->dac_r_state == 0) {
+                s->dac_r_temp[0] = s->r[s->dac_r_index];
+                s->dac_r_temp[1] = s->g[s->dac_r_index];
+                s->dac_r_temp[2] = s->b[s->dac_r_index];
+            }
+            val = s->dac_r_temp[s->dac_r_state] & s->dac_mask;
+            s->dac_r_state = (s->dac_r_state + 1) % 3;
+            if (s->dac_r_state == 0) {
+                s->dac_r_index++;
+            }
+            break;
+        default:
+            BADF("%s: invalid register at 0x%04x\n", __func__, addr);
+            val = 0;
+            break;
+    }
+    DPRINTF_IO("%s: read %02x at %04x\n", __func__, val, addr);
+    return val;
+}
+
+static void ibm8514_dac_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+
+    DPRINTF_IO("%s: write %02x at %04x\n", __func__, val, addr);
+    switch (addr) {
+        case 0x02ea:
+            s->dac_mask = val & 0xff;
+            break;
+        case 0x02eb:
+            s->dac_r_index = val & 0xff;
+            s->dac_r_state = 0;
+            break;
+        case 0x02ec:
+            s->dac_w_index = val & 0xff;
+            s->dac_w_state = 0;
+            break;
+        case 0x02ed:
+            s->dac_w_temp[s->dac_w_state] = (val & 0xff) & s->dac_mask;
+            s->dac_w_state = (s->dac_w_state + 1) % 3;
+            if (s->dac_w_state == 0) {
+                s->r[s->dac_w_index] = s->dac_w_temp[0];
+                s->g[s->dac_w_index] = s->dac_w_temp[1];
+                s->b[s->dac_w_index] = s->dac_w_temp[2];
+                update_palette_entries(s, s->dac_w_index, s->dac_w_index + 1);
+                s->dac_w_index++;
+            }
+            break;
+        default:
+            BADF("%s: invalid register at 0x%04x\n", __func__, addr);
+            break;
+    }
+}
+
+static uint16_t* ibm8514_get_register(IBM8514State *s, uint32_t addr, int is_write, uint32_t* val_if_write)
+{
+    uint16_t *p;
+
+    switch (addr) {
+        case 0x02e8:
+            p = is_write ? &s->h_total : &s->disp_stat;
+            break;
+        case 0x06e8:
+            p = is_write ? &s->h_disp : NULL;
+            break;
+        case 0x0ae8:
+            p = is_write ? &s->h_sync_strt : NULL;
+            break;
+        case 0x0ee8:
+            p = is_write ? &s->h_sync_wid : NULL;
+            break;
+        case 0x12e8:
+            p = is_write ? &s->v_total : NULL;
+            break;
+        case 0x16e8:
+            p = is_write ? &s->v_disp : NULL;
+            break;
+        case 0x1ae8:
+            p = is_write ? &s->v_sync_strt : NULL;
+            break;
+        case 0x1ee8:
+            p = is_write ? &s->v_sync_wid : NULL;
+            break;
+        case 0x22e8:
+            p = is_write ? &s->disp_cntl : NULL;
+            break;
+        case 0x26e8:
+            p = is_write ? NULL: &s->h_total;
+            break;
+        case 0x42e8:
+            p = is_write ? &s->subsys_cntl : &s->subsys_stat;
+            break;
+        case 0x46e8:
+            p = is_write ? &s->rom_page_sel : NULL;
+            break;
+        case 0x4ae8:
+            p = is_write ? &s->advfunc_cntl : NULL;
+            break;
+        case 0x82e8:
+            p = &s->cur_y;
+            break;
+        case 0x86e8:
+            p = &s->cur_x;
+            break;
+        case 0x8ae8:
+            p = is_write ? &s->desty_axstep : NULL;
+            break;
+        case 0x8ee8:
+            p = is_write ? &s->destx_diastp : NULL;
+            break;
+        case 0x92e8:
+            p = &s->err_term;
+            break;
+        case 0x96e8:
+            p = is_write ? &s->maj_axis_pcnt : NULL;
+            break;
+        case 0x9ae8:
+            p = is_write ? &s->cmd : &s->gp_stat;
+            break;
+        case 0x9ee8:
+            p = is_write ? &s->short_stroke : NULL;
+            break;
+        case 0xa2e8:
+            p = is_write ? &s->bkgd_color : NULL;
+            break;
+        case 0xa6e8:
+            p = is_write ? &s->frgd_color : NULL;
+            break;
+        case 0xaae8:
+            p = is_write ? &s->wrt_mask : NULL;
+            break;
+        case 0xaee8:
+            p = is_write ? &s->rd_mask : NULL;
+            break;
+        case 0xb2e8:
+            p = is_write ? &s->color_cmp : NULL;
+            break;
+        case 0xb6e8:
+            p = is_write ? &s->bkgd_mix : NULL;
+            break;
+        case 0xbae8:
+            p = is_write ? &s->frgd_mix : NULL;
+            break;
+        case 0xbee8:
+            if (is_write) {
+                p = &s->mfc[(*val_if_write >> 12) & 0xf];
+                *val_if_write &= 0x0fff;
+            } else {
+                p = NULL;
+            }
+            break;
+        case 0xe2e8:
+            p = &s->pix_trans;
+            break;
+        default:
+            BADF("%s: invalid register at 0x%x\n", __func__, addr);
+            p = NULL;
+            break;
+    }
+
+    return p;
+}
+
+static uint32_t ibm8514_ioport_readb(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+    uint16_t *p;
+
+    p = ibm8514_get_register(s, addr & ~0x1, 0, NULL);
+
+    if (p) {
+        val = (be16_to_cpu(*p) >> ((~addr & 1) * 8)) & 0xff;
+    } else {
+        val = 0;
+    }
+
+    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static uint32_t ibm8514_ioport_readw(void *opaque, uint32_t addr)
+{
+    IBM8514State *s = opaque;
+    uint32_t val;
+    uint16_t *p;
+
+    p = ibm8514_get_register(s, addr, 0, NULL);
+
+    if (p) {
+        val = be16_to_cpu(*p);
+    } else {
+        val = 0;
+    }
+
+    DPRINTF_IO("%s: read %x at %x\n", __func__, val, addr);
+    return val;
+}
+
+static void ibm8514_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+    uint16_t *p;
+    uint8_t *c;
+
+    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
+    p = ibm8514_get_register(s, addr & ~0x1, 1, &val);
+
+    if (p) {
+        c = (uint8_t*)p;
+        c[~addr & 1] = val;
+    }
+    if ((addr & ~0x1) == REG_CMD) {
+        do_cmd(s);
+    } else if ((addr & ~0x1) == REG_PIX_TRANS) {
+        BADF("%s: ibm8514: 8-byte PIX_TRANS access (0x%08" PRIx32 ")\n",
+            __func__, addr);
+    }
+}
+
+static void ibm8514_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    IBM8514State *s = opaque;
+    uint16_t *p;
+
+    val = cpu_to_be16(val);
+    DPRINTF_IO("%s: write %x at %x\n", __func__, val, addr);
+    p = ibm8514_get_register(s, addr, 1, &val);
+
+    if (p) {
+        *p = val & 0xffff;
+    }
+    if (addr == REG_CMD) {
+        do_cmd(s);
+    } else if (addr == REG_PIX_TRANS) {
+        if (!(s->cmd & CMD_16BIT)) {
+            do_cmd_write_pixel(s, val & 0xff);
+        } else if (s->cmd & CMD_BYTSEQ) {
+            do_cmd_write_pixel(s, val & 0xff);
+            do_cmd_write_pixel(s, val >> 8);
+        } else {
+            do_cmd_write_pixel(s, val >> 8);
+            do_cmd_write_pixel(s, val & 0xff);
+        }
+    }
+}
+
+static void ibm8514_register_dac_port(IBM8514State *s, uint32_t addr)
+{
+    register_ioport_read(addr, 1, 1, ibm8514_dac_ioport_readb, s);
+    register_ioport_write(addr, 1, 1, ibm8514_dac_ioport_writeb, s);
+}
+
+static void ibm8514_register_port(IBM8514State *s, uint32_t addr)
+{
+    register_ioport_read(addr, 2, 1, ibm8514_ioport_readb, s);
+    register_ioport_read(addr, 1, 2, ibm8514_ioport_readw, s);
+    register_ioport_write(addr, 2, 1, ibm8514_ioport_writeb, s);
+    register_ioport_write(addr, 1, 2, ibm8514_ioport_writew, s);
+}
+
+static void ibm8514_draw_line8(IBM8514State *s, uint8_t *dst,
+                               const uint8_t *src, int width)
+{
+    int x;
+    uint8_t val;
+
+    for (x = 0; x < width; x++) {
+        val = *src++;
+        *dst++ = s->palette[val];
+    }
+}
+
+static void ibm8514_draw_line16(IBM8514State *s, uint8_t *dst,
+                                const uint8_t *src, int width)
+{
+    int x;
+    uint8_t val;
+    uint16_t *p = (uint16_t *)dst;
+
+    for (x = 0; x < width; x++) {
+        val = *src++;
+        *p++ = s->palette[val];
+    }
+}
+
+static void ibm8514_draw_line32(IBM8514State *s, uint8_t *dst,
+                                const uint8_t *src, int width)
+{
+    int x;
+    uint8_t val;
+    uint32_t *p = (uint32_t *)dst;
+
+    for (x = 0; x < width; x++) {
+        val = *src++;
+        *p++ = s->palette[val];
+    }
+}
+
+static void ibm8514_update_display(void *opaque)
+{
+    IBM8514State *s = opaque;
+    ram_addr_t vram_offset, page0, page1, page_min = -1, page_max = 0;
+    uint8_t *vram;
+    uint8_t *data;
+    int y, y_start = -1;
+    void (*draw_line)(IBM8514State *s, uint8_t *dst, const uint8_t *src, int width);
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+        case 32:
+            draw_line = ibm8514_draw_line32;
+            break;
+        case 15:
+        case 16:
+            draw_line = ibm8514_draw_line16;
+            break;
+        case 8:
+            draw_line = ibm8514_draw_line8;
+            break;
+        default:
+            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
+            return;
+    }
+
+    vram = s->vram_ptr;
+    vram_offset = s->vram_offset;
+    data = ds_get_data(s->ds);
+    for (y = 0; y < 480; y++) {
+        page0 = vram_offset & TARGET_PAGE_MASK;
+        page1 = (vram_offset + 640 - 1) & TARGET_PAGE_MASK;
+        if (cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) ||
+            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG)) {
+            if (y_start < 0) {
+                y_start = y;
+            }
+            if (page0 < page_min) {
+                page_min = page0;
+            }
+            if (page_max < page1) {
+                page_max = page1;
+            }
+            draw_line(s, data, vram, 640);
+        } else if (y_start >= 0) {
+            /* flush to display */
+            dpy_update(s->ds, 0, y_start,
+                       640, y - y_start);
+            y_start = -1;
+        }
+        data += ds_get_linesize(s->ds);
+        vram += 640;
+        vram_offset += 640;
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_update(s->ds, 0, y_start,
+                   640, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        cpu_physical_memory_reset_dirty(page_min,
+                                        page_max + TARGET_PAGE_SIZE,
+                                        VGA_DIRTY_FLAG);
+    }
+}
+
+static void ibm8514_screen_dump(void *opaque, const char *filename)
+{
+    IBM8514State *s = opaque;
+    FILE *f;
+    uint8_t *vram;
+    uint8_t color;
+    int x, y;
+
+    f = fopen(filename, "wb");
+    if (f == NULL) {
+        return;
+    }
+    fprintf(f, "P6\n%d %d\n%d\n", 640, 480, 255);
+    vram = s->vram_ptr;
+    for (y = 0; y < 640; y++) {
+        for (x = 0; x < 480; x++) {
+            color = *vram;
+            fputc(s->r[color], f);
+            fputc(s->g[color], f);
+            fputc(s->b[color], f);
+            vram++;
+        }
+    }
+    fclose(f);
+}
+
+static void ibm8514_invalidate_display(void *opaque)
+{
+    IBM8514State *s = opaque;
+
+    ibm8514_set_dirty(s);
+    qemu_console_resize(s->ds, 640, 480);
+}
+
+static void ibm8514_reset(IBM8514State *s)
+{
+    int i;
+
+    /* Initialize palette */
+    /* XXX initial setup unknown */
+    for (i = 0; i < 256; i++) {
+        s->r[i] = s->g[i] = s->b[i] = i;
+    }
+    update_palette_entries(s, 0, 256);
+
+    memset(s->vram_ptr, 0, s->vram_size);
+#if 0
+    cpu_physical_memory_reset_dirty(s->vram_offset,
+                                    s->vram_offset + (640 * 480),
+                                    VGA_DIRTY_FLAG);
+#endif
+
+    s->dac_r_index = 0;
+    s->dac_r_state = 0;
+    s->dac_w_index = 0;
+    s->dac_w_state = 0;
+}
+
+static void ibm8514_init(IBM8514State *s)
+{
+    s->vram_size = 0x200000;
+    s->vram_offset = qemu_ram_alloc(NULL, "ibm8514.vram", s->vram_size);
+    s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
+
+    cpu_register_physical_memory(isa_mem_base + 0x02800000, s->vram_size, s->vram_offset);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x02800000, s->vram_size);
+
+    s->ds = graphic_console_init(ibm8514_update_display,
+                                 ibm8514_invalidate_display,
+                                 ibm8514_screen_dump, NULL, s);
+    qemu_console_resize(s->ds, 640, 480);
+
+    ibm8514_register_port(s, 0x02e8);
+    ibm8514_register_dac_port(s, 0x02ea);
+    ibm8514_register_dac_port(s, 0x02eb);
+    ibm8514_register_dac_port(s, 0x02ec);
+    ibm8514_register_dac_port(s, 0x02ed);
+    ibm8514_register_port(s, 0x06e8);
+    ibm8514_register_port(s, 0x0ae8);
+    ibm8514_register_port(s, 0x0ee8);
+    ibm8514_register_port(s, 0x12e8);
+    ibm8514_register_port(s, 0x16e8);
+    ibm8514_register_port(s, 0x1ae8);
+    ibm8514_register_port(s, 0x1ee8);
+    ibm8514_register_port(s, 0x22e8);
+    ibm8514_register_port(s, 0x26e8);
+    ibm8514_register_port(s, 0x42e8);
+    ibm8514_register_port(s, 0x46e8);
+    ibm8514_register_port(s, 0x4ae8);
+    ibm8514_register_port(s, 0x82e8);
+    ibm8514_register_port(s, 0x86e8);
+    ibm8514_register_port(s, 0x8ae8);
+    ibm8514_register_port(s, 0x8ee8);
+    ibm8514_register_port(s, 0x92e8);
+    ibm8514_register_port(s, 0x96e8);
+    ibm8514_register_port(s, 0x9ae8);
+    ibm8514_register_port(s, 0x9ae8);
+    ibm8514_register_port(s, 0x9ee8);
+    ibm8514_register_port(s, 0xa2e8);
+    ibm8514_register_port(s, 0xa6e8);
+    ibm8514_register_port(s, 0xaae8);
+    ibm8514_register_port(s, 0xaee8);
+    ibm8514_register_port(s, 0xb2e8);
+    ibm8514_register_port(s, 0xb6e8);
+    ibm8514_register_port(s, 0xbae8);
+    ibm8514_register_port(s, 0xbee8);
+    ibm8514_register_port(s, 0xe2e8);
+    
+    ibm8514_reset(s);
+}
+
+static int ibm8514_vmstate_post_load(void *opaque, int version_id)
+{
+    IBM8514State *s = opaque;
+
+    update_palette_entries(s, 0, 256);
+    ibm8514_set_dirty(s);
+
+    return 0;
+}
+
+static VMStateDescription vmstate_ibm8514 = {
+    .name = "ibm8514",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = ibm8514_vmstate_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+typedef struct PCIIBM8514State {
+    PCIDevice dev;
+    IBM8514State state;
+} PCIIBM8514State;
+
+static void s3_vision864_write_config(PCIDevice *d,
+                                      uint32_t address, uint32_t val, int len)
+{
+    BADF("%s: 0x%08" PRIx32 "\n", __func__, address);
+}
+
+static int s3_vision864_init(PCIDevice *dev)
+{
+    PCIIBM8514State *pci = DO_UPCAST(PCIIBM8514State, dev, dev);
+    IBM8514State *s = &pci->state;
+    uint8_t *pci_conf = dev->config;
+
+    DPRINTF("%s\n", __func__);
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_S3);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_S3_864);
+    pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
+
+    ibm8514_init(s);
+
+    return 0;
+}
+
+static PCIDeviceInfo s3_vision864_info = {
+    .qdev.name    = "s3-vision864",
+    .qdev.size    = sizeof(PCIIBM8514State),
+    .qdev.vmsd    = &vmstate_ibm8514,
+    // XXX these depend on mst's PCI tree
+#if 0
+    .vendor_id    = PCI_VENDOR_ID_S3,
+    .device_id    = PCI_DEVICE_ID_S3_864,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+#endif
+    .init         = s3_vision864_init,
+    .config_write = s3_vision864_write_config,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void ibm8514_register(void)
+{
+    pci_qdev_register(&s3_vision864_info);
+}
+
+device_init(ibm8514_register)
+
+/*
+21:
+  DEVICE_ID
+    BusId = PCI
+    DevId = 0x41d00909 (PNP0909)
+    SerialNum = 0x00000000
+    Flags = 0x000061c5
+      : Output
+      : ConsoleOut
+      : PowerManaged
+      : Disableable
+      : Configurable
+      : Integrated
+      : Enabled
+    BaseType = DisplayController (3)
+    SubType = SVGAController (1)
+    Interface = GeneralSVGA (0)
+  BUS_ACCESS
+    info0 = 0
+    info1 = 112
+  AllocatedOffset  = 0x00000767
+    IRQ: 15
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x102 size 0x1 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3b4 size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3b8 size 0x4 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3bf size 0xc bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3cc size 0x1 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3ce size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3d4 size 0x2 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x3d8 size 0x5 bytes
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x42e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x46e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x4ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x82e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x86e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x8ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x8ee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x92e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x96e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x9ae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0x9ee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xa2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xa6e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xaae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xaee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xb2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xb6e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xbae8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xbee8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xe2e8 size 0x1 bytes				ok
+    LargeVendorItem: Generic Address
+      I/O address (32 bits), at 0xe2ea size 0x1 bytes
+    LargeVendorItem: Generic Address
+      Memory address (32 bits), at 0x2800000 size 0x200000 bytes	ok
+    LargeVendorItem: Display
+      01 00 80 02 e0 01 80 02 00 00 80 c2 00 00 00 00 
+      00 00 20 00 00 00 00 00 78 
+  PossibleOffset   = 0x00000a58
+  CompatibleOffset = 0x00000a59
+
+*/
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index d3bef0e..821421c 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -97,6 +97,9 @@
 #define PCI_VENDOR_ID_FREESCALE          0x1957
 #define PCI_DEVICE_ID_MPC8533E           0x0030
 
+#define PCI_VENDOR_ID_S3                 0x5333
+#define PCI_DEVICE_ID_S3_864             0x88c0
+
 #define PCI_VENDOR_ID_INTEL              0x8086
 #define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 6ae1635..c215b0f 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -747,6 +747,8 @@ static void ibm_40p_init(ram_addr_t ram_size,
     qdev_prop_set_uint8(&isa->qdev, "board-identification", 0xfc);
     qdev_init_nofail(&isa->qdev);
 
+    pci_create_simple(pci_bus, PCI_DEVFN(2, 0), "s3-vision864");
+
     /* Super I/O (parallel + serial ports) */
     isa = isa_create("isa-pc87312");
     qdev_prop_set_chr(&isa->qdev, "parallel", parallel_hds[0]);
-- 
1.7.5.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2011-06-19 21:43 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-14  2:37 [Qemu-devel] [RFC 00/23] PReP 40P emulation Andreas Färber
2011-06-14  2:37 ` [Qemu-devel] [PATCH RFC 01/23] prep: Refactor CPU initialization Andreas Färber
2011-06-14  2:37   ` [Qemu-devel] [RFC 02/23] prep: qdev'ify PCI Andreas Färber
2011-06-14  2:37     ` [Qemu-devel] [RFC 03/23] prep: Prepare emulation of an IBM RS/6000 6015 / 7020 (40p) Andreas Färber
2011-06-14  2:37       ` [Qemu-devel] [RFC 04/23] 40p: Add PCI host Andreas Färber
2011-06-14  2:37         ` [Qemu-devel] [RFC 05/23] prep: Add i82374 DMA emulation Andreas Färber
2011-06-14  2:37           ` [Qemu-devel] [RFC 06/23] prep: Add i82378 PCI-to-ISA bridge emulation Andreas Färber
2011-06-14  2:37             ` [Qemu-devel] [RFC 07/23] 40p: Add a PCI to ISA bridge (i82378) Andreas Färber
2011-06-14  2:37               ` [Qemu-devel] [PATCH v5 08/23] qdev: Add support for property type bool Andreas Färber
2011-06-14  2:37                 ` [Qemu-devel] [PATCH v5 09/23] qdev: Add helpers for reading properties Andreas Färber
2011-06-14  2:37                   ` [Qemu-devel] [RFC v5 10/23] isa: Provide enable and disable callbacks Andreas Färber
2011-06-14  2:37                     ` [Qemu-devel] [RFC v5 11/23] isa: Allow to un-assign I/O ports Andreas Färber
2011-06-14  2:37                       ` [Qemu-devel] [RFC v5 12/23] isa: Allow to un-associate an IRQ Andreas Färber
2011-06-14  2:37                         ` [Qemu-devel] [RFC v5 13/23] parallel: Implement ISA state callbacks Andreas Färber
2011-06-14  2:37                           ` [Qemu-devel] [RFC v5 14/23] serial: " Andreas Färber
2011-06-14  2:37                             ` [Qemu-devel] [PATCH v5 15/23] fdc: Parametrize ISA base, IRQ and DMA Andreas Färber
2011-06-14  2:37                               ` [Qemu-devel] [RFC v5 16/23] fdc: Implement ISA state callbacks Andreas Färber
2011-06-14  2:37                                 ` [Qemu-devel] [RFC v5 17/23] ide: Allow to discard I/O ports Andreas Färber
2011-06-14  2:37                                   ` [Qemu-devel] [RFC v5 18/23] ide: Implement ISA state callbacks Andreas Färber
2011-06-14  2:37                                     ` [Qemu-devel] [RFC v5 19/23] prep: Add pc87312 Super I/O emulation Andreas Färber
2011-06-14  2:37                                       ` [Qemu-devel] [RFC 20/23] 40p: Add the Super I/O chip (pc87312) Andreas Färber
2011-06-14  2:37                                         ` [Qemu-devel] [RFC 21/23] 40p: Add an audio card and a keyboard Andreas Färber
2011-06-14  2:37                                           ` [Qemu-devel] [RFC 22/23] prep: qdev'ify System I/O (WIP) Andreas Färber
2011-06-14  2:37                                             ` [Qemu-devel] [RFC 23/23] 40p: Add an 8514/A graphics card Andreas Färber
2011-06-15  4:33                                               ` Roy Tam
2011-06-15 18:11                                                 ` Andreas Färber
2011-06-16  0:02                                                   ` [Qemu-devel] [RFC v2 23/23] 40p: Add an IBM " Andreas Färber
2011-06-18 20:42                                                     ` Blue Swirl
2011-06-19 10:04                                                       ` Andreas Färber
2011-06-19 12:10                                                         ` Hervé Poussineau
2011-06-19 13:27                                                         ` Blue Swirl
2011-06-19 18:40                                                           ` Andreas Färber
2011-06-19 19:03                                                             ` Blue Swirl
2011-06-19 21:38                                                               ` Andreas Färber
2011-06-19 21:43                                                                 ` [Qemu-devel] [RFC v3 " Andreas Färber
2011-06-16  0:05                                                   ` [Qemu-devel] [RFC 23/23] 40p: Add an " Andreas Färber
2011-06-16  1:22                                                   ` Roy Tam

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.