target/hppa: Implement PA2.0 instructions
hw/hppa: Map astro chip 64-bit I/O mem hw/hppa: Turn on 64-bit cpu for C3700 -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmVJqDEdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV8n5Qf/R15CvXGMgjDJjoV2 ILMFM+Rpg17SR2yu060sEZ01R3iHdobeCcDB184K0RI9JLrpcBFar+PeF023o9fn O9MnfIyL6/ggzaeIpQ9AD2uT0HJMU9hLFoyQqQvnhDHHcT34raL2+Zkrkb2vvauH XET7awXN9xYCnY4ALrfcapzlrHqI77ahz0vReUWPxk7eGY2ez8dEOiFW2WLBmuMx mAFAMrFQhq66GjoMDl8JiGHD/KBJQ9X4eUAEotS27lTCOYU0ryA6dWBGqBSTWCUa smpxkeGQKOew+717HV1H4FdCRYG1Rgm7yFN423JULeew+T7DHvfe0K55vMIulx5I g3oVZA== =dxC7 -----END PGP SIGNATURE----- Merge tag 'pull-pa-20231106' of https://gitlab.com/rth7680/qemu into staging target/hppa: Implement PA2.0 instructions hw/hppa: Map astro chip 64-bit I/O mem hw/hppa: Turn on 64-bit cpu for C3700 # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmVJqDEdHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV8n5Qf/R15CvXGMgjDJjoV2 # ILMFM+Rpg17SR2yu060sEZ01R3iHdobeCcDB184K0RI9JLrpcBFar+PeF023o9fn # O9MnfIyL6/ggzaeIpQ9AD2uT0HJMU9hLFoyQqQvnhDHHcT34raL2+Zkrkb2vvauH # XET7awXN9xYCnY4ALrfcapzlrHqI77ahz0vReUWPxk7eGY2ez8dEOiFW2WLBmuMx # mAFAMrFQhq66GjoMDl8JiGHD/KBJQ9X4eUAEotS27lTCOYU0ryA6dWBGqBSTWCUa # smpxkeGQKOew+717HV1H4FdCRYG1Rgm7yFN423JULeew+T7DHvfe0K55vMIulx5I # g3oVZA== # =dxC7 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 07 Nov 2023 11:00:01 HKT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * tag 'pull-pa-20231106' of https://gitlab.com/rth7680/qemu: (85 commits) hw/hppa: Allow C3700 with 64-bit and B160L with 32-bit CPU only hw/hppa: Turn on 64-bit CPU for C3700 machine hw/pci-host/astro: Trigger CPU irq on CPU HPA in high memory hw/pci-host/astro: Map Astro chip into 64-bit I/O memory region target/hppa: Improve interrupt logging target/hppa: Update IIAOQ, IIASQ for pa2.0 target/hppa: Create raise_exception_with_ior target/hppa: Add unwind_breg to CPUHPPAState target/hppa: Clear upper bits in mtctl for pa1.x target/hppa: Avoid async_safe_run_on_cpu on uniprocessor system target/hppa: Add pa2.0 cpu local tlb flushes target/hppa: Implement pa2.0 data prefetch instructions linux-user/hppa: Drop EXCP_DUMP from handled exceptions hw/hppa: Translate phys addresses for the cpu include/hw/elf: Remove truncating signed casts target/hppa: Return zero for r0 from load_gpr target/hppa: Precompute zero into DisasContext target/hppa: Fix interruption based on default PSW target/hppa: Implement PERMH target/hppa: Implement MIXH, MIXW ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
		
						commit
						bb541a7068
					
				| @ -1,4 +1,5 @@ | ||||
| TARGET_ARCH=hppa | ||||
| TARGET_ABI32=y | ||||
| TARGET_SYSTBL_ABI=common,32 | ||||
| TARGET_SYSTBL=syscall.tbl | ||||
| TARGET_BIG_ENDIAN=y | ||||
|  | ||||
| @ -87,7 +87,7 @@ static const MemoryRegionOps hppa_pci_ignore_ops = { | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| static ISABus *hppa_isa_bus(void) | ||||
| static ISABus *hppa_isa_bus(hwaddr addr) | ||||
| { | ||||
|     ISABus *isa_bus; | ||||
|     qemu_irq *isa_irqs; | ||||
| @ -96,8 +96,7 @@ static ISABus *hppa_isa_bus(void) | ||||
|     isa_region = g_new(MemoryRegion, 1); | ||||
|     memory_region_init_io(isa_region, NULL, &hppa_pci_ignore_ops, | ||||
|                           NULL, "isa-io", 0x800); | ||||
|     memory_region_add_subregion(get_system_memory(), IDE_HPA, | ||||
|                                 isa_region); | ||||
|     memory_region_add_subregion(get_system_memory(), addr, isa_region); | ||||
| 
 | ||||
|     isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region, | ||||
|                           &error_abort); | ||||
| @ -163,13 +162,24 @@ static const MemoryRegionOps hppa_io_helper_ops = { | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| typedef uint64_t TranslateFn(void *opaque, uint64_t addr); | ||||
| 
 | ||||
| static uint64_t cpu_hppa_to_phys(void *opaque, uint64_t addr) | ||||
| static uint64_t linux_kernel_virt_to_phys(void *opaque, uint64_t addr) | ||||
| { | ||||
|     addr &= (0x10000000 - 1); | ||||
|     return addr; | ||||
| } | ||||
| 
 | ||||
| static uint64_t translate_pa10(void *dummy, uint64_t addr) | ||||
| { | ||||
|     return (uint32_t)addr; | ||||
| } | ||||
| 
 | ||||
| static uint64_t translate_pa20(void *dummy, uint64_t addr) | ||||
| { | ||||
|     return hppa_abs_to_phys_pa2_w0(addr); | ||||
| } | ||||
| 
 | ||||
| static HPPACPU *cpu[HPPA_MAX_CPUS]; | ||||
| static uint64_t firmware_entry; | ||||
| 
 | ||||
| @ -179,15 +189,17 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device, | ||||
|     fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); | ||||
| } | ||||
| 
 | ||||
| static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus) | ||||
| static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus, | ||||
|                                  hwaddr addr) | ||||
| { | ||||
|     FWCfgState *fw_cfg; | ||||
|     uint64_t val; | ||||
|     const char qemu_version[] = QEMU_VERSION; | ||||
|     MachineClass *mc = MACHINE_GET_CLASS(ms); | ||||
|     int btlb_entries = HPPA_BTLB_ENTRIES(&cpu[0]->env); | ||||
|     int len; | ||||
| 
 | ||||
|     fw_cfg = fw_cfg_init_mem(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4); | ||||
|     fw_cfg = fw_cfg_init_mem(addr, addr + 4); | ||||
|     fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus); | ||||
|     fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, HPPA_MAX_CPUS); | ||||
|     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size); | ||||
| @ -196,11 +208,11 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus) | ||||
|     fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version", | ||||
|                     g_memdup(&val, sizeof(val)), sizeof(val)); | ||||
| 
 | ||||
|     val = cpu_to_le64(HPPA_TLB_ENTRIES - HPPA_BTLB_ENTRIES); | ||||
|     val = cpu_to_le64(HPPA_TLB_ENTRIES - btlb_entries); | ||||
|     fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries", | ||||
|                     g_memdup(&val, sizeof(val)), sizeof(val)); | ||||
| 
 | ||||
|     val = cpu_to_le64(HPPA_BTLB_ENTRIES); | ||||
|     val = cpu_to_le64(btlb_entries); | ||||
|     fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries", | ||||
|                     g_memdup(&val, sizeof(val)), sizeof(val)); | ||||
| 
 | ||||
| @ -257,32 +269,45 @@ static DinoState *dino_init(MemoryRegion *addr_space) | ||||
| /*
 | ||||
|  * Step 1: Create CPUs and Memory | ||||
|  */ | ||||
| static void machine_HP_common_init_cpus(MachineState *machine) | ||||
| static TranslateFn *machine_HP_common_init_cpus(MachineState *machine) | ||||
| { | ||||
|     MemoryRegion *addr_space = get_system_memory(); | ||||
|     MemoryRegion *cpu_region; | ||||
|     long i; | ||||
|     unsigned int smp_cpus = machine->smp.cpus; | ||||
|     char *name; | ||||
|     TranslateFn *translate; | ||||
|     MemoryRegion *cpu_region; | ||||
| 
 | ||||
|     /* Create CPUs.  */ | ||||
|     for (i = 0; i < smp_cpus; i++) { | ||||
|         name = g_strdup_printf("cpu%ld-io-eir", i); | ||||
|     for (unsigned int i = 0; i < smp_cpus; i++) { | ||||
|         cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type)); | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * For now, treat address layout as if PSW_W is clear. | ||||
|      * TODO: create a proper hppa64 board model and load elf64 firmware. | ||||
|      */ | ||||
|     if (hppa_is_pa20(&cpu[0]->env)) { | ||||
|         translate = translate_pa20; | ||||
|     } else { | ||||
|         translate = translate_pa10; | ||||
|     } | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < smp_cpus; i++) { | ||||
|         g_autofree char *name = g_strdup_printf("cpu%u-io-eir", i); | ||||
| 
 | ||||
|         cpu_region = g_new(MemoryRegion, 1); | ||||
|         memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops, | ||||
|                               cpu[i], name, 4); | ||||
|         memory_region_add_subregion(addr_space, CPU_HPA + i * 0x1000, | ||||
|         memory_region_add_subregion(addr_space, | ||||
|                                     translate(NULL, CPU_HPA + i * 0x1000), | ||||
|                                     cpu_region); | ||||
|         g_free(name); | ||||
|     } | ||||
| 
 | ||||
|     /* RTC and DebugOutputPort on CPU #0 */ | ||||
|     cpu_region = g_new(MemoryRegion, 1); | ||||
|     memory_region_init_io(cpu_region, OBJECT(cpu[0]), &hppa_io_helper_ops, | ||||
|                           cpu[0], "cpu0-io-rtc", 2 * sizeof(uint64_t)); | ||||
|     memory_region_add_subregion(addr_space, CPU_HPA + 16, cpu_region); | ||||
|     memory_region_add_subregion(addr_space, translate(NULL, CPU_HPA + 16), | ||||
|                                 cpu_region); | ||||
| 
 | ||||
|     /* Main memory region. */ | ||||
|     if (machine->ram_size > 3 * GiB) { | ||||
| @ -290,12 +315,15 @@ static void machine_HP_common_init_cpus(MachineState *machine) | ||||
|         exit(EXIT_FAILURE); | ||||
|     } | ||||
|     memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1); | ||||
| 
 | ||||
|     return translate; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Last creation step: Add SCSI discs, NICs, graphics & load firmware | ||||
|  */ | ||||
| static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) | ||||
| static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, | ||||
|                                         TranslateFn *translate) | ||||
| { | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
| @ -323,13 +351,13 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) | ||||
|         dev = qdev_new("artist"); | ||||
|         s = SYS_BUS_DEVICE(dev); | ||||
|         sysbus_realize_and_unref(s, &error_fatal); | ||||
|         sysbus_mmio_map(s, 0, LASI_GFX_HPA); | ||||
|         sysbus_mmio_map(s, 1, ARTIST_FB_ADDR); | ||||
|         sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA)); | ||||
|         sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR)); | ||||
|     } | ||||
| 
 | ||||
|     /* Network setup. */ | ||||
|     if (enable_lasi_lan()) { | ||||
|         lasi_82596_init(addr_space, LASI_LAN_HPA, | ||||
|         lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA), | ||||
|                         qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA)); | ||||
|     } | ||||
| 
 | ||||
| @ -373,7 +401,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) | ||||
|     qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier); | ||||
| 
 | ||||
|     /* fw_cfg configuration interface */ | ||||
|     create_fw_cfg(machine, pci_bus); | ||||
|     create_fw_cfg(machine, pci_bus, translate(NULL, FW_CFG_IO_BASE)); | ||||
| 
 | ||||
|     /* Load firmware.  Given that this is not "real" firmware,
 | ||||
|        but one explicitly written for the emulation, we might as | ||||
| @ -385,15 +413,10 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     size = load_elf(firmware_filename, NULL, NULL, NULL, | ||||
|     size = load_elf(firmware_filename, NULL, translate, NULL, | ||||
|                     &firmware_entry, &firmware_low, &firmware_high, NULL, | ||||
|                     true, EM_PARISC, 0, 0); | ||||
| 
 | ||||
|     /* Unfortunately, load_elf sign-extends reading elf32.  */ | ||||
|     firmware_entry = (target_ureg)firmware_entry; | ||||
|     firmware_low = (target_ureg)firmware_low; | ||||
|     firmware_high = (target_ureg)firmware_high; | ||||
| 
 | ||||
|     if (size < 0) { | ||||
|         error_report("could not load firmware '%s'", firmware_filename); | ||||
|         exit(1); | ||||
| @ -401,7 +424,8 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) | ||||
|     qemu_log_mask(CPU_LOG_PAGE, "Firmware loaded at 0x%08" PRIx64 | ||||
|                   "-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n", | ||||
|                   firmware_low, firmware_high, firmware_entry); | ||||
|     if (firmware_low < FIRMWARE_START || firmware_high >= FIRMWARE_END) { | ||||
|     if (firmware_low < translate(NULL, FIRMWARE_START) || | ||||
|         firmware_high >= translate(NULL, FIRMWARE_END)) { | ||||
|         error_report("Firmware overlaps with memory or IO space"); | ||||
|         exit(1); | ||||
|     } | ||||
| @ -410,18 +434,16 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) | ||||
|     rom_region = g_new(MemoryRegion, 1); | ||||
|     memory_region_init_ram(rom_region, NULL, "firmware", | ||||
|                            (FIRMWARE_END - FIRMWARE_START), &error_fatal); | ||||
|     memory_region_add_subregion(addr_space, FIRMWARE_START, rom_region); | ||||
|     memory_region_add_subregion(addr_space, | ||||
|                                 translate(NULL, FIRMWARE_START), rom_region); | ||||
| 
 | ||||
|     /* Load kernel */ | ||||
|     if (kernel_filename) { | ||||
|         size = load_elf(kernel_filename, NULL, &cpu_hppa_to_phys, | ||||
|         size = load_elf(kernel_filename, NULL, linux_kernel_virt_to_phys, | ||||
|                         NULL, &kernel_entry, &kernel_low, &kernel_high, NULL, | ||||
|                         true, EM_PARISC, 0, 0); | ||||
| 
 | ||||
|         /* Unfortunately, load_elf sign-extends reading elf32.  */ | ||||
|         kernel_entry = (target_ureg) cpu_hppa_to_phys(NULL, kernel_entry); | ||||
|         kernel_low = (target_ureg)kernel_low; | ||||
|         kernel_high = (target_ureg)kernel_high; | ||||
|         kernel_entry = linux_kernel_virt_to_phys(NULL, kernel_entry); | ||||
| 
 | ||||
|         if (size < 0) { | ||||
|             error_report("could not load kernel '%s'", kernel_filename); | ||||
| @ -499,41 +521,48 @@ static void machine_HP_B160L_init(MachineState *machine) | ||||
| { | ||||
|     DeviceState *dev, *dino_dev; | ||||
|     MemoryRegion *addr_space = get_system_memory(); | ||||
|     TranslateFn *translate; | ||||
|     ISABus *isa_bus; | ||||
|     PCIBus *pci_bus; | ||||
| 
 | ||||
|     /* Create CPUs and RAM.  */ | ||||
|     machine_HP_common_init_cpus(machine); | ||||
|     translate = machine_HP_common_init_cpus(machine); | ||||
| 
 | ||||
|     if (hppa_is_pa20(&cpu[0]->env)) { | ||||
|         error_report("The HP B160L workstation requires a 32-bit " | ||||
|                      "CPU. Use '-machine C3700' instead."); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     /* Init Lasi chip */ | ||||
|     lasi_dev = DEVICE(lasi_init()); | ||||
|     memory_region_add_subregion(addr_space, LASI_HPA, | ||||
|     memory_region_add_subregion(addr_space, translate(NULL, LASI_HPA), | ||||
|                                 sysbus_mmio_get_region( | ||||
|                                     SYS_BUS_DEVICE(lasi_dev), 0)); | ||||
| 
 | ||||
|     /* Init Dino (PCI host bus chip).  */ | ||||
|     dino_dev = DEVICE(dino_init(addr_space)); | ||||
|     memory_region_add_subregion(addr_space, DINO_HPA, | ||||
|     memory_region_add_subregion(addr_space, translate(NULL, DINO_HPA), | ||||
|                                 sysbus_mmio_get_region( | ||||
|                                     SYS_BUS_DEVICE(dino_dev), 0)); | ||||
|     pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci")); | ||||
|     assert(pci_bus); | ||||
| 
 | ||||
|     /* Create ISA bus, needed for PS/2 kbd/mouse port emulation */ | ||||
|     isa_bus = hppa_isa_bus(); | ||||
|     isa_bus = hppa_isa_bus(translate(NULL, IDE_HPA)); | ||||
|     assert(isa_bus); | ||||
| 
 | ||||
|     /* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */ | ||||
|     serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, | ||||
|     serial_mm_init(addr_space, translate(NULL, LASI_UART_HPA + 0x800), 0, | ||||
|         qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16, | ||||
|         serial_hd(0), DEVICE_BIG_ENDIAN); | ||||
| 
 | ||||
|     serial_mm_init(addr_space, DINO_UART_HPA + 0x800, 0, | ||||
|     serial_mm_init(addr_space, translate(NULL, DINO_UART_HPA + 0x800), 0, | ||||
|         qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16, | ||||
|         serial_hd(1), DEVICE_BIG_ENDIAN); | ||||
| 
 | ||||
|     /* Parallel port */ | ||||
|     parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, | ||||
|     parallel_mm_init(addr_space, translate(NULL, LASI_LPT_HPA + 0x800), 0, | ||||
|                      qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA), | ||||
|                      parallel_hds[0]); | ||||
| 
 | ||||
| @ -542,15 +571,17 @@ static void machine_HP_B160L_init(MachineState *machine) | ||||
|     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | ||||
|     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, | ||||
|                        qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA)); | ||||
|     memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA, | ||||
|     memory_region_add_subregion(addr_space, | ||||
|                                 translate(NULL, LASI_PS2KBD_HPA), | ||||
|                                 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), | ||||
|                                                        0)); | ||||
|     memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA + 0x100, | ||||
|     memory_region_add_subregion(addr_space, | ||||
|                                 translate(NULL, LASI_PS2KBD_HPA + 0x100), | ||||
|                                 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), | ||||
|                                                        1)); | ||||
| 
 | ||||
|     /* Add SCSI discs, NICs, graphics & load firmware */ | ||||
|     machine_HP_common_init_tail(machine, pci_bus); | ||||
|     machine_HP_common_init_tail(machine, pci_bus, translate); | ||||
| } | ||||
| 
 | ||||
| static AstroState *astro_init(void) | ||||
| @ -572,21 +603,28 @@ static void machine_HP_C3700_init(MachineState *machine) | ||||
|     AstroState *astro; | ||||
|     DeviceState *astro_dev; | ||||
|     MemoryRegion *addr_space = get_system_memory(); | ||||
|     TranslateFn *translate; | ||||
| 
 | ||||
|     /* Create CPUs and RAM.  */ | ||||
|     machine_HP_common_init_cpus(machine); | ||||
|     translate = machine_HP_common_init_cpus(machine); | ||||
| 
 | ||||
|     if (!hppa_is_pa20(&cpu[0]->env)) { | ||||
|         error_report("The HP C3000 workstation requires a 64-bit CPU. " | ||||
|                      "Use '-machine B160L' instead."); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     /* Init Astro and the Elroys (PCI host bus chips).  */ | ||||
|     astro = astro_init(); | ||||
|     astro_dev = DEVICE(astro); | ||||
|     memory_region_add_subregion(addr_space, ASTRO_HPA, | ||||
|     memory_region_add_subregion(addr_space, translate(NULL, ASTRO_HPA), | ||||
|                                 sysbus_mmio_get_region( | ||||
|                                     SYS_BUS_DEVICE(astro_dev), 0)); | ||||
|     pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(astro->elroy[0]), "pci")); | ||||
|     assert(pci_bus); | ||||
| 
 | ||||
|     /* Add SCSI discs, NICs, graphics & load firmware */ | ||||
|     machine_HP_common_init_tail(machine, pci_bus); | ||||
|     machine_HP_common_init_tail(machine, pci_bus, translate); | ||||
| } | ||||
| 
 | ||||
