new file mode 100644
@@ -0,0 +1,861 @@
+/*
+ * QEMU NEC PC-9821 memory
+ *
+ * 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 "isa.h"
+#include "loader.h"
+
+#define PCI_FILE_NAME "pc98pci.bin"
+#define PCI_FILE_SIZE 0x8000
+#define IDE_FILE_NAME "pc98ide.bin"
+#define IDE_FILE_SIZE 0x2000
+#define ITF_FILE_NAME "pc98itf.bin"
+#define ITF_FILE_SIZE 0x8000
+#define BIOS_FILE_NAME "pc98bios.bin"
+#define BIOS_FILE_SIZE 0x18000
+#define BANK_FILE_NAME "pc98bank%d.bin"
+#define BANK_FILE_SIZE 0x8000
+
+#define PCI_ROM_BANK 0
+#define IDE_ROM_BANK 3
+#define ITF_ROM_BANK 4
+#define BIOS_ROM_BANK 5
+#define ROM_BANK_NUM 8
+
+#define REQUIRED_ROM_BANK ((1 << ITF_ROM_BANK) | (7 << BIOS_ROM_BANK))
+
+#define BANK_BITS 12
+/* (1 << BANK_BITS) */
+#define BANK_SIZE 0x1000
+
+#define PCI_BIOS_OFS (BANK_FILE_SIZE * PCI_ROM_BANK)
+#define IDE_BIOS_OFS (BANK_FILE_SIZE * IDE_ROM_BANK)
+#define ITF_OFS (BANK_FILE_SIZE * ITF_ROM_BANK)
+#define BIOS_OFS (BANK_FILE_SIZE * BIOS_ROM_BANK)
+#define NONE_OFS (BANK_FILE_SIZE * ROM_BANK_NUM)
+#define TOTAL_ROM_SIZE (NONE_OFS + BANK_SIZE)
+
+enum {
+ D8000_BANK_IDE = 1,
+ D8000_BANK_PCI = 2,
+ D8000_BANK_PnP = 3,
+};
+
+struct MemoryState {
+ ram_addr_t ram_addr[0x1000000 >> BANK_BITS]; /* 16MB */
+ ram_addr_t rom_addr[TOTAL_ROM_SIZE >> BANK_BITS];
+ ram_addr_t mem_bank[0x100000 >> BANK_BITS]; /* 1MB */
+
+ int tvram_io_memory;
+ int vram_a8000_io_memory;
+ int vram_b0000_io_memory;
+ int vram_e0000_io_memory;
+ int vram_f00000_io_memory;
+
+ uint8_t ram_window_map1;
+ uint8_t ram_window_map2;
+ uint8_t d8000_bank;
+ uint8_t ide_bios_enabled;
+ uint8_t ide_ram_selected;
+ uint8_t bios_ram_selected;
+ uint8_t itf_selected;
+ uint8_t use_system_16mb;
+
+ uint8_t ide_bios_loaded;
+ uint8_t hd_connect;
+ uint8_t init_done;
+};
+
+typedef struct MemoryState MemoryState;
+
+static uint8_t *get_ram_ptr(void *opaque, ram_addr_t addr)
+{
+ MemoryState *s = opaque;
+ uint32_t ofs = addr & (BANK_SIZE - 1);
+
+ return qemu_get_ram_ptr(s->ram_addr[addr >> BANK_BITS]) + ofs;
+}
+
+static void register_ram(void *opaque, target_phys_addr_t top, ram_addr_t size,
+ ram_addr_t addr)
+{
+ MemoryState *s = opaque;
+ target_phys_addr_t a;
+ int smram_update = 0;
+
+ for (a = top; a < top + size; a += BANK_SIZE) {
+ ram_addr_t phys_offset = s->ram_addr[addr >> BANK_BITS];
+ if (s->mem_bank[a >> BANK_BITS] != phys_offset) {
+ cpu_register_physical_memory(a, BANK_SIZE, phys_offset);
+ if (a >= 0xa0000) {
+ smram_update = 1;
+ if (s->use_system_16mb) {
+ cpu_register_physical_memory(0xf00000 + a, BANK_SIZE,
+ phys_offset);
+ }
+ cpu_register_physical_memory(0xfff00000 + a, BANK_SIZE,
+ phys_offset);
+ }
+ s->mem_bank[a >> BANK_BITS] = phys_offset;
+ }
+ addr += BANK_SIZE;
+ }
+ if (i440fx_state && smram_update && s->init_done) {
+ i440fx_init_memory_mappings(i440fx_state);
+ }
+}
+
+static void register_rom(void *opaque, target_phys_addr_t top, ram_addr_t size,
+ ram_addr_t addr)
+{
+ MemoryState *s = opaque;
+ target_phys_addr_t a;
+ int smram_update = 0;
+
+ for (a = top; a < top + size; a += BANK_SIZE) {
+ ram_addr_t phys_offset = s->rom_addr[addr >> BANK_BITS];
+ if (s->mem_bank[a >> BANK_BITS] != phys_offset) {
+ cpu_register_physical_memory(a, BANK_SIZE,
+ phys_offset | IO_MEM_ROM);
+ if (a >= 0xa0000) {
+ smram_update = 1;
+ if (s->use_system_16mb) {
+ cpu_register_physical_memory(0xf00000 + a, BANK_SIZE,
+ phys_offset | IO_MEM_ROM);
+ }
+ cpu_register_physical_memory(0xfff00000 + a, BANK_SIZE,
+ phys_offset | IO_MEM_ROM);
+ }
+ s->mem_bank[a >> BANK_BITS] = phys_offset;
+ }
+ if (addr != NONE_OFS) {
+ addr += BANK_SIZE;
+ }
+ }
+ if (i440fx_state && smram_update && s->init_done) {
+ i440fx_init_memory_mappings(i440fx_state);
+ }
+}
+
+static void register_io_memory(void *opaque, target_phys_addr_t top, ram_addr_t size,
+ ram_addr_t phys_offset)
+{
+ MemoryState *s = opaque;
+ target_phys_addr_t a;
+ int smram_update = 0;
+
+ if (s->mem_bank[top >> BANK_BITS] != phys_offset) {
+ cpu_register_physical_memory(isa_mem_base + top, size, phys_offset);
+ if (top >= 0xa0000) {
+ smram_update = 1;
+ if (s->use_system_16mb) {
+ cpu_register_physical_memory(isa_mem_base + 0xf00000 + top,
+ size, phys_offset);
+ }
+ cpu_register_physical_memory(isa_mem_base + 0xfff00000 + top,
+ size, phys_offset);
+ }
+ for (a = top + BANK_SIZE; a < top + size; a += BANK_SIZE) {
+ s->mem_bank[a >> BANK_BITS] = -1;
+ }
+ s->mem_bank[top >> BANK_BITS] = phys_offset;
+ }
+ if (i440fx_state && smram_update && s->init_done) {
+ i440fx_init_memory_mappings(i440fx_state);
+ }
+}
+
+static void register_ide_rom(void *opaque)
+{
+ MemoryState *s = opaque;
+
+ if (!s->ide_bios_enabled) {
+ register_rom(s, 0xd8000, 0x8000, NONE_OFS);
+ } else if (s->ide_ram_selected) {
+ register_rom(s, 0xd8000, 0x2000, IDE_BIOS_OFS);
+ register_ram(s, 0xda000, 0x2000, 0xda000);
+ register_rom(s, 0xdc000, 0x4000, NONE_OFS);
+ } else {
+ register_rom(s, 0xd8000, 0x2000, IDE_BIOS_OFS);
+ register_rom(s, 0xda000, 0x6000, NONE_OFS);
+ }
+}
+
+static void register_pci_rom(void *opaque)
+{
+ register_rom(opaque, 0xd8000, 0x8000, PCI_BIOS_OFS);
+}
+
+static void register_pnp_rom(void *opaque)
+{
+ /* XXX: register plug&play bios at 0xd8000-0xdffff */
+}
+
+static void register_bios_rom(void *opaque)
+{
+ register_rom(opaque, 0xe8000, 0x18000, BIOS_OFS);
+}
+
+static void register_bios_ram(void *opaque)
+{
+ register_ram(opaque, 0xe8000, 0x18000, 0xe8000);
+}
+
+static void register_itf_rom(void *opaque)
+{
+ register_rom(opaque, 0xe8000, 0x10000, NONE_OFS);
+ register_rom(opaque, 0xf8000, 0x08000, ITF_OFS);
+}
+
+static void ioport_43b_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+ target_phys_addr_t a;
+
+ if (data & 0x04) {
+ if (s->use_system_16mb) {
+ s->use_system_16mb = 0;
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xf00000, 0xc0000);
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xfe0000, 0x08000);
+ for (a = 0xf00000; a < 0x1000000; a += BANK_SIZE) {
+ cpu_register_physical_memory(a, BANK_SIZE,
+ s->ram_addr[a >> BANK_BITS]);
+ }
+ }
+ } else {
+ if (!s->use_system_16mb) {
+ s->use_system_16mb = 1;
+ cpu_register_physical_memory(isa_mem_base + 0xf00000, 0xa0000,
+ s->vram_f00000_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfa0000, 0x08000,
+ s->tvram_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfa8000, 0x08000,
+ s->vram_a8000_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfb0000, 0x10000,
+ s->vram_b0000_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfe0000, 0x08000,
+ s->vram_e0000_io_memory);
+ for (a = 0xfc0000; a < 0xfe0000; a += BANK_SIZE) {
+ ram_addr_t phys_offset = cpu_get_physical_page_desc(a & 0xfffff);
+ cpu_register_physical_memory(a, BANK_SIZE, phys_offset);
+ }
+ for (a = 0xfe8000; a < 0x1000000; a += BANK_SIZE) {
+ ram_addr_t phys_offset = cpu_get_physical_page_desc(a & 0xfffff);
+ cpu_register_physical_memory(a, BANK_SIZE, phys_offset);
+ }
+ qemu_register_coalesced_mmio(isa_mem_base + 0xf00000, 0xc0000);
+ qemu_register_coalesced_mmio(isa_mem_base + 0xfe0000, 0x08000);
+ }
+ }
+}
+
+static uint32_t ioport_43b_read(void *opaque, uint32_t addr)
+{
+ MemoryState *s = opaque;
+
+ if (s->use_system_16mb) {
+ return 0x00;
+ } else {
+ return 0x04;
+ }
+}
+
+static void ioport_43d_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+
+ switch (data) {
+ case 0x00:
+ case 0x10:
+ case 0x18:
+ if (!s->itf_selected) {
+ s->itf_selected = 1;
+ register_itf_rom(s);
+ }
+ break;
+ case 0x02:
+ case 0x12:
+ if (s->itf_selected) {
+ s->itf_selected = 0;
+ if (s->bios_ram_selected) {
+ if (s->ide_bios_loaded && s->hd_connect) {
+ /* IDE BIOS patch */
+ if (s->hd_connect & 1) {
+ *get_ram_ptr(s, 0x457) = 0x90;
+ *get_ram_ptr(s, 0x45d) |= 0x08;
+ *get_ram_ptr(s, 0x55d) |= 0x01;
+ } else {
+ *get_ram_ptr(s, 0x457) = 0x38;
+ }
+ if (s->hd_connect & 2) {
+ *get_ram_ptr(s, 0x457) |= 0x42;
+ *get_ram_ptr(s, 0x45d) |= 0x10;
+ *get_ram_ptr(s, 0x55d) |= 0x02;
+ } else {
+ *get_ram_ptr(s, 0x457) |= 0x07;
+ }
+ *get_ram_ptr(s, 0xf8e90) |= (s->hd_connect & 0x0f);
+ }
+ register_bios_ram(s);
+ } else {
+ register_bios_rom(s);
+ }
+ }
+ break;
+ }
+}
+
+static void ioport_461_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+
+ if (s->ram_window_map1 != (data & 0xfe)) {
+ if (s->ram_window_map1 == 0x0a) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0x80000, 0x20000);
+ } else if (s->ram_window_map1 == 0x0e) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0x80000, 0x08000);
+ }
+ s->ram_window_map1 = data & 0xfe;
+ if (s->ram_window_map1 == 0x0a) {
+ register_io_memory(s, 0x80000, 0x08000, s->tvram_io_memory);
+ register_io_memory(s, 0x88000, 0x08000, s->vram_a8000_io_memory);
+ register_io_memory(s, 0x90000, 0x10000, s->vram_b0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0x80000, 0x20000);
+ } else if (s->ram_window_map1 == 0x0e) {
+ register_io_memory(s, 0x80000, 0x08000, s->vram_e0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0x80000, 0x08000);
+ register_ram(s, 0x88000, 0x18000, 0xe8000);
+ } else {
+ register_ram(s, 0x80000, 0x20000, s->ram_window_map1 * 0x10000);
+ }
+ }
+}
+
+static uint32_t ioport_461_read(void *opaque, uint32_t addr)
+{
+ MemoryState *s = opaque;
+
+ return s->ram_window_map1;
+}
+
+static void ioport_463_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+
+ if (s->ram_window_map2 != (data & 0xfe)) {
+ if (s->ram_window_map2 == 0x0a) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xa0000, 0x20000);
+ } else if (s->ram_window_map2 == 0x0e) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xa0000, 0x08000);
+ }
+ s->ram_window_map2 = data & 0xfe;
+ if (s->ram_window_map2 == 0x0a) {
+ register_io_memory(s, 0xa0000, 0x08000, s->tvram_io_memory);
+ register_io_memory(s, 0xa8000, 0x08000, s->vram_a8000_io_memory);
+ register_io_memory(s, 0xb0000, 0x10000, s->vram_b0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0xa0000, 0x20000);
+ } else if (s->ram_window_map2 == 0x0e) {
+ register_io_memory(s, 0xa0000, 0x08000, s->vram_e0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0xa0000, 0x08000);
+ register_ram(s, 0xa8000, 0x18000, 0xe8000);
+ } else {
+ register_ram(s, 0xa0000, 0x20000, s->ram_window_map2 * 0x10000);
+ }
+ }
+}
+
+static uint32_t ioport_463_read(void *opaque, uint32_t addr)
+{
+ MemoryState *s = opaque;
+
+ return s->ram_window_map2;
+}
+
+static void ioport_53d_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+
+ if (data & 0x10) {
+ if (!s->ide_bios_enabled) {
+ s->ide_bios_enabled = 1;
+ register_ide_rom(s);
+ }
+ } else {
+ if (s->ide_bios_enabled) {
+ s->ide_bios_enabled = 0;
+ register_ide_rom(s);
+ }
+ }
+ if (data & 0x02) {
+ if (!s->bios_ram_selected) {
+ s->bios_ram_selected = 1;
+ if (!s->itf_selected) {
+ register_bios_ram(s);
+ }
+ }
+ } else {
+ if (s->bios_ram_selected) {
+ s->bios_ram_selected = 0;
+ if (!s->itf_selected) {
+ register_bios_rom(s);
+ }
+ }
+ }
+}
+
+static void ioport_63c_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+
+ switch (data & 0x03) {
+ case 1:
+ if (s->d8000_bank != D8000_BANK_IDE) {
+ register_ide_rom(s);
+ }
+ break;
+ case 2:
+ if (s->d8000_bank != D8000_BANK_PCI) {
+ register_pci_rom(s);
+ }
+ break;
+ case 3:
+ if (s->d8000_bank != D8000_BANK_PnP) {
+ register_pnp_rom(s);
+ }
+ break;
+ }
+ s->d8000_bank = data & 0x03;
+}
+
+static uint32_t ioport_63c_read(void *opaque, uint32_t addr)
+{
+ MemoryState *s = opaque;
+
+ return s->d8000_bank;
+}
+
+static uint32_t ioport_63d_read(void *opaque, uint32_t addr)
+{
+ return 0x04;
+}
+
+static void ioport_1e8e_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ MemoryState *s = opaque;
+
+ switch (data) {
+ case 0x80:
+ if (s->ide_ram_selected) {
+ s->ide_ram_selected = 0;
+ if (s->d8000_bank == D8000_BANK_IDE) {
+ register_ide_rom(s);
+ }
+ }
+ break;
+ case 0x81:
+ if (!s->ide_ram_selected) {
+ s->ide_ram_selected = 1;
+ if (s->d8000_bank == D8000_BANK_IDE) {
+ register_ide_rom(s);
+ }
+ }
+ break;
+ }
+}
+
+static uint32_t ioport_1e8e_read(void *opaque, uint32_t addr)
+{
+ MemoryState *s = opaque;
+
+ if (s->ide_ram_selected) {
+ return 0x81;
+ } else {
+ return 0x80;
+ }
+}
+
+static int pc98_memory_pre_load(void *opaque)
+{
+ MemoryState *s = opaque;
+
+ if (s->ram_window_map1 == 0x0a) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0x80000, 0x20000);
+ } else if (s->ram_window_map1 == 0x0e) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0x80000, 0x08000);
+ }
+ if (s->ram_window_map2 == 0x0a) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xa0000, 0x20000);
+ } else if (s->ram_window_map2 == 0x0e) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xa0000, 0x08000);
+ }
+ if (s->use_system_16mb) {
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xf00000, 0xc0000);
+ qemu_unregister_coalesced_mmio(isa_mem_base + 0xfe0000, 0x08000);
+ }
+ return 0;
+}
+
+static int pc98_memory_post_load(void *opaque, int version_id)
+{
+ MemoryState *s = opaque;
+ target_phys_addr_t a;
+
+ /* restore memory bank */
+ if (s->ram_window_map1 == 0x0a) {
+ register_io_memory(s, 0x80000, 0x08000, s->tvram_io_memory);
+ register_io_memory(s, 0x88000, 0x08000, s->vram_a8000_io_memory);
+ register_io_memory(s, 0x90000, 0x10000, s->vram_b0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0x80000, 0x20000);
+ } else if (s->ram_window_map1 == 0x0e) {
+ register_io_memory(s, 0x80000, 0x08000, s->vram_e0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0x80000, 0x08000);
+ register_ram(s, 0x88000, 0x18000, 0xe8000);
+ } else {
+ register_ram(s, 0x80000, 0x20000, s->ram_window_map1 * 0x10000);
+ }
+ if (s->ram_window_map2 == 0x0a) {
+ register_io_memory(s, 0xa0000, 0x08000, s->tvram_io_memory);
+ register_io_memory(s, 0xa8000, 0x08000, s->vram_a8000_io_memory);
+ register_io_memory(s, 0xb0000, 0x10000, s->vram_b0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0xa0000, 0x20000);
+ } else if (s->ram_window_map2 == 0x0e) {
+ register_io_memory(s, 0xa0000, 0x08000, s->vram_e0000_io_memory);
+ qemu_register_coalesced_mmio(isa_mem_base + 0xa0000, 0x08000);
+ register_ram(s, 0xa8000, 0x18000, 0xe8000);
+ } else {
+ register_ram(s, 0xa0000, 0x20000, s->ram_window_map2 * 0x10000);
+ }
+ if (s->d8000_bank == D8000_BANK_IDE) {
+ register_ide_rom(s);
+ } else if (s->d8000_bank == D8000_BANK_PCI) {
+ register_pci_rom(s);
+ } else if (s->d8000_bank == D8000_BANK_PnP) {
+ register_pnp_rom(s);
+ }
+ if (s->itf_selected) {
+ register_itf_rom(s);
+ } else if (s->bios_ram_selected) {
+ register_bios_ram(s);
+ } else {
+ register_bios_rom(s);
+ }
+ if (s->use_system_16mb) {
+ cpu_register_physical_memory(isa_mem_base + 0xf00000, 0xa0000,
+ s->vram_f00000_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfa0000, 0x08000,
+ s->tvram_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfa8000, 0x08000,
+ s->vram_a8000_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfb0000, 0x10000,
+ s->vram_b0000_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xfe0000, 0x08000,
+ s->vram_e0000_io_memory);
+ for (a = 0xfc0000; a < 0xfe0000; a += BANK_SIZE) {
+ ram_addr_t phys_offset = cpu_get_physical_page_desc(a & 0xfffff);
+ cpu_register_physical_memory(a, BANK_SIZE, phys_offset);
+ }
+ for (a = 0xfe8000; a < 0x1000000; a += BANK_SIZE) {
+ ram_addr_t phys_offset = cpu_get_physical_page_desc(a & 0xfffff);
+ cpu_register_physical_memory(a, BANK_SIZE, phys_offset);
+ }
+ qemu_register_coalesced_mmio(isa_mem_base + 0xf00000, 0xc0000);
+ qemu_register_coalesced_mmio(isa_mem_base + 0xfe0000, 0x08000);
+ } else {
+ for (a = 0xf00000; a < 0x1000000; a += BANK_SIZE) {
+ cpu_register_physical_memory(a, BANK_SIZE,
+ s->ram_addr[a >> BANK_BITS]);
+ }
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_memory = {
+ .name = "pc98-mem",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_load = pc98_memory_pre_load,
+ .post_load = pc98_memory_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(ram_window_map1, MemoryState),
+ VMSTATE_UINT8(ram_window_map2, MemoryState),
+ VMSTATE_UINT8(d8000_bank, MemoryState),
+ VMSTATE_UINT8(ide_bios_enabled, MemoryState),
+ VMSTATE_UINT8(ide_ram_selected, MemoryState),
+ VMSTATE_UINT8(bios_ram_selected, MemoryState),
+ VMSTATE_UINT8(itf_selected, MemoryState),
+ VMSTATE_UINT8(use_system_16mb, MemoryState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void pc98_memory_reset(void *opaque)
+{
+ MemoryState *s = opaque;
+
+ if (s->ram_window_map1 != 0x08) {
+ s->ram_window_map1 = 0x08;
+ register_ram(s, 0x80000, 0x20000, 0x80000);
+ }
+ if (s->ram_window_map2 != 0x0a) {
+ s->ram_window_map2 = 0x0a;
+ register_io_memory(s, 0xa0000, 0x08000, s->tvram_io_memory);
+ register_io_memory(s, 0xa8000, 0x08000, s->vram_a8000_io_memory);
+ register_io_memory(s, 0xb0000, 0x10000, s->vram_b0000_io_memory);
+ }
+ if (!(s->d8000_bank == D8000_BANK_IDE &&
+ s->ide_bios_enabled && s->ide_ram_selected)
+ ) {
+ s->d8000_bank = D8000_BANK_IDE;
+ s->ide_bios_enabled = 1;
+ s->ide_ram_selected = 1;
+ register_ide_rom(s);
+ }
+ if (!s->itf_selected) {
+ s->itf_selected = 1;
+ register_itf_rom(s);
+ }
+ s->bios_ram_selected = 0;
+}
+
+static int patch_itf(uint8_t *buf, const char *msg)
+{
+ uint8_t op[12] = {
+ 0xbe, 0x00, 0x00, // mov si,msg
+ 0xbd, 0x00, 0x00, // mov bp,retaddr
+ 0xe9, 0x00, 0x00, // jmp disp
+ // retaddr:
+ 0xf4, // hlt
+ 0xeb, 0xfe, // jmp $-2
+ };
+ int len = strlen(msg);
+ int i, a1, a2;
+ int ret = 0;
+
+ for (a1 = 1; a1 < 0x8000 - len; a1++) {
+ for (i = 0; i < len; i++) {
+ if (buf[a1 + i] != msg[i]) {
+ break;
+ }
+ }
+ if (i == len) {
+ op[1] = (a1 - 1) & 0xff;
+ op[2] = (a1 - 1) >> 8;
+ for (a2 = 0; a2 < 0x8000 - 12; a2++) {
+ op[4] = (a2 + 9) & 0xff;
+ op[5] = (a2 + 9) >> 8;
+ for (i = 0; i < 12; i++) {
+ if (!(op[i] == buf[a2 + i] || op[i] == 0x00)) {
+ break;
+ }
+ }
+ if (i == 9 || i == 12) {
+ memset(buf + a2, 0x90, i);
+ ret = 1;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+static void update_check_sum(uint8_t *buf)
+{
+ uint8_t l = 0, h = 0;
+ int i;
+
+ for (i = 0; i < 0x8000; i += 2) {
+ l += buf[i + 0];
+ h += buf[i + 1];
+ }
+ buf[0x7ffe] -= l;
+ buf[0x7fff] -= h;
+}
+
+void pc98_memory_init(ram_addr_t ram_size, uint8_t hd_connect)
+{
+ MemoryState *s;
+ uint8_t *buf;
+ char filename[16], *filepath;
+ uint8_t loaded = 0;
+ int i;
+ ram_addr_t a;
+
+ s = qemu_mallocz(sizeof(MemoryState));
+
+ /* memory must be initialized after vga is initialized */
+ s->tvram_io_memory = cpu_get_physical_page_desc(0xa0000);
+ s->vram_a8000_io_memory = cpu_get_physical_page_desc(0xa8000);
+ s->vram_b0000_io_memory = cpu_get_physical_page_desc(0xb0000);
+ s->vram_e0000_io_memory = cpu_get_physical_page_desc(0xe0000);
+ s->vram_f00000_io_memory = cpu_get_physical_page_desc(0xf00000);
+
+ s->ram_window_map1 = 0x08;
+ s->ram_window_map2 = 0x0a;
+ s->d8000_bank = D8000_BANK_IDE;
+ s->ide_bios_enabled = 1;
+ s->ide_ram_selected = 1;
+ s->bios_ram_selected = 0;
+ s->itf_selected = 1;
+#ifdef PC98_DONT_USE_16MB_MEM
+ s->use_system_16mb = 0;
+#else
+ s->use_system_16mb = 1;
+#endif
+
+ /* allocate RAM */
+ if (ram_size < 0x1000000) {
+ ram_size = 0x1000000; /* >= 16MB */
+ }
+ ram_size &= ~0x7fffff; /* 8MB * num */
+
+ for (i = 0; i < (0x100000 >> BANK_BITS); i++) {
+ s->mem_bank[i] = -1;
+ }
+ for (a = 0; a < 0xa0000; a += BANK_SIZE) {
+ s->ram_addr[a >> BANK_BITS] = qemu_ram_alloc(BANK_SIZE);
+ }
+ qemu_ram_alloc(0x100000 - 0xa0000); /* for PAM and SMRAM */
+ for (a = 0xa0000; a < 0x1000000; a += BANK_SIZE) {
+ s->ram_addr[a >> BANK_BITS] = qemu_ram_alloc(BANK_SIZE);
+ }
+
+ register_ram(s, 0, 0xa0000, 0);
+#ifdef PC98_DONT_USE_16MB_MEM
+ for (a = 0x100000; a < 0x1000000; a += BANK_SIZE) {
+#else
+ for (a = 0x100000; a < 0x0f00000; a += BANK_SIZE) {
+#endif
+ cpu_register_physical_memory(a, BANK_SIZE, s->ram_addr[a >> BANK_BITS]);
+ }
+ if (ram_size > 0x1000000) {
+ ram_addr_t ram_addr = qemu_ram_alloc(ram_size - 0x1000000);
+ cpu_register_physical_memory(0x1000000, ram_size - 0x1000000, ram_addr);
+ }
+
+ /* BIOS load */
+ for (a = 0; a < TOTAL_ROM_SIZE; a += BANK_SIZE) {
+ s->rom_addr[a >> BANK_BITS] = qemu_ram_alloc(BANK_SIZE);
+ }
+ buf = qemu_malloc(TOTAL_ROM_SIZE);
+ memset(buf, 0xff, TOTAL_ROM_SIZE);
+
+ for (i = 0; i < ROM_BANK_NUM; i++) {
+ sprintf(filename, BANK_FILE_NAME, i);
+ filepath = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
+ if (filepath) {
+ if (load_image(filepath, buf + BANK_FILE_SIZE * i) == BANK_FILE_SIZE) {
+ loaded |= (1 << i);
+ }
+ qemu_free(filepath);
+ }
+ }
+ filepath = qemu_find_file(QEMU_FILE_TYPE_BIOS, PCI_FILE_NAME);
+ if (filepath) {
+ if (load_image(filepath, buf + PCI_BIOS_OFS) == PCI_FILE_SIZE) {
+ loaded |= (1 << PCI_ROM_BANK);
+ }
+ qemu_free(filepath);
+ }
+ filepath = qemu_find_file(QEMU_FILE_TYPE_BIOS, IDE_FILE_NAME);
+ if (filepath) {
+ if (load_image(filepath, buf + IDE_BIOS_OFS) == IDE_FILE_SIZE) {
+ loaded |= (1 << IDE_ROM_BANK);
+ }
+ qemu_free(filepath);
+ }
+ filepath = qemu_find_file(QEMU_FILE_TYPE_BIOS, ITF_FILE_NAME);
+ if (filepath) {
+ if (load_image(filepath, buf + ITF_OFS) == ITF_FILE_SIZE) {
+ loaded |= (1 << ITF_ROM_BANK);
+ }
+ qemu_free(filepath);
+ }
+ filepath = qemu_find_file(QEMU_FILE_TYPE_BIOS, BIOS_FILE_NAME);
+ if (filepath) {
+ if (load_image(filepath, buf + BIOS_OFS) == BIOS_FILE_SIZE) {
+ loaded |= (7 << BIOS_ROM_BANK);
+ }
+ qemu_free(filepath);
+ }
+ if ((loaded & REQUIRED_ROM_BANK) == REQUIRED_ROM_BANK) {
+ /* ITF: disable hardware check */
+ static const char msg[][32] = {
+ "TIMER INTERRUPT ERROR",
+ "EXTENDED GVRAM ERROR",
+ /* end of array */
+ "",
+ };
+ int patched = 0;
+ for (i = 0; msg[i][0] != '\0'; i++) {
+ patched |= patch_itf(buf + ITF_OFS, msg[i]);
+ }
+ if (patched) {
+ update_check_sum(buf + ITF_OFS);
+ }
+ /* BIOS: disable PnP BIOS */
+ for (a = 0x8000; a < 0x18000; a += 0x10) {
+ uint8_t *p = buf + BIOS_OFS + a;
+ if (p[0] == 0x24 && p[1] == 'P' && p[2] == 'n' && p[3] == 'P') {
+ p[0] = 'n';
+ p[2] = 0x24;
+ break;
+ }
+ }
+ /* copy to rom_addr */
+ for (a = 0; a < TOTAL_ROM_SIZE; a += BANK_SIZE) {
+ memcpy(qemu_get_ram_ptr(s->rom_addr[a >> BANK_BITS]), buf + a, BANK_SIZE);
+ }
+ s->ide_bios_loaded = ((loaded & (1 << IDE_ROM_BANK)) != 0);
+ } else {
+ fprintf(stderr, "qemu: could not load PC-9821 BIOS\n");
+ exit(1);
+ }
+ qemu_free(buf);
+
+ register_rom(s, 0xc0000, 0x18000, NONE_OFS);
+ register_ide_rom(s);
+ register_itf_rom(s);
+
+ register_ioport_write(0x43b, 1, 1, ioport_43b_write, s);
+ register_ioport_read(0x43b, 1, 1, ioport_43b_read, s);
+ register_ioport_write(0x43d, 1, 1, ioport_43d_write, s);
+ register_ioport_write(0x461, 1, 1, ioport_461_write, s);
+ register_ioport_read(0x461, 1, 1, ioport_461_read, s);
+ register_ioport_write(0x463, 1, 1, ioport_463_write, s);
+ register_ioport_read(0x463, 1, 1, ioport_463_read, s);
+ register_ioport_write(0x53d, 1, 1, ioport_53d_write, s);
+ register_ioport_write(0x63c, 1, 1, ioport_63c_write, s);
+ register_ioport_read(0x63c, 1, 1, ioport_63c_read, s);
+ register_ioport_read(0x63d, 1, 1, ioport_63d_read, s);
+ register_ioport_write(0x1e8e, 1, 1, ioport_1e8e_write, s);
+ register_ioport_read(0x1e8e, 1, 1, ioport_1e8e_read, s);
+
+ vmstate_register(-1, &vmstate_memory, s);
+ qemu_register_reset(pc98_memory_reset, s);
+
+ /* initialize done */
+ s->hd_connect = hd_connect;
+ s->init_done = 1;
+}
Signed-off-by: TAKEDA, toshiya <t-takeda@m1.interq.or.jp> --- hw/pc98mem.c | 861 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 861 insertions(+), 0 deletions(-) create mode 100644 hw/pc98mem.c