mirror of
https://github.com/qemu/qemu.git
synced 2024-12-12 05:03:42 +08:00
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_ARCH=hppa
|
||||||
|
TARGET_ABI32=y
|
||||||
TARGET_SYSTBL_ABI=common,32
|
TARGET_SYSTBL_ABI=common,32
|
||||||
TARGET_SYSTBL=syscall.tbl
|
TARGET_SYSTBL=syscall.tbl
|
||||||
TARGET_BIG_ENDIAN=y
|
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;
|
ISABus *isa_bus;
|
||||||
qemu_irq *isa_irqs;
|
qemu_irq *isa_irqs;
|
||||||
@ -96,8 +96,7 @@ static ISABus *hppa_isa_bus(void)
|
|||||||
isa_region = g_new(MemoryRegion, 1);
|
isa_region = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_io(isa_region, NULL, &hppa_pci_ignore_ops,
|
memory_region_init_io(isa_region, NULL, &hppa_pci_ignore_ops,
|
||||||
NULL, "isa-io", 0x800);
|
NULL, "isa-io", 0x800);
|
||||||
memory_region_add_subregion(get_system_memory(), IDE_HPA,
|
memory_region_add_subregion(get_system_memory(), addr, isa_region);
|
||||||
isa_region);
|
|
||||||
|
|
||||||
isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region,
|
isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region,
|
||||||
&error_abort);
|
&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);
|
addr &= (0x10000000 - 1);
|
||||||
return addr;
|
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 HPPACPU *cpu[HPPA_MAX_CPUS];
|
||||||
static uint64_t firmware_entry;
|
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]);
|
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;
|
FWCfgState *fw_cfg;
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
const char qemu_version[] = QEMU_VERSION;
|
const char qemu_version[] = QEMU_VERSION;
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
|
int btlb_entries = HPPA_BTLB_ENTRIES(&cpu[0]->env);
|
||||||
int len;
|
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_NB_CPUS, ms->smp.cpus);
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, HPPA_MAX_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);
|
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",
|
fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version",
|
||||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
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",
|
fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries",
|
||||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
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",
|
fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries",
|
||||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||||
|
|
||||||
@ -257,32 +269,45 @@ static DinoState *dino_init(MemoryRegion *addr_space)
|
|||||||
/*
|
/*
|
||||||
* Step 1: Create CPUs and Memory
|
* 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 *addr_space = get_system_memory();
|
||||||
MemoryRegion *cpu_region;
|
|
||||||
long i;
|
|
||||||
unsigned int smp_cpus = machine->smp.cpus;
|
unsigned int smp_cpus = machine->smp.cpus;
|
||||||
char *name;
|
TranslateFn *translate;
|
||||||
|
MemoryRegion *cpu_region;
|
||||||
|
|
||||||
/* Create CPUs. */
|
/* Create CPUs. */
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (unsigned int i = 0; i < smp_cpus; i++) {
|
||||||
name = g_strdup_printf("cpu%ld-io-eir", i);
|
|
||||||
cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type));
|
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);
|
cpu_region = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops,
|
memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops,
|
||||||
cpu[i], name, 4);
|
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);
|
cpu_region);
|
||||||
g_free(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RTC and DebugOutputPort on CPU #0 */
|
/* RTC and DebugOutputPort on CPU #0 */
|
||||||
cpu_region = g_new(MemoryRegion, 1);
|
cpu_region = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_io(cpu_region, OBJECT(cpu[0]), &hppa_io_helper_ops,
|
memory_region_init_io(cpu_region, OBJECT(cpu[0]), &hppa_io_helper_ops,
|
||||||
cpu[0], "cpu0-io-rtc", 2 * sizeof(uint64_t));
|
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. */
|
/* Main memory region. */
|
||||||
if (machine->ram_size > 3 * GiB) {
|
if (machine->ram_size > 3 * GiB) {
|
||||||
@ -290,12 +315,15 @@ static void machine_HP_common_init_cpus(MachineState *machine)
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
|
memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
|
||||||
|
|
||||||
|
return translate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Last creation step: Add SCSI discs, NICs, graphics & load firmware
|
* 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_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
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");
|
dev = qdev_new("artist");
|
||||||
s = SYS_BUS_DEVICE(dev);
|
s = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_realize_and_unref(s, &error_fatal);
|
sysbus_realize_and_unref(s, &error_fatal);
|
||||||
sysbus_mmio_map(s, 0, LASI_GFX_HPA);
|
sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
|
||||||
sysbus_mmio_map(s, 1, ARTIST_FB_ADDR);
|
sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Network setup. */
|
/* Network setup. */
|
||||||
if (enable_lasi_lan()) {
|
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));
|
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);
|
qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier);
|
||||||
|
|
||||||
/* fw_cfg configuration interface */
|
/* 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,
|
/* Load firmware. Given that this is not "real" firmware,
|
||||||
but one explicitly written for the emulation, we might as
|
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);
|
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,
|
&firmware_entry, &firmware_low, &firmware_high, NULL,
|
||||||
true, EM_PARISC, 0, 0);
|
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) {
|
if (size < 0) {
|
||||||
error_report("could not load firmware '%s'", firmware_filename);
|
error_report("could not load firmware '%s'", firmware_filename);
|
||||||
exit(1);
|
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
|
qemu_log_mask(CPU_LOG_PAGE, "Firmware loaded at 0x%08" PRIx64
|
||||||
"-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n",
|
"-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n",
|
||||||
firmware_low, firmware_high, firmware_entry);
|
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");
|
error_report("Firmware overlaps with memory or IO space");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -410,18 +434,16 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
|
|||||||
rom_region = g_new(MemoryRegion, 1);
|
rom_region = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_ram(rom_region, NULL, "firmware",
|
memory_region_init_ram(rom_region, NULL, "firmware",
|
||||||
(FIRMWARE_END - FIRMWARE_START), &error_fatal);
|
(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 */
|
/* Load kernel */
|
||||||
if (kernel_filename) {
|
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,
|
NULL, &kernel_entry, &kernel_low, &kernel_high, NULL,
|
||||||
true, EM_PARISC, 0, 0);
|
true, EM_PARISC, 0, 0);
|
||||||
|
|
||||||
/* Unfortunately, load_elf sign-extends reading elf32. */
|
kernel_entry = linux_kernel_virt_to_phys(NULL, kernel_entry);
|
||||||
kernel_entry = (target_ureg) cpu_hppa_to_phys(NULL, kernel_entry);
|
|
||||||
kernel_low = (target_ureg)kernel_low;
|
|
||||||
kernel_high = (target_ureg)kernel_high;
|
|
||||||
|
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
error_report("could not load kernel '%s'", kernel_filename);
|
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;
|
DeviceState *dev, *dino_dev;
|
||||||
MemoryRegion *addr_space = get_system_memory();
|
MemoryRegion *addr_space = get_system_memory();
|
||||||
|
TranslateFn *translate;
|
||||||
ISABus *isa_bus;
|
ISABus *isa_bus;
|
||||||
PCIBus *pci_bus;
|
PCIBus *pci_bus;
|
||||||
|
|
||||||
/* Create CPUs and RAM. */
|
/* 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 */
|
/* Init Lasi chip */
|
||||||
lasi_dev = DEVICE(lasi_init());
|
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(
|
sysbus_mmio_get_region(
|
||||||
SYS_BUS_DEVICE(lasi_dev), 0));
|
SYS_BUS_DEVICE(lasi_dev), 0));
|
||||||
|
|
||||||
/* Init Dino (PCI host bus chip). */
|
/* Init Dino (PCI host bus chip). */
|
||||||
dino_dev = DEVICE(dino_init(addr_space));
|
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(
|
sysbus_mmio_get_region(
|
||||||
SYS_BUS_DEVICE(dino_dev), 0));
|
SYS_BUS_DEVICE(dino_dev), 0));
|
||||||
pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci"));
|
pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci"));
|
||||||
assert(pci_bus);
|
assert(pci_bus);
|
||||||
|
|
||||||
/* Create ISA bus, needed for PS/2 kbd/mouse port emulation */
|
/* 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);
|
assert(isa_bus);
|
||||||
|
|
||||||
/* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */
|
/* 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,
|
qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16,
|
||||||
serial_hd(0), DEVICE_BIG_ENDIAN);
|
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,
|
qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16,
|
||||||
serial_hd(1), DEVICE_BIG_ENDIAN);
|
serial_hd(1), DEVICE_BIG_ENDIAN);
|
||||||
|
|
||||||
/* Parallel port */
|
/* 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),
|
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA),
|
||||||
parallel_hds[0]);
|
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_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA));
|
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),
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||||||
0));
|
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),
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||||||
1));
|
1));
|
||||||
|
|
||||||
/* Add SCSI discs, NICs, graphics & load firmware */
|
/* 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)
|
static AstroState *astro_init(void)
|
||||||
@ -572,21 +603,28 @@ static void machine_HP_C3700_init(MachineState *machine)
|
|||||||
AstroState *astro;
|
AstroState *astro;
|
||||||
DeviceState *astro_dev;
|
DeviceState *astro_dev;
|
||||||
MemoryRegion *addr_space = get_system_memory();
|
MemoryRegion *addr_space = get_system_memory();
|
||||||
|
TranslateFn *translate;
|
||||||
|
|
||||||
/* Create CPUs and RAM. */
|
/* 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). */
|
/* Init Astro and the Elroys (PCI host bus chips). */
|
||||||
astro = astro_init();
|
astro = astro_init();
|
||||||
astro_dev = DEVICE(astro);
|
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(
|
sysbus_mmio_get_region(
|
||||||
SYS_BUS_DEVICE(astro_dev), 0));
|
SYS_BUS_DEVICE(astro_dev), 0));
|
||||||
pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(astro->elroy[0]), "pci"));
|
pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(astro->elroy[0]), "pci"));
|
||||||
assert(pci_bus);
|
assert(pci_bus);
|
||||||
|
|
||||||
/* Add SCSI discs, NICs, graphics & load firmware */
|
/* 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)
|
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->exception_index = -1;
|
||||||
cs->halted = 0;
|
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()? */
|
/* 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)
|
static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
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->desc = "HP B160L workstation";
|
||||||
mc->default_cpu_type = TYPE_HPPA_CPU;
|
mc->default_cpu_type = TYPE_HPPA_CPU;
|
||||||
|
mc->valid_cpu_types = HP_B160L_machine_valid_cpu_types;
|
||||||
mc->init = machine_HP_B160L_init;
|
mc->init = machine_HP_B160L_init;
|
||||||
mc->reset = hppa_machine_reset;
|
mc->reset = hppa_machine_reset;
|
||||||
mc->block_default_type = IF_SCSI;
|
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)
|
static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
NMIClass *nc = NMI_CLASS(oc);
|
NMIClass *nc = NMI_CLASS(oc);
|
||||||
|
|
||||||
mc->desc = "HP C3700 workstation";
|
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->init = machine_HP_C3700_init;
|
||||||
mc->reset = hppa_machine_reset;
|
mc->reset = hppa_machine_reset;
|
||||||
mc->block_default_type = IF_SCSI;
|
mc->block_default_type = IF_SCSI;
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#define TYPE_ASTRO_IOMMU_MEMORY_REGION "astro-iommu-memory-region"
|
#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/osdep.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qemu/units.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;
|
uint32_t ena = bit & ~old_ilr;
|
||||||
s->ilr = old_ilr | bit;
|
s->ilr = old_ilr | bit;
|
||||||
if (ena != 0) {
|
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 {
|
} else {
|
||||||
s->ilr = old_ilr & ~bit;
|
s->ilr = old_ilr & ~bit;
|
||||||
@ -825,15 +827,16 @@ static void astro_realize(DeviceState *obj, Error **errp)
|
|||||||
|
|
||||||
/* map elroys mmio */
|
/* map elroys mmio */
|
||||||
map_size = LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC;
|
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),
|
memory_region_init_alias(&elroy->pci_mmio_alias, OBJECT(elroy),
|
||||||
"pci-mmio-alias",
|
"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,
|
memory_region_add_subregion(get_system_memory(), map_addr,
|
||||||
&elroy->pci_mmio_alias);
|
&elroy->pci_mmio_alias);
|
||||||
|
|
||||||
|
/* map elroys io */
|
||||||
map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC;
|
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,
|
memory_region_add_subregion(get_system_memory(), map_addr,
|
||||||
&elroy->pci_io);
|
&elroy->pci_io);
|
||||||
|
|
||||||
|
@ -385,10 +385,11 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pflags) {
|
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);
|
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)
|
if (lowaddr) {
|
||||||
*lowaddr = (uint64_t)(elf_sword)low;
|
*lowaddr = low;
|
||||||
if (highaddr)
|
}
|
||||||
*highaddr = (uint64_t)(elf_sword)high;
|
if (highaddr) {
|
||||||
|
*highaddr = high;
|
||||||
|
}
|
||||||
ret = total_size;
|
ret = total_size;
|
||||||
fail:
|
fail:
|
||||||
if (mapped_file) {
|
if (mapped_file) {
|
||||||
|
@ -147,12 +147,10 @@ void cpu_loop(CPUHPPAState *env)
|
|||||||
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f);
|
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f);
|
||||||
break;
|
break;
|
||||||
case EXCP_ILL:
|
case EXCP_ILL:
|
||||||
EXCP_DUMP(env, "qemu: EXCP_ILL exception %#x\n", trapnr);
|
|
||||||
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
|
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
|
||||||
break;
|
break;
|
||||||
case EXCP_PRIV_OPR:
|
case EXCP_PRIV_OPR:
|
||||||
/* check for glibc ABORT_INSTRUCTION "iitlbp %r0,(%sr0, %r0)" */
|
/* 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) {
|
if (env->cr[CR_IIR] == 0x04000000) {
|
||||||
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
|
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
|
||||||
} else {
|
} else {
|
||||||
@ -160,7 +158,6 @@ void cpu_loop(CPUHPPAState *env)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXCP_PRIV_REG:
|
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);
|
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f);
|
||||||
break;
|
break;
|
||||||
case EXCP_OVERFLOW:
|
case EXCP_OVERFLOW:
|
||||||
@ -173,7 +170,6 @@ void cpu_loop(CPUHPPAState *env)
|
|||||||
force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
|
force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
|
||||||
break;
|
break;
|
||||||
case EXCP_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);
|
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f & ~3);
|
||||||
break;
|
break;
|
||||||
case EXCP_DEBUG:
|
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)
|
static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
|
||||||
{
|
{
|
||||||
target_ulong psw;
|
abi_ulong psw;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
__get_user(psw, &sc->sc_gr[0]);
|
__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;
|
haddr = ka->_sa_handler;
|
||||||
if (haddr & 2) {
|
if (haddr & 2) {
|
||||||
/* Function descriptor. */
|
/* Function descriptor. */
|
||||||
target_ulong *fdesc, dest;
|
abi_ptr *fdesc, dest;
|
||||||
|
|
||||||
haddr &= -4;
|
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) {
|
if (!fdesc) {
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
#define HPPA_TARGET_ELF_H
|
#define HPPA_TARGET_ELF_H
|
||||||
static inline const char *cpu_get_model(uint32_t eflags)
|
static inline const char *cpu_get_model(uint32_t eflags)
|
||||||
{
|
{
|
||||||
return "any";
|
return "hppa";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,26 +8,16 @@
|
|||||||
#ifndef HPPA_CPU_PARAM_H
|
#ifndef HPPA_CPU_PARAM_H
|
||||||
#define HPPA_CPU_PARAM_H
|
#define HPPA_CPU_PARAM_H
|
||||||
|
|
||||||
#ifdef TARGET_HPPA64
|
#define TARGET_LONG_BITS 64
|
||||||
# define TARGET_LONG_BITS 64
|
|
||||||
# define TARGET_REGISTER_BITS 64
|
#if defined(CONFIG_USER_ONLY) && defined(TARGET_ABI32)
|
||||||
# define TARGET_VIRT_ADDR_SPACE_BITS 64
|
# define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||||
# define TARGET_PHYS_ADDR_SPACE_BITS 64
|
|
||||||
#elif defined(CONFIG_USER_ONLY)
|
|
||||||
# define TARGET_LONG_BITS 32
|
|
||||||
# define TARGET_REGISTER_BITS 32
|
|
||||||
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||||
# define TARGET_PHYS_ADDR_SPACE_BITS 32
|
|
||||||
#else
|
#else
|
||||||
/*
|
# define TARGET_PHYS_ADDR_SPACE_BITS 64
|
||||||
* 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_VIRT_ADDR_SPACE_BITS 64
|
# define TARGET_VIRT_ADDR_SPACE_BITS 64
|
||||||
# define TARGET_PHYS_ADDR_SPACE_BITS 32
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TARGET_PAGE_BITS 12
|
#define TARGET_PAGE_BITS 12
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
#define TYPE_HPPA_CPU "hppa-cpu"
|
#define TYPE_HPPA_CPU "hppa-cpu"
|
||||||
|
#define TYPE_HPPA64_CPU "hppa64-cpu"
|
||||||
|
|
||||||
OBJECT_DECLARE_CPU_TYPE(HPPACPU, HPPACPUClass, HPPA_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);
|
HPPACPU *cpu = HPPA_CPU(cs);
|
||||||
|
|
||||||
cpu->env.iaoq_f = data[0];
|
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.iaoq_b = data[1];
|
||||||
}
|
}
|
||||||
|
cpu->env.unwind_breg = data[2];
|
||||||
/*
|
/*
|
||||||
* Since we were executing the instruction at IAOQ_F, and took some
|
* Since we were executing the instruction at IAOQ_F, and took some
|
||||||
* sort of action that provoked the cpu_restore_state, we can infer
|
* 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
|
#ifndef CONFIG_USER_ONLY
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
HPPACPU *cpu = HPPA_CPU(cs);
|
||||||
|
|
||||||
cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
hppa_cpu_alarm_timer, cpu);
|
hppa_cpu_alarm_timer, cpu);
|
||||||
|
hppa_ptlbe(&cpu->env);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -156,7 +159,39 @@ static void hppa_cpu_initfn(Object *obj)
|
|||||||
|
|
||||||
static ObjectClass *hppa_cpu_class_by_name(const char *cpu_model)
|
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
|
#ifndef CONFIG_USER_ONLY
|
||||||
@ -207,20 +242,21 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->tcg_ops = &hppa_tcg_ops;
|
cc->tcg_ops = &hppa_tcg_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo hppa_cpu_type_info = {
|
static const TypeInfo hppa_cpu_type_infos[] = {
|
||||||
.name = TYPE_HPPA_CPU,
|
{
|
||||||
.parent = TYPE_CPU,
|
.name = TYPE_HPPA_CPU,
|
||||||
.instance_size = sizeof(HPPACPU),
|
.parent = TYPE_CPU,
|
||||||
.instance_align = __alignof(HPPACPU),
|
.instance_size = sizeof(HPPACPU),
|
||||||
.instance_init = hppa_cpu_initfn,
|
.instance_align = __alignof(HPPACPU),
|
||||||
.abstract = false,
|
.instance_init = hppa_cpu_initfn,
|
||||||
.class_size = sizeof(HPPACPUClass),
|
.abstract = false,
|
||||||
.class_init = hppa_cpu_class_init,
|
.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)
|
DEFINE_TYPES(hppa_cpu_type_infos)
|
||||||
{
|
|
||||||
type_register_static(&hppa_cpu_type_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(hppa_cpu_register_types)
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "cpu-qom.h"
|
#include "cpu-qom.h"
|
||||||
#include "exec/cpu-defs.h"
|
#include "exec/cpu-defs.h"
|
||||||
#include "qemu/cpu-float.h"
|
#include "qemu/cpu-float.h"
|
||||||
|
#include "qemu/interval-tree.h"
|
||||||
|
|
||||||
/* PA-RISC 1.x processors have a strong memory model. */
|
/* PA-RISC 1.x processors have a strong memory model. */
|
||||||
/* ??? While we do not yet implement PA-RISC 2.0, those processors have
|
/* ??? 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. */
|
basis. It's probably easier to fall back to a strong memory model. */
|
||||||
#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL
|
#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL
|
||||||
|
|
||||||
#define MMU_KERNEL_IDX 11
|
#define MMU_KERNEL_IDX 7
|
||||||
#define MMU_PL1_IDX 12
|
#define MMU_KERNEL_P_IDX 8
|
||||||
#define MMU_PL2_IDX 13
|
#define MMU_PL1_IDX 9
|
||||||
#define MMU_USER_IDX 14
|
#define MMU_PL1_P_IDX 10
|
||||||
#define MMU_PHYS_IDX 15
|
#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(MIDX) (((MIDX) - MMU_KERNEL_IDX) / 2)
|
||||||
#define MMU_IDX_TO_PRIV(mmu_idx) ((mmu_idx) - MMU_KERNEL_IDX)
|
#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 */
|
/* No need to flush MMU_PHYS_IDX */
|
||||||
#define HPPA_MMU_FLUSH_MASK \
|
#define HPPA_MMU_FLUSH_MASK \
|
||||||
(1 << MMU_KERNEL_IDX | 1 << MMU_PL1_IDX | \
|
(1 << MMU_KERNEL_IDX | 1 << MMU_KERNEL_P_IDX | \
|
||||||
1 << MMU_PL2_IDX | 1 << MMU_USER_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. */
|
/* Hardware exceptions, interrupts, faults, and traps. */
|
||||||
#define EXCP_HPMC 1 /* high priority machine check */
|
#define EXCP_HPMC 1 /* high priority machine check */
|
||||||
@ -107,11 +120,7 @@
|
|||||||
#define PSW_T 0x01000000
|
#define PSW_T 0x01000000
|
||||||
#define PSW_S 0x02000000
|
#define PSW_S 0x02000000
|
||||||
#define PSW_E 0x04000000
|
#define PSW_E 0x04000000
|
||||||
#ifdef TARGET_HPPA64
|
|
||||||
#define PSW_W 0x08000000 /* PA2.0 only */
|
#define PSW_W 0x08000000 /* PA2.0 only */
|
||||||
#else
|
|
||||||
#define PSW_W 0
|
|
||||||
#endif
|
|
||||||
#define PSW_Z 0x40000000 /* PA1.x only */
|
#define PSW_Z 0x40000000 /* PA1.x only */
|
||||||
#define PSW_Y 0x80000000 /* PA1.x only */
|
#define PSW_Y 0x80000000 /* PA1.x only */
|
||||||
|
|
||||||
@ -124,15 +133,12 @@
|
|||||||
#define PSW_SM_P PSW_P
|
#define PSW_SM_P PSW_P
|
||||||
#define PSW_SM_Q PSW_Q /* Enable Interrupt State Collection */
|
#define PSW_SM_Q PSW_Q /* Enable Interrupt State Collection */
|
||||||
#define PSW_SM_R PSW_R /* Enable Recover Counter Trap */
|
#define PSW_SM_R PSW_R /* Enable Recover Counter Trap */
|
||||||
#ifdef TARGET_HPPA64
|
|
||||||
#define PSW_SM_E 0x100
|
#define PSW_SM_E 0x100
|
||||||
#define PSW_SM_W 0x200 /* PA2.0 only : Enable Wide Mode */
|
#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_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_PID1 8
|
||||||
#define CR_PID2 9
|
#define CR_PID2 9
|
||||||
#define CR_PID3 12
|
#define CR_PID3 12
|
||||||
@ -150,45 +156,37 @@
|
|||||||
#define CR_IPSW 22
|
#define CR_IPSW 22
|
||||||
#define CR_EIRR 23
|
#define CR_EIRR 23
|
||||||
|
|
||||||
#if TARGET_REGISTER_BITS == 32
|
typedef struct HPPATLBEntry {
|
||||||
typedef uint32_t target_ureg;
|
union {
|
||||||
typedef int32_t target_sreg;
|
IntervalTreeNode itree;
|
||||||
#define TREG_FMT_lx "%08"PRIx32
|
struct HPPATLBEntry *unused_next;
|
||||||
#define TREG_FMT_ld "%"PRId32
|
};
|
||||||
#else
|
|
||||||
typedef uint64_t target_ureg;
|
target_ulong pa;
|
||||||
typedef int64_t target_sreg;
|
|
||||||
#define TREG_FMT_lx "%016"PRIx64
|
unsigned entry_valid : 1;
|
||||||
#define TREG_FMT_ld "%"PRId64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t va_b;
|
|
||||||
uint64_t va_e;
|
|
||||||
target_ureg pa;
|
|
||||||
unsigned u : 1;
|
unsigned u : 1;
|
||||||
unsigned t : 1;
|
unsigned t : 1;
|
||||||
unsigned d : 1;
|
unsigned d : 1;
|
||||||
unsigned b : 1;
|
unsigned b : 1;
|
||||||
unsigned page_size : 4;
|
|
||||||
unsigned ar_type : 3;
|
unsigned ar_type : 3;
|
||||||
unsigned ar_pl1 : 2;
|
unsigned ar_pl1 : 2;
|
||||||
unsigned ar_pl2 : 2;
|
unsigned ar_pl2 : 2;
|
||||||
unsigned entry_valid : 1;
|
|
||||||
unsigned access_id : 16;
|
unsigned access_id : 16;
|
||||||
} hppa_tlb_entry;
|
} HPPATLBEntry;
|
||||||
|
|
||||||
typedef struct CPUArchState {
|
typedef struct CPUArchState {
|
||||||
target_ureg iaoq_f; /* front */
|
target_ulong iaoq_f; /* front */
|
||||||
target_ureg iaoq_b; /* back, aka next instruction */
|
target_ulong iaoq_b; /* back, aka next instruction */
|
||||||
|
|
||||||
target_ureg gr[32];
|
target_ulong gr[32];
|
||||||
uint64_t fr[32];
|
uint64_t fr[32];
|
||||||
uint64_t sr[8]; /* stored shifted into place for gva */
|
uint64_t sr[8]; /* stored shifted into place for gva */
|
||||||
|
|
||||||
target_ureg psw; /* All psw bits except the following: */
|
target_ulong psw; /* All psw bits except the following: */
|
||||||
target_ureg psw_n; /* boolean */
|
target_ulong psw_n; /* boolean */
|
||||||
target_sreg psw_v; /* in most significant bit */
|
target_long psw_v; /* in most significant bit */
|
||||||
|
|
||||||
/* Splitting the carry-borrow field into the MSB and "the rest", allows
|
/* 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.
|
* 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).
|
* host has the appropriate add-with-carry insn to compute the msb).
|
||||||
* Therefore the carry bits are stored as: cb_msb : cb & 0x11111110.
|
* Therefore the carry bits are stored as: cb_msb : cb & 0x11111110.
|
||||||
*/
|
*/
|
||||||
target_ureg psw_cb; /* in least significant bit of next nibble */
|
target_ulong psw_cb; /* in least significant bit of next nibble */
|
||||||
target_ureg psw_cb_msb; /* boolean */
|
target_ulong psw_cb_msb; /* boolean */
|
||||||
|
|
||||||
uint64_t iasq_f;
|
uint64_t iasq_f;
|
||||||
uint64_t iasq_b;
|
uint64_t iasq_b;
|
||||||
@ -206,24 +204,40 @@ typedef struct CPUArchState {
|
|||||||
uint32_t fr0_shadow; /* flags, c, ca/cq, rm, d, enables */
|
uint32_t fr0_shadow; /* flags, c, ca/cq, rm, d, enables */
|
||||||
float_status fp_status;
|
float_status fp_status;
|
||||||
|
|
||||||
target_ureg cr[32]; /* control registers */
|
target_ulong cr[32]; /* control registers */
|
||||||
target_ureg cr_back[2]; /* back of cr17/cr18 */
|
target_ulong cr_back[2]; /* back of cr17/cr18 */
|
||||||
target_ureg shadow[7]; /* shadow registers */
|
target_ulong shadow[7]; /* shadow registers */
|
||||||
|
|
||||||
/* ??? The number of entries isn't specified by the architecture. */
|
/*
|
||||||
#ifdef TARGET_HPPA64
|
* During unwind of a memory insn, the base register of the address.
|
||||||
#define HPPA_BTLB_FIXED 0 /* BTLBs are not supported in 64-bit machines */
|
* This is used to construct CR_IOR for pa2.0.
|
||||||
#else
|
*/
|
||||||
#define HPPA_BTLB_FIXED 16
|
uint32_t unwind_breg;
|
||||||
#endif
|
|
||||||
#define HPPA_BTLB_VARIABLE 0
|
/*
|
||||||
|
* ??? 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_TLB_ENTRIES 256
|
||||||
#define HPPA_BTLB_ENTRIES (HPPA_BTLB_FIXED + HPPA_BTLB_VARIABLE)
|
|
||||||
|
|
||||||
/* ??? Implement a unified itlb/dtlb for the moment. */
|
/* Index for round-robin tlb eviction. */
|
||||||
/* ??? We should use a more intelligent data structure. */
|
|
||||||
hppa_tlb_entry tlb[HPPA_TLB_ENTRIES];
|
|
||||||
uint32_t tlb_last;
|
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;
|
} CPUHPPAState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -243,13 +257,23 @@ struct ArchCPU {
|
|||||||
|
|
||||||
#include "exec/cpu-all.h"
|
#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)
|
static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
return MMU_USER_IDX;
|
return MMU_USER_IDX;
|
||||||
#else
|
#else
|
||||||
if (env->psw & (ifetch ? PSW_C : PSW_D)) {
|
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 */
|
return MMU_PHYS_IDX; /* mmu disabled */
|
||||||
#endif
|
#endif
|
||||||
@ -259,23 +283,26 @@ void hppa_translate_init(void);
|
|||||||
|
|
||||||
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
|
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
|
||||||
|
|
||||||
static inline target_ulong hppa_form_gva_psw(target_ureg psw, uint64_t spc,
|
static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
|
||||||
target_ureg off)
|
target_ulong off)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
return off;
|
return off;
|
||||||
#else
|
#else
|
||||||
off &= (psw & PSW_W ? 0x3fffffffffffffffull : 0xffffffffull);
|
off &= psw & PSW_W ? MAKE_64BIT_MASK(0, 62) : MAKE_64BIT_MASK(0, 32);
|
||||||
return spc | off;
|
return spc | off;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc,
|
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);
|
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.
|
* 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
|
* 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;
|
*cs_base = env->iaoq_b & -4;
|
||||||
flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus;
|
flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus;
|
||||||
#else
|
#else
|
||||||
/* ??? E, T, H, L, B, P bits need to be here, when implemented. */
|
/* ??? E, T, H, L, B bits need to be here, when implemented. */
|
||||||
flags |= env->psw & (PSW_W | PSW_C | PSW_D);
|
flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P);
|
||||||
flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT;
|
flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT;
|
||||||
|
|
||||||
*pc = (env->psw & PSW_C
|
*pc = hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
|
||||||
? hppa_form_gva_psw(env->psw, env->iasq_f, env->iaoq_f & -4)
|
env->iaoq_f & -4);
|
||||||
: env->iaoq_f & -4);
|
|
||||||
*cs_base = env->iasq_f;
|
*cs_base = env->iasq_f;
|
||||||
|
|
||||||
/* Insert a difference between IAOQ_B and IAOQ_F within the otherwise zero
|
/* 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.
|
which is the primary case we care about -- using goto_tb within a page.
|
||||||
Failure is indicated by a zero difference. */
|
Failure is indicated by a zero difference. */
|
||||||
if (env->iasq_f == env->iasq_b) {
|
if (env->iasq_f == env->iasq_b) {
|
||||||
target_sreg diff = env->iaoq_b - env->iaoq_f;
|
target_long diff = env->iaoq_b - env->iaoq_f;
|
||||||
if (TARGET_REGISTER_BITS == 32 || diff == (int32_t)diff) {
|
if (diff == (int32_t)diff) {
|
||||||
*cs_base |= (uint32_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;
|
*pflags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ureg cpu_hppa_get_psw(CPUHPPAState *env);
|
target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
|
||||||
void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg);
|
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
|
||||||
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
|
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#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);
|
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
|
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
void hppa_ptlbe(CPUHPPAState *env);
|
||||||
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
|
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
|
||||||
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||||
MMUAccessType access_type, int mmu_idx,
|
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);
|
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
||||||
int type, hwaddr *pphys, int *pprot,
|
int type, hwaddr *pphys, int *pprot,
|
||||||
hppa_tlb_entry **tlb_entry);
|
HPPATLBEntry **tlb_entry);
|
||||||
extern const MemoryRegionOps hppa_io_eir_ops;
|
extern const MemoryRegionOps hppa_io_eir_ops;
|
||||||
extern const VMStateDescription vmstate_hppa_cpu;
|
extern const VMStateDescription vmstate_hppa_cpu;
|
||||||
void hppa_cpu_alarm_timer(void *);
|
void hppa_cpu_alarm_timer(void *);
|
||||||
@ -358,4 +385,9 @@ int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr);
|
|||||||
#endif
|
#endif
|
||||||
G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra);
|
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 */
|
#endif /* HPPA_CPU_H */
|
||||||
|
@ -21,11 +21,16 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "gdbstub/helpers.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)
|
int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
CPUHPPAState *env = cpu_env(cs);
|
||||||
CPUHPPAState *env = &cpu->env;
|
uint32_t val;
|
||||||
target_ureg val;
|
|
||||||
|
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -139,24 +144,13 @@ int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TARGET_REGISTER_BITS == 64) {
|
return gdb_get_reg32(mem_buf, val);
|
||||||
return gdb_get_reg64(mem_buf, val);
|
|
||||||
} else {
|
|
||||||
return gdb_get_reg32(mem_buf, val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
CPUHPPAState *env = cpu_env(cs);
|
||||||
CPUHPPAState *env = &cpu->env;
|
uint32_t val = ldl_p(mem_buf);
|
||||||
target_ureg val;
|
|
||||||
|
|
||||||
if (TARGET_REGISTER_BITS == 64) {
|
|
||||||
val = ldq_p(mem_buf);
|
|
||||||
} else {
|
|
||||||
val = ldl_p(mem_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -166,7 +160,7 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|||||||
env->gr[n] = val;
|
env->gr[n] = val;
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
env->cr[CR_SAR] = val;
|
env->cr[CR_SAR] = val & (hppa_is_pa20(env) ? 63 : 31);
|
||||||
break;
|
break;
|
||||||
case 33:
|
case 33:
|
||||||
env->iaoq_f = val;
|
env->iaoq_f = val;
|
||||||
@ -278,5 +272,5 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return sizeof(target_ureg);
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -25,22 +25,32 @@
|
|||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "qemu/qemu-print.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. */
|
/* Fold carry bits down to 8 consecutive bits. */
|
||||||
/* ??? Needs tweaking for hppa64. */
|
/* ^^^b^^^c^^^d^^^e^^^f^^^g^^^h^^^i^^^j^^^k^^^l^^^m^^^n^^^o^^^p^^^^ */
|
||||||
/* .......b...c...d...e...f...g...h */
|
psw = (env->psw_cb >> 4) & mask1;
|
||||||
psw = (env->psw_cb >> 4) & 0x01111111;
|
/* .......b...c...d...e...f...g...h...i...j...k...l...m...n...o...p */
|
||||||
/* .......b..bc..cd..de..ef..fg..gh */
|
|
||||||
psw |= psw >> 3;
|
psw |= psw >> 3;
|
||||||
/* .............bcd............efgh */
|
/* .......b..bc..cd..de..ef..fg..gh..hi..ij..jk..kl..lm..mn..no..op */
|
||||||
psw |= (psw >> 6) & 0x000f000f;
|
psw |= psw >> 6;
|
||||||
/* .........................bcdefgh */
|
psw &= maskf;
|
||||||
psw |= (psw >> 12) & 0xf;
|
/* .............bcd............efgh............ijkl............mnop */
|
||||||
psw |= env->psw_cb_msb << 7;
|
psw |= psw >> 12;
|
||||||
psw = (psw & 0xff) << 8;
|
/* .............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_n * PSW_N;
|
||||||
psw |= (env->psw_v < 0) * PSW_V;
|
psw |= (env->psw_v < 0) * PSW_V;
|
||||||
@ -49,16 +59,36 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
|
|||||||
return psw;
|
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;
|
uint64_t reserved;
|
||||||
target_ureg cb = 0;
|
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 = psw & ~(PSW_N | PSW_V | PSW_CB);
|
||||||
env->psw_n = (psw / PSW_N) & 1;
|
env->psw_n = (psw / PSW_N) & 1;
|
||||||
env->psw_v = -((psw / PSW_V) & 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 >> 14) & 1) << 28;
|
||||||
cb |= ((psw >> 13) & 1) << 24;
|
cb |= ((psw >> 13) & 1) << 24;
|
||||||
cb |= ((psw >> 12) & 1) << 20;
|
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 >> 9) & 1) << 8;
|
||||||
cb |= ((psw >> 8) & 1) << 4;
|
cb |= ((psw >> 8) & 1) << 4;
|
||||||
env->psw_cb = cb;
|
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)
|
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
CPUHPPAState *env = cpu_env(cs);
|
||||||
CPUHPPAState *env = &cpu->env;
|
target_ulong psw = cpu_hppa_get_psw(env);
|
||||||
target_ureg psw = cpu_hppa_get_psw(env);
|
target_ulong psw_cb;
|
||||||
target_ureg psw_cb;
|
|
||||||
char psw_c[20];
|
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
|
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_f, env->iaoq_f),
|
||||||
hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b),
|
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[0] = (psw & PSW_W ? 'W' : '-');
|
||||||
psw_c[1] = (psw & PSW_E ? 'E' : '-');
|
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[16] = (psw & PSW_D ? 'D' : '-');
|
||||||
psw_c[17] = (psw & PSW_I ? 'I' : '-');
|
psw_c[17] = (psw & PSW_I ? 'I' : '-');
|
||||||
psw_c[18] = '\0';
|
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",
|
qemu_fprintf(f, "PSW %0*" PRIx64 " CB %0*" PRIx64 " %s\n",
|
||||||
psw, psw_cb, psw_c);
|
w, m & psw, w, m & psw_cb, psw_c);
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
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' : ' ');
|
(i & 3) == 3 ? '\n' : ' ');
|
||||||
}
|
}
|
||||||
#ifndef CONFIG_USER_ONLY
|
#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_2(excp, noreturn, env, int)
|
||||||
DEF_HELPER_FLAGS_2(tsv, 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, tr)
|
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, TCG_CALL_NO_WG, void, env, tl, tl)
|
||||||
DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tr)
|
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, tr)
|
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, tr)
|
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_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)
|
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(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_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
|
#ifndef CONFIG_USER_ONLY
|
||||||
DEF_HELPER_1(halt, noreturn, env)
|
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(getshadowregs, void, env)
|
||||||
DEF_HELPER_1(rfi, void, env)
|
DEF_HELPER_1(rfi, void, env)
|
||||||
DEF_HELPER_1(rfi_r, 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_interval_timer, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tr)
|
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, tr)
|
DEF_HELPER_FLAGS_2(write_eiem, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tr, env, tr)
|
DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tl, env, tl)
|
||||||
DEF_HELPER_FLAGS_3(itlba, TCG_CALL_NO_RWG, void, env, tl, tr)
|
DEF_HELPER_FLAGS_3(itlba_pa11, TCG_CALL_NO_RWG, void, env, tl, tl)
|
||||||
DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr)
|
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, 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_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_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
|
||||||
DEF_HELPER_1(diag_btlb, void, env)
|
DEF_HELPER_1(diag_btlb, void, env)
|
||||||
#endif
|
#endif
|
||||||
|
@ -46,11 +46,16 @@
|
|||||||
|
|
||||||
%im5_0 0:s1 1:4
|
%im5_0 0:s1 1:4
|
||||||
%im5_16 16:s1 17: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
|
%ma_to_m 5:1 13:1 !function=ma_to_m
|
||||||
%ma2_to_m 2:2 !function=ma_to_m
|
%ma2_to_m 2:2 !function=ma_to_m
|
||||||
%pos_to_m 0:1 !function=pos_to_m
|
%pos_to_m 0:1 !function=pos_to_m
|
||||||
%neg_to_m 0:1 !function=neg_to_m
|
%neg_to_m 0:1 !function=neg_to_m
|
||||||
%a_to_m 2:1 !function=neg_to_m
|
%a_to_m 2:1 !function=neg_to_m
|
||||||
|
%cmpbid_c 13:2 !function=cmpbid_c
|
||||||
|
|
||||||
####
|
####
|
||||||
# Argument set definitions
|
# Argument set definitions
|
||||||
@ -59,28 +64,43 @@
|
|||||||
# All insns that need to form a virtual address should use this set.
|
# All insns that need to form a virtual address should use this set.
|
||||||
&ldst t b x disp sp m scale size
|
&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 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 t r i cf
|
||||||
|
&rri_cf_d t r i cf d
|
||||||
|
|
||||||
&rrb_c_f disp n c f r1 r2
|
&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_f disp n c f r i
|
||||||
|
&rib_c_d_f disp n c d f r i
|
||||||
|
|
||||||
####
|
####
|
||||||
# Format definitions
|
# 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 ...... 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_d ...... r2:5 r1:5 cf:4 ...... d:1 t:5 &rrr_cf_d
|
||||||
@rrr_cf_sh0 ...... r2:5 r1:5 cf:4 ....... t:5 &rrr_cf_sh sh=0
|
@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 ...... 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_cf ...... r2:5 r1:5 c:3 ........... n:1 . \
|
||||||
&rrb_c_f disp=%assemble_12
|
&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_cf ...... r:5 ..... c:3 ........... n:1 . \
|
||||||
&rib_c_f disp=%assemble_12 i=%im5_16
|
&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
|
# 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
|
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 sp:2 0100000 addr:1 0 00000 data=1
|
||||||
ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \
|
ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \
|
||||||
sp=%assemble_sr3x data=0
|
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
|
# pcxl and pcxl2 Fast TLB Insert instructions
|
||||||
ixtlbxf 000001 00000 r:5 00 0 data:1 01000 addr:1 0 00000
|
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
|
# pa2.0 tlb insert idtlbt and iitlbt instructions
|
||||||
pxtlbx 000001 b:5 x:5 ... 000100 local:1 m:1 ----- \
|
ixtlbt 000001 r2:5 r1:5 000 data:1 100000 0 00000 # idtlbt
|
||||||
sp=%assemble_sr3x data=0
|
|
||||||
|
# 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 \
|
lpa 000001 b:5 x:5 sp:2 01001101 m:1 t:5 \
|
||||||
&ldst disp=0 scale=0 size=0
|
&ldst disp=0 scale=0 size=0
|
||||||
@ -150,30 +188,36 @@ lci 000001 ----- ----- -- 01001100 0 t:5
|
|||||||
# Arith/Log
|
# Arith/Log
|
||||||
####
|
####
|
||||||
|
|
||||||
andcm 000010 ..... ..... .... 000000 - ..... @rrr_cf
|
andcm 000010 ..... ..... .... 000000 . ..... @rrr_cf_d
|
||||||
and 000010 ..... ..... .... 001000 - ..... @rrr_cf
|
and 000010 ..... ..... .... 001000 . ..... @rrr_cf_d
|
||||||
or 000010 ..... ..... .... 001001 - ..... @rrr_cf
|
or 000010 ..... ..... .... 001001 . ..... @rrr_cf_d
|
||||||
xor 000010 ..... ..... .... 001010 0 ..... @rrr_cf
|
xor 000010 ..... ..... .... 001010 . ..... @rrr_cf_d
|
||||||
uxor 000010 ..... ..... .... 001110 0 ..... @rrr_cf
|
uxor 000010 ..... ..... .... 001110 . ..... @rrr_cf_d
|
||||||
ds 000010 ..... ..... .... 010001 0 ..... @rrr_cf
|
ds 000010 ..... ..... .... 010001 0 ..... @rrr_cf
|
||||||
cmpclr 000010 ..... ..... .... 100010 0 ..... @rrr_cf
|
cmpclr 000010 ..... ..... .... 100010 . ..... @rrr_cf_d
|
||||||
uaddcm 000010 ..... ..... .... 100110 0 ..... @rrr_cf
|
uaddcm 000010 ..... ..... .... 100110 . ..... @rrr_cf_d
|
||||||
uaddcm_tc 000010 ..... ..... .... 100111 0 ..... @rrr_cf
|
uaddcm_tc 000010 ..... ..... .... 100111 . ..... @rrr_cf_d
|
||||||
dcor 000010 ..... 00000 .... 101110 0 ..... @rr_cf
|
dcor 000010 ..... 00000 .... 101110 . ..... @rr_cf_d
|
||||||
dcor_i 000010 ..... 00000 .... 101111 0 ..... @rr_cf
|
dcor_i 000010 ..... 00000 .... 101111 . ..... @rr_cf_d
|
||||||
|
|
||||||
add 000010 ..... ..... .... 0110.. - ..... @rrr_cf_sh
|
add 000010 ..... ..... .... 0110.. . ..... @rrr_cf_d_sh
|
||||||
add_l 000010 ..... ..... .... 1010.. 0 ..... @rrr_cf_sh
|
add_l 000010 ..... ..... .... 1010.. . ..... @rrr_cf_d_sh
|
||||||
add_tsv 000010 ..... ..... .... 1110.. 0 ..... @rrr_cf_sh
|
add_tsv 000010 ..... ..... .... 1110.. . ..... @rrr_cf_d_sh
|
||||||
add_c 000010 ..... ..... .... 011100 0 ..... @rrr_cf_sh0
|
{
|
||||||
add_c_tsv 000010 ..... ..... .... 111100 0 ..... @rrr_cf_sh0
|
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 000010 ..... ..... .... 010000 . ..... @rrr_cf_d
|
||||||
sub_tsv 000010 ..... ..... .... 110000 0 ..... @rrr_cf
|
sub_tsv 000010 ..... ..... .... 110000 . ..... @rrr_cf_d
|
||||||
sub_tc 000010 ..... ..... .... 010011 0 ..... @rrr_cf
|
sub_tc 000010 ..... ..... .... 010011 . ..... @rrr_cf_d
|
||||||
sub_tsv_tc 000010 ..... ..... .... 110011 0 ..... @rrr_cf
|
sub_tsv_tc 000010 ..... ..... .... 110011 . ..... @rrr_cf_d
|
||||||
sub_b 000010 ..... ..... .... 010100 0 ..... @rrr_cf
|
{
|
||||||
sub_b_tsv 000010 ..... ..... .... 110100 0 ..... @rrr_cf
|
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
|
ldil 001000 t:5 ..................... i=%assemble_21
|
||||||
addil 001010 r: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 100101 ..... ..... .... 0 ........... @rri_cf
|
||||||
subi_tsv 100101 ..... ..... .... 1 ........... @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
|
# Index Mem
|
||||||
@ -204,10 +269,16 @@ ld 000011 ..... ..... .. . 0 -- 00 size:2 ...... @ldstx
|
|||||||
st 000011 ..... ..... .. . 1 -- 10 size:2 ...... @stim5
|
st 000011 ..... ..... .. . 1 -- 10 size:2 ...... @stim5
|
||||||
ldc 000011 ..... ..... .. . 1 -- 0111 ...... @ldim5 size=2
|
ldc 000011 ..... ..... .. . 1 -- 0111 ...... @ldim5 size=2
|
||||||
ldc 000011 ..... ..... .. . 0 -- 0111 ...... @ldstx 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 ..... ..... .. . 1 -- 0110 ...... @ldim5 size=2
|
||||||
lda 000011 ..... ..... .. . 0 -- 0110 ...... @ldstx 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 -- 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
|
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 ..... \
|
@fldstwx ...... b:5 x:5 sp:2 scale:1 ....... m:1 ..... \
|
||||||
&ldst t=%rt64 disp=0 size=2
|
&ldst t=%rt64 disp=0 size=2
|
||||||
@ -233,6 +304,8 @@ fstd 001011 ..... ..... .. . 1 -- 100 0 . ..... @fldstdi
|
|||||||
# Offset Mem
|
# 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 .............. \
|
@ldstim14 ...... b:5 t:5 sp:2 .............. \
|
||||||
&ldst disp=%lowsign_14 x=0 scale=0 m=0
|
&ldst disp=%lowsign_14 x=0 scale=0 m=0
|
||||||
@ldstim14m ...... b:5 t:5 sp:2 .............. \
|
@ldstim14m ...... b:5 t:5 sp:2 .............. \
|
||||||
@ -264,11 +337,11 @@ fstw 011110 b:5 ..... sp:2 .............. \
|
|||||||
fstw 011111 b:5 ..... sp:2 ...........0.. \
|
fstw 011111 b:5 ..... sp:2 ...........0.. \
|
||||||
&ldst disp=%assemble_12a t=%rm64 m=0 x=0 scale=0 size=2
|
&ldst disp=%assemble_12a t=%rm64 m=0 x=0 scale=0 size=2
|
||||||
|
|
||||||
fldd 010100 b:5 t:5 sp:2 .......... .. 1 . \
|
ld 010100 ..... ..... .. ............0. @ldstim11
|
||||||
&ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3
|
fldd 010100 ..... ..... .. ............1. @ldstim11
|
||||||
|
|
||||||
fstd 011100 b:5 t:5 sp:2 .......... .. 1 . \
|
st 011100 ..... ..... .. ............0. @ldstim11
|
||||||
&ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3
|
fstd 011100 ..... ..... .. ............1. @ldstim11
|
||||||
|
|
||||||
####
|
####
|
||||||
# Floating-point Multiply Add
|
# Floating-point Multiply Add
|
||||||
@ -286,16 +359,20 @@ fmpysub_d 100110 ..... ..... ..... ..... 1 ..... @mpyadd
|
|||||||
# Conditional Branches
|
# Conditional Branches
|
||||||
####
|
####
|
||||||
|
|
||||||
bb_sar 110000 00000 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 10 ........... 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
|
movb 110010 ..... ..... ... ........... . . @rrb_cf f=0
|
||||||
movbi 110011 ..... ..... ... ........... . . @rib_cf f=0
|
movbi 110011 ..... ..... ... ........... . . @rib_cf f=0
|
||||||
|
|
||||||
cmpb 100000 ..... ..... ... ........... . . @rrb_cf f=0
|
cmpb 100000 ..... ..... ... ........... . . @rrb_cdf d=0 f=0
|
||||||
cmpb 100010 ..... ..... ... ........... . . @rrb_cf f=1
|
cmpb 100010 ..... ..... ... ........... . . @rrb_cdf d=0 f=1
|
||||||
cmpbi 100001 ..... ..... ... ........... . . @rib_cf f=0
|
cmpb 100111 ..... ..... ... ........... . . @rrb_cdf d=1 f=0
|
||||||
cmpbi 100011 ..... ..... ... ........... . . @rib_cf f=1
|
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 101000 ..... ..... ... ........... . . @rrb_cf f=0
|
||||||
addb 101010 ..... ..... ... ........... . . @rrb_cf f=1
|
addb 101010 ..... ..... ... ........... . . @rrb_cf f=1
|
||||||
@ -306,16 +383,28 @@ addbi 101011 ..... ..... ... ........... . . @rib_cf f=1
|
|||||||
# Shift, Extract, Deposit
|
# Shift, Extract, Deposit
|
||||||
####
|
####
|
||||||
|
|
||||||
shrpw_sar 110100 r2:5 r1:5 c:3 00 0 00000 t:5
|
shrp_sar 110100 r2:5 r1:5 c:3 00 0 d:1 0000 t:5
|
||||||
shrpw_imm 110100 r2:5 r1:5 c:3 01 0 cpos:5 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
|
extr_sar 110100 r:5 t:5 c:3 10 se:1 00 000 ..... d=0 len=%len5
|
||||||
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 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
|
dep_sar 110101 t:5 r:5 c:3 00 nz:1 00 000 ..... d=0 len=%len5
|
||||||
depw_imm 110101 t:5 r:5 c:3 01 nz:1 cpos:5 clen:5
|
dep_sar 110101 t:5 r:5 c:3 00 nz:1 1. 000 ..... d=1 len=%len6_8
|
||||||
depwi_sar 110101 t:5 ..... c:3 10 nz:1 00000 clen:5 i=%im5_16
|
dep_imm 110101 t:5 r:5 c:3 01 nz:1 cpos:5 ..... d=0 len=%len5
|
||||||
depwi_imm 110101 t:5 ..... c:3 11 nz:1 cpos:5 clen:5 i=%im5_16
|
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
|
# Branch External
|
||||||
@ -343,6 +432,8 @@ bl 111010 ..... ..... 101 ........... n:1 . &BL l=2 \
|
|||||||
disp=%assemble_22
|
disp=%assemble_22
|
||||||
b_gate 111010 ..... ..... 001 ........... . . @bl
|
b_gate 111010 ..... ..... 001 ........... . . @bl
|
||||||
blr 111010 l:5 x:5 010 00000000000 n:1 0
|
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
|
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 110 10000000000 n:1 - l=0
|
||||||
bve 111010 b:5 00000 111 10000000000 n:1 - l=2
|
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 ..... \
|
@f0e_f_3 ...... ..... ..... ... .0 110 ..0 ..... \
|
||||||
&fclass3 r1=%ra64 r2=%rb64 t=%rt64
|
&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
|
# Floating point class 0
|
||||||
|
|
||||||
|
@ -52,9 +52,17 @@ static void io_eir_write(void *opaque, hwaddr addr,
|
|||||||
uint64_t data, unsigned size)
|
uint64_t data, unsigned size)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = opaque;
|
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);
|
eval_interrupt(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +81,7 @@ void hppa_cpu_alarm_timer(void *opaque)
|
|||||||
io_eir_write(opaque, 0, 0, 4);
|
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;
|
env->cr[CR_EIRR] &= ~val;
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
@ -81,7 +89,7 @@ void HELPER(write_eirr)(CPUHPPAState *env, target_ureg val)
|
|||||||
qemu_mutex_unlock_iothread();
|
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;
|
env->cr[CR_EIEM] = val;
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
@ -94,25 +102,37 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
|||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
HPPACPU *cpu = HPPA_CPU(cs);
|
||||||
CPUHPPAState *env = &cpu->env;
|
CPUHPPAState *env = &cpu->env;
|
||||||
int i = cs->exception_index;
|
int i = cs->exception_index;
|
||||||
target_ureg iaoq_f = env->iaoq_f;
|
uint64_t old_psw;
|
||||||
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;
|
|
||||||
|
|
||||||
/* As documented in pa2.0 -- interruption handling. */
|
/* As documented in pa2.0 -- interruption handling. */
|
||||||
/* step 1 */
|
/* step 1 */
|
||||||
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
|
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
|
||||||
|
|
||||||
/* step 2 -- note PSW_W == 0 for !HPPA64. */
|
/* step 2 -- Note PSW_W is masked out again for pa1.x */
|
||||||
cpu_hppa_put_psw(env, PSW_W | (i == EXCP_HPMC ? PSW_M : 0));
|
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 */
|
/* step 3 */
|
||||||
env->cr[CR_IIASQ] = iasq_f >> 32;
|
/*
|
||||||
env->cr_back[0] = iasq_b >> 32;
|
* For pa1.x, IIASQ is simply a copy of IASQ.
|
||||||
env->cr[CR_IIAOQ] = iaoq_f;
|
* For pa2.0, IIASQ is the top bits of the virtual address,
|
||||||
env->cr_back[1] = iaoq_b;
|
* 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) {
|
if (old_psw & PSW_Q) {
|
||||||
/* step 5 */
|
/* step 5 */
|
||||||
@ -145,14 +165,13 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
|||||||
/* ??? An alternate fool-proof method would be to store the
|
/* ??? An alternate fool-proof method would be to store the
|
||||||
instruction data into the unwind info. That's probably
|
instruction data into the unwind info. That's probably
|
||||||
a bit too much in the way of extra storage required. */
|
a bit too much in the way of extra storage required. */
|
||||||
vaddr vaddr;
|
vaddr vaddr = env->iaoq_f & -4;
|
||||||
hwaddr paddr;
|
hwaddr paddr = vaddr;
|
||||||
|
|
||||||
paddr = vaddr = iaoq_f & -4;
|
|
||||||
if (old_psw & PSW_C) {
|
if (old_psw & PSW_C) {
|
||||||
int prot, t;
|
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,
|
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
|
||||||
0, &paddr, &prot, NULL);
|
0, &paddr, &prot, NULL);
|
||||||
if (t >= 0) {
|
if (t >= 0) {
|
||||||
@ -182,14 +201,14 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
|||||||
|
|
||||||
/* step 7 */
|
/* step 7 */
|
||||||
if (i == EXCP_TOC) {
|
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 */
|
/* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
|
||||||
env->gr[24] = env->cr_back[0];
|
env->gr[24] = env->cr_back[0];
|
||||||
env->gr[25] = env->cr_back[1];
|
env->gr[25] = env->cr_back[1];
|
||||||
} else {
|
} 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_f = 0;
|
||||||
env->iasq_b = 0;
|
env->iasq_b = 0;
|
||||||
|
|
||||||
@ -239,14 +258,10 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
|||||||
snprintf(unknown, sizeof(unknown), "unknown %d", i);
|
snprintf(unknown, sizeof(unknown), "unknown %d", i);
|
||||||
name = unknown;
|
name = unknown;
|
||||||
}
|
}
|
||||||
qemu_log("INT %6d: %s @ " TARGET_FMT_lx "," TARGET_FMT_lx
|
qemu_log("INT %6d: %s @ " TARGET_FMT_lx ":" TARGET_FMT_lx
|
||||||
" -> " TREG_FMT_lx " " TARGET_FMT_lx "\n",
|
" for " TARGET_FMT_lx ":" TARGET_FMT_lx "\n",
|
||||||
++count, name,
|
++count, name, env->cr[CR_IIASQ], env->cr[CR_IIAOQ],
|
||||||
hppa_form_gva(env, iasq_f, iaoq_f),
|
env->cr[CR_ISR], env->cr[CR_IOR]);
|
||||||
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]));
|
|
||||||
}
|
}
|
||||||
cs->exception_index = -1;
|
cs->exception_index = -1;
|
||||||
}
|
}
|
||||||
|
@ -21,33 +21,12 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "migration/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,
|
static int get_psw(QEMUFile *f, void *opaque, size_t size,
|
||||||
const VMStateField *field)
|
const VMStateField *field)
|
||||||
{
|
{
|
||||||
CPUHPPAState *env = opaque;
|
CPUHPPAState *env = opaque;
|
||||||
cpu_hppa_put_psw(env, qemu_get_betr(f));
|
cpu_hppa_put_psw(env, qemu_get_be64(f));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +34,7 @@ static int put_psw(QEMUFile *f, void *opaque, size_t size,
|
|||||||
const VMStateField *field, JSONWriter *vmdesc)
|
const VMStateField *field, JSONWriter *vmdesc)
|
||||||
{
|
{
|
||||||
CPUHPPAState *env = opaque;
|
CPUHPPAState *env = opaque;
|
||||||
qemu_put_betr(f, cpu_hppa_get_psw(env));
|
qemu_put_be64(f, cpu_hppa_get_psw(env));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,70 +44,138 @@ static const VMStateInfo vmstate_psw = {
|
|||||||
.put = put_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,
|
static int get_tlb(QEMUFile *f, void *opaque, size_t size,
|
||||||
const VMStateField *field)
|
const VMStateField *field)
|
||||||
{
|
{
|
||||||
hppa_tlb_entry *ent = opaque;
|
HPPATLBEntry *ent = opaque;
|
||||||
uint32_t val;
|
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);
|
if (val) {
|
||||||
ent->pa = qemu_get_betr(f);
|
ent->t = extract64(val, 61, 1);
|
||||||
val = qemu_get_be32(f);
|
ent->d = extract64(val, 60, 1);
|
||||||
|
ent->b = extract64(val, 59, 1);
|
||||||
ent->entry_valid = extract32(val, 0, 1);
|
ent->ar_type = extract64(val, 56, 3);
|
||||||
ent->access_id = extract32(val, 1, 18);
|
ent->ar_pl1 = extract64(val, 54, 2);
|
||||||
ent->u = extract32(val, 19, 1);
|
ent->ar_pl2 = extract64(val, 52, 2);
|
||||||
ent->ar_pl2 = extract32(val, 20, 2);
|
ent->u = extract64(val, 51, 1);
|
||||||
ent->ar_pl1 = extract32(val, 22, 2);
|
/* o = bit 50 */
|
||||||
ent->ar_type = extract32(val, 24, 3);
|
/* p = bit 49 */
|
||||||
ent->b = extract32(val, 27, 1);
|
ent->access_id = extract64(val, 1, 31);
|
||||||
ent->d = extract32(val, 28, 1);
|
ent->entry_valid = 1;
|
||||||
ent->t = extract32(val, 29, 1);
|
}
|
||||||
|
|
||||||
ent->va_e = ent->va_b + TARGET_PAGE_SIZE - 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int put_tlb(QEMUFile *f, void *opaque, size_t size,
|
static int put_tlb(QEMUFile *f, void *opaque, size_t size,
|
||||||
const VMStateField *field, JSONWriter *vmdesc)
|
const VMStateField *field, JSONWriter *vmdesc)
|
||||||
{
|
{
|
||||||
hppa_tlb_entry *ent = opaque;
|
HPPATLBEntry *ent = opaque;
|
||||||
uint32_t val = 0;
|
uint64_t val = 0;
|
||||||
|
|
||||||
if (ent->entry_valid) {
|
if (ent->entry_valid) {
|
||||||
val = 1;
|
val = 1;
|
||||||
val = deposit32(val, 1, 18, ent->access_id);
|
val = deposit64(val, 61, 1, ent->t);
|
||||||
val = deposit32(val, 19, 1, ent->u);
|
val = deposit64(val, 60, 1, ent->d);
|
||||||
val = deposit32(val, 20, 2, ent->ar_pl2);
|
val = deposit64(val, 59, 1, ent->b);
|
||||||
val = deposit32(val, 22, 2, ent->ar_pl1);
|
val = deposit64(val, 56, 3, ent->ar_type);
|
||||||
val = deposit32(val, 24, 3, ent->ar_type);
|
val = deposit64(val, 54, 2, ent->ar_pl1);
|
||||||
val = deposit32(val, 27, 1, ent->b);
|
val = deposit64(val, 52, 2, ent->ar_pl2);
|
||||||
val = deposit32(val, 28, 1, ent->d);
|
val = deposit64(val, 51, 1, ent->u);
|
||||||
val = deposit32(val, 29, 1, ent->t);
|
/* o = bit 50 */
|
||||||
|
/* p = bit 49 */
|
||||||
|
val = deposit64(val, 1, 31, ent->access_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_put_be64(f, ent->va_b);
|
qemu_put_be64(f, ent->itree.start);
|
||||||
qemu_put_betr(f, ent->pa);
|
qemu_put_be64(f, ent->itree.last);
|
||||||
qemu_put_be32(f, val);
|
qemu_put_be64(f, ent->pa);
|
||||||
|
qemu_put_be64(f, val);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateInfo vmstate_tlb = {
|
static const VMStateInfo vmstate_tlb_entry = {
|
||||||
.name = "tlb entry",
|
.name = "tlb entry",
|
||||||
.get = get_tlb,
|
.get = get_tlb,
|
||||||
.put = put_tlb,
|
.put = put_tlb,
|
||||||
};
|
};
|
||||||
|
|
||||||
static VMStateField vmstate_env_fields[] = {
|
static int tlb_pre_load(void *opaque)
|
||||||
VMSTATE_UINTTR_ARRAY(gr, CPUHPPAState, 32),
|
{
|
||||||
|
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(fr, CPUHPPAState, 32),
|
||||||
VMSTATE_UINT64_ARRAY(sr, CPUHPPAState, 8),
|
VMSTATE_UINT64_ARRAY(sr, CPUHPPAState, 8),
|
||||||
VMSTATE_UINTTR_ARRAY(cr, CPUHPPAState, 32),
|
VMSTATE_UINT64_ARRAY(cr, CPUHPPAState, 32),
|
||||||
VMSTATE_UINTTR_ARRAY(cr_back, CPUHPPAState, 2),
|
VMSTATE_UINT64_ARRAY(cr_back, CPUHPPAState, 2),
|
||||||
VMSTATE_UINTTR_ARRAY(shadow, CPUHPPAState, 7),
|
VMSTATE_UINT64_ARRAY(shadow, CPUHPPAState, 7),
|
||||||
|
|
||||||
/* Save the architecture value of the psw, not the internally
|
/* Save the architecture value of the psw, not the internally
|
||||||
expanded version. Since this architecture value does not
|
expanded version. Since this architecture value does not
|
||||||
@ -145,28 +192,29 @@ static VMStateField vmstate_env_fields[] = {
|
|||||||
.offset = 0
|
.offset = 0
|
||||||
},
|
},
|
||||||
|
|
||||||
VMSTATE_UINTTR(iaoq_f, CPUHPPAState),
|
VMSTATE_UINT64(iaoq_f, CPUHPPAState),
|
||||||
VMSTATE_UINTTR(iaoq_b, CPUHPPAState),
|
VMSTATE_UINT64(iaoq_b, CPUHPPAState),
|
||||||
VMSTATE_UINT64(iasq_f, CPUHPPAState),
|
VMSTATE_UINT64(iasq_f, CPUHPPAState),
|
||||||
VMSTATE_UINT64(iasq_b, CPUHPPAState),
|
VMSTATE_UINT64(iasq_b, CPUHPPAState),
|
||||||
|
|
||||||
VMSTATE_UINT32(fr0_shadow, 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()
|
VMSTATE_END_OF_LIST()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const VMStateDescription *vmstate_env_subsections[] = {
|
||||||
|
&vmstate_tlb,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_env = {
|
static const VMStateDescription vmstate_env = {
|
||||||
.name = "env",
|
.name = "env",
|
||||||
.version_id = 1,
|
.version_id = 3,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 3,
|
||||||
.fields = vmstate_env_fields,
|
.fields = vmstate_env_fields,
|
||||||
|
.subsections = vmstate_env_subsections,
|
||||||
};
|
};
|
||||||
|
|
||||||
static VMStateField vmstate_cpu_fields[] = {
|
static const VMStateField vmstate_cpu_fields[] = {
|
||||||
VMSTATE_CPU(),
|
VMSTATE_CPU(),
|
||||||
VMSTATE_STRUCT(env, HPPACPU, 1, vmstate_env, CPUHPPAState),
|
VMSTATE_STRUCT(env, HPPACPU, 1, vmstate_env, CPUHPPAState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
@ -25,72 +25,136 @@
|
|||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
#include "trace.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) {
|
hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr)
|
||||||
hppa_tlb_entry *ent = &env->tlb[i];
|
{
|
||||||
if (ent->va_b <= addr && addr <= ent->va_e) {
|
if (likely(extract32(addr, 28, 4) != 0xf)) {
|
||||||
trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid,
|
/* Memory address space */
|
||||||
ent->va_b, ent->va_e, ent->pa);
|
return addr & MAKE_64BIT_MASK(0, 32);
|
||||||
return ent;
|
}
|
||||||
}
|
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);
|
trace_hppa_tlb_find_entry_not_found(env, addr);
|
||||||
return NULL;
|
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)
|
bool force_flush_btlb)
|
||||||
{
|
{
|
||||||
CPUState *cs = env_cpu(env);
|
CPUState *cs = env_cpu(env);
|
||||||
|
bool is_btlb;
|
||||||
|
|
||||||
if (!ent->entry_valid) {
|
if (!ent->entry_valid) {
|
||||||
return;
|
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,
|
tlb_flush_range_by_mmuidx(cs, ent->itree.start,
|
||||||
ent->va_e - ent->va_b + 1,
|
ent->itree.last - ent->itree.start + 1,
|
||||||
HPPA_MMU_FLUSH_MASK, TARGET_LONG_BITS);
|
HPPA_MMU_FLUSH_MASK, TARGET_LONG_BITS);
|
||||||
|
|
||||||
/* never clear BTLBs, unless forced to do so. */
|
/* Never clear BTLBs, unless forced to do so. */
|
||||||
if (ent < &env->tlb[HPPA_BTLB_ENTRIES] && !force_flush_btlb) {
|
is_btlb = ent < &env->tlb[HPPA_BTLB_ENTRIES(env)];
|
||||||
|
if (is_btlb && !force_flush_btlb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interval_tree_remove(&ent->itree, &env->tlb_root);
|
||||||
memset(ent, 0, sizeof(*ent));
|
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;
|
IntervalTreeNode *i, *n;
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
if (env->tlb_last < HPPA_BTLB_ENTRIES || env->tlb_last >= ARRAY_SIZE(env->tlb)) {
|
i = interval_tree_iter_first(&env->tlb_root, va_b, va_e);
|
||||||
i = HPPA_BTLB_ENTRIES;
|
for (; i ; i = n) {
|
||||||
env->tlb_last = HPPA_BTLB_ENTRIES + 1;
|
HPPATLBEntry *ent = container_of(i, HPPATLBEntry, itree);
|
||||||
} else {
|
|
||||||
i = env->tlb_last;
|
/*
|
||||||
env->tlb_last++;
|
* 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];
|
env->tlb_unused = ent->unused_next;
|
||||||
|
|
||||||
hppa_flush_tlb_ent(env, ent, false);
|
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
||||||
int type, hwaddr *pphys, int *pprot,
|
int type, hwaddr *pphys, int *pprot,
|
||||||
hppa_tlb_entry **tlb_entry)
|
HPPATLBEntry **tlb_entry)
|
||||||
{
|
{
|
||||||
hwaddr phys;
|
hwaddr phys;
|
||||||
int prot, r_prot, w_prot, x_prot, priv;
|
int prot, r_prot, w_prot, x_prot, priv;
|
||||||
hppa_tlb_entry *ent;
|
HPPATLBEntry *ent;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (tlb_entry) {
|
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. */
|
/* Find a valid tlb entry that matches the virtual address. */
|
||||||
ent = hppa_find_tlb(env, addr);
|
ent = hppa_find_tlb(env, addr);
|
||||||
if (ent == NULL || !ent->entry_valid) {
|
if (ent == NULL) {
|
||||||
phys = 0;
|
phys = 0;
|
||||||
prot = 0;
|
prot = 0;
|
||||||
ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
|
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. */
|
/* 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. */
|
/* Map TLB access_rights field to QEMU protection. */
|
||||||
priv = MMU_IDX_TO_PRIV(mmu_idx);
|
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 */
|
/* 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. */
|
/* If bits [31:1] match, and bit 0 is set, suppress write. */
|
||||||
int match = ent->access_id * 2 + 1;
|
int match = ent->access_id * 2 + 1;
|
||||||
|
|
||||||
@ -197,7 +261,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
egress:
|
egress:
|
||||||
*pphys = phys;
|
*pphys = phys = hppa_abs_to_phys(env, phys);
|
||||||
*pprot = prot;
|
*pprot = prot;
|
||||||
trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
|
trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
|
||||||
return ret;
|
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,
|
/* ??? We really ought to know if the code mmu is disabled too,
|
||||||
in order to get the correct debugging dumps. */
|
in order to get the correct debugging dumps. */
|
||||||
if (!(cpu->env.psw & PSW_D)) {
|
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,
|
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;
|
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,
|
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||||
MMUAccessType type, int mmu_idx,
|
MMUAccessType type, int mmu_idx,
|
||||||
bool probe, uintptr_t retaddr)
|
bool probe, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
HPPACPU *cpu = HPPA_CPU(cs);
|
||||||
CPUHPPAState *env = &cpu->env;
|
CPUHPPAState *env = &cpu->env;
|
||||||
hppa_tlb_entry *ent;
|
HPPATLBEntry *ent;
|
||||||
int prot, excp, a_prot;
|
int prot, excp, a_prot;
|
||||||
hwaddr phys;
|
hwaddr phys;
|
||||||
|
|
||||||
@ -254,56 +365,51 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
|
trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
|
||||||
|
|
||||||
/* Failure. Raise the indicated exception. */
|
/* Failure. Raise the indicated exception. */
|
||||||
cs->exception_index = excp;
|
raise_exception_with_ior(env, excp, retaddr,
|
||||||
if (cpu->env.psw & PSW_Q) {
|
addr, mmu_idx == MMU_PHYS_IDX);
|
||||||
/* ??? Needs tweaking for hppa64. */
|
|
||||||
cpu->env.cr[CR_IOR] = addr;
|
|
||||||
cpu->env.cr[CR_ISR] = addr >> 32;
|
|
||||||
}
|
|
||||||
cpu_loop_exit_restore(cs, retaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
|
trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
|
||||||
phys & TARGET_PAGE_MASK, size, type, mmu_idx);
|
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,
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert (Insn/Data) TLB Address. Note this is PA 1.1 only. */
|
/* 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;
|
HPPATLBEntry *ent;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Zap any old entries covering ADDR; notice empty entries on the way. */
|
/* Zap any old entries covering ADDR. */
|
||||||
for (i = HPPA_BTLB_ENTRIES; i < ARRAY_SIZE(env->tlb); ++i) {
|
addr &= TARGET_PAGE_MASK;
|
||||||
hppa_tlb_entry *ent = &env->tlb[i];
|
hppa_flush_tlb_range(env, addr, addr + TARGET_PAGE_SIZE - 1);
|
||||||
if (ent->va_b <= addr && addr <= ent->va_e) {
|
|
||||||
if (ent->entry_valid) {
|
ent = env->tlb_partial;
|
||||||
hppa_flush_tlb_ent(env, ent, false);
|
if (ent == NULL) {
|
||||||
}
|
ent = hppa_alloc_tlb_ent(env);
|
||||||
if (!empty) {
|
env->tlb_partial = ent;
|
||||||
empty = ent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we didn't see an empty entry, evict one. */
|
/* Note that ent->entry_valid == 0 already. */
|
||||||
if (empty == NULL) {
|
ent->itree.start = addr;
|
||||||
empty = hppa_alloc_tlb_ent(env);
|
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);
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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->access_id = extract32(reg, 1, 18);
|
||||||
ent->u = extract32(reg, 19, 1);
|
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->d = extract32(reg, 28, 1);
|
||||||
ent->t = extract32(reg, 29, 1);
|
ent->t = extract32(reg, 29, 1);
|
||||||
ent->entry_valid = 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,
|
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);
|
ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
|
/* 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)) {
|
if (ent) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
|
env->tlb_partial = NULL;
|
||||||
return;
|
if (ent->itree.start <= addr && addr <= ent->itree.last) {
|
||||||
|
set_access_bits_pa11(env, ent, reg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
|
||||||
set_access_bits(env, ent, reg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
|
static void itlbt_pa20(CPUHPPAState *env, target_ulong r1,
|
||||||
synchronous across all processors. */
|
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)
|
static void ptlb_work(CPUState *cpu, run_on_cpu_data data)
|
||||||
{
|
{
|
||||||
CPUHPPAState *env = cpu_env(cpu);
|
CPUHPPAState *env = cpu_env(cpu);
|
||||||
target_ulong addr = (target_ulong) data.target_ptr;
|
vaddr start = data.target_ptr;
|
||||||
hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
|
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)
|
void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
|
||||||
{
|
{
|
||||||
CPUState *src = env_cpu(env);
|
CPUState *src = env_cpu(env);
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
bool wait = false;
|
||||||
|
|
||||||
trace_hppa_tlb_ptlb(env);
|
trace_hppa_tlb_ptlb(env);
|
||||||
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
|
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
if (cpu != src) {
|
if (cpu != src) {
|
||||||
async_run_on_cpu(cpu, ptlb_work, data);
|
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
|
/* Purge (Insn/Data) TLB entry. This affects an implementation-defined
|
||||||
@ -365,17 +575,12 @@ void HELPER(ptlbe)(CPUHPPAState *env)
|
|||||||
{
|
{
|
||||||
trace_hppa_tlb_ptlbe(env);
|
trace_hppa_tlb_ptlbe(env);
|
||||||
qemu_log_mask(CPU_LOG_MMU, "FLUSH ALL TLB ENTRIES\n");
|
qemu_log_mask(CPU_LOG_MMU, "FLUSH ALL TLB ENTRIES\n");
|
||||||
memset(&env->tlb[HPPA_BTLB_ENTRIES], 0,
|
hppa_ptlbe(env);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_hppa_change_prot_id(CPUHPPAState *env)
|
void cpu_hppa_change_prot_id(CPUHPPAState *env)
|
||||||
{
|
{
|
||||||
if (env->psw & PSW_P) {
|
tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_P_MASK);
|
||||||
tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(change_prot_id)(CPUHPPAState *env)
|
void HELPER(change_prot_id)(CPUHPPAState *env)
|
||||||
@ -383,7 +588,7 @@ void HELPER(change_prot_id)(CPUHPPAState *env)
|
|||||||
cpu_hppa_change_prot_id(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;
|
hwaddr phys;
|
||||||
int prot, excp;
|
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,
|
excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0,
|
||||||
&phys, &prot, NULL);
|
&phys, &prot, NULL);
|
||||||
if (excp >= 0) {
|
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) {
|
if (excp == EXCP_DTLB_MISS) {
|
||||||
excp = EXCP_NA_DTLB_MISS;
|
excp = EXCP_NA_DTLB_MISS;
|
||||||
}
|
}
|
||||||
trace_hppa_tlb_lpa_failed(env, addr);
|
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);
|
trace_hppa_tlb_lpa_success(env, addr, phys);
|
||||||
return 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. */
|
/* Return the ar_type of the TLB at VADDR, or -1. */
|
||||||
int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
|
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;
|
return ent ? ent->ar_type : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,15 +624,17 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
|
|||||||
unsigned int phys_page, len, slot;
|
unsigned int phys_page, len, slot;
|
||||||
int mmu_idx = cpu_mmu_index(env, 0);
|
int mmu_idx = cpu_mmu_index(env, 0);
|
||||||
uintptr_t ra = GETPC();
|
uintptr_t ra = GETPC();
|
||||||
hppa_tlb_entry *btlb;
|
HPPATLBEntry *btlb;
|
||||||
uint64_t virt_page;
|
uint64_t virt_page;
|
||||||
uint32_t *vaddr;
|
uint32_t *vaddr;
|
||||||
|
uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env);
|
||||||
|
|
||||||
#ifdef TARGET_HPPA64
|
|
||||||
/* BTLBs are not supported on 64-bit CPUs */
|
/* BTLBs are not supported on 64-bit CPUs */
|
||||||
env->gr[28] = -1; /* nonexistent procedure */
|
if (btlb_entries == 0) {
|
||||||
return;
|
env->gr[28] = -1; /* nonexistent procedure */
|
||||||
#endif
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
env->gr[28] = 0; /* PDC_OK */
|
env->gr[28] = 0; /* PDC_OK */
|
||||||
|
|
||||||
switch (env->gr[25]) {
|
switch (env->gr[25]) {
|
||||||
@ -446,8 +648,8 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
|
|||||||
} else {
|
} else {
|
||||||
vaddr[0] = cpu_to_be32(1);
|
vaddr[0] = cpu_to_be32(1);
|
||||||
vaddr[1] = cpu_to_be32(16 * 1024);
|
vaddr[1] = cpu_to_be32(16 * 1024);
|
||||||
vaddr[2] = cpu_to_be32(HPPA_BTLB_FIXED);
|
vaddr[2] = cpu_to_be32(PA10_BTLB_FIXED);
|
||||||
vaddr[3] = cpu_to_be32(HPPA_BTLB_VARIABLE);
|
vaddr[3] = cpu_to_be32(PA10_BTLB_VARIABLE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -464,15 +666,17 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
|
|||||||
(long long) virt_page << TARGET_PAGE_BITS,
|
(long long) virt_page << TARGET_PAGE_BITS,
|
||||||
(long long) (virt_page + len) << TARGET_PAGE_BITS,
|
(long long) (virt_page + len) << TARGET_PAGE_BITS,
|
||||||
(long long) virt_page, phys_page, len, slot);
|
(long long) virt_page, phys_page, len, slot);
|
||||||
if (slot < HPPA_BTLB_ENTRIES) {
|
if (slot < btlb_entries) {
|
||||||
btlb = &env->tlb[slot];
|
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);
|
hppa_flush_tlb_ent(env, btlb, true);
|
||||||
/* create new BTLB entry */
|
|
||||||
btlb->va_b = virt_page << TARGET_PAGE_BITS;
|
/* Create new BTLB entry */
|
||||||
btlb->va_e = btlb->va_b + len * TARGET_PAGE_SIZE - 1;
|
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;
|
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->t = 0;
|
||||||
btlb->d = 1;
|
btlb->d = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -484,7 +688,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
|
|||||||
slot = env->gr[22];
|
slot = env->gr[22];
|
||||||
qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE slot %d\n",
|
qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE slot %d\n",
|
||||||
slot);
|
slot);
|
||||||
if (slot < HPPA_BTLB_ENTRIES) {
|
if (slot < btlb_entries) {
|
||||||
btlb = &env->tlb[slot];
|
btlb = &env->tlb[slot];
|
||||||
hppa_flush_tlb_ent(env, btlb, true);
|
hppa_flush_tlb_ent(env, btlb, true);
|
||||||
} else {
|
} else {
|
||||||
@ -494,7 +698,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
|
|||||||
case 3:
|
case 3:
|
||||||
/* Purge all BTLB entries */
|
/* Purge all BTLB entries */
|
||||||
qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE_ALL\n");
|
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];
|
btlb = &env->tlb[slot];
|
||||||
hppa_flush_tlb_ent(env, btlb, true);
|
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);
|
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());
|
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)) {
|
if (unlikely(cond)) {
|
||||||
hppa_dynamic_excp(env, EXCP_COND, GETPC());
|
hppa_dynamic_excp(env, EXCP_COND, GETPC());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atomic_store_3(CPUHPPAState *env, target_ulong addr,
|
static void atomic_store_mask32(CPUHPPAState *env, target_ulong addr,
|
||||||
uint32_t val, uintptr_t ra)
|
uint32_t val, uint32_t mask, uintptr_t ra)
|
||||||
{
|
{
|
||||||
int mmu_idx = cpu_mmu_index(env, 0);
|
int mmu_idx = cpu_mmu_index(env, 0);
|
||||||
uint32_t old, new, cmp, mask, *haddr;
|
uint32_t old, new, cmp, *haddr;
|
||||||
void *vaddr;
|
void *vaddr;
|
||||||
|
|
||||||
vaddr = probe_access(env, addr, 3, MMU_DATA_STORE, mmu_idx, ra);
|
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)
|
bool parallel, uintptr_t ra)
|
||||||
{
|
{
|
||||||
switch (addr & 3) {
|
switch (addr & 3) {
|
||||||
@ -94,7 +123,7 @@ static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val,
|
|||||||
case 1:
|
case 1:
|
||||||
/* The 3 byte store must appear atomic. */
|
/* The 3 byte store must appear atomic. */
|
||||||
if (parallel) {
|
if (parallel) {
|
||||||
atomic_store_3(env, addr, val, ra);
|
atomic_store_mask32(env, addr, val, 0x00ffffffu, ra);
|
||||||
} else {
|
} else {
|
||||||
cpu_stb_data_ra(env, addr, val >> 16, ra);
|
cpu_stb_data_ra(env, addr, val >> 16, ra);
|
||||||
cpu_stw_data_ra(env, addr + 1, val, 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());
|
do_stby_b(env, addr, val, false, GETPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(stby_b_parallel)(CPUHPPAState *env, target_ulong addr,
|
void HELPER(stby_b_parallel)(CPUHPPAState *env, target_ulong addr,
|
||||||
target_ureg val)
|
target_ulong val)
|
||||||
{
|
{
|
||||||
do_stby_b(env, addr, val, true, GETPC());
|
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)
|
bool parallel, uintptr_t ra)
|
||||||
{
|
{
|
||||||
switch (addr & 3) {
|
switch (addr & 3) {
|
||||||
case 3:
|
case 3:
|
||||||
/* The 3 byte store must appear atomic. */
|
/* The 3 byte store must appear atomic. */
|
||||||
if (parallel) {
|
if (parallel) {
|
||||||
atomic_store_3(env, addr - 3, val, ra);
|
atomic_store_mask32(env, addr - 3, val, 0xffffff00u, ra);
|
||||||
} else {
|
} else {
|
||||||
cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
|
cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
|
||||||
cpu_stb_data_ra(env, addr - 1, val >> 8, 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());
|
do_stby_e(env, addr, val, false, GETPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(stby_e_parallel)(CPUHPPAState *env, target_ulong addr,
|
void HELPER(stby_e_parallel)(CPUHPPAState *env, target_ulong addr,
|
||||||
target_ureg val)
|
target_ulong val)
|
||||||
{
|
{
|
||||||
do_stby_e(env, addr, val, true, GETPC());
|
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)
|
void HELPER(ldc_check)(target_ulong addr)
|
||||||
{
|
{
|
||||||
if (unlikely(addr & 0xf)) {
|
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)
|
uint32_t level, uint32_t want)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
@ -196,7 +364,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ureg HELPER(read_interval_timer)(void)
|
target_ulong HELPER(read_interval_timer)(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
/* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist.
|
/* 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;
|
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 2;
|
||||||
#endif
|
#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 "qemu/timer.h"
|
||||||
#include "sysemu/runstate.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);
|
HPPACPU *cpu = env_archcpu(env);
|
||||||
uint64_t current = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
uint64_t current = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
@ -58,7 +58,7 @@ void HELPER(reset)(CPUHPPAState *env)
|
|||||||
helper_excp(env, EXCP_HLT);
|
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;
|
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->iasq_b = (uint64_t)env->cr_back[0] << 32;
|
||||||
env->iaoq_f = env->cr[CR_IIAOQ];
|
env->iaoq_f = env->cr[CR_IIAOQ];
|
||||||
env->iaoq_b = env->cr_back[1];
|
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]);
|
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_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_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(void *env) "env=%p"
|
||||||
|
disable hppa_tlb_ptlb_local(void *env) "env=%p"
|
||||||
disable hppa_tlb_ptlbe(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_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"
|
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…
Reference in New Issue
Block a user