| static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) | ||||
| @ -608,10 +646,6 @@ static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) | ||||
| 
 | ||||
|         cs->exception_index = -1; | ||||
|         cs->halted = 0; | ||||
| 
 | ||||
|         /* clear any existing TLB and BTLB entries */ | ||||
|         memset(cpu[i]->env.tlb, 0, sizeof(cpu[i]->env.tlb)); | ||||
|         cpu[i]->env.tlb_last = HPPA_BTLB_ENTRIES; | ||||
|     } | ||||
| 
 | ||||
|     /* already initialized by machine_hppa_init()? */ | ||||
| @ -637,6 +671,11 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static const char *HP_B160L_machine_valid_cpu_types[] = { | ||||
|     TYPE_HPPA_CPU, | ||||
|     NULL | ||||
| }; | ||||
| 
 | ||||
| static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     MachineClass *mc = MACHINE_CLASS(oc); | ||||
| @ -644,6 +683,7 @@ static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data) | ||||
| 
 | ||||
|     mc->desc = "HP B160L workstation"; | ||||
|     mc->default_cpu_type = TYPE_HPPA_CPU; | ||||
|     mc->valid_cpu_types = HP_B160L_machine_valid_cpu_types; | ||||
|     mc->init = machine_HP_B160L_init; | ||||
|     mc->reset = hppa_machine_reset; | ||||
|     mc->block_default_type = IF_SCSI; | ||||
| @ -668,13 +708,19 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = { | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| static const char *HP_C3700_machine_valid_cpu_types[] = { | ||||
|     TYPE_HPPA64_CPU, | ||||
|     NULL | ||||
| }; | ||||
| 
 | ||||
| static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     MachineClass *mc = MACHINE_CLASS(oc); | ||||
|     NMIClass *nc = NMI_CLASS(oc); | ||||
| 
 | ||||
|     mc->desc = "HP C3700 workstation"; | ||||
|     mc->default_cpu_type = TYPE_HPPA_CPU; | ||||
|     mc->default_cpu_type = TYPE_HPPA64_CPU; | ||||
|     mc->valid_cpu_types = HP_C3700_machine_valid_cpu_types; | ||||
|     mc->init = machine_HP_C3700_init; | ||||
|     mc->reset = hppa_machine_reset; | ||||
|     mc->block_default_type = IF_SCSI; | ||||
|  | ||||
| @ -19,6 +19,8 @@ | ||||
| 
 | ||||
| #define TYPE_ASTRO_IOMMU_MEMORY_REGION "astro-iommu-memory-region" | ||||
| 
 | ||||
| #define F_EXTEND(addr) ((addr) | MAKE_64BIT_MASK(32, 32)) | ||||
| 
 | ||||
| #include "qemu/osdep.h" | ||||
| #include "qemu/module.h" | ||||
| #include "qemu/units.h" | ||||
| @ -386,7 +388,7 @@ static void elroy_set_irq(void *opaque, int irq, int level) | ||||
|         uint32_t ena = bit & ~old_ilr; | ||||
|         s->ilr = old_ilr | bit; | ||||
|         if (ena != 0) { | ||||
|             stl_be_phys(&address_space_memory, cpu_hpa, val & 63); | ||||
|             stl_be_phys(&address_space_memory, F_EXTEND(cpu_hpa), val & 63); | ||||
|         } | ||||
|     } else { | ||||
|         s->ilr = old_ilr & ~bit; | ||||
| @ -825,15 +827,16 @@ static void astro_realize(DeviceState *obj, Error **errp) | ||||
| 
 | ||||
|         /* map elroys mmio */ | ||||
|         map_size = LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC; | ||||
|         map_addr = (uint32_t) (LMMIO_DIST_BASE_ADDR + rope * map_size); | ||||
|         map_addr = F_EXTEND(LMMIO_DIST_BASE_ADDR + rope * map_size); | ||||
|         memory_region_init_alias(&elroy->pci_mmio_alias, OBJECT(elroy), | ||||
|                                  "pci-mmio-alias", | ||||
|                                  &elroy->pci_mmio, map_addr, map_size); | ||||
|                                  &elroy->pci_mmio, (uint32_t) map_addr, map_size); | ||||
|         memory_region_add_subregion(get_system_memory(), map_addr, | ||||
|                                  &elroy->pci_mmio_alias); | ||||
| 
 | ||||
|         /* map elroys io */ | ||||
|         map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC; | ||||
|         map_addr = (uint32_t) (IOS_DIST_BASE_ADDR + rope * map_size); | ||||
|         map_addr = F_EXTEND(IOS_DIST_BASE_ADDR + rope * map_size); | ||||
|         memory_region_add_subregion(get_system_memory(), map_addr, | ||||
|                                  &elroy->pci_io); | ||||
| 
 | ||||
|  | ||||
| @ -385,10 +385,11 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd, | ||||
|     } | ||||
| 
 | ||||
|     if (pflags) { | ||||
|         *pflags = (elf_word)ehdr.e_flags; | ||||
|         *pflags = ehdr.e_flags; | ||||
|     } | ||||
|     if (pentry) { | ||||
|         *pentry = ehdr.e_entry; | ||||
|     } | ||||
|     if (pentry) | ||||
|         *pentry = (uint64_t)(elf_sword)ehdr.e_entry; | ||||
| 
 | ||||
|     glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb); | ||||
| 
 | ||||
| @ -610,10 +611,12 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (lowaddr) | ||||
|         *lowaddr = (uint64_t)(elf_sword)low; | ||||
|     if (highaddr) | ||||
|         *highaddr = (uint64_t)(elf_sword)high; | ||||
|     if (lowaddr) { | ||||
|         *lowaddr = low; | ||||
|     } | ||||
|     if (highaddr) { | ||||
|         *highaddr = high; | ||||
|     } | ||||
|     ret = total_size; | ||||
|  fail: | ||||
|     if (mapped_file) { | ||||
|  | ||||
| @ -147,12 +147,10 @@ void cpu_loop(CPUHPPAState *env) | ||||
|             force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f); | ||||
|             break; | ||||
|         case EXCP_ILL: | ||||
|             EXCP_DUMP(env, "qemu: EXCP_ILL exception %#x\n", trapnr); | ||||
|             force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f); | ||||
|             break; | ||||
|         case EXCP_PRIV_OPR: | ||||
|             /* check for glibc ABORT_INSTRUCTION "iitlbp %r0,(%sr0, %r0)" */ | ||||
|             EXCP_DUMP(env, "qemu: EXCP_PRIV_OPR exception %#x\n", trapnr); | ||||
|             if (env->cr[CR_IIR] == 0x04000000) { | ||||
| 		    force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f); | ||||
|             } else { | ||||
| @ -160,7 +158,6 @@ void cpu_loop(CPUHPPAState *env) | ||||
|             } | ||||
|             break; | ||||
|         case EXCP_PRIV_REG: | ||||
|             EXCP_DUMP(env, "qemu: EXCP_PRIV_REG exception %#x\n", trapnr); | ||||
|             force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f); | ||||
|             break; | ||||
|         case EXCP_OVERFLOW: | ||||
| @ -173,7 +170,6 @@ void cpu_loop(CPUHPPAState *env) | ||||
|             force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f); | ||||
|             break; | ||||
|         case EXCP_BREAK: | ||||
|             EXCP_DUMP(env, "qemu: EXCP_BREAK exception %#x\n", trapnr); | ||||
|             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f & ~3); | ||||
|             break; | ||||
|         case EXCP_DEBUG: | ||||
|  | ||||
| @ -86,7 +86,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env) | ||||
| 
 | ||||
| static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc) | ||||
| { | ||||
|     target_ulong psw; | ||||
|     abi_ulong psw; | ||||
|     int i; | ||||
| 
 | ||||
|     __get_user(psw, &sc->sc_gr[0]); | ||||
| @ -150,10 +150,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, | ||||
|     haddr = ka->_sa_handler; | ||||
|     if (haddr & 2) { | ||||
|         /* Function descriptor.  */ | ||||
|         target_ulong *fdesc, dest; | ||||
|         abi_ptr *fdesc, dest; | ||||
| 
 | ||||
|         haddr &= -4; | ||||
|         fdesc = lock_user(VERIFY_READ, haddr, 2 * sizeof(target_ulong), 1); | ||||
|         fdesc = lock_user(VERIFY_READ, haddr, 2 * sizeof(abi_ptr), 1); | ||||
|         if (!fdesc) { | ||||
|             goto give_sigsegv; | ||||
|         } | ||||
|  | ||||
| @ -9,6 +9,6 @@ | ||||
| #define HPPA_TARGET_ELF_H | ||||
| static inline const char *cpu_get_model(uint32_t eflags) | ||||
| { | ||||
|     return "any"; | ||||
|     return "hppa"; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -8,26 +8,16 @@ | ||||
| #ifndef HPPA_CPU_PARAM_H | ||||
| #define HPPA_CPU_PARAM_H | ||||
| 
 | ||||
| #ifdef TARGET_HPPA64 | ||||
| # define TARGET_LONG_BITS             64 | ||||
| # define TARGET_REGISTER_BITS         64 | ||||
| # define TARGET_VIRT_ADDR_SPACE_BITS  64 | ||||
| # define TARGET_PHYS_ADDR_SPACE_BITS  64 | ||||
| #elif defined(CONFIG_USER_ONLY) | ||||
| # define TARGET_LONG_BITS             32 | ||||
| # define TARGET_REGISTER_BITS         32 | ||||
| #define TARGET_LONG_BITS              64 | ||||
| 
 | ||||
| #if defined(CONFIG_USER_ONLY) && defined(TARGET_ABI32) | ||||
| # define TARGET_PHYS_ADDR_SPACE_BITS  32 | ||||
| # define TARGET_VIRT_ADDR_SPACE_BITS  32 | ||||
| # define TARGET_PHYS_ADDR_SPACE_BITS  32 | ||||
| #else | ||||
| /*
 | ||||
|  * In order to form the GVA from space:offset, | ||||
|  * we need a 64-bit virtual address space. | ||||
|  */ | ||||
| # define TARGET_LONG_BITS             64 | ||||
| # define TARGET_REGISTER_BITS         32 | ||||
| # define TARGET_PHYS_ADDR_SPACE_BITS  64 | ||||
| # define TARGET_VIRT_ADDR_SPACE_BITS  64 | ||||
| # define TARGET_PHYS_ADDR_SPACE_BITS  32 | ||||
| #endif | ||||
| 
 | ||||
| #define TARGET_PAGE_BITS 12 | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -24,6 +24,7 @@ | ||||
| #include "qom/object.h" | ||||
| 
 | ||||
| #define TYPE_HPPA_CPU "hppa-cpu" | ||||
| #define TYPE_HPPA64_CPU "hppa64-cpu" | ||||
| 
 | ||||
| OBJECT_DECLARE_CPU_TYPE(HPPACPU, HPPACPUClass, HPPA_CPU) | ||||
| 
 | ||||
|  | ||||
| @ -77,9 +77,10 @@ static void hppa_restore_state_to_opc(CPUState *cs, | ||||
|     HPPACPU *cpu = HPPA_CPU(cs); | ||||
| 
 | ||||
|     cpu->env.iaoq_f = data[0]; | ||||
|     if (data[1] != (target_ureg)-1) { | ||||
|     if (data[1] != (target_ulong)-1) { | ||||
|         cpu->env.iaoq_b = data[1]; | ||||
|     } | ||||
|     cpu->env.unwind_breg = data[2]; | ||||
|     /*
 | ||||
|      * Since we were executing the instruction at IAOQ_F, and took some | ||||
|      * sort of action that provoked the cpu_restore_state, we can infer | ||||
| @ -137,8 +138,10 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp) | ||||
| #ifndef CONFIG_USER_ONLY | ||||
|     { | ||||
|         HPPACPU *cpu = HPPA_CPU(cs); | ||||
| 
 | ||||
|         cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, | ||||
|                                         hppa_cpu_alarm_timer, cpu); | ||||
|         hppa_ptlbe(&cpu->env); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| @ -156,7 +159,39 @@ static void hppa_cpu_initfn(Object *obj) | ||||
| 
 | ||||
| static ObjectClass *hppa_cpu_class_by_name(const char *cpu_model) | ||||
| { | ||||
|     return object_class_by_name(TYPE_HPPA_CPU); | ||||
|     g_autofree char *typename = g_strconcat(cpu_model, "-cpu", NULL); | ||||
|     ObjectClass *oc = object_class_by_name(typename); | ||||
| 
 | ||||
|     if (oc && | ||||
|         !object_class_is_abstract(oc) && | ||||
|         object_class_dynamic_cast(oc, TYPE_HPPA_CPU)) { | ||||
|         return oc; | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| static void hppa_cpu_list_entry(gpointer data, gpointer user_data) | ||||
| { | ||||
|     ObjectClass *oc = data; | ||||
|     CPUClass *cc = CPU_CLASS(oc); | ||||
|     const char *tname = object_class_get_name(oc); | ||||
|     g_autofree char *name = g_strndup(tname, strchr(tname, '-') - tname); | ||||
| 
 | ||||
|     if (cc->deprecation_note) { | ||||
|         qemu_printf("  %s (deprecated)\n", name); | ||||
|     } else { | ||||
|         qemu_printf("  %s\n", name); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void hppa_cpu_list(void) | ||||
| { | ||||
|     GSList *list; | ||||
| 
 | ||||
|     list = object_class_get_list_sorted(TYPE_HPPA_CPU, false); | ||||
|     qemu_printf("Available CPUs:\n"); | ||||
|     g_slist_foreach(list, hppa_cpu_list_entry, NULL); | ||||
|     g_slist_free(list); | ||||
| } | ||||
| 
 | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| @ -207,20 +242,21 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data) | ||||
|     cc->tcg_ops = &hppa_tcg_ops; | ||||
| } | ||||
| 
 | ||||
| static const TypeInfo hppa_cpu_type_info = { | ||||
|     .name = TYPE_HPPA_CPU, | ||||
|     .parent = TYPE_CPU, | ||||
|     .instance_size = sizeof(HPPACPU), | ||||
|     .instance_align = __alignof(HPPACPU), | ||||
|     .instance_init = hppa_cpu_initfn, | ||||
|     .abstract = false, | ||||
|     .class_size = sizeof(HPPACPUClass), | ||||
|     .class_init = hppa_cpu_class_init, | ||||
| static const TypeInfo hppa_cpu_type_infos[] = { | ||||
|     { | ||||
|         .name = TYPE_HPPA_CPU, | ||||
|         .parent = TYPE_CPU, | ||||
|         .instance_size = sizeof(HPPACPU), | ||||
|         .instance_align = __alignof(HPPACPU), | ||||
|         .instance_init = hppa_cpu_initfn, | ||||
|         .abstract = false, | ||||
|         .class_size = sizeof(HPPACPUClass), | ||||
|         .class_init = hppa_cpu_class_init, | ||||
|     }, | ||||
|     { | ||||
|         .name = TYPE_HPPA64_CPU, | ||||
|         .parent = TYPE_HPPA_CPU, | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| static void hppa_cpu_register_types(void) | ||||
| { | ||||
|     type_register_static(&hppa_cpu_type_info); | ||||
| } | ||||
| 
 | ||||
| type_init(hppa_cpu_register_types) | ||||
| DEFINE_TYPES(hppa_cpu_type_infos) | ||||
|  | ||||
| @ -23,6 +23,7 @@ | ||||
| #include "cpu-qom.h" | ||||
| #include "exec/cpu-defs.h" | ||||
| #include "qemu/cpu-float.h" | ||||
| #include "qemu/interval-tree.h" | ||||
| 
 | ||||
| /* PA-RISC 1.x processors have a strong memory model.  */ | ||||
| /* ??? While we do not yet implement PA-RISC 2.0, those processors have
 | ||||
| @ -30,21 +31,33 @@ | ||||
|    basis.  It's probably easier to fall back to a strong memory model.  */ | ||||
| #define TCG_GUEST_DEFAULT_MO        TCG_MO_ALL | ||||
| 
 | ||||
| #define MMU_KERNEL_IDX   11 | ||||
| #define MMU_PL1_IDX      12 | ||||
| #define MMU_PL2_IDX      13 | ||||
| #define MMU_USER_IDX     14 | ||||
| #define MMU_PHYS_IDX     15 | ||||
| #define MMU_KERNEL_IDX    7 | ||||
| #define MMU_KERNEL_P_IDX  8 | ||||
| #define MMU_PL1_IDX       9 | ||||
| #define MMU_PL1_P_IDX     10 | ||||
| #define MMU_PL2_IDX       11 | ||||
| #define MMU_PL2_P_IDX     12 | ||||
| #define MMU_USER_IDX      13 | ||||
| #define MMU_USER_P_IDX    14 | ||||
| #define MMU_PHYS_IDX      15 | ||||
| 
 | ||||
| #define PRIV_TO_MMU_IDX(priv)    (MMU_KERNEL_IDX + (priv)) | ||||
| #define MMU_IDX_TO_PRIV(mmu_idx) ((mmu_idx) - MMU_KERNEL_IDX) | ||||
| #define MMU_IDX_TO_PRIV(MIDX)       (((MIDX) - MMU_KERNEL_IDX) / 2) | ||||
| #define MMU_IDX_TO_P(MIDX)          (((MIDX) - MMU_KERNEL_IDX) & 1) | ||||
| #define PRIV_P_TO_MMU_IDX(PRIV, P)  ((PRIV) * 2 + !!(P) + MMU_KERNEL_IDX) | ||||
| 
 | ||||
| #define TARGET_INSN_START_EXTRA_WORDS 1 | ||||
| #define TARGET_INSN_START_EXTRA_WORDS 2 | ||||
| 
 | ||||
| /* No need to flush MMU_PHYS_IDX  */ | ||||
| #define HPPA_MMU_FLUSH_MASK                             \ | ||||
|         (1 << MMU_KERNEL_IDX | 1 << MMU_PL1_IDX |       \ | ||||
|          1 << MMU_PL2_IDX    | 1 << MMU_USER_IDX) | ||||
|         (1 << MMU_KERNEL_IDX | 1 << MMU_KERNEL_P_IDX |  \ | ||||
|          1 << MMU_PL1_IDX    | 1 << MMU_PL1_P_IDX    |  \ | ||||
|          1 << MMU_PL2_IDX    | 1 << MMU_PL2_P_IDX    |  \ | ||||
|          1 << MMU_USER_IDX   | 1 << MMU_USER_P_IDX) | ||||
| 
 | ||||
| /* Indicies to flush for access_id changes. */ | ||||
| #define HPPA_MMU_FLUSH_P_MASK \ | ||||
|         (1 << MMU_KERNEL_P_IDX | 1 << MMU_PL1_P_IDX  |  \ | ||||
|          1 << MMU_PL2_P_IDX    | 1 << MMU_USER_P_IDX) | ||||
| 
 | ||||
| /* Hardware exceptions, interrupts, faults, and traps.  */ | ||||
| #define EXCP_HPMC                1  /* high priority machine check */ | ||||
| @ -107,11 +120,7 @@ | ||||
| #define PSW_T            0x01000000 | ||||
| #define PSW_S            0x02000000 | ||||
| #define PSW_E            0x04000000 | ||||
| #ifdef TARGET_HPPA64 | ||||
| #define PSW_W            0x08000000 /* PA2.0 only */ | ||||
| #else | ||||
| #define PSW_W            0 | ||||
| #endif | ||||
| #define PSW_Z            0x40000000 /* PA1.x only */ | ||||
| #define PSW_Y            0x80000000 /* PA1.x only */ | ||||
| 
 | ||||
| @ -124,15 +133,12 @@ | ||||
| #define PSW_SM_P         PSW_P | ||||
| #define PSW_SM_Q         PSW_Q      /* Enable Interrupt State Collection */ | ||||
| #define PSW_SM_R         PSW_R      /* Enable Recover Counter Trap */ | ||||
| #ifdef TARGET_HPPA64 | ||||
| #define PSW_SM_E         0x100 | ||||
| #define PSW_SM_W         0x200      /* PA2.0 only : Enable Wide Mode */ | ||||
| #else | ||||
| #define PSW_SM_E         0 | ||||
| #define PSW_SM_W         0 | ||||
| #endif | ||||
| 
 | ||||
| #define CR_RC            0 | ||||
| #define CR_PSW_DEFAULT   6          /* see SeaBIOS PDC_PSW firmware call */ | ||||
| #define  PDC_PSW_WIDE_BIT 2 | ||||
| #define CR_PID1          8 | ||||
| #define CR_PID2          9 | ||||
| #define CR_PID3          12 | ||||
| @ -150,45 +156,37 @@ | ||||
| #define CR_IPSW          22 | ||||
| #define CR_EIRR          23 | ||||
| 
 | ||||
| #if TARGET_REGISTER_BITS == 32 | ||||
| typedef uint32_t target_ureg; | ||||
| typedef int32_t  target_sreg; | ||||
| #define TREG_FMT_lx   "%08"PRIx32 | ||||
| #define TREG_FMT_ld   "%"PRId32 | ||||
| #else | ||||
| typedef uint64_t target_ureg; | ||||
| typedef int64_t  target_sreg; | ||||
| #define TREG_FMT_lx   "%016"PRIx64 | ||||
| #define TREG_FMT_ld   "%"PRId64 | ||||
| #endif | ||||
| typedef struct HPPATLBEntry { | ||||
|     union { | ||||
|         IntervalTreeNode itree; | ||||
|         struct HPPATLBEntry *unused_next; | ||||
|     }; | ||||
| 
 | ||||
|     target_ulong pa; | ||||
| 
 | ||||
|     unsigned entry_valid : 1; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint64_t va_b; | ||||
|     uint64_t va_e; | ||||
|     target_ureg pa; | ||||
|     unsigned u : 1; | ||||
|     unsigned t : 1; | ||||
|     unsigned d : 1; | ||||
|     unsigned b : 1; | ||||
|     unsigned page_size : 4; | ||||
|     unsigned ar_type : 3; | ||||
|     unsigned ar_pl1 : 2; | ||||
|     unsigned ar_pl2 : 2; | ||||
|     unsigned entry_valid : 1; | ||||
|     unsigned access_id : 16; | ||||
| } hppa_tlb_entry; | ||||
| } HPPATLBEntry; | ||||
| 
 | ||||
| typedef struct CPUArchState { | ||||
|     target_ureg iaoq_f;      /* front */ | ||||
|     target_ureg iaoq_b;      /* back, aka next instruction */ | ||||
|     target_ulong iaoq_f;     /* front */ | ||||
|     target_ulong iaoq_b;     /* back, aka next instruction */ | ||||
| 
 | ||||
|     target_ureg gr[32]; | ||||
|     target_ulong gr[32]; | ||||
|     uint64_t fr[32]; | ||||
|     uint64_t sr[8];          /* stored shifted into place for gva */ | ||||
| 
 | ||||
|     target_ureg psw;         /* All psw bits except the following:  */ | ||||
|     target_ureg psw_n;       /* boolean */ | ||||
|     target_sreg psw_v;       /* in most significant bit */ | ||||
|     target_ulong psw;        /* All psw bits except the following:  */ | ||||
|     target_ulong psw_n;      /* boolean */ | ||||
|     target_long psw_v;       /* in most significant bit */ | ||||
| 
 | ||||
|     /* Splitting the carry-borrow field into the MSB and "the rest", allows
 | ||||
|      * for "the rest" to be deleted when it is unused, but the MSB is in use. | ||||
| @ -197,8 +195,8 @@ typedef struct CPUArchState { | ||||
|      * host has the appropriate add-with-carry insn to compute the msb). | ||||
|      * Therefore the carry bits are stored as: cb_msb : cb & 0x11111110. | ||||
|      */ | ||||
|     target_ureg psw_cb;      /* in least significant bit of next nibble */ | ||||
|     target_ureg psw_cb_msb;  /* boolean */ | ||||
|     target_ulong psw_cb;     /* in least significant bit of next nibble */ | ||||
|     target_ulong psw_cb_msb; /* boolean */ | ||||
| 
 | ||||
|     uint64_t iasq_f; | ||||
|     uint64_t iasq_b; | ||||
| @ -206,24 +204,40 @@ typedef struct CPUArchState { | ||||
|     uint32_t fr0_shadow;     /* flags, c, ca/cq, rm, d, enables */ | ||||
|     float_status fp_status; | ||||
| 
 | ||||
|     target_ureg cr[32];      /* control registers */ | ||||
|     target_ureg cr_back[2];  /* back of cr17/cr18 */ | ||||
|     target_ureg shadow[7];   /* shadow registers */ | ||||
|     target_ulong cr[32];     /* control registers */ | ||||
|     target_ulong cr_back[2]; /* back of cr17/cr18 */ | ||||
|     target_ulong shadow[7];  /* shadow registers */ | ||||
| 
 | ||||
|     /* ??? The number of entries isn't specified by the architecture.  */ | ||||
| #ifdef TARGET_HPPA64 | ||||
| #define HPPA_BTLB_FIXED         0       /* BTLBs are not supported in 64-bit machines */ | ||||
| #else | ||||
| #define HPPA_BTLB_FIXED         16 | ||||
| #endif | ||||
| #define HPPA_BTLB_VARIABLE      0 | ||||
|     /*
 | ||||
|      * During unwind of a memory insn, the base register of the address. | ||||
|      * This is used to construct CR_IOR for pa2.0. | ||||
|      */ | ||||
|     uint32_t unwind_breg; | ||||
| 
 | ||||
|     /*
 | ||||
|      * ??? The number of entries isn't specified by the architecture. | ||||
|      * BTLBs are not supported in 64-bit machines. | ||||
|      */ | ||||
| #define PA10_BTLB_FIXED         16 | ||||
| #define PA10_BTLB_VARIABLE      0 | ||||
| #define HPPA_TLB_ENTRIES        256 | ||||
| #define HPPA_BTLB_ENTRIES       (HPPA_BTLB_FIXED + HPPA_BTLB_VARIABLE) | ||||
| 
 | ||||
|     /* ??? Implement a unified itlb/dtlb for the moment.  */ | ||||
|     /* ??? We should use a more intelligent data structure.  */ | ||||
|     hppa_tlb_entry tlb[HPPA_TLB_ENTRIES]; | ||||
|     /* Index for round-robin tlb eviction. */ | ||||
|     uint32_t tlb_last; | ||||
| 
 | ||||
|     /*
 | ||||
|      * For pa1.x, the partial initialized, still invalid tlb entry | ||||
|      * which has had ITLBA performed, but not yet ITLBP. | ||||
|      */ | ||||
|     HPPATLBEntry *tlb_partial; | ||||
| 
 | ||||
|     /* Linked list of all invalid (unused) tlb entries. */ | ||||
|     HPPATLBEntry *tlb_unused; | ||||
| 
 | ||||
|     /* Root of the search tree for all valid tlb entries. */ | ||||
|     IntervalTreeRoot tlb_root; | ||||
| 
 | ||||
|     HPPATLBEntry tlb[HPPA_TLB_ENTRIES]; | ||||
| } CPUHPPAState; | ||||
| 
 | ||||
| /**
 | ||||
| @ -243,13 +257,23 @@ struct ArchCPU { | ||||
| 
 | ||||
| #include "exec/cpu-all.h" | ||||
| 
 | ||||
| static inline bool hppa_is_pa20(CPUHPPAState *env) | ||||
| { | ||||
|     return object_dynamic_cast(OBJECT(env_cpu(env)), TYPE_HPPA64_CPU) != NULL; | ||||
| } | ||||
| 
 | ||||
| static inline int HPPA_BTLB_ENTRIES(CPUHPPAState *env) | ||||
| { | ||||
|     return hppa_is_pa20(env) ? 0 : PA10_BTLB_FIXED + PA10_BTLB_VARIABLE; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch) | ||||
| { | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     return MMU_USER_IDX; | ||||
| #else | ||||
|     if (env->psw & (ifetch ? PSW_C : PSW_D)) { | ||||
|         return PRIV_TO_MMU_IDX(env->iaoq_f & 3); | ||||
|         return PRIV_P_TO_MMU_IDX(env->iaoq_f & 3, env->psw & PSW_P); | ||||
|     } | ||||
|     return MMU_PHYS_IDX;  /* mmu disabled */ | ||||
| #endif | ||||
| @ -259,23 +283,26 @@ void hppa_translate_init(void); | ||||
| 
 | ||||
| #define CPU_RESOLVING_TYPE TYPE_HPPA_CPU | ||||
| 
 | ||||
| static inline target_ulong hppa_form_gva_psw(target_ureg psw, uint64_t spc, | ||||
|                                              target_ureg off) | ||||
| static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc, | ||||
|                                              target_ulong off) | ||||
| { | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     return off; | ||||
| #else | ||||
|     off &= (psw & PSW_W ? 0x3fffffffffffffffull : 0xffffffffull); | ||||
|     off &= psw & PSW_W ? MAKE_64BIT_MASK(0, 62) : MAKE_64BIT_MASK(0, 32); | ||||
|     return spc | off; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc, | ||||
|                                          target_ureg off) | ||||
|                                          target_ulong off) | ||||
| { | ||||
|     return hppa_form_gva_psw(env->psw, spc, off); | ||||
| } | ||||
| 
 | ||||
| hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr); | ||||
| hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr); | ||||
| 
 | ||||
| /*
 | ||||
|  * Since PSW_{I,CB} will never need to be in tb->flags, reuse them. | ||||
|  * TB_FLAG_SR_SAME indicates that SR4 through SR7 all contain the | ||||
| @ -299,13 +326,12 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, | ||||
|     *cs_base = env->iaoq_b & -4; | ||||
|     flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; | ||||
| #else | ||||
|     /* ??? E, T, H, L, B, P bits need to be here, when implemented.  */ | ||||
|     flags |= env->psw & (PSW_W | PSW_C | PSW_D); | ||||
|     /* ??? E, T, H, L, B bits need to be here, when implemented.  */ | ||||
|     flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P); | ||||
|     flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT; | ||||
| 
 | ||||
