From patchwork Tue Dec 22 17:40:21 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?5q2m55SwID0/SVNPLTIwMjItSlA/Qj9JQnNrUWoxVFRHa2JLRUk9Pz0=?= X-Patchwork-Id: 41623 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 16153B7BBB for ; Wed, 23 Dec 2009 04:55:24 +1100 (EST) Received: from localhost ([127.0.0.1]:54817 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NN8x0-0004AR-N9 for incoming@patchwork.ozlabs.org; Tue, 22 Dec 2009 12:55:14 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NN8kv-0007nJ-VC for qemu-devel@nongnu.org; Tue, 22 Dec 2009 12:42:46 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NN8ko-0007jt-Bv for qemu-devel@nongnu.org; Tue, 22 Dec 2009 12:42:43 -0500 Received: from [199.232.76.173] (port=56251 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NN8kn-0007jb-NL for qemu-devel@nongnu.org; Tue, 22 Dec 2009 12:42:37 -0500 Received: from smtp-vip.mem.interq.net ([210.157.1.50]:22941 helo=smtp01.mem.internal-gmo) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NN8km-0001ze-N9 for qemu-devel@nongnu.org; Tue, 22 Dec 2009 12:42:37 -0500 Received: (from root@localhost) by smtp01.mem.internal-gmo (8.13.8/8.12.6) id nBMHgHdv021770 for qemu-devel@nongnu.org; Wed, 23 Dec 2009 02:42:17 +0900 (JST) Received: from YOUR-BD18D6DD63.m1.interq.or.jp (ntymns039132.ymns.nt.ftth.ppp.infoweb.ne.jp [121.92.167.132]) by smtp01.mem.internal-gmo with ESMTP id nBMHgGgE021741 for ; (me101664 for with PLAIN) Wed, 23 Dec 2009 02:42:17 +0900 (JST) Message-Id: <200912221740.AA00207@YOUR-BD18D6DD63.m1.interq.or.jp> From: "TAKEDA, toshiya" Date: Wed, 23 Dec 2009 02:40:21 +0900 To: qemu-devel MIME-Version: 1.0 X-Mailer: AL-Mail32 Version 1.13 X-detected-operating-system: by monty-python.gnu.org: Solaris 10 (beta) Subject: [Qemu-devel] [PATCH V4 04/18] support NEC PC-9821 architecture X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: TAKEDA, toshiya --- hw/pc98.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc98.h | 65 +++++++++++++ 2 files changed, 382 insertions(+), 0 deletions(-) create mode 100644 hw/pc98.c create mode 100644 hw/pc98.h diff --git a/hw/pc98.c b/hw/pc98.c new file mode 100644 index 0000000..4bc4805 --- /dev/null +++ b/hw/pc98.c @@ -0,0 +1,317 @@ +/* + * QEMU NEC PC-9821 System Emulator + * + * Copyright (c) 2009 TAKEDA, toshiya + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "pc.h" +#include "fdc.h" +#include "pci.h" +#include "block.h" +#include "sysemu.h" +#include "audio/audio.h" +#include "audiodev.h" +#include "net.h" +#include "boards.h" +#include "monitor.h" +#include "ide.h" + +static void *sys; + +#define MAX_IDE_BUS 2 + +typedef struct isa_irq_state { + qemu_irq *i8259; + qemu_irq *ioapic; +} IsaIrqState; + +/* IRQ handling */ +static void isa_irq_handler(void *opaque, int n, int level) +{ + IsaIrqState *isa = (IsaIrqState *)opaque; + + if (n < 16) { + qemu_set_irq(isa->i8259[n], level); + } + if (isa->ioapic) { + qemu_set_irq(isa->ioapic[n], level); + } +}; + +static void pic_irq_request(void *opaque, int irq, int level) +{ + CPUState *env = first_cpu; + + if (env->apic_state) { + while (env) { + if (apic_accept_pic_intr(env)) { + apic_deliver_pic_intr(env, level); + } + env = env->next_cpu; + } + } else { + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } + } +} + +#define NE2000_NB_MAX 4 + +static const int ne2000_io[NE2000_NB_MAX] = { 0x00d0, 0x10d0, 0x20d0, 0x30d0 }; +static const int ne2000_irq[NE2000_NB_MAX] = { 3, 5, 6, 12 }; + +static void pc98_init_ne2k_isa(NICInfo *nd) +{ + static int nb_ne2k = 0; + + if (nb_ne2k == NE2000_NB_MAX) { + return; + } + pc98_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd); + nb_ne2k++; +} + +static CPUState *pc_new_cpu(const char *cpu_model) +{ + CPUState *env; + + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find x86 CPU definition\n"); + exit(1); + } + if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) { + env->cpuid_apic_id = env->cpu_index; + /* APIC reset callback resets cpu */ + apic_init(env); + } else { + qemu_register_reset((QEMUResetHandler*)cpu_reset, env); + } + return env; +} + +/* I/O */ +static void ioport_f2_write(void *opaque, uint32_t addr, uint32_t data) +{ + ioport_set_a20(1); +} + +static uint32_t ioport_f2_read(void *opaque, uint32_t addr) +{ + return (ioport_get_a20() ^ 1) | 0x2e; +} + +static void ioport_f6_write(void *opaque, uint32_t addr, uint32_t data) +{ + switch (data) { + case 0x02: + ioport_set_a20(1); + break; + case 0x03: + ioport_set_a20(0); + break; + } +} + +static uint32_t ioport_f6_read(void *opaque, uint32_t addr) +{ + return (ioport_get_a20() ^ 1) | 0x5e; +} + +static uint32_t ioport_534_read(void *opaque, uint32_t addr) +{ + return 0xec; /* cpu mode */ +} + +static uint32_t ioport_9894_read(void *opaque, uint32_t addr) +{ + return 0x90; /* cpu wait */ +} + +void pc98_cpu_shutdown(void) +{ + if (pc98_sys_read_shut(sys)) { + qemu_system_reset_request(); + } else { + qemu_cpu_reset_request(); + } +} + +/* PC-9821 hardware initialisation */ +static void pc98_init1(ram_addr_t ram_size, + const char *cpu_model, + int pci_enabled) +{ + char cpu_model_opt[64]; + PCIBus *pci_bus; + int piix3_devfn = -1; + CPUState *env = NULL; + qemu_irq *cpu_irq; + qemu_irq *isa_irq; + qemu_irq *i8259; + IsaIrqState *isa_irq_state; + PITState *pit; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + DriveInfo *fd[MAX_FD]; + int i; + uint8_t hd_connect = 0; + + i440fx_state = NULL; + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif + } + sprintf(cpu_model_opt, "%s,+pc98_a20mask", cpu_model); + + for (i = 0; i < smp_cpus; i++) { + env = pc_new_cpu(cpu_model_opt); + } + + /* init drives */ + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\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); + if (hd[i]) { + hd_connect |= (1 << i); + } + } + for(i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + } + + /* init basic PC-9821 hardware */ + cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); + i8259 = pc98_i8259_init(cpu_irq[0]); + isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state)); + isa_irq_state->i8259 = i8259; + isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); + + if (pci_enabled) { + pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq); + } else { + pci_bus = NULL; + isa_bus_new(NULL); + } + isa_bus_irqs(isa_irq); + + ferr_irq = isa_reserve_irq(8); + + if (pci_enabled) { + isa_irq_state->ioapic = ioapic_init(); + } + pit = pc98_pit_init(isa_reserve_irq(0)); + pc98_pcspk_init(pit); +#ifdef HAS_AUDIO + pcspk_audio_init(isa_irq); +#endif + pc98_DMA_init(1); + + pc98_kbd_init(); + pc98_mouse_init(); + sys = pc98_sys_init(); + pc98_vga_init(); + pc98_memory_init(ram_size, hd_connect); + + pc98_ide_init(hd); + pc98_fdctrl_init(fd); + + for(i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) { + pc98_init_ne2k_isa(nd); /* MELCO LGY-98 */ + } else { + pci_nic_init(nd, "ne2k_pci", NULL); + } + } + +// if (pci_enabled && usb_enabled) { +// usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); +// } + + if (pci_enabled && acpi_enabled) { + piix4_acpi_system_hot_add_init(pci_bus); + } + + if (i440fx_state) { + i440fx_init_memory_mappings(i440fx_state); + } + + register_ioport_write(0xf2, 1, 1, ioport_f2_write, env); + register_ioport_read(0xf2, 1, 1, ioport_f2_read, env); + register_ioport_write(0xf6, 1, 1, ioport_f6_write, env); + register_ioport_read(0xf6, 1, 1, ioport_f6_read, env); + register_ioport_read(0x534, 1, 1, ioport_534_read, env); + register_ioport_read(0x9894, 1, 1, ioport_9894_read, env); +} + +static void pc98_init_pci(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) +{ + pc98_init1(ram_size, cpu_model, 1); +} + +static void pc98_init_isa(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) +{ + pc98_init1(ram_size, cpu_model, 0); +} + +static QEMUMachine pc98pci_machine = { + .name = "pc98pci", + .desc = "NEC PC-9821 with PCI", + .init = pc98_init_pci, + .max_cpus = 2, +}; + +static QEMUMachine pc98_machine = { + .name = "pc98", + .desc = "NEC PC-9821", + .init = pc98_init_isa, + .max_cpus = 1, +}; + +static void pc98_machine_init(void) +{ + qemu_register_machine(&pc98pci_machine); + qemu_register_machine(&pc98_machine); +} + +machine_init(pc98_machine_init); diff --git a/hw/pc98.h b/hw/pc98.h new file mode 100644 index 0000000..6dceeef --- /dev/null +++ b/hw/pc98.h @@ -0,0 +1,65 @@ +#ifndef HW_PC98_H +#define HW_PC98_H + +#define PC98_SYSCLOCK_5MHZ +//#define PC98_SYSCLOCK_8MHZ + +#ifdef PC98_SYSCLOCK_5MHZ + #define PC98_PIT_FREQ 2457600 +#else + #define PC98_PIT_FREQ 1996800 +#endif + +#define PC98_DONT_USE_16MB_MEM + +#define PC98_CIRRUS_VRAM_SIZE 0x100000 + +/* pc98.c */ +void pc98_cpu_shutdown(void); + +/* pc98bkd.c */ +void pc98_kbd_init(void); + +/* pc98mouse.c */ +void pc98_mouse_init(void); + +/* pc98sys.c */ +void *pc98_sys_init(void); +uint8_t pc98_sys_read_shut(void *opaque); + +/* pc98vga.c */ +void pc98_vga_init(void); + +/* pc98mem.c */ +void pc98_memory_init(ram_addr_t ram_size, uint8_t hd_connect); + +/* cirrus_vga.c */ +void *pc98_cirrus_vga_init(DisplayState *ds); +void pc98_cirrus_vga_invalidate_display_size(void *opaque); +void pc98_cirrus_vga_update_display(void *opaque); +void pc98_cirrus_vga_invalidate_display(void *opaque); + +uint32_t pc98_cirrus_vram_readb(void *opaque, target_phys_addr_t addr); +uint32_t pc98_cirrus_vram_readw(void *opaque, target_phys_addr_t addr); +uint32_t pc98_cirrus_vram_readl(void *opaque, target_phys_addr_t addr); +void pc98_cirrus_vram_writeb(void *opaque, + target_phys_addr_t addr, uint32_t value); +void pc98_cirrus_vram_writew(void *opaque, + target_phys_addr_t addr, uint32_t value); +void pc98_cirrus_vram_writel(void *opaque, + target_phys_addr_t addr, uint32_t value); + +/* i8254.c */ +PITState *pc98_pit_init(qemu_irq irq); + +/* i8259.c */ +qemu_irq *pc98_i8259_init(qemu_irq parent_irq); + +/* pcspk.c */ +void pc98_pcspk_init(PITState *); +void pc98_pcspk_write(uint32_t val); + +/* ne2000.c */ +void pc98_ne2000_init(int base, int irq, NICInfo *nd); + +#endif