Patchwork [24/24] target-alpha: Add SX164 emulation.

login
register
mail settings
Submitter Richard Henderson
Date April 19, 2011, 3:05 p.m.
Message ID <1303225501-12778-25-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/92005/
State New
Headers show

Comments

Richard Henderson - April 19, 2011, 3:05 p.m.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 Makefile.target  |    1 +
 hw/alpha_pci.c   |  327 +++++++++++++++++
 hw/alpha_pyxis.c | 1057 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/alpha_sx164.c |  195 ++++++++++
 hw/alpha_sys.h   |   41 +++
 5 files changed, 1621 insertions(+), 0 deletions(-)
 create mode 100644 hw/alpha_pci.c
 create mode 100644 hw/alpha_pyxis.c
 create mode 100644 hw/alpha_sx164.c
 create mode 100644 hw/alpha_sys.h

Patch

diff --git a/Makefile.target b/Makefile.target
index 443679b..f702780 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -364,6 +364,7 @@  obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 
 obj-alpha-y += i8259.o mc146818rtc.o
 obj-alpha-y += vga.o cirrus_vga.o
+obj-alpha-y += alpha_pci.o alpha_sx164.o alpha_pyxis.o
 
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
new file mode 100644
index 0000000..744b68b
--- /dev/null
+++ b/hw/alpha_pci.c
@@ -0,0 +1,327 @@ 
+/* There's nothing in here that's Alpha specific, really.  */
+
+#include "config.h"
+#include "alpha_sys.h"
+#include "qemu-log.h"
+
+
+/* PCI IO reads, to byte-word addressable memory.  */
+/* ??? Doesn't handle multiple PCI busses.  */
+
+static uint32_t bw_io_readb(void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inb(addr);
+}
+
+static uint32_t bw_io_readw(void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inw(addr);
+}
+
+static uint32_t bw_io_readl(void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inl(addr);
+}
+
+/* PCI IO writes, to byte-word addressable memory.  */
+/* ??? Doesn't handle multiple PCI busses.  */
+
+static void bw_io_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outb(addr, val);
+}
+
+static void bw_io_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outw(addr, val);
+}
+
+static void bw_io_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outl(addr, val);
+}
+
+CPUReadMemoryFunc * const alpha_pci_bw_io_reads[] = {
+    bw_io_readb,
+    bw_io_readw,
+    bw_io_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_bw_io_writes[] = {
+    bw_io_writeb,
+    bw_io_writew,
+    bw_io_writel,
+};
+
+/* PCI config space reads, to byte-word addressable memory.  */
+static uint32_t bw_conf1_readb(void *opaque, target_phys_addr_t addr)
+{
+    PCIHostState *s = opaque;
+    return pci_data_read(s->bus, addr, 1);
+}
+
+static uint32_t bw_conf1_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCIHostState *s = opaque;
+    return pci_data_read(s->bus, addr, 2);
+}
+
+static uint32_t bw_conf1_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIHostState *s = opaque;
+    return pci_data_read(s->bus, addr, 4);
+}
+
+/* PCI config space writes, to byte-word addressable memory.  */
+static void bw_conf1_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCIHostState *s = opaque;
+    pci_data_write(s->bus, addr, val, 1);
+}
+
+static void bw_conf1_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCIHostState *s = opaque;
+    pci_data_write(s->bus, addr, val, 2);
+}
+
+static void bw_conf1_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCIHostState *s = opaque;
+    pci_data_write(s->bus, addr, val, 4);
+}
+
+CPUReadMemoryFunc * const alpha_pci_bw_conf1_reads[] = {
+    bw_conf1_readb,
+    bw_conf1_readw,
+    bw_conf1_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_bw_conf1_writes[] = {
+    bw_conf1_writeb,
+    bw_conf1_writew,
+    bw_conf1_writel,
+};
+
+/* PCI MEM access to dense (but not byte-word addressable) memory.  */
+static uint32_t dense_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIBus *b = opaque;
+    return ldl_phys(pci_to_cpu_addr(b, addr));
+}
+
+static void dense_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t v)
+{
+    PCIBus *b = opaque;
+    stl_phys(pci_to_cpu_addr(b, addr), v);
+}
+
+CPUReadMemoryFunc * const alpha_pci_dense_mem_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    dense_mem_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_dense_mem_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    dense_mem_writel,
+};
+
+/* PCI IO to sparse memory.  These are helper routines, which expect that the
+   relevant HAE has already been prepended to ADDR by the core-specific
+   routine that is actually registered with the memory region.  */
+
+uint32_t alpha_sparse_io_read(target_phys_addr_t addr)
+{
+    int size = (addr >> 3) & 3;
+    uint32_t val;
+
+    addr >>= 5;
+    switch (size) {
+    case 0:
+        /* byte access */
+        val = cpu_inb(addr);
+        break;
+    case 1:
+        /* word access */
+        val = cpu_inw(addr);
+        break;
+    case 2:
+        /* tri-byte access; apparently possible with real pci lines.  */
+        qemu_log("pci: tri-byte io read");
+        return ~0u;
+    default:
+        /* long access */
+        return cpu_inl(addr);
+    }
+
+    val <<= (addr & 3) * 8;
+    return val;
+}
+
+void alpha_sparse_io_write(target_phys_addr_t addr, uint32_t val)
+{
+    int size = (addr >> 3) & 3;
+
+    addr >>= 5;
+    switch (size) {
+    case 0:
+        /* byte access */
+        val >>= (addr & 3) * 8;
+        cpu_outb(addr, val);
+        break;
+    case 1:
+        /* word access */
+        val >>= (addr & 3) * 8;
+        cpu_outw(addr, val);
+        break;
+    case 2:
+        /* tri-byte access; apparently possible with real pci lines.  */
+        qemu_log("pci: tri-byte io write");
+        break;
+    default:
+        /* long access */
+        cpu_outl(addr, val);
+        break;
+    }
+}
+
+uint32_t alpha_sparse_mem_read(PCIBus *b, target_phys_addr_t addr)
+{
+    int size = (addr >> 3) & 3;
+    uint32_t val;
+
+    addr = pci_to_cpu_addr(b, addr >> 5);
+    switch (size) {
+    case 0:
+        /* byte access */
+        val = ldub_phys(addr);
+        break;
+    case 1:
+        /* word access */
+        val = lduw_phys(addr);
+        break;
+    case 2:
+        /* tri-byte access; apparently possible with real pci lines.  */
+        qemu_log("pci: tri-byte mem read");
+        return ~0u;
+    default:
+        /* long access */
+        return ldl_phys(addr);
+    }
+
+    val <<= (addr & 3) * 8;
+    return val;
+}
+
+void alpha_sparse_mem_write(PCIBus *b, target_phys_addr_t addr, uint32_t val)
+{
+    int size = (addr >> 3) & 3;
+
+    addr = pci_to_cpu_addr(b, addr >> 5);
+    switch (size) {
+    case 0:
+        /* byte access */
+        val >>= (addr & 3) * 8;
+        stb_phys(addr, val);
+        break;
+    case 1:
+        /* word access */
+        val >>= (addr & 3) * 8;
+        stw_phys(addr, val);
+        break;
+    case 2:
+        /* tri-byte access; apparently possible with real pci lines.  */
+        qemu_log("pci: tri-byte mem write");
+        break;
+    default:
+        /* long access */
+        stl_phys(addr, val);
+        break;
+    }
+}
+
+uint32_t alpha_sparse_conf1_read(PCIBus *b, target_phys_addr_t addr)
+{
+    int size = ((addr >> 3) & 3) + 1;
+    uint32_t val;
+
+    if (size == 3) {
+        qemu_log("pci: tri-byte configuration read");
+        return ~0u;
+    }
+
+    addr >>= 5;
+    val = pci_data_read(b, addr, size);
+    val <<= (addr & 3) * 8;
+
+    return val;
+}
+
+void alpha_sparse_conf1_write(PCIBus *b, target_phys_addr_t addr, uint32_t val)
+{
+    int size = ((addr >> 3) & 3) + 1;
+
+    if (size == 3) {
+        qemu_log("pci: tri-byte configuration write");
+        return;
+    }
+
+    addr >>= 5;
+    val >>= (addr & 3) * 8;
+    pci_data_write(b, addr, val, size);
+}
+
+/* Configuration space accesses do not normall use an HAE.  */
+static uint32_t sparse_conf1_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIBus *b = opaque;
+    return alpha_sparse_conf1_read(b, addr);
+}
+
+static void sparse_conf1_writel(void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    PCIBus *b = opaque;
+    alpha_sparse_conf1_write(b, addr, val);
+}
+
+CPUReadMemoryFunc * const alpha_pci_sparse_conf1_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    sparse_conf1_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_sparse_conf1_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    sparse_conf1_writel,
+};
+
+/* PCI/EISA Interrupt Acknowledge Cycle.  */
+
+static uint32_t iack_readl(void *opaque, target_phys_addr_t addr)
+{
+    if (addr & 15) {
+        return unassigned_mem_readl(opaque, addr);
+    }
+    return pic_read_irq(isa_pic);
+}
+
+static void special_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    qemu_log("pci: special write cycle %08x", val);
+}
+
+CPUReadMemoryFunc * const alpha_pci_iack_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    iack_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_special_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    special_writel,
+};
diff --git a/hw/alpha_pyxis.c b/hw/alpha_pyxis.c
new file mode 100644
index 0000000..0f4c038
--- /dev/null
+++ b/hw/alpha_pyxis.c
@@ -0,0 +1,1057 @@ 
+/*
+ * Qemu 21174 (PYXIS) chipset emulation.
+ *
+ * Written by Richard Henderson.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "hw.h"
+#include "devices.h"
+#include "sysemu.h"
+#include "alpha_sys.h"
+
+/* TODO:
+   ERR_MASK MEM_NEM controls do_unassigned_access behavior.
+
+   RT_COUNT is a 33Mhz free-running counter.
+   INT_TIME should generate interrupt on RT_COUNT match.
+*/
+
+typedef struct PyxisState {
+    PCIHostState host;
+    /* General registers.  */
+    uint32_t pyxis_rev;
+    uint32_t pci_lat;
+    uint32_t pyxis_ctrl;
+    uint32_t pyxis_ctrl1;
+    uint32_t flash_ctrl;
+    uint32_t hae_mem;
+    uint32_t hae_io;
+    uint32_t cfg;
+    /* Diagnostic registers.  */
+    uint32_t pyxis_diag;
+    uint32_t diag_check;
+    /* Performance monitor registers.  */
+    uint32_t perf_monitor;
+    uint32_t perf_control;
+    /* Error registers.  */
+    uint32_t pyxis_err;
+    uint32_t pyxis_stat;
+    uint32_t err_mask;
+    uint32_t pyxis_syn;
+    uint32_t pyxis_err_data;
+    uint32_t mear;
+    uint32_t mesr;
+    uint32_t pci_err0;
+    uint32_t pci_err1;
+    uint32_t pci_err2;
+    /* Memory controler registers.  */
+    uint32_t mcr;
+    uint32_t mcmr;
+    uint32_t gtr;
+    uint32_t rtr;
+    uint32_t rhpr;
+    uint32_t mdr[2];
+    uint32_t bbar[8];
+    uint32_t bcr[8];
+    uint32_t btr[8];
+    uint32_t cvm;
+    /* PCI window control registers.  */
+    uint32_t tbia;
+    uint32_t wbase[4];
+    uint32_t wmask[4];
+    uint32_t tbase[4];
+    uint32_t w_dac;
+    /* Scatter-gather address translation registers.  */
+    uint32_t tb_tag[8];
+    uint32_t tb_page[8][4];
+    /* Misc registers.  */
+    uint32_t ccr;
+    uint32_t clk_stat;
+    uint32_t reset;
+    /* Interrupt control registers.  */
+    uint64_t int_req;
+    uint64_t int_mask;
+    uint32_t int_hilo;
+    uint32_t int_route;
+    uint64_t gpo;
+    uint64_t int_time;
+    uint32_t iic_ctrl;
+    uint32_t int_cnfg;
+    /* QEMU emulation state.  */
+    uint32_t latch_tmp;
+    uint64_t ram_size;
+    /* Items with which to raise interrupts.  */
+    qemu_irq *irqs;
+} PyxisState;
+
+/* Called when one of INT_REQ or INT_MASK changes,
+   adjust the signalled state of the cpu.  */
+static void pyxis_irq_change(PyxisState *s)
+{
+    CPUState *env = first_cpu;
+    uint64_t req;
+
+    req = s->int_req & s->int_mask;
+
+    /* If there are any non-masked interrupts, tell the cpu.  */
+    if (req) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void invalidate_tag(PyxisState *s, int i)
+{
+    s->tb_tag[i] = 0;
+    memset(s->tb_page[i], 0, sizeof(s->tb_page[i]));
+}
+
+static uint32_t dummy_read(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static CPUReadMemoryFunc * const dummy_reads[] = {
+    dummy_read,
+    dummy_read,
+    dummy_read,
+};
+
+static CPUWriteMemoryFunc * const dummy_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    unassigned_mem_writel,
+};
+
+static uint32_t sparse0_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = (s->hae_mem & 0xe0000000ull) << 5;
+    return alpha_sparse_mem_read(s->host.bus, hae + addr);
+}
+
+static void sparse0_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = (s->hae_mem & 0xe0000000ull) << 5;
+    alpha_sparse_mem_write(s->host.bus, hae + addr, val);
+}
+
+static uint32_t sparse1_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = ((s->hae_mem >> 11) & 0x1full) << (27 + 5);
+    return alpha_sparse_mem_read(s->host.bus, hae + addr);
+}
+
+static void sparse1_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = ((s->hae_mem >> 11) & 0x1full) << (27 + 5);
+    alpha_sparse_mem_write(s->host.bus, hae + addr, val);
+}
+
+static uint32_t sparse2_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = ((s->hae_mem >> 2) & 0x3full) << (26 + 5);
+    return alpha_sparse_mem_read(s->host.bus, hae + addr);
+}
+
+static void sparse2_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = ((s->hae_mem >> 2) & 0x3full) << (26 + 5);
+    alpha_sparse_mem_write(s->host.bus, hae + addr, val);
+}
+
+static uint32_t sparseA_inl(void *opaque, target_phys_addr_t addr)
+{
+    /* Region A is fixed at the lower 32MB of I/O space.  */
+    return alpha_sparse_io_read(addr);
+}
+
+static void sparseA_outl(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    /* Region A is fixed at the lower 32MB of I/O space.  */
+    alpha_sparse_io_write(addr, val);
+}
+
+static uint32_t sparseB_inl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = (s->hae_io & 0xfe000000ull) << 5;
+    return alpha_sparse_io_read(hae + addr);
+}
+
+static void sparseB_outl(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+    target_phys_addr_t hae;
+
+    hae = (s->hae_io & 0xfe000000ull) << 5;
+    alpha_sparse_io_write(hae + addr, val);
+}
+
+static uint32_t csr_874_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* General Registers.  */
+    case 0x0080: return s->pyxis_rev;
+    case 0x00c0: return s->pci_lat;
+    case 0x0100: return s->pyxis_ctrl;
+    case 0x0140: return s->pyxis_ctrl1;
+    case 0x0200: return s->flash_ctrl;
+    case 0x0400: return s->hae_mem;
+    case 0x0440: return s->hae_io;
+    case 0x0480: return s->cfg;
+
+    /* Diagnostic Registers.  */
+    case 0x2000: return s->pyxis_diag;
+    case 0x3000: return s->diag_check;
+
+    /* Performance Monitor Registers.  */
+    case 0x4000: return s->perf_monitor;
+    case 0x4040: return s->perf_control;
+
+    /* Error Registers.  */
+    case 0x8200: return s->pyxis_err;
+    case 0x8240: return s->pyxis_stat;
+    case 0x8280: return s->err_mask;
+    case 0x8300: return s->pyxis_syn;
+    case 0x8308: return s->pyxis_err_data;
+    case 0x8400: return s->mear;
+    case 0x8440: return s->mesr;
+    case 0x8800: return s->pci_err0;
+    case 0x8840: return s->pci_err1;
+    case 0x8880: return s->pci_err2;
+
+    default:
+        do_unassigned_access(addr + 0x8740000000ull, 0, 0, 0, 4);
+        return -1;
+    }
+}
+
+static uint32_t csr_875_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* Memory Controller Registers.  */
+    case 0x0000: return s->mcr;
+    case 0x0040: return s->mcmr;
+    case 0x0200: return s->gtr;
+    case 0x0300: return s->rtr;
+    case 0x0400: return s->rhpr;
+    case 0x0500: return s->mdr[0];
+    case 0x0540: return s->mdr[1];
+
+    case 0x0600:
+    case 0x0640:
+    case 0x0680:
+    case 0x06c0:
+    case 0x0700:
+    case 0x0740:
+    case 0x0780:
+    case 0x07c0:
+        return s->bbar[(addr - 0x0600) / 0x40];
+
+    case 0x0800:
+    case 0x0840:
+    case 0x0880:
+    case 0x08c0:
+    case 0x0900:
+    case 0x0940:
+    case 0x0980:
+    case 0x09c0:
+        return s->bcr[(addr - 0x0800) / 0x40];
+
+    case 0x0a00:
+    case 0x0a40:
+    case 0x0a80:
+    case 0x0ac0:
+    case 0x0b00:
+    case 0x0b40:
+    case 0x0b80:
+    case 0x0bc0:
+        return s->btr[(addr - 0x0a00) / 0x40];
+
+    case 0x0c00: return s->cvm;
+
+    default:
+        do_unassigned_access(addr + 0x8750000000ull, 0, 0, 0, 4);
+        return -1;
+    }
+}
+
+static uint32_t csr_876_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* PCI Window Control Registers.  */
+    case 0x0100: return s->tbia;
+
+    case 0x0400:
+    case 0x0500:
+    case 0x0600:
+    case 0x0700:
+        return s->wbase[(addr - 0x0400) / 0x0100];
+
+    case 0x0440:
+    case 0x0540:
+    case 0x0640:
+    case 0x0740:
+        return s->wmask[(addr - 0x0440) / 0x0100];
+
+    case 0x0480:
+    case 0x0580:
+    case 0x0680:
+    case 0x0780:
+        return s->tbase[(addr - 0x0480) / 0x0100];
+
+    case 0x07c0: return s->w_dac;
+
+    /* Scatter-gather Address Translation Registers.  */
+    case 0x0800:
+    case 0x0840:
+    case 0x0880:
+    case 0x08c0:
+    case 0x0900:
+    case 0x0940:
+    case 0x0980:
+    case 0x09c0:
+        return s->tb_tag[(addr - 0x0800) / 0x40];
+
+    case 0x1000: case 0x1040: case 0x1080: case 0x10c0:
+    case 0x1100: case 0x1140: case 0x1180: case 0x11c0:
+    case 0x1200: case 0x1240: case 0x1280: case 0x12c0:
+    case 0x1300: case 0x1340: case 0x1380: case 0x13c0:
+    case 0x1400: case 0x1440: case 0x1480: case 0x14c0:
+    case 0x1500: case 0x1540: case 0x1580: case 0x15c0:
+    case 0x1600: case 0x1640: case 0x1680: case 0x16c0:
+    case 0x1700: case 0x1740: case 0x1780: case 0x17c0:
+        return *(&s->tb_page[0][0] + ((addr - 0x1000) / 0x40));
+
+    default:
+        do_unassigned_access(addr + 0x8760000000ull, 0, 0, 0, 4);
+        return -1;
+    }
+}
+
+static uint32_t csr_878_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* Miscellaneous Registers.  */
+    case 0x0000: return s->ccr;
+    case 0x0100: return s->clk_stat;
+    case 0x0900: return s->reset;
+
+    default:
+        do_unassigned_access(addr + 0x8780000000ull, 0, 0, 0, 4);
+        return -1;
+    }
+}
+
+static uint32_t csr_87a_readl(void *opaque, target_phys_addr_t addr)
+{
+    PyxisState *s = opaque;
+    uint64_t ret;
+
+    switch (addr) {
+    /* Interrupt Control Registers.  */
+    case 0x0000:
+        ret = s->int_req;
+        break;
+    case 0x0040:
+        ret = s->int_mask;
+        break;
+    case 0x00c0:
+        ret = s->int_hilo;
+        break;
+    case 0x0140:
+        ret = s->int_route;
+        break;
+    case 0x0180:
+        ret = s->gpo;
+        break;
+    case 0x01c0: return s->int_cnfg;
+    case 0x0200:
+        /* The RT_COUNT clock runs at 66.66MHz.  */
+        ret = qemu_get_clock_ns(vm_clock) / 15;
+        break;
+    case 0x0240:
+        ret = s->int_time;
+        break;
+    case 0x02c0:
+        return s->iic_ctrl;
+
+    case 0x0004:
+    case 0x0044:
+    case 0x00c4:
+    case 0x0144:
+    case 0x0184:
+    case 0x0204:
+    case 0x0244:
+        return s->latch_tmp;
+
+    default:
+        do_unassigned_access(addr + 0x87a0000000ull, 0, 0, 0, 4);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static void csr_874_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* General Registers.  */
+    case 0x0080:
+        /* pyxis_rev: RO */
+        break;
+    case 0x00c0:
+        s->pci_lat = val & 0xffff;
+        break;
+    case 0x0100:
+        s->pyxis_ctrl = val & 0x77703ffd;
+        break;
+    case 0x0140:
+        s->pyxis_ctrl1 = val & 0xffffff11;
+        break;
+    case 0x0200:
+        s->flash_ctrl = val & 0x3fff;
+        break;
+    case 0x0400:
+        s->hae_mem = val & 0xe000f8fc;
+        break;
+    case 0x0440:
+        s->hae_io = val & 0xfe000000;
+        break;
+    case 0x0480:
+        s->cfg = val & 3;
+        break;
+
+    /* Diagnostic Registers.  */
+    case 0x2000:
+        s->pyxis_diag = val & 0xb0000003;
+        break;
+    case 0x3000:
+        s->diag_check = val & 0xff;
+        break;
+
+    /* Performance Monitor Registers.  */
+    case 0x4000:
+        /* perf_monitor: RO */
+        break;
+    case 0x4040:
+        /* perf_control: */
+        /* If LOW_COUNT_CLR set, zero the low counter.  */
+        if (val & (1 << 13)) {
+            s->perf_monitor &= 0xffff0000;
+        }
+        /* If HIGH_COUNT_CLR set, zero the high counter.  */
+        if (val & (1 << 29)) {
+            s->perf_monitor &= 0x0000ffff;
+        }
+        s->perf_control = val & 0xd007d007;
+        break;
+
+    /* Error Registers.  */
+    case 0x8200:
+        /* pyxis_err */
+        /* Zap the RW1C fields; the rest are RO.  */
+        s->pyxis_err &= ~(val & 0xbff);
+        break;
+
+    case 0x8240:
+        /* pyxis_stat: RO */
+        break;
+    case 0x8280:
+        s->err_mask = val & 0x5ff;
+        break;
+    case 0x8300:
+        /* pyxis_syn: RO */
+        break;
+    case 0x8308:
+        /* pyxis_err_data: RO */
+        break;
+    case 0x8400:
+        /* mear: RO */
+        break;
+    case 0x8440:
+        /* mesr: */
+        /* There are a bunch of RO fields in here; preserve them.  */
+        s->mesr = (s->mesr & ~0xfe000000) | (val & 0xfe000000);
+        break;
+    case 0x8800:
+        /* pci_err0: RO */
+        break;
+    case 0x8840:
+        /* pci_err1: RO */
+        break;
+    case 0x8880:
+        /* pci_err2: RO */
+        break;
+
+    default:
+        do_unassigned_access(addr + 0x8740000000ull, 1, 0, 0, 4);
+        return;
+    }
+}
+
+static void csr_875_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* Memory Controller Registers.  */
+    case 0x0000: /* mcr: */
+        /* The SERVER_MODE and BCACHE_TYPE fields are RO.  */
+        s->mcr = (s->mcr & 0x300) | (val & 0x3ffffc01);
+        break;
+    case 0x0040:
+        s->mcmr = val & 0xffff;
+        break;
+    case 0x0200:
+        s->gtr = val & 0x0737;
+        break;
+    case 0x0300:
+        s->rtr = val & 0x9ff0;
+        break;
+    case 0x0400:
+        s->rhpr = val & 0xffff;
+        break;
+    case 0x0500:
+        s->mdr[0] = val & 0xbf3f3f3f;
+        break;
+    case 0x0540:
+        s->mdr[1] = val & 0xbf3f3f3f;
+        break;
+
+    case 0x0600: case 0x0640: case 0x0680: case 0x06c0:
+    case 0x0700: case 0x0740: case 0x0780: case 0x07c0:
+        s->bbar[(addr - 0x0600) / 0x40] = val & 0xffc0;
+        break;
+
+    case 0x0800: case 0x0840: case 0x0880: case 0x08c0:
+    case 0x0900: case 0x0940: case 0x0980: case 0x09c0:
+        s->bcr[(addr - 0x0800) / 0x40] = val & 0xff;
+        break;
+
+    case 0x0a00: case 0x0a40: case 0x0a80: case 0x0ac0:
+    case 0x0b00: case 0x0b40: case 0x0b80: case 0x0bc0:
+        s->btr[(addr - 0x0a00) / 0x40] = val & 0x23;
+        break;
+
+    case 0x0c00: /* cvm: */
+        /* All bits are RW1C.  */
+        s->cvm &= ~val;
+        break;
+
+    default:
+        do_unassigned_access(addr + 0x8750000000ull, 1, 0, 0, 4);
+        return;
+    }
+}
+
+static void csr_876_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+    int i;
+
+    switch (addr) {
+    /* PCI Window Control Registers.  */
+    case 0x0100:
+        switch (val & 3) {
+        case 0: /* No operation.  */
+            break;
+        case 1: /* Invalidate and unlock TLB tags that are locked.  */
+            for (i = 0; i < 4; ++i) {
+                if (s->tb_tag[i] & 2) {
+                    invalidate_tag(s, i);
+                }
+            }
+            break;
+        case 2: /* Invalidate and unlock TLB tags that are unlocked.  */
+            for (i = 0; i < 4; ++i) {
+                if ((s->tb_tag[i] & 2) == 0) {
+                    invalidate_tag(s, i);
+                }
+            }
+            break;
+        case 3: /* Invalidate and unlock all TLB tag entries.  */
+            memset(s->tb_tag, 0, sizeof(s->tb_tag));
+            memset(s->tb_page, 0, sizeof(s->tb_page));
+            break;
+        }
+        break;
+
+    case 0x0400: case 0x0500: case 0x0600: case 0x0700:
+        s->wbase[(addr - 0x0400) / 0x0100] = val & 0xfff0000f;
+        break;
+
+    case 0x0440: case 0x0540: case 0x0640: case 0x0740:
+        s->wmask[(addr - 0x0440) / 0x0100] = val & 0xfff00000;
+        break;
+
+    case 0x0480: case 0x0580: case 0x0680: case 0x0780:
+        s->tbase[(addr - 0x0480) / 0x0100] = val & 0xffffff00;
+        break;
+
+    case 0x07c0:
+        s->w_dac = val & 0xffffff00;
+        break;
+
+    /* Scatter-gather Address Translation Registers.  */
+    case 0x0800: case 0x0840: case 0x0880: case 0x08c0: /* lockable */
+        s->tb_tag[(addr - 0x0800) / 0x40] = val & 0xffff8007;
+        break;
+    case 0x0900: case 0x0940: case 0x0980: case 0x09c0: /* not lockable */
+        s->tb_tag[(addr - 0x0800) / 0x40] = val & 0xffff8005;
+        break;
+
+    case 0x1000: case 0x1040: case 0x1080: case 0x10c0:
+    case 0x1100: case 0x1140: case 0x1180: case 0x11c0:
+    case 0x1200: case 0x1240: case 0x1280: case 0x12c0:
+    case 0x1300: case 0x1340: case 0x1380: case 0x13c0:
+    case 0x1400: case 0x1440: case 0x1480: case 0x14c0:
+    case 0x1500: case 0x1540: case 0x1580: case 0x15c0:
+    case 0x1600: case 0x1640: case 0x1680: case 0x16c0:
+    case 0x1700: case 0x1740: case 0x1780: case 0x17c0:
+        *(&s->tb_page[0][0] + ((addr - 0x1000) / 0x40)) = val & 0x003fffff;
+        break;
+
+    default:
+        do_unassigned_access(addr + 0x8760000000ull, 1, 0, 0, 4);
+        return;
+    }
+}
+
+static void csr_878_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+
+    switch (addr) {
+    /* Miscellaneous Registers.  */
+    case 0x0000:
+        s->ccr = val & 0xff071773;
+        break;
+    case 0x0100:
+        /* clk_stat: RO */
+        break;
+    case 0x0900:
+        /* reset: */
+        /* Yes, the value is architected.  Jokers...  */
+        if (val == 0x0000dead) {
+            /* ??? This should be reset, but shutdown makes for easier
+               debugging for the moment.  */
+            qemu_system_shutdown_request();
+        }
+        break;
+
+    default:
+        do_unassigned_access(addr + 0x8780000000ull, 1, 0, 0, 4);
+        return;
+    }
+}
+
+/* ??? We should probably not accept partial writes to the 64-bit registers.
+   In particular, INT_MASK, RT_COUNT and INT_TIME are likely to do the wrong
+   thing with partial writes.  */
+
+static void csr_87a_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PyxisState *s = opaque;
+    uint64_t val64 = ((uint64_t)val << 32) | s->latch_tmp;
+
+    switch (addr) {
+    /* Interrupt Control Registers.  */
+    case 0x0000:
+        s->latch_tmp = val;
+        break;
+    case 0x0004:
+        s->int_req &= ~(val64 & 0x7ffffffffffffffful);
+        pyxis_irq_change(s);
+        break;
+    case 0x0040:
+        s->latch_tmp = val;
+        break;
+    case 0x0044:
+        s->int_mask = val64;
+        pyxis_irq_change(s);
+        break;
+    case 0x00c0:
+        s->int_hilo = val & 0x7f;
+        break;
+    case 0x00c4:
+        /* int_hilo highpart all 0 */
+        break;
+    case 0x0140:
+        s->int_route = val & 0x7f;
+        break;
+    case 0x0144:
+        /* int_route highpart all 0 */
+        break;
+    case 0x0180:
+        s->latch_tmp = val;
+        break;
+    case 0x0184:
+        s->gpo = val64;
+        break;
+    case 0x01c0:
+        s->int_cnfg = val;
+        break;
+    case 0x0200:
+        /* rt_count low */
+        break;
+    case 0x0204:
+        /* rt_count high */
+        break;
+    case 0x0240:
+        s->latch_tmp = val;
+        break;
+    case 0x0244:
+        s->int_time = val64;
+        break;
+    case 0x02c0:
+        s->iic_ctrl = val;
+        break;
+
+    default:
+        do_unassigned_access(addr + 0x87a0000000ull, 1, 0, 0, 4);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const sparse0_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    sparse0_readl
+};
+
+static CPUWriteMemoryFunc * const sparse0_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    sparse0_writel
+};
+
+static CPUReadMemoryFunc * const sparse1_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    sparse1_readl
+};
+
+static CPUWriteMemoryFunc * const sparse1_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    sparse1_writel
+};
+
+static CPUReadMemoryFunc * const sparse2_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    sparse2_readl
+};
+
+static CPUWriteMemoryFunc * const sparse2_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    sparse2_writel
+};
+
+static CPUReadMemoryFunc * const sparseA_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    sparseA_inl
+};
+
+static CPUWriteMemoryFunc * const sparseA_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    sparseA_outl
+};
+
+static CPUReadMemoryFunc * const sparseB_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    sparseB_inl
+};
+
+static CPUWriteMemoryFunc * const sparseB_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    sparseB_outl
+};
+
+static CPUReadMemoryFunc * const csr_874_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    csr_874_readl
+};
+
+static CPUWriteMemoryFunc * const csr_874_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    csr_874_writel
+};
+
+static CPUReadMemoryFunc * const csr_875_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    csr_875_readl
+};
+
+static CPUWriteMemoryFunc * const csr_875_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    csr_875_writel
+};
+
+static CPUReadMemoryFunc * const csr_876_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    csr_876_readl
+};
+
+static CPUWriteMemoryFunc * const csr_876_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    csr_876_writel
+};
+
+static CPUReadMemoryFunc * const csr_878_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    csr_878_readl
+};
+
+static CPUWriteMemoryFunc * const csr_878_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    csr_878_writel
+};
+
+static CPUReadMemoryFunc * const csr_87a_reads[] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    csr_87a_readl
+};
+
+static CPUWriteMemoryFunc * const csr_87a_writes[] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    csr_87a_writel
+};
+
+
+static void pyxis_line_change(void *opaque, int irq, int level)
+{
+    PyxisState *s = opaque;
+    uint64_t req;
+
+    /* Set/Reset the bit in INT_REQ based on IRQ+LEVEL.  */
+    req = s->int_req;
+    if (level) {
+        req |= 1ull << irq;
+    } else {
+        req &= ~(1ull << irq);
+    }
+    s->int_req = req;
+
+    pyxis_irq_change(s);
+}
+
+static void pyxis_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *irqs = opaque;
+    qemu_set_irq(irqs[irq_num], level);
+}
+
+static int pyxis_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    int slot = (d->devfn >> 3) & 3;
+
+    assert(irq_num >= 0 && irq_num <= 3);
+
+    return irq_num * 4 + (11 - slot);
+}
+
+PCIBus *pyxis_init(uint64_t ram_size, qemu_irq *p_isa_irq)
+{
+    const uint64_t GB = 1024 * 1024 * 1024;
+    DeviceState *dev;
+    PCIHostState *p;
+    PyxisState *s;
+    PCIBus *b;
+    int region;
+
+    dev = qdev_create(NULL, "pyxis-pcihost");
+    p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = container_of(p, PyxisState, host);
+
+    s->irqs = qemu_allocate_irqs(pyxis_line_change, s, 64);
+    *p_isa_irq = s->irqs[7];
+
+    b = pci_register_bus(&s->host.busdev.qdev, "pci", pyxis_pci_set_irq,
+                         pyxis_pci_map_irq, s->irqs, 0, 32);
+    s->host.bus = b;
+
+    qdev_init_nofail(dev);
+
+    /* Main memory region, 0x00.0000.0000, 8GB.  */
+
+    /* Dummy memory region, 0x0e.0000.0000, 4GB.  */
+    region = cpu_register_io_memory(dummy_reads, dummy_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0xe00000000ull, 4*GB, region);
+
+    /* PCI Sparse memory region 0, 0x80.0000.0000, 16GB (covers 512MB).  */
+    region = cpu_register_io_memory(sparse0_reads, sparse0_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8000000000ull, 16*GB, region);
+
+    /* PCI Sparse memory region 1, 0x84.0000.0000, 4GB (covers 128MB).  */
+    region = cpu_register_io_memory(sparse1_reads, sparse1_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8400000000ull, 4*GB, region);
+
+    /* PCI Sparse memory region 2, 0x85.0000.0000, 2GB (covers 64MB).  */
+    region = cpu_register_io_memory(sparse2_reads, sparse2_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8500000000ull, 2*GB, region);
+
+    /* PCI Sparse I/O region A, 0x85.8000.0000, 1GB (covers 32MB).  */
+    region = cpu_register_io_memory(sparseA_reads, sparseA_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8580000000ull, 1*GB, region);
+
+    /* PCI Sparse I/O region B, 0x85.C000.0000, 1GB (covers 32MB).  */
+    region = cpu_register_io_memory(sparseB_reads, sparseB_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x85c0000000ull, 1*GB, region);
+
+    /* PCI Dense memory, 0x86.0000.0000, 4GB.  */
+    region = cpu_register_io_memory(alpha_pci_dense_mem_reads,
+                                    alpha_pci_dense_mem_writes, b,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8600000000ull, 4*GB, region);
+
+    /* Sparse configuration space, 0x87.0000.0000, 512MB.  */
+    /* ??? Best I can tell, type 0 and type 1 accesses really only differ
+       when it comes to the actual bits placed on the PCI bus lines.
+       Which does not matter inside QEMU.  Which means that the contents
+       of the CFG register doesn't really matter.  */
+    region = cpu_register_io_memory(alpha_pci_sparse_conf1_reads,
+                                    alpha_pci_sparse_conf1_writes, b,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8700000000ull, GB/2, region);
+
+    /* PCI special/interrupt acknowledge 0x87.2000.0000, 512MB.  */
+    region = cpu_register_io_memory(alpha_pci_iack_reads,
+                                    alpha_pci_special_writes, b,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8720000000ull, GB/2, region);
+
+    /* PYXIS Main CSRs, 0x87.4000.0000, 128MB.  */
+    region = cpu_register_io_memory(csr_874_reads, csr_874_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8740000000ull, GB/4, region);
+
+    /* PYXIS Memory Control CSRs, 0x87.5000.0000, 128MB.  */
+    region = cpu_register_io_memory(csr_875_reads, csr_875_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8750000000ull, GB/4, region);
+
+    /* PYXIS Address Translation CSRs, 0x87.6000.0000, 128MB.  */
+    region = cpu_register_io_memory(csr_876_reads, csr_876_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8760000000ull, GB/4, region);
+
+    /* PYXIS Miscellaneous CSRs, 0x87.8000.0000, 128MB.  */
+    region = cpu_register_io_memory(csr_878_reads, csr_878_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8780000000ull, GB/4, region);
+
+    /* ??? PYXIS Power Management CSRs, 0x87.9000.0000, 128MB.  */
+
+    /* PYXIS Interrupt Control CSRs, 0x87.a000.0000, 128MB.  */
+    region = cpu_register_io_memory(csr_87a_reads, csr_87a_writes, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x87a0000000ull, GB/4, region);
+
+    /* ??? Flash ROM read/write space, 0x87.c000.0000, 1GB.  */
+
+    /* PCI BW memory, 0x88.0000.0000, 4GB.  */
+    pci_bus_set_mem_base(b, 0x8800000000ull);
+
+    /* PCI BW I/O, 0x89.0000.0000, 4GB.  */
+    region = cpu_register_io_memory(alpha_pci_bw_io_reads,
+                                    alpha_pci_bw_io_writes, b,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8900000000ull, 4*GB, region);
+
+    /* PCI configuration space type 0, 0x8a.0000.0000, 4GB.  */
+    /* ??? Best I can tell, type 0 and type 1 accesses really only differ
+       when it comes to the actual bits placed on the PCI bus lines.
+       Which does not matter inside QEMU.  */
+    region = cpu_register_io_memory(alpha_pci_bw_conf1_reads,
+                                    alpha_pci_bw_conf1_writes, b,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8a00000000ull, 4*GB, region);
+
+    /* PCI configuration space type 1, 0x8b.0000.0000, 4GB.  */
+    region = cpu_register_io_memory(alpha_pci_bw_conf1_reads,
+                                    alpha_pci_bw_conf1_writes, b,
+                                    DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x8b00000000ull, 4*GB, region);
+
+    s->ram_size = ram_size;
+    /* Call reset function.  */
+
+    return b;
+}
+
+static int pyxis_pcihost_init(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static SysBusDeviceInfo pyxis_pcihost_info = {
+    .init = pyxis_pcihost_init,
+    .qdev.name = "pyxis-pcihost",
+    .qdev.size = sizeof(PyxisState),
+    .qdev.no_user = 1
+};
+
+static void pyxis_register(void)
+{
+    sysbus_register_withprop(&pyxis_pcihost_info);
+}
+device_init(pyxis_register);
diff --git a/hw/alpha_sx164.c b/hw/alpha_sx164.c
new file mode 100644
index 0000000..95e297c
--- /dev/null
+++ b/hw/alpha_sx164.c
@@ -0,0 +1,195 @@ 
+/*
+ * QEMU Alpha SX164 hardware system emulator.
+ */
+
+#include "hw.h"
+#include "elf.h"
+#include "loader.h"
+#include "boards.h"
+#include "alpha_sys.h"
+#include "sysemu.h"
+#include "mc146818rtc.h"
+
+
+#define MAX_IDE_BUS 2
+
+
+static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
+{
+    if (((addr >> 41) & 3) == 2) {
+        addr &= 0xffffffffffull;
+    }
+    return addr;
+}
+
+static void rtc_set_irq(void *opaque, int irq_num, int level)
+{
+    CPUState *env = first_cpu;
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER);
+    }
+}
+
+static void sx164_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 = NULL;
+    ram_addr_t ram_offset;
+    PCIBus *pci_bus;
+    ISABus *isa_bus;
+    qemu_irq isa_pci_irq, *rtc_irqs, *isa_irqs;
+    long size, i;
+    const char *palcode_filename;
+    uint64_t palcode_entry, palcode_low, palcode_high;
+    uint64_t kernel_entry, kernel_low, kernel_high;
+
+    env = cpu_init(cpu_model ? cpu_model : "pca56");
+
+    env->trap_arg0 = ram_size;
+    env->trap_arg1 = 0;
+    env->trap_arg2 = 0;
+
+    ram_offset = qemu_ram_alloc(NULL, "ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* Init pyxis.  */
+    pci_bus = pyxis_init(ram_size, &isa_pci_irq);
+
+    /* ??? There should be a Cypress CY82C693U SuperIO chip here
+       providing the PCI-to-ISA bridge.  But the generic ISA support
+       doesn't expect a bridge, so we sort-of hard-code things in.
+       Ideally, the SuperIO device would capture all unhandled accesses
+       within the PCI space and then forward to the ISA bus.  If the
+       access is unhandled within the ISA bus only then report to the
+       CPU via machine check.  */
+    isa_bus = isa_bus_new(NULL);
+    isa_mem_base = 0x8800000000ull;
+
+    isa_irqs = i8259_init(isa_pci_irq);
+    isa_bus_irqs(isa_irqs);
+
+    /* ??? This isn't 100% correct, but should be Good Enough given that
+       we hide most of the actual details inside our custom PALcode.
+       The real HW somehow routes the TOY clock to cpu_int<2> (Int22).
+       How this relates to either the i8259 or the 21174 interrupt masks
+       is not documented.  */
+    rtc_irqs = qemu_allocate_irqs(rtc_set_irq, NULL, 1);
+    rtc_init(1980, rtc_irqs[0]);
+
+    pit_init(0x40, 0);
+
+    /* VGA setup.  Don't bother loading the bios.  */
+    pci_vga_init(pci_bus);
+
+    for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+#if 0
+    /* IDE setup.  */
+    /* ??? Real SX164 actually has a Cypress CY82C693U.  */
+    {
+        DriveInfo * hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+
+        if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+            hw_error("qemu: too many IDE buses\n");
+            exit(1);
+        }
+
+        for (i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+            hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+        }
+        pci_cmd646_ide_init(pci_bus, hd, 0);
+    }
+#endif
+
+#if 0
+    /* USB setup.  The Cypress chip is OHCI compliant; this ought not
+       be too far off Really Correct.  */
+    usb_ohci_init_pci(pci_bus, -1);
+#endif
+
+    /* Network setup.  NE2K is good enough, failing Tulip support.  */
+    for (i = 0; i < nb_nics; i++) {
+        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+    }
+
+    /* Load PALcode.  Given that this is not "real" cpu palcode,
+       but one explicitly written for the emulation, we might as
+       well load it directly from and ELF image.  */
+    palcode_filename = (bios_name ? bios_name : "palcode-sx164");
+    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
+    if (palcode_filename == NULL) {
+        hw_error("qemu: no palcode provided\n");
+        exit(1);
+    }
+    size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
+                    NULL, &palcode_entry, &palcode_low, &palcode_high,
+                    0, EM_ALPHA, 0);
+    if (size < 0) {
+        hw_error("qemu: could not load palcode '%s'\n", palcode_filename);
+        exit(1);
+    }
+    env->pc = palcode_entry;
+    env->palbr = palcode_entry;
+
+    /* Load a kernel.  */
+    if (kernel_filename) {
+        uint64_t param_offset;
+
+        size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
+                        NULL, &kernel_entry, &kernel_low, &kernel_high,
+                        0, EM_ALPHA, 0);
+        if (size < 0) {
+            hw_error("qemu: could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+
+        env->trap_arg1 = kernel_entry;
+
+        param_offset = kernel_low - 0x6000;
+
+        if (kernel_cmdline) {
+            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
+        }
+
+        if (initrd_filename) {
+            long initrd_base, initrd_size;
+
+            initrd_base = (kernel_high | TARGET_PAGE_SIZE) + 1;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                hw_error("qemu: could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+
+            stq_phys(param_offset + 0x100, initrd_base);
+            stq_phys(param_offset + 0x108, initrd_size);
+        }
+    }
+}
+
+static QEMUMachine sx164_machine = {
+    .name = "sx164",
+    .desc = "Alpha SX164",
+    .init = sx164_init,
+    .max_cpus = 1,
+    .is_default = 1,
+};
+
+static void sx164_machine_init(void)
+{
+    qemu_register_machine(&sx164_machine);
+}
+
+machine_init(sx164_machine_init);
diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h
new file mode 100644
index 0000000..43e9892
--- /dev/null
+++ b/hw/alpha_sys.h
@@ -0,0 +1,41 @@ 
+/* Alpha cores and system support chips.  */
+
+#ifndef HW_ALPHA_H
+#define HW_ALPHA_H 1
+
+#include "pci.h"
+#include "pci_host.h"
+#include "ide.h"
+#include "net.h"
+#include "pc.h"
+#include "usb-ohci.h"
+#include "irq.h"
+
+
+extern PCIBus *pyxis_init(uint64_t, qemu_irq *);
+
+/* alpha_pci.c.  */
+extern CPUReadMemoryFunc * const alpha_pci_bw_io_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_bw_io_writes[];
+extern CPUReadMemoryFunc * const alpha_pci_bw_conf1_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_bw_conf1_writes[];
+
+extern CPUReadMemoryFunc * const alpha_pci_dense_mem_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_dense_mem_writes[];
+
+extern CPUReadMemoryFunc * const alpha_pci_sparse_conf1_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_sparse_conf1_writes[];
+
+extern CPUReadMemoryFunc * const alpha_pci_iack_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_special_writes[];
+
+extern uint32_t alpha_sparse_io_read(target_phys_addr_t);
+extern void alpha_sparse_io_write(target_phys_addr_t, uint32_t);
+
+extern uint32_t alpha_sparse_mem_read(PCIBus *, target_phys_addr_t);
+extern void alpha_sparse_mem_write(PCIBus *, target_phys_addr_t, uint32_t);
+
+extern uint32_t alpha_sparse_conf1_read(PCIBus *, target_phys_addr_t);
+extern void alpha_sparse_conf1_write(PCIBus *, target_phys_addr_t, uint32_t);
+
+#endif