|     *pc = (env->psw & PSW_C | ||||
|            ? hppa_form_gva_psw(env->psw, env->iasq_f, env->iaoq_f & -4) | ||||
|            : env->iaoq_f & -4); | ||||
|     *pc = hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0), | ||||
|                             env->iaoq_f & -4); | ||||
|     *cs_base = env->iasq_f; | ||||
| 
 | ||||
|     /* Insert a difference between IAOQ_B and IAOQ_F within the otherwise zero
 | ||||
| @ -313,8 +339,8 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, | ||||
|        which is the primary case we care about -- using goto_tb within a page. | ||||
|        Failure is indicated by a zero difference.  */ | ||||
|     if (env->iasq_f == env->iasq_b) { | ||||
|         target_sreg diff = env->iaoq_b - env->iaoq_f; | ||||
|         if (TARGET_REGISTER_BITS == 32 || diff == (int32_t)diff) { | ||||
|         target_long diff = env->iaoq_b - env->iaoq_f; | ||||
|         if (diff == (int32_t)diff) { | ||||
|             *cs_base |= (uint32_t)diff; | ||||
|         } | ||||
|     } | ||||
| @ -328,8 +354,8 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, | ||||
|     *pflags = flags; | ||||
| } | ||||
| 
 | ||||
| target_ureg cpu_hppa_get_psw(CPUHPPAState *env); | ||||
| void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg); | ||||
| target_ulong cpu_hppa_get_psw(CPUHPPAState *env); | ||||
| void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong); | ||||
| void cpu_hppa_loaded_fr0(CPUHPPAState *env); | ||||
| 
 | ||||
| #ifdef CONFIG_USER_ONLY | ||||
| @ -342,6 +368,7 @@ int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); | ||||
| int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); | ||||
| void hppa_cpu_dump_state(CPUState *cs, FILE *f, int); | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| void hppa_ptlbe(CPUHPPAState *env); | ||||
| hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr); | ||||
| bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size, | ||||
|                        MMUAccessType access_type, int mmu_idx, | ||||
| @ -350,7 +377,7 @@ void hppa_cpu_do_interrupt(CPUState *cpu); | ||||
| bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req); | ||||
| int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, | ||||
|                               int type, hwaddr *pphys, int *pprot, | ||||
|                               hppa_tlb_entry **tlb_entry); | ||||
|                               HPPATLBEntry **tlb_entry); | ||||
| extern const MemoryRegionOps hppa_io_eir_ops; | ||||
| extern const VMStateDescription vmstate_hppa_cpu; | ||||
| void hppa_cpu_alarm_timer(void *); | ||||
| @ -358,4 +385,9 @@ int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr); | ||||
| #endif | ||||
| G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra); | ||||
| 
 | ||||
| #define CPU_RESOLVING_TYPE TYPE_HPPA_CPU | ||||
| 
 | ||||
| #define cpu_list hppa_cpu_list | ||||
| void hppa_cpu_list(void); | ||||
| 
 | ||||
| #endif /* HPPA_CPU_H */ | ||||
|  | ||||
| @ -21,11 +21,16 @@ | ||||
| #include "cpu.h" | ||||
| #include "gdbstub/helpers.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * GDB 15 only supports PA1.0 via the remote protocol, and ignores | ||||
|  * any provided xml.  Which means that any attempt to provide more | ||||
|  * data results in "Remote 'g' packet reply is too long". | ||||
|  */ | ||||
| 
 | ||||
| int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) | ||||
| { | ||||
|     HPPACPU *cpu = HPPA_CPU(cs); | ||||
|     CPUHPPAState *env = &cpu->env; | ||||
|     target_ureg val; | ||||
|     CPUHPPAState *env = cpu_env(cs); | ||||
|     uint32_t val; | ||||
| 
 | ||||
|     switch (n) { | ||||
|     case 0: | ||||
| @ -139,24 +144,13 @@ int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     if (TARGET_REGISTER_BITS == 64) { | ||||
|         return gdb_get_reg64(mem_buf, val); | ||||
|     } else { | ||||
|         return gdb_get_reg32(mem_buf, val); | ||||
|     } | ||||
|     return gdb_get_reg32(mem_buf, val); | ||||
| } | ||||
| 
 | ||||
| int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) | ||||
| { | ||||
|     HPPACPU *cpu = HPPA_CPU(cs); | ||||
|     CPUHPPAState *env = &cpu->env; | ||||
|     target_ureg val; | ||||
| 
 | ||||
|     if (TARGET_REGISTER_BITS == 64) { | ||||
|         val = ldq_p(mem_buf); | ||||
|     } else { | ||||
|         val = ldl_p(mem_buf); | ||||
|     } | ||||
|     CPUHPPAState *env = cpu_env(cs); | ||||
|     uint32_t val = ldl_p(mem_buf); | ||||
| 
 | ||||
|     switch (n) { | ||||
|     case 0: | ||||
| @ -166,7 +160,7 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) | ||||
|         env->gr[n] = val; | ||||
|         break; | ||||
|     case 32: | ||||
|         env->cr[CR_SAR] = val; | ||||
|         env->cr[CR_SAR] = val & (hppa_is_pa20(env) ? 63 : 31); | ||||
|         break; | ||||
|     case 33: | ||||
|         env->iaoq_f = val; | ||||
| @ -278,5 +272,5 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     return sizeof(target_ureg); | ||||
|     return 4; | ||||
| } | ||||
|  | ||||
| @ -25,22 +25,32 @@ | ||||
| #include "exec/helper-proto.h" | ||||
| #include "qemu/qemu-print.h" | ||||
| 
 | ||||
| target_ureg cpu_hppa_get_psw(CPUHPPAState *env) | ||||
| target_ulong cpu_hppa_get_psw(CPUHPPAState *env) | ||||
| { | ||||
|     target_ureg psw; | ||||
|     target_ulong psw; | ||||
|     target_ulong mask1 = (target_ulong)-1 / 0xf; | ||||
|     target_ulong maskf = (target_ulong)-1 / 0xffff * 0xf; | ||||
| 
 | ||||
|     /* Fold carry bits down to 8 consecutive bits.  */ | ||||
|     /* ??? Needs tweaking for hppa64.  */ | ||||
|     /* .......b...c...d...e...f...g...h */ | ||||
|     psw = (env->psw_cb >> 4) & 0x01111111; | ||||
|     /* .......b..bc..cd..de..ef..fg..gh */ | ||||
|     /* ^^^b^^^c^^^d^^^e^^^f^^^g^^^h^^^i^^^j^^^k^^^l^^^m^^^n^^^o^^^p^^^^ */ | ||||
|     psw = (env->psw_cb >> 4) & mask1; | ||||
|     /* .......b...c...d...e...f...g...h...i...j...k...l...m...n...o...p */ | ||||
|     psw |= psw >> 3; | ||||
|     /* .............bcd............efgh */ | ||||
|     psw |= (psw >> 6) & 0x000f000f; | ||||
|     /* .........................bcdefgh */ | ||||
|     psw |= (psw >> 12) & 0xf; | ||||
|     psw |= env->psw_cb_msb << 7; | ||||
|     psw = (psw & 0xff) << 8; | ||||
|     /* .......b..bc..cd..de..ef..fg..gh..hi..ij..jk..kl..lm..mn..no..op */ | ||||
|     psw |= psw >> 6; | ||||
|     psw &= maskf; | ||||
|     /* .............bcd............efgh............ijkl............mnop */ | ||||
|     psw |= psw >> 12; | ||||
|     /* .............bcd.........bcdefgh........efghijkl........ijklmnop */ | ||||
|     psw |= env->psw_cb_msb << 39; | ||||
|     /* .............bcd........abcdefgh........efghijkl........ijklmnop */ | ||||
| 
 | ||||
|     /* For hppa64, the two 8-bit fields are discontiguous. */ | ||||
|     if (hppa_is_pa20(env)) { | ||||
|         psw = (psw & 0xff00000000ull) | ((psw & 0xff) << 8); | ||||
|     } else { | ||||
|         psw = (psw & 0xff) << 8; | ||||
|     } | ||||
| 
 | ||||
|     psw |= env->psw_n * PSW_N; | ||||
|     psw |= (env->psw_v < 0) * PSW_V; | ||||
| @ -49,16 +59,36 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env) | ||||
|     return psw; | ||||
| } | ||||
| 
 | ||||
| void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw) | ||||
| void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw) | ||||
| { | ||||
|     target_ureg old_psw = env->psw; | ||||
|     target_ureg cb = 0; | ||||
|     uint64_t reserved; | ||||
|     target_ulong cb = 0; | ||||
| 
 | ||||
|     /* Do not allow reserved bits to be set. */ | ||||
|     if (hppa_is_pa20(env)) { | ||||
|         reserved = MAKE_64BIT_MASK(40, 24) | MAKE_64BIT_MASK(28, 4); | ||||
|         reserved |= PSW_G;                  /* PA1.x only */ | ||||
|         reserved |= PSW_E;                  /* not implemented */ | ||||
|     } else { | ||||
|         reserved = MAKE_64BIT_MASK(32, 32) | MAKE_64BIT_MASK(28, 2); | ||||
|         reserved |= PSW_O | PSW_W;          /* PA2.0 only */ | ||||
|         reserved |= PSW_E | PSW_Y | PSW_Z;  /* not implemented */ | ||||
|     } | ||||
|     psw &= ~reserved; | ||||
| 
 | ||||
|     env->psw = psw & ~(PSW_N | PSW_V | PSW_CB); | ||||
|     env->psw_n = (psw / PSW_N) & 1; | ||||
|     env->psw_v = -((psw / PSW_V) & 1); | ||||
|     env->psw_cb_msb = (psw >> 15) & 1; | ||||
| 
 | ||||
|     env->psw_cb_msb = (psw >> 39) & 1; | ||||
|     cb |= ((psw >> 38) & 1) << 60; | ||||
|     cb |= ((psw >> 37) & 1) << 56; | ||||
|     cb |= ((psw >> 36) & 1) << 52; | ||||
|     cb |= ((psw >> 35) & 1) << 48; | ||||
|     cb |= ((psw >> 34) & 1) << 44; | ||||
|     cb |= ((psw >> 33) & 1) << 40; | ||||
|     cb |= ((psw >> 32) & 1) << 36; | ||||
|     cb |= ((psw >> 15) & 1) << 32; | ||||
|     cb |= ((psw >> 14) & 1) << 28; | ||||
|     cb |= ((psw >> 13) & 1) << 24; | ||||
|     cb |= ((psw >> 12) & 1) << 20; | ||||
| @ -67,29 +97,30 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw) | ||||
|     cb |= ((psw >>  9) & 1) <<  8; | ||||
|     cb |= ((psw >>  8) & 1) <<  4; | ||||
|     env->psw_cb = cb; | ||||
| 
 | ||||
