From patchwork Tue Apr 19 15:05:01 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 92005 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B5BF8B6FE8 for ; Wed, 20 Apr 2011 01:44:12 +1000 (EST) Received: from localhost ([::1]:58096 helo=lists2.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QCD62-0006da-5Z for incoming@patchwork.ozlabs.org; Tue, 19 Apr 2011 11:44:10 -0400 Received: from eggs.gnu.org ([140.186.70.92]:53519) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QCD3l-0002m3-U8 for qemu-devel@nongnu.org; Tue, 19 Apr 2011 11:41:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QCD3c-0005FC-VB for qemu-devel@nongnu.org; Tue, 19 Apr 2011 11:41:49 -0400 Received: from a.mail.sonic.net ([64.142.16.245]:56224) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QCD3c-0005EY-DX for qemu-devel@nongnu.org; Tue, 19 Apr 2011 11:41:40 -0400 Received: from are.twiddle.net (are.twiddle.net [75.101.38.216]) by a.mail.sonic.net (8.13.8.Beta0-Sonic/8.13.7) with ESMTP id p3JF5B0o030918 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 19 Apr 2011 08:05:11 -0700 Received: from are.twiddle.net (localhost [127.0.0.1]) by are.twiddle.net (8.14.4/8.14.4) with ESMTP id p3JF5BTW012908 for ; Tue, 19 Apr 2011 08:05:11 -0700 Received: (from rth@localhost) by are.twiddle.net (8.14.4/8.14.4/Submit) id p3JF5BlH012907 for qemu-devel@nongnu.org; Tue, 19 Apr 2011 08:05:11 -0700 From: Richard Henderson To: qemu-devel@nongnu.org Date: Tue, 19 Apr 2011 08:05:01 -0700 Message-Id: <1303225501-12778-25-git-send-email-rth@twiddle.net> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1303225501-12778-1-git-send-email-rth@twiddle.net> References: <1303225501-12778-1-git-send-email-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 X-Received-From: 64.142.16.245 Subject: [Qemu-devel] [PATCH 24/24] target-alpha: Add SX164 emulation. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Richard Henderson --- 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 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