@@ -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)
new file mode 100644
@@ -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,
+};
new file mode 100644
@@ -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);
new file mode 100644
@@ -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);
new file mode 100644
@@ -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
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