|     /* If PSW_P changes, it affects how we translate addresses.  */ | ||||
|     if ((psw ^ old_psw) & PSW_P) { | ||||
| #ifndef CONFIG_USER_ONLY | ||||
|         tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); | ||||
| #endif | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags) | ||||
| { | ||||
|     HPPACPU *cpu = HPPA_CPU(cs); | ||||
|     CPUHPPAState *env = &cpu->env; | ||||
|     target_ureg psw = cpu_hppa_get_psw(env); | ||||
|     target_ureg psw_cb; | ||||
|     CPUHPPAState *env = cpu_env(cs); | ||||
|     target_ulong psw = cpu_hppa_get_psw(env); | ||||
|     target_ulong psw_cb; | ||||
|     char psw_c[20]; | ||||
|     int i; | ||||
|     int i, w; | ||||
|     uint64_t m; | ||||
| 
 | ||||
|     if (hppa_is_pa20(env)) { | ||||
|         w = 16; | ||||
|         m = UINT64_MAX; | ||||
|     } else { | ||||
|         w = 8; | ||||
|         m = UINT32_MAX; | ||||
|     } | ||||
| 
 | ||||
|     qemu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx | ||||
|                  " IIR " TREG_FMT_lx  "\n", | ||||
|                  " IIR %0*" PRIx64 "\n", | ||||
|                  hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f), | ||||
|                  hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b), | ||||
|                  env->cr[CR_IIR]); | ||||
|                  w, m & env->cr[CR_IIR]); | ||||
| 
 | ||||
|     psw_c[0]  = (psw & PSW_W ? 'W' : '-'); | ||||
|     psw_c[1]  = (psw & PSW_E ? 'E' : '-'); | ||||
| @ -110,13 +141,15 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags) | ||||
|     psw_c[16] = (psw & PSW_D ? 'D' : '-'); | ||||
|     psw_c[17] = (psw & PSW_I ? 'I' : '-'); | ||||
|     psw_c[18] = '\0'; | ||||
|     psw_cb = ((env->psw_cb >> 4) & 0x01111111) | (env->psw_cb_msb << 28); | ||||
|     psw_cb = ((env->psw_cb >> 4) & 0x1111111111111111ull) | ||||
|            | (env->psw_cb_msb << 60); | ||||
| 
 | ||||
|     qemu_fprintf(f, "PSW  " TREG_FMT_lx " CB   " TREG_FMT_lx " %s\n", | ||||
|                  psw, psw_cb, psw_c); | ||||
|     qemu_fprintf(f, "PSW  %0*" PRIx64 " CB   %0*" PRIx64 " %s\n", | ||||
|                  w, m & psw, w, m & psw_cb, psw_c); | ||||
| 
 | ||||
|     for (i = 0; i < 32; i++) { | ||||
|         qemu_fprintf(f, "GR%02d " TREG_FMT_lx "%c", i, env->gr[i], | ||||
|         qemu_fprintf(f, "GR%02d %0*" PRIx64 "%c", | ||||
|                      i, w, m & env->gr[i], | ||||
|                      (i & 3) == 3 ? '\n' : ' '); | ||||
|     } | ||||
| #ifndef CONFIG_USER_ONLY | ||||
|  | ||||
| @ -1,24 +1,28 @@ | ||||
| #if TARGET_REGISTER_BITS == 64 | ||||
| # define dh_alias_tr     i64 | ||||
| # define dh_typecode_tr  dh_typecode_i64 | ||||
| #else | ||||
| # define dh_alias_tr     i32 | ||||
| # define dh_typecode_tr  dh_typecode_i32 | ||||
| #endif | ||||
| #define dh_ctype_tr      target_ureg | ||||
| 
 | ||||
| DEF_HELPER_2(excp, noreturn, env, int) | ||||
| DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tr) | ||||
| DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tr) | ||||
| DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tl) | ||||
| DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tl) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tr) | ||||
| DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tr) | ||||
| DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tr) | ||||
| DEF_HELPER_FLAGS_3(stby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tr) | ||||
| DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(stby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_3(stdby_b, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(stdby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(stdby_e, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(stdby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tl) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_1(ldc_check, TCG_CALL_NO_RWG, void, tl) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_4(probe, TCG_CALL_NO_WG, tr, env, tl, i32, i32) | ||||
| DEF_HELPER_FLAGS_2(hadd_ss, TCG_CALL_NO_RWG_SE, i64, i64, i64) | ||||
| DEF_HELPER_FLAGS_2(hadd_us, TCG_CALL_NO_RWG_SE, i64, i64, i64) | ||||
| DEF_HELPER_FLAGS_2(havg, TCG_CALL_NO_RWG_SE, i64, i64, i64) | ||||
| DEF_HELPER_FLAGS_3(hshladd, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) | ||||
| DEF_HELPER_FLAGS_3(hshradd, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) | ||||
| DEF_HELPER_FLAGS_2(hsub_ss, TCG_CALL_NO_RWG_SE, i64, i64, i64) | ||||
| DEF_HELPER_FLAGS_2(hsub_us, TCG_CALL_NO_RWG_SE, i64, i64, i64) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_4(probe, TCG_CALL_NO_WG, tl, env, tl, i32, i32) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env) | ||||
| 
 | ||||
| @ -77,7 +81,7 @@ DEF_HELPER_FLAGS_4(fmpynfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) | ||||
| DEF_HELPER_FLAGS_4(fmpyfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) | ||||
| DEF_HELPER_FLAGS_4(fmpynfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) | ||||
| 
 | ||||
| DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tr) | ||||
| DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tl) | ||||
| 
 | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| DEF_HELPER_1(halt, noreturn, env) | ||||
| @ -85,15 +89,18 @@ DEF_HELPER_1(reset, noreturn, env) | ||||
| DEF_HELPER_1(getshadowregs, void, env) | ||||
| DEF_HELPER_1(rfi, void, env) | ||||
| DEF_HELPER_1(rfi_r, void, env) | ||||
| DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tr) | ||||
| DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tr) | ||||
| DEF_HELPER_FLAGS_2(write_eiem, TCG_CALL_NO_RWG, void, env, tr) | ||||
| DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tr, env, tr) | ||||
| DEF_HELPER_FLAGS_3(itlba, TCG_CALL_NO_RWG, void, env, tl, tr) | ||||
| DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr) | ||||
| DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tl) | ||||
| DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tl) | ||||
| DEF_HELPER_FLAGS_2(write_eiem, TCG_CALL_NO_RWG, void, env, tl) | ||||
| DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tl, env, tl) | ||||
| DEF_HELPER_FLAGS_3(itlba_pa11, TCG_CALL_NO_RWG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(itlbp_pa11, TCG_CALL_NO_RWG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(idtlbt_pa20, TCG_CALL_NO_RWG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_3(iitlbt_pa20, TCG_CALL_NO_RWG, void, env, tl, tl) | ||||
| DEF_HELPER_FLAGS_2(ptlb, TCG_CALL_NO_RWG, void, env, tl) | ||||
| DEF_HELPER_FLAGS_2(ptlb_l, TCG_CALL_NO_RWG, void, env, tl) | ||||
| DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env) | ||||
| DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tr, env, tl) | ||||
| DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tl, env, tl) | ||||
| DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env) | ||||
| DEF_HELPER_1(diag_btlb, void, env) | ||||
| #endif | ||||
|  | ||||
| @ -46,11 +46,16 @@ | ||||
| 
 | ||||
| %im5_0          0:s1 1:4 | ||||
| %im5_16         16:s1 17:4 | ||||
| %len5           0:5      !function=assemble_6 | ||||
| %len6_8         8:1 0:5  !function=assemble_6 | ||||
| %len6_12        12:1 0:5 !function=assemble_6 | ||||
| %cpos6_11       11:1 5:5 | ||||
| %ma_to_m        5:1 13:1 !function=ma_to_m | ||||
| %ma2_to_m       2:2      !function=ma_to_m | ||||
| %pos_to_m       0:1      !function=pos_to_m | ||||
| %neg_to_m       0:1      !function=neg_to_m | ||||
| %a_to_m         2:1      !function=neg_to_m | ||||
| %cmpbid_c       13:2     !function=cmpbid_c | ||||
| 
 | ||||
| #### | ||||
| # Argument set definitions | ||||
| @ -59,28 +64,43 @@ | ||||
| # All insns that need to form a virtual address should use this set. | ||||
| &ldst           t b x disp sp m scale size | ||||
| 
 | ||||
| &rr_cf          t r cf | ||||
| &rr_cf_d        t r cf d | ||||
| &rrr            t r1 r2 | ||||
| &rrr_cf         t r1 r2 cf | ||||
| &rrr_cf_sh      t r1 r2 cf sh | ||||
| &rrr_cf_d       t r1 r2 cf d | ||||
| &rrr_sh         t r1 r2 sh | ||||
| &rrr_cf_d_sh    t r1 r2 cf d sh | ||||
| &rri            t r i | ||||
| &rri_cf         t r i cf | ||||
| &rri_cf_d       t r i cf d | ||||
| 
 | ||||
| &rrb_c_f        disp n c f r1 r2 | ||||
| &rrb_c_d_f      disp n c d f r1 r2 | ||||
| &rib_c_f        disp n c f r i | ||||
| &rib_c_d_f      disp n c d f r i | ||||
| 
 | ||||
| #### | ||||
| # Format definitions | ||||
| #### | ||||
| 
 | ||||
| @rr_cf          ...... r:5 ..... cf:4 ....... t:5       &rr_cf | ||||
| @rr_cf_d        ...... r:5 ..... cf:4 ...... d:1 t:5    &rr_cf_d | ||||
| @rrr            ...... r2:5 r1:5 .... ....... t:5       &rrr | ||||
| @rrr_cf         ...... r2:5 r1:5 cf:4 ....... t:5       &rrr_cf | ||||
| @rrr_cf_sh      ...... r2:5 r1:5 cf:4 .... sh:2 . t:5   &rrr_cf_sh | ||||
| @rrr_cf_sh0     ...... r2:5 r1:5 cf:4 ....... t:5       &rrr_cf_sh sh=0 | ||||
| @rrr_cf_d       ...... r2:5 r1:5 cf:4 ...... d:1 t:5    &rrr_cf_d | ||||
| @rrr_sh         ...... r2:5 r1:5 ........ sh:2 . t:5    &rrr_sh | ||||
| @rrr_cf_d_sh    ...... r2:5 r1:5 cf:4 .... sh:2 d:1 t:5 &rrr_cf_d_sh | ||||
| @rrr_cf_d_sh0   ...... r2:5 r1:5 cf:4 ...... d:1 t:5    &rrr_cf_d_sh sh=0 | ||||
| @rri_cf         ...... r:5  t:5  cf:4 . ...........     &rri_cf i=%lowsign_11 | ||||
| @rri_cf_d       ...... r:5  t:5  cf:4 d:1 ...........   &rri_cf_d i=%lowsign_11 | ||||
| 
 | ||||
| @rrb_cf         ...... r2:5 r1:5 c:3 ........... n:1 .  \ | ||||
|                 &rrb_c_f disp=%assemble_12 | ||||
| @rrb_cdf        ...... r2:5 r1:5 c:3 ........... n:1 .  \ | ||||
|                 &rrb_c_d_f disp=%assemble_12 | ||||
| @rib_cf         ...... r:5 ..... c:3 ........... n:1 .  \ | ||||
|                 &rib_c_f disp=%assemble_12 i=%im5_16 | ||||
| @rib_cdf        ...... r:5 ..... c:3 ........... n:1 .  \ | ||||
|                 &rib_c_d_f disp=%assemble_12 i=%im5_16 | ||||
| 
 | ||||
| #### | ||||
| # System | ||||
| @ -130,6 +150,7 @@ nop_addrx       000001 ..... ..... -- 01001110 . 00000  @addrx # pdc | ||||
| 
 | ||||
| probe           000001 b:5 ri:5 sp:2 imm:1 100011 write:1 0 t:5 | ||||
| 
 | ||||
| # pa1.x tlb insert instructions | ||||
| ixtlbx          000001 b:5 r:5 sp:2 0100000 addr:1 0 00000      data=1 | ||||
| ixtlbx          000001 b:5 r:5 ... 000000 addr:1 0 00000        \ | ||||
|                 sp=%assemble_sr3x data=0 | ||||
| @ -137,9 +158,26 @@ ixtlbx          000001 b:5 r:5 ... 000000 addr:1 0 00000        \ | ||||
| # pcxl and pcxl2 Fast TLB Insert instructions | ||||
| ixtlbxf         000001 00000 r:5 00 0 data:1 01000 addr:1 0 00000 | ||||
| 
 | ||||
| pxtlbx          000001 b:5 x:5 sp:2 0100100 local:1 m:1 -----   data=1 | ||||
| pxtlbx          000001 b:5 x:5 ... 000100 local:1 m:1 -----     \ | ||||
|                 sp=%assemble_sr3x data=0 | ||||
| # pa2.0 tlb insert idtlbt and iitlbt instructions | ||||
| ixtlbt          000001 r2:5 r1:5 000 data:1 100000 0 00000    # idtlbt | ||||
| 
 | ||||
| # pdtlb, pitlb | ||||
| pxtlb           000001 b:5 x:5 sp:2 01001000 m:1 ----- \ | ||||
|                 &ldst disp=0 scale=0 size=0 t=0 | ||||
| pxtlb           000001 b:5 x:5 ...   0001000 m:1 ----- \ | ||||
|                 &ldst disp=0 scale=0 size=0 t=0 sp=%assemble_sr3x | ||||
| 
 | ||||
| # ... pa20 local | ||||
| pxtlb_l         000001 b:5 x:5 sp:2 01011000 m:1 ----- \ | ||||
|                 &ldst disp=0 scale=0 size=0 t=0 | ||||
| pxtlb_l         000001 b:5 x:5 ...   0011000 m:1 ----- \ | ||||
|                 &ldst disp=0 scale=0 size=0 t=0 sp=%assemble_sr3x | ||||
| 
 | ||||
| # pdtlbe, pitlbe | ||||
| pxtlbe          000001 b:5 x:5 sp:2 01001001 m:1 ----- \ | ||||
|                 &ldst disp=0 scale=0 size=0 t=0 | ||||
| pxtlbe          000001 b:5 x:5 ...   0001001 m:1 ----- \ | ||||
|                 &ldst disp=0 scale=0 size=0 t=0 sp=%assemble_sr3x | ||||
| 
 | ||||
| lpa             000001 b:5 x:5 sp:2 01001101 m:1 t:5    \ | ||||
|                 &ldst disp=0 scale=0 size=0 | ||||
| @ -150,30 +188,36 @@ lci             000001 ----- ----- -- 01001100 0 t:5 | ||||
| # Arith/Log | ||||
| #### | ||||
| 
 | ||||
| andcm           000010 ..... ..... .... 000000 - .....  @rrr_cf | ||||
| and             000010 ..... ..... .... 001000 - .....  @rrr_cf | ||||
| or              000010 ..... ..... .... 001001 - .....  @rrr_cf | ||||
| xor             000010 ..... ..... .... 001010 0 .....  @rrr_cf | ||||
| uxor            000010 ..... ..... .... 001110 0 .....  @rrr_cf | ||||
| andcm           000010 ..... ..... .... 000000 . .....  @rrr_cf_d | ||||
| and             000010 ..... ..... .... 001000 . .....  @rrr_cf_d | ||||
| or              000010 ..... ..... .... 001001 . .....  @rrr_cf_d | ||||
| xor             000010 ..... ..... .... 001010 . .....  @rrr_cf_d | ||||
| uxor            000010 ..... ..... .... 001110 . .....  @rrr_cf_d | ||||
| ds              000010 ..... ..... .... 010001 0 .....  @rrr_cf | ||||
| cmpclr          000010 ..... ..... .... 100010 0 .....  @rrr_cf | ||||
| uaddcm          000010 ..... ..... .... 100110 0 .....  @rrr_cf | ||||
| uaddcm_tc       000010 ..... ..... .... 100111 0 .....  @rrr_cf | ||||
| dcor            000010 ..... 00000 .... 101110 0 .....  @rr_cf | ||||
| dcor_i          000010 ..... 00000 .... 101111 0 .....  @rr_cf | ||||
| cmpclr          000010 ..... ..... .... 100010 . .....  @rrr_cf_d | ||||
| uaddcm          000010 ..... ..... .... 100110 . .....  @rrr_cf_d | ||||
| uaddcm_tc       000010 ..... ..... .... 100111 . .....  @rrr_cf_d | ||||
| dcor            000010 ..... 00000 .... 101110 . .....  @rr_cf_d | ||||
| dcor_i          000010 ..... 00000 .... 101111 . .....  @rr_cf_d | ||||
| 
 | ||||
| add             000010 ..... ..... .... 0110.. - .....  @rrr_cf_sh | ||||
| add_l           000010 ..... ..... .... 1010.. 0 .....  @rrr_cf_sh | ||||
| add_tsv         000010 ..... ..... .... 1110.. 0 .....  @rrr_cf_sh | ||||
| add_c           000010 ..... ..... .... 011100 0 .....  @rrr_cf_sh0 | ||||
| add_c_tsv       000010 ..... ..... .... 111100 0 .....  @rrr_cf_sh0 | ||||
| add             000010 ..... ..... .... 0110.. . .....  @rrr_cf_d_sh | ||||
| add_l           000010 ..... ..... .... 1010.. . .....  @rrr_cf_d_sh | ||||
| add_tsv         000010 ..... ..... .... 1110.. . .....  @rrr_cf_d_sh | ||||
| { | ||||
|   add_c         000010 ..... ..... .... 011100 . .....  @rrr_cf_d_sh0 | ||||
|   hshladd       000010 ..... ..... 0000 0111.. 0 .....  @rrr_sh | ||||
| } | ||||
| add_c_tsv       000010 ..... ..... .... 111100 . .....  @rrr_cf_d_sh0 | ||||
| 
 | ||||
| sub             000010 ..... ..... .... 010000 - .....  @rrr_cf | ||||
| sub_tsv         000010 ..... ..... .... 110000 0 .....  @rrr_cf | ||||
| sub_tc          000010 ..... ..... .... 010011 0 .....  @rrr_cf | ||||
| sub_tsv_tc      000010 ..... ..... .... 110011 0 .....  @rrr_cf | ||||
| sub_b           000010 ..... ..... .... 010100 0 .....  @rrr_cf | ||||
| sub_b_tsv       000010 ..... ..... .... 110100 0 .....  @rrr_cf | ||||
| sub             000010 ..... ..... .... 010000 . .....  @rrr_cf_d | ||||
| sub_tsv         000010 ..... ..... .... 110000 . .....  @rrr_cf_d | ||||
| sub_tc          000010 ..... ..... .... 010011 . .....  @rrr_cf_d | ||||
| sub_tsv_tc      000010 ..... ..... .... 110011 . .....  @rrr_cf_d | ||||
| { | ||||
|   sub_b         000010 ..... ..... .... 010100 . .....  @rrr_cf_d | ||||
|   hshradd       000010 ..... ..... 0000 0101.. 0 .....  @rrr_sh | ||||
| } | ||||
| sub_b_tsv       000010 ..... ..... .... 110100 . .....  @rrr_cf_d | ||||
| 
 | ||||
| ldil            001000 t:5 .....................        i=%assemble_21 | ||||
| addil           001010 r:5 .....................        i=%assemble_21 | ||||
| @ -187,7 +231,28 @@ addi_tc_tsv     101100 ..... ..... .... 1 ...........   @rri_cf | ||||
| subi            100101 ..... ..... .... 0 ...........   @rri_cf | ||||
| subi_tsv        100101 ..... ..... .... 1 ...........   @rri_cf | ||||
| 
 | ||||
| cmpiclr         100100 ..... ..... .... 0 ...........   @rri_cf | ||||
| cmpiclr         100100 ..... ..... .... . ...........   @rri_cf_d | ||||
| 
 | ||||
| hadd            000010 ..... ..... 00000011 11 0 .....  @rrr | ||||
| hadd_ss         000010 ..... ..... 00000011 01 0 .....  @rrr | ||||
| hadd_us         000010 ..... ..... 00000011 00 0 .....  @rrr | ||||
| 
 | ||||
| havg            000010 ..... ..... 00000010 11 0 .....  @rrr | ||||
| 
 | ||||
| hshl            111110 00000 r:5   100010 i:4  0 t:5    &rri | ||||
| hshr_s          111110 r:5   00000 110011 i:4  0 t:5    &rri | ||||
| hshr_u          111110 r:5   00000 110010 i:4  0 t:5    &rri | ||||
| 
 | ||||
| hsub            000010 ..... ..... 00000001 11 0 .....  @rrr | ||||
| hsub_ss         000010 ..... ..... 00000001 01 0 .....  @rrr | ||||
| hsub_us         000010 ..... ..... 00000001 00 0 .....  @rrr | ||||
| 
 | ||||
| mixh_l          111110 ..... ..... 1 00 00100000 .....  @rrr | ||||
| mixh_r          111110 ..... ..... 1 10 00100000 .....  @rrr | ||||
| mixw_l          111110 ..... ..... 1 00 00000000 .....  @rrr | ||||
| mixw_r          111110 ..... ..... 1 10 00000000 .....  @rrr | ||||
| 
 | ||||
| permh           111110 r1:5  r2:5  0 c0:2 0 c1:2 c2:2 c3:2 0 t:5 | ||||
| 
 | ||||
| #### | ||||
| # Index Mem | ||||
| @ -204,10 +269,16 @@ ld              000011 ..... ..... .. . 0 -- 00 size:2 ......   @ldstx | ||||
| st              000011 ..... ..... .. . 1 -- 10 size:2 ......   @stim5 | ||||
| ldc             000011 ..... ..... .. . 1 -- 0111      ......   @ldim5 size=2 | ||||
| ldc             000011 ..... ..... .. . 0 -- 0111      ......   @ldstx size=2 | ||||
| ldc             000011 ..... ..... .. . 1 -- 0101      ......   @ldim5 size=3 | ||||
| ldc             000011 ..... ..... .. . 0 -- 0101      ......   @ldstx size=3 | ||||
| lda             000011 ..... ..... .. . 1 -- 0110      ......   @ldim5 size=2 | ||||
| lda             000011 ..... ..... .. . 0 -- 0110      ......   @ldstx size=2 | ||||
| lda             000011 ..... ..... .. . 1 -- 0100      ......   @ldim5 size=3 | ||||
| lda             000011 ..... ..... .. . 0 -- 0100      ......   @ldstx size=3 | ||||
| sta             000011 ..... ..... .. . 1 -- 1110      ......   @stim5 size=2 | ||||
| sta             000011 ..... ..... .. . 1 -- 1111      ......   @stim5 size=3 | ||||
| stby            000011 b:5 r:5 sp:2 a:1 1 -- 1100 m:1   .....   disp=%im5_0 | ||||
| stdby           000011 b:5 r:5 sp:2 a:1 1 -- 1101 m:1   .....   disp=%im5_0 | ||||
| 
 | ||||
| @fldstwx        ...... b:5 x:5   sp:2 scale:1 ....... m:1 ..... \ | ||||
|                 &ldst t=%rt64 disp=0 size=2 | ||||
| @ -233,6 +304,8 @@ fstd            001011 ..... ..... .. . 1 -- 100 0 . .....      @fldstdi | ||||
| # Offset Mem | ||||
| #### | ||||
| 
 | ||||
| @ldstim11       ...... b:5 t:5 sp:2 ..............      \ | ||||
|                 &ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3 | ||||
| @ldstim14       ...... b:5 t:5 sp:2 ..............      \ | ||||
|                 &ldst disp=%lowsign_14 x=0 scale=0 m=0 | ||||
| @ldstim14m      ...... b:5 t:5 sp:2 ..............      \ | ||||
| @ -264,11 +337,11 @@ fstw            011110 b:5 ..... sp:2 ..............    \ | ||||
| fstw            011111 b:5 ..... sp:2 ...........0..    \ | ||||
|                 &ldst disp=%assemble_12a t=%rm64 m=0 x=0 scale=0 size=2 | ||||
| 
 | ||||
| fldd            010100 b:5 t:5   sp:2 .......... .. 1 . \ | ||||
|                 &ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3 | ||||
| ld              010100 ..... ..... .. ............0.    @ldstim11 | ||||
| fldd            010100 ..... ..... .. ............1.    @ldstim11 | ||||
| 
 | ||||
| fstd            011100 b:5 t:5   sp:2 .......... .. 1 . \ | ||||
|                 &ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3 | ||||
| st              011100 ..... ..... .. ............0.    @ldstim11 | ||||
| fstd            011100 ..... ..... .. ............1.    @ldstim11 | ||||
| 
 | ||||
| #### | ||||
| # Floating-point Multiply Add | ||||
| @ -286,16 +359,20 @@ fmpysub_d       100110 ..... ..... ..... ..... 1 .....  @mpyadd | ||||
| # Conditional Branches | ||||
| #### | ||||
| 
 | ||||
| bb_sar          110000 00000 r:5 c:1 10 ........... n:1 .  disp=%assemble_12 | ||||
| bb_imm          110001 p:5   r:5 c:1 10 ........... n:1 .  disp=%assemble_12 | ||||
| bb_sar          110000 00000 r:5 c:1 1 d:1 ........... n:1 . disp=%assemble_12 | ||||
| bb_imm          110001 p:5   r:5 c:1 1 d:1 ........... n:1 . disp=%assemble_12 | ||||
| 
 | ||||
| movb            110010 ..... ..... ... ........... . .  @rrb_cf f=0 | ||||
| movbi           110011 ..... ..... ... ........... . .  @rib_cf f=0 | ||||
| 
 | ||||
| cmpb            100000 ..... ..... ... ........... . .  @rrb_cf f=0 | ||||
| cmpb            100010 ..... ..... ... ........... . .  @rrb_cf f=1 | ||||
| cmpbi           100001 ..... ..... ... ........... . .  @rib_cf f=0 | ||||
| cmpbi           100011 ..... ..... ... ........... . .  @rib_cf f=1 | ||||
| cmpb            100000 ..... ..... ... ........... . .  @rrb_cdf d=0 f=0 | ||||
| cmpb            100010 ..... ..... ... ........... . .  @rrb_cdf d=0 f=1 | ||||
| cmpb            100111 ..... ..... ... ........... . .  @rrb_cdf d=1 f=0 | ||||
| cmpb            101111 ..... ..... ... ........... . .  @rrb_cdf d=1 f=1 | ||||
| cmpbi           100001 ..... ..... ... ........... . .  @rib_cdf d=0 f=0 | ||||
| cmpbi           100011 ..... ..... ... ........... . .  @rib_cdf d=0 f=1 | ||||
| cmpbi           111011 r:5 ..... f:1 .. ........... n:1 . \ | ||||
|                 &rib_c_d_f d=1 disp=%assemble_12 c=%cmpbid_c i=%im5_16 | ||||
| 
 | ||||
| addb            101000 ..... ..... ... ........... . .  @rrb_cf f=0 | ||||
| addb            101010 ..... ..... ... ........... . .  @rrb_cf f=1 | ||||
| @ -306,16 +383,28 @@ addbi           101011 ..... ..... ... ........... . .  @rib_cf f=1 | ||||
| # Shift, Extract, Deposit | ||||
| #### | ||||
| 
 | ||||
| shrpw_sar       110100 r2:5 r1:5 c:3 00 0    00000  t:5 | ||||
| shrpw_imm       110100 r2:5 r1:5 c:3 01 0    cpos:5 t:5 | ||||
| shrp_sar        110100 r2:5 r1:5 c:3 00 0 d:1 0000  t:5 | ||||
| shrp_imm        110100 r2:5 r1:5 c:3 01 0 cpos:5    t:5       d=0 | ||||
| shrp_imm        110100 r2:5 r1:5 c:3 0. 1 .....  t:5          \ | ||||
|                 d=1 cpos=%cpos6_11 | ||||
| 
 | ||||
| extrw_sar       110100 r:5  t:5  c:3 10 se:1 00000  clen:5 | ||||
| extrw_imm       110100 r:5  t:5  c:3 11 se:1 pos:5  clen:5 | ||||
| extr_sar        110100 r:5  t:5  c:3 10 se:1 00 000 .....     d=0 len=%len5 | ||||
| extr_sar        110100 r:5  t:5  c:3 10 se:1 1. 000 .....     d=1 len=%len6_8 | ||||
| extr_imm        110100 r:5  t:5  c:3 11 se:1 pos:5  .....     d=0 len=%len5 | ||||
| extr_imm        110110 r:5  t:5  c:3 .. se:1 ..... .....      \ | ||||
|                 d=1 len=%len6_12 pos=%cpos6_11 | ||||
| 
 | ||||
| depw_sar        110101 t:5 r:5   c:3 00 nz:1 00000  clen:5 | ||||
| depw_imm        110101 t:5 r:5   c:3 01 nz:1 cpos:5 clen:5 | ||||
| depwi_sar       110101 t:5 ..... c:3 10 nz:1 00000  clen:5      i=%im5_16 | ||||
| depwi_imm       110101 t:5 ..... c:3 11 nz:1 cpos:5 clen:5      i=%im5_16 | ||||
| dep_sar         110101 t:5 r:5   c:3 00 nz:1 00 000 .....     d=0 len=%len5 | ||||
| dep_sar         110101 t:5 r:5   c:3 00 nz:1 1. 000 .....     d=1 len=%len6_8 | ||||
| dep_imm         110101 t:5 r:5   c:3 01 nz:1 cpos:5 .....     d=0 len=%len5 | ||||
| dep_imm         111100 t:5 r:5   c:3 .. nz:1 ..... .....      \ | ||||
|                 d=1 len=%len6_12 cpos=%cpos6_11 | ||||
| depi_sar        110101 t:5 ..... c:3 10 nz:1 d:1 . 000 .....  \ | ||||
|                 i=%im5_16 len=%len6_8 | ||||
| depi_imm        110101 t:5 ..... c:3 11 nz:1 cpos:5 .....     \ | ||||
|                 d=0 i=%im5_16 len=%len5 | ||||
| depi_imm        111101 t:5 ..... c:3 .. nz:1 ..... .....      \ | ||||
|                 d=1 i=%im5_16 len=%len6_12 cpos=%cpos6_11 | ||||
| 
 | ||||
| #### | ||||
| # Branch External | ||||
| @ -343,6 +432,8 @@ bl              111010 ..... ..... 101 ........... n:1 .        &BL l=2 \ | ||||
|                 disp=%assemble_22 | ||||
| b_gate          111010 ..... ..... 001 ........... .   .        @bl | ||||
| blr             111010 l:5   x:5   010 00000000000 n:1 0 | ||||
| nopbts          111010 00000 00000 010 0---------1   0 1    # clrbts/popbts | ||||
| nopbts          111010 00000 ----- 010 00000000000   0 1    # pushbts/pushnom | ||||
| bv              111010 b:5   x:5   110 00000000000 n:1 0 | ||||
| bve             111010 b:5   00000 110 10000000000 n:1 -        l=0 | ||||
| bve             111010 b:5   00000 111 10000000000 n:1 -        l=2 | ||||
| @ -384,7 +475,7 @@ fmpyfadd_d      101110 rm1:5 rm2:5 ... 0 1 ..0 0 0 neg:1 t:5    ra3=%rc32 | ||||
| 
 | ||||
| @f0e_f_3        ...... ..... ..... ... .0 110 ..0 .....    \ | ||||
|                 &fclass3 r1=%ra64 r2=%rb64 t=%rt64 | ||||
| @f0e_d_3        ...... r1:5  r2:5  ... 01 110 000 t:5 | ||||
| @f0e_d_3        ...... r1:5  r2:5  ... 01 110 000 t:5      &fclass3 | ||||
| 
 | ||||
| # Floating point class 0 | ||||
| 
 | ||||
|  | ||||
| @ -52,9 +52,17 @@ static void io_eir_write(void *opaque, hwaddr addr, | ||||
|                          uint64_t data, unsigned size) | ||||
| { | ||||
|     HPPACPU *cpu = opaque; | ||||
|     int le_bit = ~data & (TARGET_REGISTER_BITS - 1); | ||||
|     CPUHPPAState *env = &cpu->env; | ||||
|     int widthm1 = 31; | ||||
|     int le_bit; | ||||
| 
 | ||||
|     cpu->env.cr[CR_EIRR] |= (target_ureg)1 << le_bit; | ||||
|     /* The default PSW.W controls the width of EIRR. */ | ||||
|     if (hppa_is_pa20(env) && env->cr[CR_PSW_DEFAULT] & PDC_PSW_WIDE_BIT) { | ||||
|         widthm1 = 63; | ||||
|     } | ||||
|     le_bit = ~data & widthm1; | ||||
| 
 | ||||
|     env->cr[CR_EIRR] |= 1ull << le_bit; | ||||
|     eval_interrupt(cpu); | ||||
| } | ||||
| 
 | ||||
| @ -73,7 +81,7 @@ void hppa_cpu_alarm_timer(void *opaque) | ||||
|     io_eir_write(opaque, 0, 0, 4); | ||||
| } | ||||
| 
 | ||||
| void HELPER(write_eirr)(CPUHPPAState *env, target_ureg val) | ||||
| void HELPER(write_eirr)(CPUHPPAState *env, target_ulong val) | ||||
| { | ||||
|     env->cr[CR_EIRR] &= ~val; | ||||
|     qemu_mutex_lock_iothread(); | ||||
| @ -81,7 +89,7 @@ void HELPER(write_eirr)(CPUHPPAState *env, target_ureg val) | ||||
|     qemu_mutex_unlock_iothread(); | ||||
| } | ||||
| 
 | ||||
| void HELPER(write_eiem)(CPUHPPAState *env, target_ureg val) | ||||
| void HELPER(write_eiem)(CPUHPPAState *env, target_ulong val) | ||||
| { | ||||
|     env->cr[CR_EIEM] = val; | ||||
|     qemu_mutex_lock_iothread(); | ||||
| @ -94,25 +102,37 @@ void hppa_cpu_do_interrupt(CPUState *cs) | ||||
|     HPPACPU *cpu = HPPA_CPU(cs); | ||||
|     CPUHPPAState *env = &cpu->env; | ||||
|     int i = cs->exception_index; | ||||
|     target_ureg iaoq_f = env->iaoq_f; | ||||
|     target_ureg iaoq_b = env->iaoq_b; | ||||
|     uint64_t iasq_f = env->iasq_f; | ||||
|     uint64_t iasq_b = env->iasq_b; | ||||
| 
 | ||||
|     target_ureg old_psw; | ||||
|     uint64_t old_psw; | ||||
| 
 | ||||
|     /* As documented in pa2.0 -- interruption handling.  */ | ||||
|     /* step 1 */ | ||||
|     env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env); | ||||
| 
 | ||||
|     /* step 2 -- note PSW_W == 0 for !HPPA64.  */ | ||||
|     cpu_hppa_put_psw(env, PSW_W | (i == EXCP_HPMC ? PSW_M : 0)); | ||||
|     /* step 2 -- Note PSW_W is masked out again for pa1.x */ | ||||
|     cpu_hppa_put_psw(env, | ||||
|                      (env->cr[CR_PSW_DEFAULT] & PDC_PSW_WIDE_BIT ? PSW_W : 0) | | ||||
|                      (i == EXCP_HPMC ? PSW_M : 0)); | ||||
| 
 | ||||
|     /* step 3 */ | ||||
|     env->cr[CR_IIASQ] = iasq_f >> 32; | ||||
|     env->cr_back[0] = iasq_b >> 32; | ||||
|     env->cr[CR_IIAOQ] = iaoq_f; | ||||
|     env->cr_back[1] = iaoq_b; | ||||
|     /*
 | ||||
|      * For pa1.x, IIASQ is simply a copy of IASQ. | ||||
|      * For pa2.0, IIASQ is the top bits of the virtual address, | ||||
|      *            or zero if translation is disabled. | ||||
|      */ | ||||
|     if (!hppa_is_pa20(env)) { | ||||
|         env->cr[CR_IIASQ] = env->iasq_f >> 32; | ||||
|         env->cr_back[0] = env->iasq_b >> 32; | ||||
|     } else if (old_psw & PSW_C) { | ||||
|         env->cr[CR_IIASQ] = | ||||
|             hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32; | ||||
|         env->cr_back[0] = | ||||
|             hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32; | ||||
|     } else { | ||||
|         env->cr[CR_IIASQ] = 0; | ||||
|         env->cr_back[0] = 0; | ||||
|     } | ||||
|     env->cr[CR_IIAOQ] = env->iaoq_f; | ||||
|     env->cr_back[1] = env->iaoq_b; | ||||
| 
 | ||||
|     if (old_psw & PSW_Q) { | ||||
|         /* step 5 */ | ||||
| @ -145,14 +165,13 @@ void hppa_cpu_do_interrupt(CPUState *cs) | ||||
|                 /* ??? An alternate fool-proof method would be to store the
 | ||||
|                    instruction data into the unwind info.  That's probably | ||||
|                    a bit too much in the way of extra storage required.  */ | ||||
|                 vaddr vaddr; | ||||
|                 hwaddr paddr; | ||||
|                 vaddr vaddr = env->iaoq_f & -4; | ||||
|                 hwaddr paddr = vaddr; | ||||
| 
 | ||||
|                 paddr = vaddr = iaoq_f & -4; | ||||
|                 if (old_psw & PSW_C) { | ||||
|                     int prot, t; | ||||
| 
 | ||||
|                     vaddr = hppa_form_gva_psw(old_psw, iasq_f, vaddr); | ||||
|                     vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr); | ||||
|                     t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX, | ||||
|                                                   0, &paddr, &prot, NULL); | ||||
|                     if (t >= 0) { | ||||
| @ -182,14 +201,14 @@ void hppa_cpu_do_interrupt(CPUState *cs) | ||||
| 
 | ||||
|     /* step 7 */ | ||||
|     if (i == EXCP_TOC) { | ||||
|         env->iaoq_f = FIRMWARE_START; | ||||
|         env->iaoq_f = hppa_form_gva(env, 0, FIRMWARE_START); | ||||
|         /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */ | ||||
|         env->gr[24] = env->cr_back[0]; | ||||
|         env->gr[25] = env->cr_back[1]; | ||||
|     } else { | ||||
|         env->iaoq_f = env->cr[CR_IVA] + 32 * i; | ||||
|         env->iaoq_f = hppa_form_gva(env, 0, env->cr[CR_IVA] + 32 * i); | ||||
|     } | ||||
|     env->iaoq_b = env->iaoq_f + 4; | ||||
|     env->iaoq_b = hppa_form_gva(env, 0, env->iaoq_f + 4); | ||||
|     env->iasq_f = 0; | ||||
|     env->iasq_b = 0; | ||||
| 
 | ||||
| @ -239,14 +258,10 @@ void hppa_cpu_do_interrupt(CPUState *cs) | ||||
|             snprintf(unknown, sizeof(unknown), "unknown %d", i); | ||||
|             name = unknown; | ||||
|         } | ||||
|         qemu_log("INT %6d: %s @ " TARGET_FMT_lx "," TARGET_FMT_lx | ||||
|                  " -> " TREG_FMT_lx " " TARGET_FMT_lx "\n", | ||||
|                  ++count, name, | ||||
|                  hppa_form_gva(env, iasq_f, iaoq_f), | ||||
|                  hppa_form_gva(env, iasq_b, iaoq_b), | ||||
|                  env->iaoq_f, | ||||
|                  hppa_form_gva(env, (uint64_t)env->cr[CR_ISR] << 32, | ||||
|                                env->cr[CR_IOR])); | ||||
|         qemu_log("INT %6d: %s @ " TARGET_FMT_lx ":" TARGET_FMT_lx | ||||
|                  " for " TARGET_FMT_lx ":" TARGET_FMT_lx "\n", | ||||
|                  ++count, name, env->cr[CR_IIASQ], env->cr[CR_IIAOQ], | ||||
|                  env->cr[CR_ISR], env->cr[CR_IOR]); | ||||
|     } | ||||
|     cs->exception_index = -1; | ||||
| } | ||||
|  | ||||
| @ -21,33 +21,12 @@ | ||||
| #include "cpu.h" | ||||
| #include "migration/cpu.h" | ||||
| 
 | ||||
| #if TARGET_REGISTER_BITS == 64 | ||||
| #define qemu_put_betr   qemu_put_be64 | ||||
| #define qemu_get_betr   qemu_get_be64 | ||||
| #define VMSTATE_UINTTL_V(_f, _s, _v) \ | ||||
|     VMSTATE_UINT64_V(_f, _s, _v) | ||||
| #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ | ||||
|     VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) | ||||
| #else | ||||
| #define qemu_put_betr   qemu_put_be32 | ||||
| #define qemu_get_betr   qemu_get_be32 | ||||
| #define VMSTATE_UINTTR_V(_f, _s, _v) \ | ||||
|     VMSTATE_UINT32_V(_f, _s, _v) | ||||
| #define VMSTATE_UINTTR_ARRAY_V(_f, _s, _n, _v) \ | ||||
|     VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) | ||||
| #endif | ||||
| 
 | ||||
| #define VMSTATE_UINTTR(_f, _s) \ | ||||
|     VMSTATE_UINTTR_V(_f, _s, 0) | ||||
| #define VMSTATE_UINTTR_ARRAY(_f, _s, _n) \ | ||||
|     VMSTATE_UINTTR_ARRAY_V(_f, _s, _n, 0) | ||||
| 
 | ||||
| 
 | ||||
| static int get_psw(QEMUFile *f, void *opaque, size_t size, | ||||
|                    const VMStateField *field) | ||||
| { | ||||
|     CPUHPPAState *env = opaque; | ||||
|     cpu_hppa_put_psw(env, qemu_get_betr(f)); | ||||
|     cpu_hppa_put_psw(env, qemu_get_be64(f)); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -55,7 +34,7 @@ static int put_psw(QEMUFile *f, void *opaque, size_t size, | ||||
|                    const VMStateField *field, JSONWriter *vmdesc) | ||||
| { | ||||
|     CPUHPPAState *env = opaque; | ||||
|     qemu_put_betr(f, cpu_hppa_get_psw(env)); | ||||
|     qemu_put_be64(f, cpu_hppa_get_psw(env)); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -65,70 +44,138 @@ static const VMStateInfo vmstate_psw = { | ||||
|     .put = put_psw, | ||||
| }; | ||||
| 
 | ||||
| /* FIXME: Use the PA2.0 format, which is a superset of the PA1.1 format.  */ | ||||
| static int get_tlb(QEMUFile *f, void *opaque, size_t size, | ||||
|                    const VMStateField *field) | ||||
| { | ||||
|     hppa_tlb_entry *ent = opaque; | ||||
|     uint32_t val; | ||||
|     HPPATLBEntry *ent = opaque; | ||||
|     uint64_t val; | ||||
| 
 | ||||
|     memset(ent, 0, sizeof(*ent)); | ||||
|     ent->itree.start = qemu_get_be64(f); | ||||
|     ent->itree.last = qemu_get_be64(f); | ||||
|     ent->pa = qemu_get_be64(f); | ||||
|     val = qemu_get_be64(f); | ||||
| 
 | ||||
|     ent->va_b = qemu_get_be64(f); | ||||
|     ent->pa = qemu_get_betr(f); | ||||
|     val = qemu_get_be32(f); | ||||
| 
 | ||||
|     ent->entry_valid = extract32(val, 0, 1); | ||||
|     ent->access_id = extract32(val, 1, 18); | ||||
|     ent->u = extract32(val, 19, 1); | ||||
|     ent->ar_pl2 = extract32(val, 20, 2); | ||||
|     ent->ar_pl1 = extract32(val, 22, 2); | ||||
|     ent->ar_type = extract32(val, 24, 3); | ||||
|     ent->b = extract32(val, 27, 1); | ||||
|     ent->d = extract32(val, 28, 1); | ||||
|     ent->t = extract32(val, 29, 1); | ||||
| 
 | ||||
|     ent->va_e = ent->va_b + TARGET_PAGE_SIZE - 1; | ||||
|     if (val) { | ||||
|         ent->t = extract64(val, 61, 1); | ||||
|         ent->d = extract64(val, 60, 1); | ||||
|         ent->b = extract64(val, 59, 1); | ||||
|         ent->ar_type = extract64(val, 56, 3); | ||||
|         ent->ar_pl1 = extract64(val, 54, 2); | ||||
|         ent->ar_pl2 = extract64(val, 52, 2); | ||||
|         ent->u = extract64(val, 51, 1); | ||||
|         /* o = bit 50 */ | ||||
|         /* p = bit 49 */ | ||||
|         ent->access_id = extract64(val, 1, 31); | ||||
|         ent->entry_valid = 1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int put_tlb(QEMUFile *f, void *opaque, size_t size, | ||||
|                    const VMStateField *field, JSONWriter *vmdesc) | ||||
| { | ||||
|     hppa_tlb_entry *ent = opaque; | ||||
|     uint32_t val = 0; | ||||
|     HPPATLBEntry *ent = opaque; | ||||
|     uint64_t val = 0; | ||||
| 
 | ||||
|     if (ent->entry_valid) { | ||||
|         val = 1; | ||||
|         val = deposit32(val, 1, 18, ent->access_id); | ||||
|         val = deposit32(val, 19, 1, ent->u); | ||||
|         val = deposit32(val, 20, 2, ent->ar_pl2); | ||||
|         val = deposit32(val, 22, 2, ent->ar_pl1); | ||||
|         val = deposit32(val, 24, 3, ent->ar_type); | ||||
|         val = deposit32(val, 27, 1, ent->b); | ||||
|         val = deposit32(val, 28, 1, ent->d); | ||||
|         val = deposit32(val, 29, 1, ent->t); | ||||
|         val = deposit64(val, 61, 1, ent->t); | ||||
|         val = deposit64(val, 60, 1, ent->d); | ||||
|         val = deposit64(val, 59, 1, ent->b); | ||||
|         val = deposit64(val, 56, 3, ent->ar_type); | ||||
|         val = deposit64(val, 54, 2, ent->ar_pl1); | ||||
|         val = deposit64(val, 52, 2, ent->ar_pl2); | ||||
|         val = deposit64(val, 51, 1, ent->u); | ||||
|         /* o = bit 50 */ | ||||
|         /* p = bit 49 */ | ||||
|         val = deposit64(val, 1, 31, ent->access_id); | ||||
|     } | ||||
| 
 | ||||
|     qemu_put_be64(f, ent->va_b); | ||||
|     qemu_put_betr(f, ent->pa); | ||||
|     qemu_put_be32(f, val); | ||||
|     qemu_put_be64(f, ent->itree.start); | ||||
|     qemu_put_be64(f, ent->itree.last); | ||||
|     qemu_put_be64(f, ent->pa); | ||||
|     qemu_put_be64(f, val); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static const VMStateInfo vmstate_tlb = { | ||||
| static const VMStateInfo vmstate_tlb_entry = { | ||||
|     .name = "tlb entry", | ||||
|     .get = get_tlb, | ||||
|     .put = put_tlb, | ||||
| }; | ||||
| 
 | ||||
| static VMStateField vmstate_env_fields[] = { | ||||
|     VMSTATE_UINTTR_ARRAY(gr, CPUHPPAState, 32), | ||||
| static int tlb_pre_load(void *opaque) | ||||
| { | ||||
|     CPUHPPAState *env = opaque; | ||||
| 
 | ||||
|     /*
 | ||||
|      * Zap the entire tlb, on-the-side data structures and all. | ||||
|      * Each tlb entry will have data re-filled by put_tlb. | ||||
|      */ | ||||
|     memset(env->tlb, 0, sizeof(env->tlb)); | ||||
|     memset(&env->tlb_root, 0, sizeof(env->tlb_root)); | ||||
|     env->tlb_unused = NULL; | ||||
|     env->tlb_partial = NULL; | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int tlb_post_load(void *opaque, int version_id) | ||||
| { | ||||
|     CPUHPPAState *env = opaque; | ||||
|     uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env); | ||||
|     HPPATLBEntry **unused = &env->tlb_unused; | ||||
|     HPPATLBEntry *partial = NULL; | ||||
| 
 | ||||
|     /*
 | ||||
|      * Re-create the interval tree from the valid entries. | ||||
|      * Truely invalid entries should have start == end == 0. | ||||
|      * Otherwise it should be the in-flight tlb_partial entry. | ||||
|      */ | ||||
|     for (uint32_t i = 0; i < ARRAY_SIZE(env->tlb); ++i) { | ||||
|         HPPATLBEntry *e = &env->tlb[i]; | ||||
| 
 | ||||
|         if (e->entry_valid) { | ||||
|             interval_tree_insert(&e->itree, &env->tlb_root); | ||||
|         } else if (i < btlb_entries) { | ||||
|             /* btlb not in unused list */ | ||||
|         } else if (partial == NULL && e->itree.start < e->itree.last) { | ||||
|             partial = e; | ||||
|         } else { | ||||
|             *unused = e; | ||||
|             unused = &e->unused_next; | ||||
|         } | ||||
|     } | ||||
|     env->tlb_partial = partial; | ||||
|     *unused = NULL; | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static const VMStateField vmstate_tlb_fields[] = { | ||||
|     VMSTATE_ARRAY(tlb, CPUHPPAState, | ||||
|                   ARRAY_SIZE(((CPUHPPAState *)0)->tlb), | ||||
|                   0, vmstate_tlb_entry, HPPATLBEntry), | ||||
|     VMSTATE_UINT32(tlb_last, CPUHPPAState), | ||||
|     VMSTATE_END_OF_LIST() | ||||
| }; | ||||
| 
 | ||||
| static const VMStateDescription vmstate_tlb = { | ||||
|     .name = "env/tlb", | ||||
|     .version_id = 1, | ||||
|     .minimum_version_id = 1, | ||||
|     .fields = vmstate_tlb_fields, | ||||
|     .pre_load = tlb_pre_load, | ||||
|     .post_load = tlb_post_load, | ||||
| }; | ||||
| 
 | ||||
| static const VMStateField vmstate_env_fields[] = { | ||||
|     VMSTATE_UINT64_ARRAY(gr, CPUHPPAState, 32), | ||||
|     VMSTATE_UINT64_ARRAY(fr, CPUHPPAState, 32), | ||||
|     VMSTATE_UINT64_ARRAY(sr, CPUHPPAState, 8), | ||||
|     VMSTATE_UINTTR_ARRAY(cr, CPUHPPAState, 32), | ||||
|     VMSTATE_UINTTR_ARRAY(cr_back, CPUHPPAState, 2), | ||||
|     VMSTATE_UINTTR_ARRAY(shadow, CPUHPPAState, 7), | ||||
|     VMSTATE_UINT64_ARRAY(cr, CPUHPPAState, 32), | ||||
|     VMSTATE_UINT64_ARRAY(cr_back, CPUHPPAState, 2), | ||||
|     VMSTATE_UINT64_ARRAY(shadow, CPUHPPAState, 7), | ||||
| 
 | ||||
|     /* Save the architecture value of the psw, not the internally
 | ||||
|        expanded version.  Since this architecture value does not | ||||
| @ -145,28 +192,29 @@ static VMStateField vmstate_env_fields[] = { | ||||
|         .offset = 0 | ||||
|     }, | ||||
| 
 | ||||
|     VMSTATE_UINTTR(iaoq_f, CPUHPPAState), | ||||
|     VMSTATE_UINTTR(iaoq_b, CPUHPPAState), | ||||
|     VMSTATE_UINT64(iaoq_f, CPUHPPAState), | ||||
|     VMSTATE_UINT64(iaoq_b, CPUHPPAState), | ||||
|     VMSTATE_UINT64(iasq_f, CPUHPPAState), | ||||
|     VMSTATE_UINT64(iasq_b, CPUHPPAState), | ||||
| 
 | ||||
|     VMSTATE_UINT32(fr0_shadow, CPUHPPAState), | ||||
| 
 | ||||
|     VMSTATE_ARRAY(tlb, CPUHPPAState, ARRAY_SIZE(((CPUHPPAState *)0)->tlb), | ||||
|                   0, vmstate_tlb, hppa_tlb_entry), | ||||
|     VMSTATE_UINT32(tlb_last, CPUHPPAState), | ||||
| 
 | ||||
|     VMSTATE_END_OF_LIST() | ||||
| }; | ||||
| 
 | ||||
| static const VMStateDescription *vmstate_env_subsections[] = { | ||||
|     &vmstate_tlb, | ||||
|     NULL | ||||
| }; | ||||
| 
 | ||||
| static const VMStateDescription vmstate_env = { | ||||
|     .name = "env", | ||||
|     .version_id = 1, | ||||
|     .minimum_version_id = 1, | ||||
|     .version_id = 3, | ||||
|     .minimum_version_id = 3, | ||||
|     .fields = vmstate_env_fields, | ||||
|     .subsections = vmstate_env_subsections, | ||||
| }; | ||||
| 
 | ||||
| static VMStateField vmstate_cpu_fields[] = { | ||||
| static const VMStateField vmstate_cpu_fields[] = { | ||||
|     VMSTATE_CPU(), | ||||
|     VMSTATE_STRUCT(env, HPPACPU, 1, vmstate_env, CPUHPPAState), | ||||
|     VMSTATE_END_OF_LIST() | ||||
|  | ||||
| @ -25,72 +25,136 @@ | ||||
| #include "hw/core/cpu.h" | ||||
| #include "trace.h" | ||||
| 
 | ||||
| static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr) | ||||
| hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr) | ||||
| { | ||||
|     int i; | ||||
|     if (likely(extract64(addr, 58, 4) != 0xf)) { | ||||
|         /* Memory address space */ | ||||
|         return addr & MAKE_64BIT_MASK(0, 62); | ||||
|     } | ||||
|     if (extract64(addr, 54, 4) != 0) { | ||||
|         /* I/O address space */ | ||||
|         return addr | MAKE_64BIT_MASK(62, 2); | ||||
|     } | ||||
|     /* PDC address space */ | ||||
|     return (addr & MAKE_64BIT_MASK(0, 54)) | MAKE_64BIT_MASK(60, 4); | ||||
| } | ||||
| 
 | ||||
|     for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) { | ||||
|         hppa_tlb_entry *ent = &env->tlb[i]; | ||||
|         if (ent->va_b <= addr && addr <= ent->va_e) { | ||||
|             trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid, | ||||
|                                       ent->va_b, ent->va_e, ent->pa); | ||||
|             return ent; | ||||
|         } | ||||
| hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr) | ||||
| { | ||||
|     if (likely(extract32(addr, 28, 4) != 0xf)) { | ||||
|         /* Memory address space */ | ||||
|         return addr & MAKE_64BIT_MASK(0, 32); | ||||
|     } | ||||
|     if (extract32(addr, 24, 4) != 0) { | ||||
|         /* I/O address space */ | ||||
|         return addr | MAKE_64BIT_MASK(32, 32); | ||||
|     } | ||||
|     /* PDC address space */ | ||||
|     return (addr & MAKE_64BIT_MASK(0, 24)) | MAKE_64BIT_MASK(60, 4); | ||||
| } | ||||
| 
 | ||||
| static hwaddr hppa_abs_to_phys(CPUHPPAState *env, vaddr addr) | ||||
| { | ||||
|     if (!hppa_is_pa20(env)) { | ||||
|         return addr; | ||||
|     } else if (env->psw & PSW_W) { | ||||
|         return hppa_abs_to_phys_pa2_w1(addr); | ||||
|     } else { | ||||
|         return hppa_abs_to_phys_pa2_w0(addr); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static HPPATLBEntry *hppa_find_tlb(CPUHPPAState *env, vaddr addr) | ||||
| { | ||||
|     IntervalTreeNode *i = interval_tree_iter_first(&env->tlb_root, addr, addr); | ||||
| 
 | ||||
|     if (i) { | ||||
|         HPPATLBEntry *ent = container_of(i, HPPATLBEntry, itree); | ||||
|         trace_hppa_tlb_find_entry(env, ent, ent->entry_valid, | ||||
|                                   ent->itree.start, ent->itree.last, ent->pa); | ||||
|         return ent; | ||||
|     } | ||||
|     trace_hppa_tlb_find_entry_not_found(env, addr); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent, | ||||
| static void hppa_flush_tlb_ent(CPUHPPAState *env, HPPATLBEntry *ent, | ||||
|                                bool force_flush_btlb) | ||||
| { | ||||
|     CPUState *cs = env_cpu(env); | ||||
|     bool is_btlb; | ||||
| 
 | ||||
|     if (!ent->entry_valid) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa); | ||||
|     trace_hppa_tlb_flush_ent(env, ent, ent->itree.start, | ||||
|                              ent->itree.last, ent->pa); | ||||
| 
 | ||||
|     tlb_flush_range_by_mmuidx(cs, ent->va_b, | ||||
|                                 ent->va_e - ent->va_b + 1, | ||||
|                                 HPPA_MMU_FLUSH_MASK, TARGET_LONG_BITS); | ||||
|     tlb_flush_range_by_mmuidx(cs, ent->itree.start, | ||||
|                               ent->itree.last - ent->itree.start + 1, | ||||
|                               HPPA_MMU_FLUSH_MASK, TARGET_LONG_BITS); | ||||
| 
 | ||||
|     /* never clear BTLBs, unless forced to do so. */ | ||||
|     if (ent < &env->tlb[HPPA_BTLB_ENTRIES] && !force_flush_btlb) { | ||||
|     /* Never clear BTLBs, unless forced to do so. */ | ||||
|     is_btlb = ent < &env->tlb[HPPA_BTLB_ENTRIES(env)]; | ||||
|     if (is_btlb && !force_flush_btlb) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     interval_tree_remove(&ent->itree, &env->tlb_root); | ||||
|     memset(ent, 0, sizeof(*ent)); | ||||
|     ent->va_b = -1; | ||||
| 
 | ||||
|     if (!is_btlb) { | ||||
|         ent->unused_next = env->tlb_unused; | ||||
|         env->tlb_unused = ent; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static hppa_tlb_entry *hppa_alloc_tlb_ent(CPUHPPAState *env) | ||||
| static void hppa_flush_tlb_range(CPUHPPAState *env, vaddr va_b, vaddr va_e) | ||||
| { | ||||
|     hppa_tlb_entry *ent; | ||||
|     uint32_t i; | ||||
|     IntervalTreeNode *i, *n; | ||||
| 
 | ||||
|     if (env->tlb_last < HPPA_BTLB_ENTRIES || env->tlb_last >= ARRAY_SIZE(env->tlb)) { | ||||
|         i = HPPA_BTLB_ENTRIES; | ||||
|         env->tlb_last = HPPA_BTLB_ENTRIES + 1; | ||||
|     } else { | ||||
|         i = env->tlb_last; | ||||
|         env->tlb_last++; | ||||
|     i = interval_tree_iter_first(&env->tlb_root, va_b, va_e); | ||||
|     for (; i ; i = n) { | ||||
|         HPPATLBEntry *ent = container_of(i, HPPATLBEntry, itree); | ||||
| 
 | ||||
|         /*
 | ||||
|          * Find the next entry now: In the normal case the current entry | ||||
|          * will be removed, but in the BTLB case it will remain. | ||||
|          */ | ||||
|         n = interval_tree_iter_next(i, va_b, va_e); | ||||
|         hppa_flush_tlb_ent(env, ent, false); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static HPPATLBEntry *hppa_alloc_tlb_ent(CPUHPPAState *env) | ||||
| { | ||||
|     HPPATLBEntry *ent = env->tlb_unused; | ||||
| 
 | ||||
|     if (ent == NULL) { | ||||
|         uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env); | ||||
|         uint32_t i = env->tlb_last; | ||||
| 
 | ||||
|         if (i < btlb_entries || i >= ARRAY_SIZE(env->tlb)) { | ||||
|             i = btlb_entries; | ||||
|         } | ||||
|         env->tlb_last = i + 1; | ||||
| 
 | ||||
|         ent = &env->tlb[i]; | ||||
|         hppa_flush_tlb_ent(env, ent, false); | ||||
|     } | ||||
| 
 | ||||
|     ent = &env->tlb[i]; | ||||
| 
 | ||||
|     hppa_flush_tlb_ent(env, ent, false); | ||||
|     env->tlb_unused = ent->unused_next; | ||||
|     return ent; | ||||
| } | ||||
| 
 | ||||
| int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, | ||||
|                               int type, hwaddr *pphys, int *pprot, | ||||
|                               hppa_tlb_entry **tlb_entry) | ||||
|                               HPPATLBEntry **tlb_entry) | ||||
| { | ||||
|     hwaddr phys; | ||||
|     int prot, r_prot, w_prot, x_prot, priv; | ||||
|     hppa_tlb_entry *ent; | ||||
|     HPPATLBEntry *ent; | ||||
|     int ret = -1; | ||||
| 
 | ||||
|     if (tlb_entry) { | ||||
| @ -106,7 +170,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, | ||||
| 
 | ||||
|     /* Find a valid tlb entry that matches the virtual address.  */ | ||||
|     ent = hppa_find_tlb(env, addr); | ||||
|     if (ent == NULL || !ent->entry_valid) { | ||||
|     if (ent == NULL) { | ||||
|         phys = 0; | ||||
|         prot = 0; | ||||
|         ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS; | ||||
| @ -118,7 +182,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, | ||||
|     } | ||||
| 
 | ||||
|     /* We now know the physical address.  */ | ||||
|     phys = ent->pa + (addr - ent->va_b); | ||||
|     phys = ent->pa + (addr - ent->itree.start); | ||||
| 
 | ||||
|     /* Map TLB access_rights field to QEMU protection.  */ | ||||
|     priv = MMU_IDX_TO_PRIV(mmu_idx); | ||||
| @ -144,7 +208,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, | ||||
|     } | ||||
| 
 | ||||
|     /* access_id == 0 means public page and no check is performed */ | ||||
|     if ((env->psw & PSW_P) && ent->access_id) { | ||||
|     if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) { | ||||
|         /* If bits [31:1] match, and bit 0 is set, suppress write.  */ | ||||
|         int match = ent->access_id * 2 + 1; | ||||
| 
 | ||||
| @ -197,7 +261,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, | ||||
|     } | ||||
| 
 | ||||
|  egress: | ||||
|     *pphys = phys; | ||||
|     *pphys = phys = hppa_abs_to_phys(env, phys); | ||||
|     *pprot = prot; | ||||
|     trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys); | ||||
|     return ret; | ||||
| @ -213,7 +277,7 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
|     /* ??? We really ought to know if the code mmu is disabled too,
 | ||||
|        in order to get the correct debugging dumps.  */ | ||||
|     if (!(cpu->env.psw & PSW_D)) { | ||||
|         return addr; | ||||
|         return hppa_abs_to_phys(&cpu->env, addr); | ||||
|     } | ||||
| 
 | ||||
|     excp = hppa_get_physical_address(&cpu->env, addr, MMU_KERNEL_IDX, 0, | ||||
| @ -225,13 +289,60 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
|     return excp == EXCP_DTLB_MISS ? -1 : phys; | ||||
| } | ||||
| 
 | ||||
| G_NORETURN static void | ||||
| raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr, | ||||
|                          vaddr addr, bool mmu_disabled) | ||||
| { | ||||
|     CPUState *cs = env_cpu(env); | ||||
| 
 | ||||
|     cs->exception_index = excp; | ||||
| 
 | ||||
|     if (env->psw & PSW_Q) { | ||||
|         /*
 | ||||
|          * For pa1.x, the offset and space never overlap, and so we | ||||
|          * simply extract the high and low part of the virtual address. | ||||
|          * | ||||
|          * For pa2.0, the formation of these are described in section | ||||
|          * "Interruption Parameter Registers", page 2-15. | ||||
|          */ | ||||
|         env->cr[CR_IOR] = (uint32_t)addr; | ||||
|         env->cr[CR_ISR] = addr >> 32; | ||||
| 
 | ||||
|         if (hppa_is_pa20(env)) { | ||||
|             if (mmu_disabled) { | ||||
|                 /*
 | ||||
|                  * If data translation was disabled, the ISR contains | ||||
|                  * the upper portion of the abs address, zero-extended. | ||||
|                  */ | ||||
|                 env->cr[CR_ISR] &= 0x3fffffff; | ||||
|             } else { | ||||
|                 /*
 | ||||
|                  * If data translation was enabled, the upper two bits | ||||
|                  * of the IOR (the b field) are equal to the two space | ||||
|                  * bits from the base register used to form the gva. | ||||
|                  */ | ||||
|                 uint64_t b; | ||||
| 
 | ||||
|                 cpu_restore_state(cs, retaddr); | ||||
| 
 | ||||
|                 b = env->gr[env->unwind_breg]; | ||||
|                 b >>= (env->psw & PSW_W ? 62 : 30); | ||||
|                 env->cr[CR_IOR] |= b << 62; | ||||
| 
 | ||||
|                 cpu_loop_exit(cs); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     cpu_loop_exit_restore(cs, retaddr); | ||||
| } | ||||
| 
 | ||||
| bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, | ||||
|                        MMUAccessType type, int mmu_idx, | ||||
|                        bool probe, uintptr_t retaddr) | ||||
| { | ||||
|     HPPACPU *cpu = HPPA_CPU(cs); | ||||
|     CPUHPPAState *env = &cpu->env; | ||||
|     hppa_tlb_entry *ent; | ||||
|     HPPATLBEntry *ent; | ||||
|     int prot, excp, a_prot; | ||||
|     hwaddr phys; | ||||
| 
 | ||||
| @ -254,56 +365,51 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, | ||||
|             return false; | ||||
|         } | ||||
|         trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx); | ||||
| 
 | ||||
|         /* Failure.  Raise the indicated exception.  */ | ||||
|         cs->exception_index = excp; | ||||
|         if (cpu->env.psw & PSW_Q) { | ||||
|             /* ??? Needs tweaking for hppa64.  */ | ||||
|             cpu->env.cr[CR_IOR] = addr; | ||||
|             cpu->env.cr[CR_ISR] = addr >> 32; | ||||
|         } | ||||
|         cpu_loop_exit_restore(cs, retaddr); | ||||
|         raise_exception_with_ior(env, excp, retaddr, | ||||
|                                  addr, mmu_idx == MMU_PHYS_IDX); | ||||
|     } | ||||
| 
 | ||||
|     trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK, | ||||
|                                 phys & TARGET_PAGE_MASK, size, type, mmu_idx); | ||||
|     /* Success!  Store the translation into the QEMU TLB.  */ | ||||
| 
 | ||||
|     /*
 | ||||
|      * Success!  Store the translation into the QEMU TLB. | ||||
|      * Note that we always install a single-page entry, because that | ||||
|      * is what works best with softmmu -- anything else will trigger | ||||
|      * the large page protection mask.  We do not require this, | ||||
|      * because we record the large page here in the hppa tlb. | ||||
|      */ | ||||
|     tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, | ||||
|                  prot, mmu_idx, TARGET_PAGE_SIZE << (ent ? 2 * ent->page_size : 0)); | ||||
|                  prot, mmu_idx, TARGET_PAGE_SIZE); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /* Insert (Insn/Data) TLB Address.  Note this is PA 1.1 only.  */ | ||||
| void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg) | ||||
| void HELPER(itlba_pa11)(CPUHPPAState *env, target_ulong addr, target_ulong reg) | ||||
| { | ||||
|     hppa_tlb_entry *empty = NULL; | ||||
|     int i; | ||||
|     HPPATLBEntry *ent; | ||||
| 
 | ||||
|     /* Zap any old entries covering ADDR; notice empty entries on the way.  */ | ||||
|     for (i = HPPA_BTLB_ENTRIES; i < ARRAY_SIZE(env->tlb); ++i) { | ||||
|         hppa_tlb_entry *ent = &env->tlb[i]; | ||||
|         if (ent->va_b <= addr && addr <= ent->va_e) { | ||||
|             if (ent->entry_valid) { | ||||
|                 hppa_flush_tlb_ent(env, ent, false); | ||||
|             } | ||||
|             if (!empty) { | ||||
|                 empty = ent; | ||||
|             } | ||||
|         } | ||||
|     /* Zap any old entries covering ADDR. */ | ||||
|     addr &= TARGET_PAGE_MASK; | ||||
|     hppa_flush_tlb_range(env, addr, addr + TARGET_PAGE_SIZE - 1); | ||||
| 
 | ||||
|     ent = env->tlb_partial; | ||||
|     if (ent == NULL) { | ||||
|         ent = hppa_alloc_tlb_ent(env); | ||||
|         env->tlb_partial = ent; | ||||
|     } | ||||
| 
 | ||||
|     /* If we didn't see an empty entry, evict one.  */ | ||||
|     if (empty == NULL) { | ||||
|         empty = hppa_alloc_tlb_ent(env); | ||||
|     } | ||||
| 
 | ||||
|     /* Note that empty->entry_valid == 0 already.  */ | ||||
|     empty->va_b = addr & TARGET_PAGE_MASK; | ||||
|     empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1; | ||||
|     empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS; | ||||
|     trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa); | ||||
|     /* Note that ent->entry_valid == 0 already.  */ | ||||
|     ent->itree.start = addr; | ||||
|     ent->itree.last = addr + TARGET_PAGE_SIZE - 1; | ||||
|     ent->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS; | ||||
|     trace_hppa_tlb_itlba(env, ent, ent->itree.start, ent->itree.last, ent->pa); | ||||
| } | ||||
| 
 | ||||
| static void set_access_bits(CPUHPPAState *env, hppa_tlb_entry *ent, target_ureg reg) | ||||
| static void set_access_bits_pa11(CPUHPPAState *env, HPPATLBEntry *ent, | ||||
|                                  target_ulong reg) | ||||
| { | ||||
|     ent->access_id = extract32(reg, 1, 18); | ||||
|     ent->u = extract32(reg, 19, 1); | ||||
| @ -314,49 +420,153 @@ static void set_access_bits(CPUHPPAState *env, hppa_tlb_entry *ent, target_ureg | ||||
|     ent->d = extract32(reg, 28, 1); | ||||
|     ent->t = extract32(reg, 29, 1); | ||||
|     ent->entry_valid = 1; | ||||
| 
 | ||||
|     interval_tree_insert(&ent->itree, &env->tlb_root); | ||||
|     trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, ent->ar_pl2, | ||||
|                          ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t); | ||||
| } | ||||
| 
 | ||||
| /* Insert (Insn/Data) TLB Protection.  Note this is PA 1.1 only.  */ | ||||
| void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg) | ||||
| void HELPER(itlbp_pa11)(CPUHPPAState *env, target_ulong addr, target_ulong reg) | ||||
| { | ||||
|     hppa_tlb_entry *ent = hppa_find_tlb(env, addr); | ||||
|     HPPATLBEntry *ent = env->tlb_partial; | ||||
| 
 | ||||
|     if (unlikely(ent == NULL)) { | ||||
|         qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n"); | ||||
|         return; | ||||
|     if (ent) { | ||||
|         env->tlb_partial = NULL; | ||||
|         if (ent->itree.start <= addr && addr <= ent->itree.last) { | ||||
|             set_access_bits_pa11(env, ent, reg); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     set_access_bits(env, ent, reg); | ||||
|     qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n"); | ||||
| } | ||||
| 
 | ||||
| /* Purge (Insn/Data) TLB.  This is explicitly page-based, and is
 | ||||
|    synchronous across all processors.  */ | ||||
| static void itlbt_pa20(CPUHPPAState *env, target_ulong r1, | ||||
|                        target_ulong r2, vaddr va_b) | ||||
| { | ||||
|     HPPATLBEntry *ent; | ||||
|     vaddr va_e; | ||||
|     uint64_t va_size; | ||||
|     int mask_shift; | ||||
| 
 | ||||
|     mask_shift = 2 * (r1 & 0xf); | ||||
|     va_size = TARGET_PAGE_SIZE << mask_shift; | ||||
|     va_b &= -va_size; | ||||
|     va_e = va_b + va_size - 1; | ||||
| 
 | ||||
|     hppa_flush_tlb_range(env, va_b, va_e); | ||||
|     ent = hppa_alloc_tlb_ent(env); | ||||
| 
 | ||||
|     ent->itree.start = va_b; | ||||
|     ent->itree.last = va_e; | ||||
|     ent->pa = (r1 << 7) & (TARGET_PAGE_MASK << mask_shift); | ||||
|     ent->t = extract64(r2, 61, 1); | ||||
|     ent->d = extract64(r2, 60, 1); | ||||
|     ent->b = extract64(r2, 59, 1); | ||||
|     ent->ar_type = extract64(r2, 56, 3); | ||||
|     ent->ar_pl1 = extract64(r2, 54, 2); | ||||
|     ent->ar_pl2 = extract64(r2, 52, 2); | ||||
|     ent->u = extract64(r2, 51, 1); | ||||
|     /* o = bit 50 */ | ||||
|     /* p = bit 49 */ | ||||
|     ent->access_id = extract64(r2, 1, 31); | ||||
|     ent->entry_valid = 1; | ||||
| 
 | ||||
|     interval_tree_insert(&ent->itree, &env->tlb_root); | ||||
|     trace_hppa_tlb_itlba(env, ent, ent->itree.start, ent->itree.last, ent->pa); | ||||
|     trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, | ||||
|                          ent->ar_pl2, ent->ar_pl1, ent->ar_type, | ||||
|                          ent->b, ent->d, ent->t); | ||||
| } | ||||
| 
 | ||||
| void HELPER(idtlbt_pa20)(CPUHPPAState *env, target_ulong r1, target_ulong r2) | ||||
| { | ||||
|     vaddr va_b = deposit64(env->cr[CR_IOR], 32, 32, env->cr[CR_ISR]); | ||||
|     itlbt_pa20(env, r1, r2, va_b); | ||||
| } | ||||
| 
 | ||||
| void HELPER(iitlbt_pa20)(CPUHPPAState *env, target_ulong r1, target_ulong r2) | ||||
| { | ||||
|     vaddr va_b = deposit64(env->cr[CR_IIAOQ], 32, 32, env->cr[CR_IIASQ]); | ||||
|     itlbt_pa20(env, r1, r2, va_b); | ||||
| } | ||||
| 
 | ||||
| /* Purge (Insn/Data) TLB. */ | ||||
| static void ptlb_work(CPUState *cpu, run_on_cpu_data data) | ||||
| { | ||||
|     CPUHPPAState *env = cpu_env(cpu); | ||||
|     target_ulong addr = (target_ulong) data.target_ptr; | ||||
|     hppa_tlb_entry *ent = hppa_find_tlb(env, addr); | ||||
|     vaddr start = data.target_ptr; | ||||
|     vaddr end; | ||||
| 
 | ||||
|     if (ent && ent->entry_valid) { | ||||
|         hppa_flush_tlb_ent(env, ent, false); | ||||
|     } | ||||
|     /*
 | ||||
|      * PA2.0 allows a range of pages encoded into GR[b], which we have | ||||
|      * copied into the bottom bits of the otherwise page-aligned address. | ||||
|      * PA1.x will always provide zero here, for a single page flush. | ||||
|      */ | ||||
|     end = start & 0xf; | ||||
|     start &= TARGET_PAGE_MASK; | ||||
|     end = TARGET_PAGE_SIZE << (2 * end); | ||||
|     end = start + end - 1; | ||||
| 
 | ||||
|     hppa_flush_tlb_range(env, start, end); | ||||
| } | ||||
| 
 | ||||
| /* This is local to the current cpu. */ | ||||
| void HELPER(ptlb_l)(CPUHPPAState *env, target_ulong addr) | ||||
| { | ||||
|     trace_hppa_tlb_ptlb_local(env); | ||||
|     ptlb_work(env_cpu(env), RUN_ON_CPU_TARGET_PTR(addr)); | ||||
| } | ||||
| 
 | ||||
| /* This is synchronous across all processors.  */ | ||||
| void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr) | ||||
| { | ||||
|     CPUState *src = env_cpu(env); | ||||
|     CPUState *cpu; | ||||
|     bool wait = false; | ||||
| 
 | ||||
|     trace_hppa_tlb_ptlb(env); | ||||
|     run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr); | ||||
| 
 | ||||
|     CPU_FOREACH(cpu) { | ||||
|         if (cpu != src) { | ||||
|             async_run_on_cpu(cpu, ptlb_work, data); | ||||
|             wait = true; | ||||
|         } | ||||
|     } | ||||
|     async_safe_run_on_cpu(src, ptlb_work, data); | ||||
|     if (wait) { | ||||
|         async_safe_run_on_cpu(src, ptlb_work, data); | ||||
|     } else { | ||||
|         ptlb_work(src, data); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void hppa_ptlbe(CPUHPPAState *env) | ||||
| { | ||||
|     uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env); | ||||
|     uint32_t i; | ||||
| 
 | ||||
|     /* Zap the (non-btlb) tlb entries themselves. */ | ||||
|     memset(&env->tlb[btlb_entries], 0, | ||||
|            sizeof(env->tlb) - btlb_entries * sizeof(env->tlb[0])); | ||||
|     env->tlb_last = btlb_entries; | ||||
|     env->tlb_partial = NULL; | ||||
| 
 | ||||
|     /* Put them all onto the unused list. */ | ||||
|     env->tlb_unused = &env->tlb[btlb_entries]; | ||||
|     for (i = btlb_entries; i < ARRAY_SIZE(env->tlb) - 1; ++i) { | ||||
|         env->tlb[i].unused_next = &env->tlb[i + 1]; | ||||
|     } | ||||
| 
 | ||||
|     /* Re-initialize the interval tree with only the btlb entries. */ | ||||
|     memset(&env->tlb_root, 0, sizeof(env->tlb_root)); | ||||
|     for (i = 0; i < btlb_entries; ++i) { | ||||
|         if (env->tlb[i].entry_valid) { | ||||
|             interval_tree_insert(&env->tlb[i].itree, &env->tlb_root); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); | ||||
| } | ||||
| 
 | ||||
| /* Purge (Insn/Data) TLB entry.  This affects an implementation-defined
 | ||||
| @ -365,17 +575,12 @@ void HELPER(ptlbe)(CPUHPPAState *env) | ||||
| { | ||||
|     trace_hppa_tlb_ptlbe(env); | ||||
|     qemu_log_mask(CPU_LOG_MMU, "FLUSH ALL TLB ENTRIES\n"); | ||||
|     memset(&env->tlb[HPPA_BTLB_ENTRIES], 0, | ||||
|         sizeof(env->tlb) - HPPA_BTLB_ENTRIES * sizeof(env->tlb[0])); | ||||
|     env->tlb_last = HPPA_BTLB_ENTRIES; | ||||
|     tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); | ||||
|     hppa_ptlbe(env); | ||||
| } | ||||
| 
 | ||||
| void cpu_hppa_change_prot_id(CPUHPPAState *env) | ||||
| { | ||||
|     if (env->psw & PSW_P) { | ||||
|         tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); | ||||
|     } | ||||
|     tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_P_MASK); | ||||
| } | ||||
| 
 | ||||
| void HELPER(change_prot_id)(CPUHPPAState *env) | ||||
| @ -383,7 +588,7 @@ void HELPER(change_prot_id)(CPUHPPAState *env) | ||||
|     cpu_hppa_change_prot_id(env); | ||||
| } | ||||
| 
 | ||||
| target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr) | ||||
| target_ulong HELPER(lpa)(CPUHPPAState *env, target_ulong addr) | ||||
| { | ||||
|     hwaddr phys; | ||||
|     int prot, excp; | ||||
| @ -391,16 +596,11 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr) | ||||
|     excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0, | ||||
|                                      &phys, &prot, NULL); | ||||
|     if (excp >= 0) { | ||||
|         if (env->psw & PSW_Q) { | ||||
|             /* ??? Needs tweaking for hppa64.  */ | ||||
|             env->cr[CR_IOR] = addr; | ||||
|             env->cr[CR_ISR] = addr >> 32; | ||||
|         } | ||||
|         if (excp == EXCP_DTLB_MISS) { | ||||
|             excp = EXCP_NA_DTLB_MISS; | ||||
|         } | ||||
|         trace_hppa_tlb_lpa_failed(env, addr); | ||||
|         hppa_dynamic_excp(env, excp, GETPC()); | ||||
|         raise_exception_with_ior(env, excp, GETPC(), addr, false); | ||||
|     } | ||||
|     trace_hppa_tlb_lpa_success(env, addr, phys); | ||||
|     return phys; | ||||
| @ -409,7 +609,7 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr) | ||||
| /* Return the ar_type of the TLB at VADDR, or -1.  */ | ||||
| int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr) | ||||
| { | ||||
|     hppa_tlb_entry *ent = hppa_find_tlb(env, vaddr); | ||||
|     HPPATLBEntry *ent = hppa_find_tlb(env, vaddr); | ||||
|     return ent ? ent->ar_type : -1; | ||||
| } | ||||
| 
 | ||||
| @ -424,15 +624,17 @@ void HELPER(diag_btlb)(CPUHPPAState *env) | ||||
|     unsigned int phys_page, len, slot; | ||||
|     int mmu_idx = cpu_mmu_index(env, 0); | ||||
|     uintptr_t ra = GETPC(); | ||||
|     hppa_tlb_entry *btlb; | ||||
|     HPPATLBEntry *btlb; | ||||
|     uint64_t virt_page; | ||||
|     uint32_t *vaddr; | ||||
|     uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env); | ||||
| 
 | ||||
| #ifdef TARGET_HPPA64 | ||||
|     /* BTLBs are not supported on 64-bit CPUs */ | ||||
|     env->gr[28] = -1; /* nonexistent procedure */ | ||||
|     return; | ||||
| #endif | ||||
|     if (btlb_entries == 0) { | ||||
|         env->gr[28] = -1; /* nonexistent procedure */ | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     env->gr[28] = 0; /* PDC_OK */ | ||||
| 
 | ||||
|     switch (env->gr[25]) { | ||||
| @ -446,8 +648,8 @@ void HELPER(diag_btlb)(CPUHPPAState *env) | ||||
|         } else { | ||||
|             vaddr[0] = cpu_to_be32(1); | ||||
|             vaddr[1] = cpu_to_be32(16 * 1024); | ||||
|             vaddr[2] = cpu_to_be32(HPPA_BTLB_FIXED); | ||||
|             vaddr[3] = cpu_to_be32(HPPA_BTLB_VARIABLE); | ||||
|             vaddr[2] = cpu_to_be32(PA10_BTLB_FIXED); | ||||
|             vaddr[3] = cpu_to_be32(PA10_BTLB_VARIABLE); | ||||
|         } | ||||
|         break; | ||||
|     case 1: | ||||
| @ -464,15 +666,17 @@ void HELPER(diag_btlb)(CPUHPPAState *env) | ||||
|                     (long long) virt_page << TARGET_PAGE_BITS, | ||||
|                     (long long) (virt_page + len) << TARGET_PAGE_BITS, | ||||
|                     (long long) virt_page, phys_page, len, slot); | ||||
|         if (slot < HPPA_BTLB_ENTRIES) { | ||||
|         if (slot < btlb_entries) { | ||||
|             btlb = &env->tlb[slot]; | ||||
|             /* force flush of possibly existing BTLB entry */ | ||||
| 
 | ||||
|             /* Force flush of possibly existing BTLB entry. */ | ||||
|             hppa_flush_tlb_ent(env, btlb, true); | ||||
|             /* create new BTLB entry */ | ||||
|             btlb->va_b = virt_page << TARGET_PAGE_BITS; | ||||
|             btlb->va_e = btlb->va_b + len * TARGET_PAGE_SIZE - 1; | ||||
| 
 | ||||
|             /* Create new BTLB entry */ | ||||
|             btlb->itree.start = virt_page << TARGET_PAGE_BITS; | ||||
|             btlb->itree.last = btlb->itree.start + len * TARGET_PAGE_SIZE - 1; | ||||
|             btlb->pa = phys_page << TARGET_PAGE_BITS; | ||||
|             set_access_bits(env, btlb, env->gr[20]); | ||||
|             set_access_bits_pa11(env, btlb, env->gr[20]); | ||||
|             btlb->t = 0; | ||||
|             btlb->d = 1; | ||||
|         } else { | ||||
| @ -484,7 +688,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env) | ||||
|         slot = env->gr[22]; | ||||
|         qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE slot %d\n", | ||||
|                                     slot); | ||||
|         if (slot < HPPA_BTLB_ENTRIES) { | ||||
|         if (slot < btlb_entries) { | ||||
|             btlb = &env->tlb[slot]; | ||||
|             hppa_flush_tlb_ent(env, btlb, true); | ||||
|         } else { | ||||
| @ -494,7 +698,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env) | ||||
|     case 3: | ||||
|         /* Purge all BTLB entries */ | ||||
|         qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE_ALL\n"); | ||||
|         for (slot = 0; slot < HPPA_BTLB_ENTRIES; slot++) { | ||||
|         for (slot = 0; slot < btlb_entries; slot++) { | ||||
|             btlb = &env->tlb[slot]; | ||||
|             hppa_flush_tlb_ent(env, btlb, true); | ||||
|         } | ||||
|  | ||||
| @ -42,25 +42,25 @@ G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra) | ||||
|     cpu_loop_exit_restore(cs, ra); | ||||
| } | ||||
| 
 | ||||
| void HELPER(tsv)(CPUHPPAState *env, target_ureg cond) | ||||
| void HELPER(tsv)(CPUHPPAState *env, target_ulong cond) | ||||
| { | ||||
|     if (unlikely((target_sreg)cond < 0)) { | ||||
|     if (unlikely((target_long)cond < 0)) { | ||||
|         hppa_dynamic_excp(env, EXCP_OVERFLOW, GETPC()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HELPER(tcond)(CPUHPPAState *env, target_ureg cond) | ||||
| void HELPER(tcond)(CPUHPPAState *env, target_ulong cond) | ||||
| { | ||||
|     if (unlikely(cond)) { | ||||
|         hppa_dynamic_excp(env, EXCP_COND, GETPC()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void atomic_store_3(CPUHPPAState *env, target_ulong addr, | ||||
|                            uint32_t val, uintptr_t ra) | ||||
| static void atomic_store_mask32(CPUHPPAState *env, target_ulong addr, | ||||
|                                 uint32_t val, uint32_t mask, uintptr_t ra) | ||||
| { | ||||
|     int mmu_idx = cpu_mmu_index(env, 0); | ||||
|     uint32_t old, new, cmp, mask, *haddr; | ||||
|     uint32_t old, new, cmp, *haddr; | ||||
|     void *vaddr; | ||||
| 
 | ||||
|     vaddr = probe_access(env, addr, 3, MMU_DATA_STORE, mmu_idx, ra); | ||||
| @ -81,7 +81,36 @@ static void atomic_store_3(CPUHPPAState *env, target_ulong addr, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val, | ||||
| static void atomic_store_mask64(CPUHPPAState *env, target_ulong addr, | ||||
|                                 uint64_t val, uint64_t mask, | ||||
|                                 int size, uintptr_t ra) | ||||
| { | ||||
| #ifdef CONFIG_ATOMIC64 | ||||
|     int mmu_idx = cpu_mmu_index(env, 0); | ||||
|     uint64_t old, new, cmp, *haddr; | ||||
|     void *vaddr; | ||||
| 
 | ||||
|     vaddr = probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, ra); | ||||
|     if (vaddr == NULL) { | ||||
|         cpu_loop_exit_atomic(env_cpu(env), ra); | ||||
|     } | ||||
|     haddr = (uint64_t *)((uintptr_t)vaddr & -8); | ||||
| 
 | ||||
|     old = *haddr; | ||||
|     while (1) { | ||||
|         new = be32_to_cpu((cpu_to_be32(old) & ~mask) | (val & mask)); | ||||
|         cmp = qatomic_cmpxchg__nocheck(haddr, old, new); | ||||
|         if (cmp == old) { | ||||
|             return; | ||||
|         } | ||||
|         old = cmp; | ||||
|     } | ||||
| #else | ||||
|     cpu_loop_exit_atomic(env_cpu(env), ra); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ulong val, | ||||
|                       bool parallel, uintptr_t ra) | ||||
| { | ||||
|     switch (addr & 3) { | ||||
| @ -94,7 +123,7 @@ static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val, | ||||
|     case 1: | ||||
|         /* The 3 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_3(env, addr, val, ra); | ||||
|             atomic_store_mask32(env, addr, val, 0x00ffffffu, ra); | ||||
|         } else { | ||||
|             cpu_stb_data_ra(env, addr, val >> 16, ra); | ||||
|             cpu_stw_data_ra(env, addr + 1, val, ra); | ||||
| @ -106,25 +135,92 @@ static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ureg val) | ||||
| static void do_stdby_b(CPUHPPAState *env, target_ulong addr, uint64_t val, | ||||
|                        bool parallel, uintptr_t ra) | ||||
| { | ||||
|     switch (addr & 7) { | ||||
|     case 7: | ||||
|         cpu_stb_data_ra(env, addr, val, ra); | ||||
|         break; | ||||
|     case 6: | ||||
|         cpu_stw_data_ra(env, addr, val, ra); | ||||
|         break; | ||||
|     case 5: | ||||
|         /* The 3 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask32(env, addr, val, 0x00ffffffu, ra); | ||||
|         } else { | ||||
|             cpu_stb_data_ra(env, addr, val >> 16, ra); | ||||
|             cpu_stw_data_ra(env, addr + 1, val, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 4: | ||||
|         cpu_stl_data_ra(env, addr, val, ra); | ||||
|         break; | ||||
|     case 3: | ||||
|         /* The 5 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask64(env, addr, val, 0x000000ffffffffffull, 5, ra); | ||||
|         } else { | ||||
|             cpu_stb_data_ra(env, addr, val >> 32, ra); | ||||
|             cpu_stl_data_ra(env, addr + 1, val, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 2: | ||||
|         /* The 6 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask64(env, addr, val, 0x0000ffffffffffffull, 6, ra); | ||||
|         } else { | ||||
|             cpu_stw_data_ra(env, addr, val >> 32, ra); | ||||
|             cpu_stl_data_ra(env, addr + 2, val, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 1: | ||||
|         /* The 7 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask64(env, addr, val, 0x00ffffffffffffffull, 7, ra); | ||||
|         } else { | ||||
|             cpu_stb_data_ra(env, addr, val >> 48, ra); | ||||
|             cpu_stw_data_ra(env, addr + 1, val >> 32, ra); | ||||
|             cpu_stl_data_ra(env, addr + 3, val, ra); | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         cpu_stq_data_ra(env, addr, val, ra); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val) | ||||
| { | ||||
|     do_stby_b(env, addr, val, false, GETPC()); | ||||
| } | ||||
| 
 | ||||
| void HELPER(stby_b_parallel)(CPUHPPAState *env, target_ulong addr, | ||||
|                              target_ureg val) | ||||
|                              target_ulong val) | ||||
| { | ||||
|     do_stby_b(env, addr, val, true, GETPC()); | ||||
| } | ||||
| 
 | ||||
| static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val, | ||||
| void HELPER(stdby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val) | ||||
| { | ||||
|     do_stdby_b(env, addr, val, false, GETPC()); | ||||
| } | ||||
| 
 | ||||
| void HELPER(stdby_b_parallel)(CPUHPPAState *env, target_ulong addr, | ||||
|                               target_ulong val) | ||||
| { | ||||
|     do_stdby_b(env, addr, val, true, GETPC()); | ||||
| } | ||||
| 
 | ||||
| static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ulong val, | ||||
|                       bool parallel, uintptr_t ra) | ||||
| { | ||||
|     switch (addr & 3) { | ||||
|     case 3: | ||||
|         /* The 3 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_3(env, addr - 3, val, ra); | ||||
|             atomic_store_mask32(env, addr - 3, val, 0xffffff00u, ra); | ||||
|         } else { | ||||
|             cpu_stw_data_ra(env, addr - 3, val >> 16, ra); | ||||
|             cpu_stb_data_ra(env, addr - 1, val >> 8, ra); | ||||
| @ -144,17 +240,89 @@ static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ureg val) | ||||
| static void do_stdby_e(CPUHPPAState *env, target_ulong addr, uint64_t val, | ||||
|                        bool parallel, uintptr_t ra) | ||||
| { | ||||
|     switch (addr & 7) { | ||||
|     case 7: | ||||
|         /* The 7 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask64(env, addr - 7, val, | ||||
|                                 0xffffffffffffff00ull, 7, ra); | ||||
|         } else { | ||||
|             cpu_stl_data_ra(env, addr - 7, val >> 32, ra); | ||||
|             cpu_stw_data_ra(env, addr - 3, val >> 16, ra); | ||||
|             cpu_stb_data_ra(env, addr - 1, val >> 8, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 6: | ||||
|         /* The 6 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask64(env, addr - 6, val, | ||||
|                                 0xffffffffffff0000ull, 6, ra); | ||||
|         } else { | ||||
|             cpu_stl_data_ra(env, addr - 6, val >> 32, ra); | ||||
|             cpu_stw_data_ra(env, addr - 2, val >> 16, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 5: | ||||
|         /* The 5 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask64(env, addr - 5, val, | ||||
|                                 0xffffffffff000000ull, 5, ra); | ||||
|         } else { | ||||
|             cpu_stl_data_ra(env, addr - 5, val >> 32, ra); | ||||
|             cpu_stb_data_ra(env, addr - 1, val >> 24, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 4: | ||||
|         cpu_stl_data_ra(env, addr - 4, val >> 32, ra); | ||||
|         break; | ||||
|     case 3: | ||||
|         /* The 3 byte store must appear atomic.  */ | ||||
|         if (parallel) { | ||||
|             atomic_store_mask32(env, addr - 3, val, 0xffffff00u, ra); | ||||
|         } else { | ||||
|             cpu_stw_data_ra(env, addr - 3, val >> 16, ra); | ||||
|             cpu_stb_data_ra(env, addr - 1, val >> 8, ra); | ||||
|         } | ||||
|         break; | ||||
|     case 2: | ||||
|         cpu_stw_data_ra(env, addr - 2, val >> 16, ra); | ||||
|         break; | ||||
|     case 1: | ||||
|         cpu_stb_data_ra(env, addr - 1, val >> 24, ra); | ||||
|         break; | ||||
|     default: | ||||
|         /* Nothing is stored, but protection is checked and the
 | ||||
|            cacheline is marked dirty.  */ | ||||
|         probe_write(env, addr, 0, cpu_mmu_index(env, 0), ra); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val) | ||||
| { | ||||
|     do_stby_e(env, addr, val, false, GETPC()); | ||||
| } | ||||
| 
 | ||||
| void HELPER(stby_e_parallel)(CPUHPPAState *env, target_ulong addr, | ||||
|                              target_ureg val) | ||||
|                              target_ulong val) | ||||
| { | ||||
|     do_stby_e(env, addr, val, true, GETPC()); | ||||
| } | ||||
| 
 | ||||
| void HELPER(stdby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val) | ||||
| { | ||||
|     do_stdby_e(env, addr, val, false, GETPC()); | ||||
| } | ||||
| 
 | ||||
| void HELPER(stdby_e_parallel)(CPUHPPAState *env, target_ulong addr, | ||||
|                               target_ulong val) | ||||
| { | ||||
|     do_stdby_e(env, addr, val, true, GETPC()); | ||||
| } | ||||
| 
 | ||||
| void HELPER(ldc_check)(target_ulong addr) | ||||
| { | ||||
|     if (unlikely(addr & 0xf)) { | ||||
| @ -164,7 +332,7 @@ void HELPER(ldc_check)(target_ulong addr) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr, | ||||
| target_ulong HELPER(probe)(CPUHPPAState *env, target_ulong addr, | ||||
|                           uint32_t level, uint32_t want) | ||||
| { | ||||
| #ifdef CONFIG_USER_ONLY | ||||
| @ -196,7 +364,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr, | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| target_ureg HELPER(read_interval_timer)(void) | ||||
| target_ulong HELPER(read_interval_timer)(void) | ||||
| { | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist.
 | ||||
| @ -209,3 +377,113 @@ target_ureg HELPER(read_interval_timer)(void) | ||||
|     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 2; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(hadd_ss)(uint64_t r1, uint64_t r2) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = sextract64(r1, i, 16); | ||||
|         int f2 = sextract64(r2, i, 16); | ||||
|         int fr = f1 + f2; | ||||
| 
 | ||||
|         fr = MIN(fr, INT16_MAX); | ||||
|         fr = MAX(fr, INT16_MIN); | ||||
|         ret = deposit64(ret, i, 16, fr); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(hadd_us)(uint64_t r1, uint64_t r2) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = extract64(r1, i, 16); | ||||
|         int f2 = sextract64(r2, i, 16); | ||||
|         int fr = f1 + f2; | ||||
| 
 | ||||
|         fr = MIN(fr, UINT16_MAX); | ||||
|         fr = MAX(fr, 0); | ||||
|         ret = deposit64(ret, i, 16, fr); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(havg)(uint64_t r1, uint64_t r2) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = extract64(r1, i, 16); | ||||
|         int f2 = extract64(r2, i, 16); | ||||
|         int fr = f1 + f2; | ||||
| 
 | ||||
|         ret = deposit64(ret, i, 16, (fr >> 1) | (fr & 1)); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(hsub_ss)(uint64_t r1, uint64_t r2) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = sextract64(r1, i, 16); | ||||
|         int f2 = sextract64(r2, i, 16); | ||||
|         int fr = f1 - f2; | ||||
| 
 | ||||
|         fr = MIN(fr, INT16_MAX); | ||||
|         fr = MAX(fr, INT16_MIN); | ||||
|         ret = deposit64(ret, i, 16, fr); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(hsub_us)(uint64_t r1, uint64_t r2) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = extract64(r1, i, 16); | ||||
|         int f2 = sextract64(r2, i, 16); | ||||
|         int fr = f1 - f2; | ||||
| 
 | ||||
|         fr = MIN(fr, UINT16_MAX); | ||||
|         fr = MAX(fr, 0); | ||||
|         ret = deposit64(ret, i, 16, fr); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(hshladd)(uint64_t r1, uint64_t r2, uint32_t sh) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = sextract64(r1, i, 16); | ||||
|         int f2 = sextract64(r2, i, 16); | ||||
|         int fr = (f1 << sh) + f2; | ||||
| 
 | ||||
|         fr = MIN(fr, INT16_MAX); | ||||
|         fr = MAX(fr, INT16_MIN); | ||||
|         ret = deposit64(ret, i, 16, fr); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| uint64_t HELPER(hshradd)(uint64_t r1, uint64_t r2, uint32_t sh) | ||||
| { | ||||
|     uint64_t ret = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 64; i += 16) { | ||||
|         int f1 = sextract64(r1, i, 16); | ||||
|         int f2 = sextract64(r2, i, 16); | ||||
|         int fr = (f1 >> sh) + f2; | ||||
| 
 | ||||
|         fr = MIN(fr, INT16_MAX); | ||||
|         fr = MAX(fr, INT16_MIN); | ||||
|         ret = deposit64(ret, i, 16, fr); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| @ -24,7 +24,7 @@ | ||||
| #include "qemu/timer.h" | ||||
| #include "sysemu/runstate.h" | ||||
| 
 | ||||
| void HELPER(write_interval_timer)(CPUHPPAState *env, target_ureg val) | ||||
| void HELPER(write_interval_timer)(CPUHPPAState *env, target_ulong val) | ||||
| { | ||||
|     HPPACPU *cpu = env_archcpu(env); | ||||
|     uint64_t current = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | ||||
| @ -58,7 +58,7 @@ void HELPER(reset)(CPUHPPAState *env) | ||||
|     helper_excp(env, EXCP_HLT); | ||||
| } | ||||
| 
 | ||||
| target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm) | ||||
| target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm) | ||||
| { | ||||
|     target_ulong psw = env->psw; | ||||
|     /*
 | ||||
| @ -80,6 +80,16 @@ void HELPER(rfi)(CPUHPPAState *env) | ||||
|     env->iasq_b = (uint64_t)env->cr_back[0] << 32; | ||||
|     env->iaoq_f = env->cr[CR_IIAOQ]; | ||||
|     env->iaoq_b = env->cr_back[1]; | ||||
| 
 | ||||
|     /*
 | ||||
|      * For pa2.0, IIASQ is the top bits of the virtual address. | ||||
|      * To recreate the space identifier, remove the offset bits. | ||||
|      */ | ||||
|     if (hppa_is_pa20(env)) { | ||||
|         env->iasq_f &= ~env->iaoq_f; | ||||
|         env->iasq_b &= ~env->iaoq_b; | ||||
|     } | ||||
| 
 | ||||
|     cpu_hppa_put_psw(env, env->cr[CR_IPSW]); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -10,6 +10,7 @@ disable hppa_tlb_fill_success(void *env, uint64_t addr, uint64_t phys, int size, | ||||
| disable hppa_tlb_itlba(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx" | ||||
| disable hppa_tlb_itlbp(void *env, void *ent, int access_id, int u, int pl2, int pl1, int type, int b, int d, int t) "env=%p ent=%p access_id=%x u=%d pl2=%d pl1=%d type=%d b=%d d=%d t=%d" | ||||
| disable hppa_tlb_ptlb(void *env) "env=%p" | ||||
| disable hppa_tlb_ptlb_local(void *env) "env=%p" | ||||
| disable hppa_tlb_ptlbe(void *env) "env=%p" | ||||
| disable hppa_tlb_lpa_success(void *env, uint64_t addr, uint64_t phys) "env=%p addr=0x%lx phys=0x%lx" | ||||
| disable hppa_tlb_lpa_failed(void *env, uint64_t addr) "env=%p addr=0x%lx" | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Stefan Hajnoczi
						Stefan Hajnoczi