diff options
59 files changed, 2121 insertions, 911 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index cf1158a434..1f5f8b7a2c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -935,6 +935,7 @@ M: Aurelien Jarno <aurelien@aurel32.net> R: Aleksandar Rikalo <arikalo@wavecomp.com> S: Maintained F: hw/mips/mips_malta.c +F: tests/acceptance/linux_ssh_mips_malta.py Mipssim M: Aleksandar Markovic <amarkovic@wavecomp.com> diff --git a/Makefile.objs b/Makefile.objs index d7491413c1..b61568ad06 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -182,6 +182,7 @@ trace-events-subdirs += hw/virtio trace-events-subdirs += hw/watchdog trace-events-subdirs += hw/xen trace-events-subdirs += hw/gpio +trace-events-subdirs += hw/riscv trace-events-subdirs += migration trace-events-subdirs += net trace-events-subdirs += ui diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 415cff7a01..33070a6df8 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -160,9 +160,9 @@ static void aspeed_board_init(MachineState *machine, ram_addr_t max_ram_size; bmc = g_new0(AspeedBoardState, 1); - object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), - &error_abort); + object_initialize_child(OBJECT(machine), "soc", &bmc->soc, + (sizeof(bmc->soc)), cfg->soc_name, &error_abort, + NULL); sc = ASPEED_SOC_GET_CLASS(&bmc->soc); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index a27233d487..faff42b84a 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -106,12 +106,11 @@ static void aspeed_soc_init(Object *obj) AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); int i; - object_initialize(&s->cpu, sizeof(s->cpu), sc->info->cpu_type); - object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL); + object_initialize_child(obj, "cpu", OBJECT(&s->cpu), sizeof(s->cpu), + sc->info->cpu_type, &error_abort, NULL); - object_initialize(&s->scu, sizeof(s->scu), TYPE_ASPEED_SCU); - object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL); - qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default()); + sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu), + TYPE_ASPEED_SCU); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->info->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), @@ -121,36 +120,29 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), "hw-prot-key", &error_abort); - object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); - object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); - qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default()); + sysbus_init_child_obj(obj, "vic", OBJECT(&s->vic), sizeof(s->vic), + TYPE_ASPEED_VIC); - object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); - object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); + sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl), + sizeof(s->timerctrl), TYPE_ASPEED_TIMER); object_property_add_const_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), &error_abort); - qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); - object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); - object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL); - qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default()); + sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c), + TYPE_ASPEED_I2C); - object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); - object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); - qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); + sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc), + sc->info->fmc_typename); object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs", &error_abort); for (i = 0; i < sc->info->spis_num; i++) { - object_initialize(&s->spi[i], sizeof(s->spi[i]), - sc->info->spi_typename[i]); - object_property_add_child(obj, "spi[*]", OBJECT(&s->spi[i]), NULL); - qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); + sysbus_init_child_obj(obj, "spi[*]", OBJECT(&s->spi[i]), + sizeof(s->spi[i]), sc->info->spi_typename[i]); } - object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC); - object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); - qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default()); + sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc), + TYPE_ASPEED_SDMC); qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev", sc->info->silicon_rev); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), @@ -159,16 +151,14 @@ static void aspeed_soc_init(Object *obj) "max-ram-size", &error_abort); for (i = 0; i < sc->info->wdts_num; i++) { - object_initialize(&s->wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT); - object_property_add_child(obj, "wdt[*]", OBJECT(&s->wdt[i]), NULL); - qdev_set_parent_bus(DEVICE(&s->wdt[i]), sysbus_get_default()); + sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]), + sizeof(s->wdt[i]), TYPE_ASPEED_WDT); qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev", sc->info->silicon_rev); } - object_initialize(&s->ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100); - object_property_add_child(obj, "ftgmac100", OBJECT(&s->ftgmac100), NULL); - qdev_set_parent_bus(DEVICE(&s->ftgmac100), sysbus_get_default()); + sysbus_init_child_obj(obj, "ftgmac100", OBJECT(&s->ftgmac100), + sizeof(s->ftgmac100), TYPE_FTGMAC100); } static void aspeed_soc_realize(DeviceState *dev, Error **errp) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 6be7660e8c..0fb54c7964 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -41,44 +41,36 @@ static void bcm2835_peripherals_init(Object *obj) MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT); /* Interrupt Controller */ - object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC); - object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL); - qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default()); + sysbus_init_child_obj(obj, "ic", &s->ic, sizeof(s->ic), TYPE_BCM2835_IC); /* UART0 */ - s->uart0 = SYS_BUS_DEVICE(object_new("pl011")); - object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL); - qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default()); + sysbus_init_child_obj(obj, "uart0", &s->uart0, sizeof(s->uart0), + TYPE_PL011); /* AUX / UART1 */ - object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX); - object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL); - qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default()); + sysbus_init_child_obj(obj, "aux", &s->aux, sizeof(s->aux), + TYPE_BCM2835_AUX); /* Mailboxes */ - object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX); - object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL); - qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default()); + sysbus_init_child_obj(obj, "mbox", &s->mboxes, sizeof(s->mboxes), + TYPE_BCM2835_MBOX); object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr", OBJECT(&s->mbox_mr), &error_abort); /* Framebuffer */ - object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB); - object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL); + sysbus_init_child_obj(obj, "fb", &s->fb, sizeof(s->fb), TYPE_BCM2835_FB); object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size", &error_abort); - qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default()); object_property_add_const_link(OBJECT(&s->fb), "dma-mr", OBJECT(&s->gpu_bus_mr), &error_abort); /* Property channel */ - object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY); - object_property_add_child(obj, "property", OBJECT(&s->property), NULL); + sysbus_init_child_obj(obj, "property", &s->property, sizeof(s->property), + TYPE_BCM2835_PROPERTY); object_property_add_alias(obj, "board-rev", OBJECT(&s->property), "board-rev", &error_abort); - qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default()); object_property_add_const_link(OBJECT(&s->property), "fb", OBJECT(&s->fb), &error_abort); @@ -86,32 +78,27 @@ static void bcm2835_peripherals_init(Object *obj) OBJECT(&s->gpu_bus_mr), &error_abort); /* Random Number Generator */ - object_initialize(&s->rng, sizeof(s->rng), TYPE_BCM2835_RNG); - object_property_add_child(obj, "rng", OBJECT(&s->rng), NULL); - qdev_set_parent_bus(DEVICE(&s->rng), sysbus_get_default()); + sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng), + TYPE_BCM2835_RNG); /* Extended Mass Media Controller */ - object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI); - object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL); - qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default()); + sysbus_init_child_obj(obj, "sdhci", &s->sdhci, sizeof(s->sdhci), + TYPE_SYSBUS_SDHCI); /* SDHOST */ - object_initialize(&s->sdhost, sizeof(s->sdhost), TYPE_BCM2835_SDHOST); - object_property_add_child(obj, "sdhost", OBJECT(&s->sdhost), NULL); - qdev_set_parent_bus(DEVICE(&s->sdhost), sysbus_get_default()); + sysbus_init_child_obj(obj, "sdhost", &s->sdhost, sizeof(s->sdhost), + TYPE_BCM2835_SDHOST); /* DMA Channels */ - object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA); - object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL); - qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default()); + sysbus_init_child_obj(obj, "dma", &s->dma, sizeof(s->dma), + TYPE_BCM2835_DMA); object_property_add_const_link(OBJECT(&s->dma), "dma-mr", OBJECT(&s->gpu_bus_mr), &error_abort); /* GPIO */ - object_initialize(&s->gpio, sizeof(s->gpio), TYPE_BCM2835_GPIO); - object_property_add_child(obj, "gpio", OBJECT(&s->gpio), NULL); - qdev_set_parent_bus(DEVICE(&s->gpio), sysbus_get_default()); + sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), + TYPE_BCM2835_GPIO); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci", OBJECT(&s->sdhci.sdbus), &error_abort); @@ -166,16 +153,16 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* UART0 */ - qdev_prop_set_chr(DEVICE(s->uart0), "chardev", serial_hd(0)); - object_property_set_bool(OBJECT(s->uart0), true, "realized", &err); + qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0)); + object_property_set_bool(OBJECT(&s->uart0), true, "realized", &err); if (err) { error_propagate(errp, err); return; } memory_region_add_subregion(&s->peri_mr, UART0_OFFSET, - sysbus_mmio_get_region(s->uart0, 0)); - sysbus_connect_irq(s->uart0, 0, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart0), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart0), 0, qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_UART)); /* AUX / UART1 */ diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 726abb9b48..6ef26c6bac 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -32,27 +32,22 @@ static void digic_init(Object *obj) { DigicState *s = DIGIC(obj); - DeviceState *dev; int i; - object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU); - object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL); + object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), + "arm946-" TYPE_ARM_CPU, &error_abort, NULL); for (i = 0; i < DIGIC4_NB_TIMERS; i++) { #define DIGIC_TIMER_NAME_MLEN 11 char name[DIGIC_TIMER_NAME_MLEN]; - object_initialize(&s->timer[i], sizeof(s->timer[i]), TYPE_DIGIC_TIMER); - dev = DEVICE(&s->timer[i]); - qdev_set_parent_bus(dev, sysbus_get_default()); snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i); - object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL); + sysbus_init_child_obj(obj, name, &s->timer[i], sizeof(s->timer[i]), + TYPE_DIGIC_TIMER); } - object_initialize(&s->uart, sizeof(s->uart), TYPE_DIGIC_UART); - dev = DEVICE(&s->uart); - qdev_set_parent_bus(dev, sysbus_get_default()); - object_property_add_child(obj, "uart", OBJECT(&s->uart), NULL); + sysbus_init_child_obj(obj, "uart", &s->uart, sizeof(s->uart), + TYPE_DIGIC_UART); } static void digic_realize(DeviceState *dev, Error **errp) diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 9f3ee14739..eef1b184b0 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -72,9 +72,8 @@ static void imx25_pdk_init(MachineState *machine) unsigned int alias_offset; int i; - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX25); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); + object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_FSL_IMX25, &error_abort, NULL); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 139934c4ec..44cba8782b 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -71,9 +71,8 @@ static void kzm_init(MachineState *machine) unsigned int alias_offset; unsigned int i; - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX31); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); + object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_FSL_IMX31, &error_abort, NULL); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index c167a5fa59..d85dc2c4bd 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -214,9 +214,9 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, DeviceState *sccdev; MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); - object_initialize(scc, sizeof(mms->scc), TYPE_MPS2_SCC); + sysbus_init_child_obj(OBJECT(mms), "scc", scc, + sizeof(mms->scc), TYPE_MPS2_SCC); sccdev = DEVICE(scc); - qdev_set_parent_bus(sccdev, sysbus_get_default()); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); @@ -229,8 +229,8 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque, { MPS2FPGAIO *fpgaio = opaque; - object_initialize(fpgaio, sizeof(mms->fpgaio), TYPE_MPS2_FPGAIO); - qdev_set_parent_bus(DEVICE(fpgaio), sysbus_get_default()); + sysbus_init_child_obj(OBJECT(mms), "fpgaio", fpgaio, + sizeof(mms->fpgaio), TYPE_MPS2_FPGAIO); object_property_set_bool(OBJECT(fpgaio), true, "realized", &error_fatal); return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0); } diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index b74f1378c9..10efff36b2 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -174,9 +174,9 @@ static void mps2_common_init(MachineState *machine) g_assert_not_reached(); } - object_initialize(&mms->armv7m, sizeof(mms->armv7m), TYPE_ARMV7M); + sysbus_init_child_obj(OBJECT(mms), "armv7m", &mms->armv7m, + sizeof(mms->armv7m), TYPE_ARMV7M); armv7m = DEVICE(&mms->armv7m); - qdev_set_parent_bus(armv7m, sysbus_get_default()); switch (mmc->fpga_type) { case FPGA_AN385: qdev_prop_set_uint32(armv7m, "num-irq", 32); @@ -308,9 +308,9 @@ static void mps2_common_init(MachineState *machine) qdev_get_gpio_in(armv7m, 10)); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); - object_initialize(&mms->scc, sizeof(mms->scc), TYPE_MPS2_SCC); + sysbus_init_child_obj(OBJECT(mms), "scc", &mms->scc, + sizeof(mms->scc), TYPE_MPS2_SCC); sccdev = DEVICE(&mms->scc); - qdev_set_parent_bus(sccdev, sysbus_get_default()); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 2b5fe10e2f..8c249fcabb 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -182,10 +182,9 @@ static void raspi_init(MachineState *machine, int version) exit(1); } - object_initialize(&s->soc, sizeof(s->soc), - version == 3 ? TYPE_BCM2837 : TYPE_BCM2836); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); + object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + version == 3 ? TYPE_BCM2837 : TYPE_BCM2836, + &error_abort, NULL); /* Allocate and map RAM */ memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram", diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index ee140e5d9e..f1b00de229 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -55,9 +55,8 @@ static void sabrelite_init(MachineState *machine) exit(1); } - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX6); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); + object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_FSL_IMX6, &error_abort, NULL); object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); if (err != NULL) { diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index b6bc6a93b8..c802f26fbd 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -91,9 +91,8 @@ static void xlnx_zcu102_init(MachineState *machine) memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", ram_size); - object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); + object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_XLNX_ZYNQMP, &error_abort, NULL); object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram), "ddr-ram", &error_abort); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 4f8bc41d9d..6e99190302 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -191,10 +191,10 @@ static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu, for (i = 0; i < num_rpus; i++) { char *name; - object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), - "cortex-r5f-" TYPE_ARM_CPU); - object_property_add_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]", - OBJECT(&s->rpu_cpu[i]), &error_abort); + object_initialize_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]", + &s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), + "cortex-r5f-" TYPE_ARM_CPU, &error_abort, + NULL); name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); if (strcmp(name, boot_cpu)) { diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 815e720cfa..dc2c206d9a 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2595,9 +2595,9 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) * as we didn't know then if the CPU had the security extensions; * so we have to do it here. */ - object_initialize(&s->systick[M_REG_S], sizeof(s->systick[M_REG_S]), - TYPE_SYSTICK); - qdev_set_parent_bus(DEVICE(&s->systick[M_REG_S]), sysbus_get_default()); + sysbus_init_child_obj(OBJECT(dev), "systick-reg-s", + &s->systick[M_REG_S], + sizeof(s->systick[M_REG_S]), TYPE_SYSTICK); object_property_set_bool(OBJECT(&s->systick[M_REG_S]), true, "realized", &err); diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index 57dc1ccd42..df6c0048aa 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -55,6 +55,7 @@ typedef struct XlnxZynqMPPMUSoCState { /*< public >*/ MicroBlazeCPU cpu; XlnxPMUIOIntc intc; + XlnxZynqMPIPI ipi[XLNX_ZYNQMP_PMU_NUM_IPIS]; } XlnxZynqMPPMUSoCState; @@ -67,6 +68,14 @@ static void xlnx_zynqmp_pmu_soc_init(Object *obj) sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), TYPE_XLNX_PMU_IO_INTC); + + /* Create the IPI device */ + for (int i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { + char *name = g_strdup_printf("ipi%d", i); + sysbus_init_child_obj(obj, name, &s->ipi[i], + sizeof(XlnxZynqMPIPI), TYPE_XLNX_ZYNQMP_IPI); + g_free(name); + } } static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) @@ -112,6 +121,15 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->intc), 0, XLNX_ZYNQMP_PMU_INTC_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->intc), 0, qdev_get_gpio_in(DEVICE(&s->cpu), MB_CPU_IRQ)); + + /* Connect the IPI device */ + for (int i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { + object_property_set_bool(OBJECT(&s->ipi[i]), true, "realized", + &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ipi[i]), 0, ipi_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ipi[i]), 0, + qdev_get_gpio_in(DEVICE(&s->intc), ipi_irq[i])); + } } static void xlnx_zynqmp_pmu_soc_class_init(ObjectClass *oc, void *data) @@ -144,9 +162,6 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *pmu_rom = g_new(MemoryRegion, 1); MemoryRegion *pmu_ram = g_new(MemoryRegion, 1); - XlnxZynqMPIPI *ipi[XLNX_ZYNQMP_PMU_NUM_IPIS]; - qemu_irq irq[32]; - int i; /* Create the ROM */ memory_region_init_rom(pmu_rom, NULL, "xlnx-zynqmp-pmu.rom", @@ -161,29 +176,11 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) pmu_ram); /* Create the PMU device */ - object_initialize(pmu, sizeof(XlnxZynqMPPMUSoCState), TYPE_XLNX_ZYNQMP_PMU_SOC); - object_property_add_child(OBJECT(machine), "pmu", OBJECT(pmu), - &error_abort); + object_initialize_child(OBJECT(machine), "pmu", pmu, + sizeof(XlnxZynqMPPMUSoCState), + TYPE_XLNX_ZYNQMP_PMU_SOC, &error_abort, NULL); object_property_set_bool(OBJECT(pmu), true, "realized", &error_fatal); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(DEVICE(&pmu->intc), i); - } - - /* Create and connect the IPI device */ - for (i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { - ipi[i] = g_new0(XlnxZynqMPIPI, 1); - object_initialize(ipi[i], sizeof(XlnxZynqMPIPI), TYPE_XLNX_ZYNQMP_IPI); - qdev_set_parent_bus(DEVICE(ipi[i]), sysbus_get_default()); - } - - for (i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { - object_property_set_bool(OBJECT(ipi[i]), true, "realized", - &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(ipi[i]), 0, ipi_addr[i]); - sysbus_connect_irq(SYS_BUS_DEVICE(ipi[i]), 0, irq[ipi_irq[i]]); - } - /* Load the kernel */ microblaze_load_kernel(&pmu->cpu, XLNX_ZYNQMP_PMU_RAM_ADDR, machine->ram_size, diff --git a/hw/mips/boston.c b/hw/mips/boston.c index a8b29f62f5..1ffccc8da9 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -49,7 +49,7 @@ typedef struct { SysBusDevice parent_obj; MachineState *mach; - MIPSCPSState *cps; + MIPSCPSState cps; SerialState *uart; CharBackend lcd_display; @@ -188,7 +188,7 @@ static uint64_t boston_platreg_read(void *opaque, hwaddr addr, case PLAT_DDR3_STATUS: return PLAT_DDR3_STATUS_LOCKED | PLAT_DDR3_STATUS_CALIBRATED; case PLAT_MMCM_DIV: - gic_freq = mips_gictimer_get_freq(s->cps->gic.gic_timer) / 1000000; + gic_freq = mips_gictimer_get_freq(s->cps.gic.gic_timer) / 1000000; val = gic_freq << PLAT_MMCM_DIV_INPUT_SHIFT; val |= 1 << PLAT_MMCM_DIV_MUL_SHIFT; val |= 1 << PLAT_MMCM_DIV_CLK0DIV_SHIFT; @@ -455,20 +455,19 @@ static void boston_mach_init(MachineState *machine) is_64b = cpu_supports_isa(machine->cpu_type, ISA_MIPS64); - s->cps = MIPS_CPS(object_new(TYPE_MIPS_CPS)); - qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default()); - - object_property_set_str(OBJECT(s->cps), machine->cpu_type, "cpu-type", + sysbus_init_child_obj(OBJECT(machine), "cps", OBJECT(&s->cps), + sizeof(s->cps), TYPE_MIPS_CPS); + object_property_set_str(OBJECT(&s->cps), machine->cpu_type, "cpu-type", &err); - object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err); - object_property_set_bool(OBJECT(s->cps), true, "realized", &err); + object_property_set_int(OBJECT(&s->cps), smp_cpus, "num-vp", &err); + object_property_set_bool(OBJECT(&s->cps), true, "realized", &err); if (err != NULL) { error_report("%s", error_get_pretty(err)); exit(1); } - sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1); + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); flash = g_new(MemoryRegion, 1); memory_region_init_rom(flash, NULL, "boston.flash", 128 * MiB, &err); @@ -487,17 +486,17 @@ static void boston_mach_init(MachineState *machine) xilinx_pcie_init(sys_mem, 0, 0x10000000, 32 * MiB, 0x40000000, 1 * GiB, - get_cps_irq(s->cps, 2), false); + get_cps_irq(&s->cps, 2), false); xilinx_pcie_init(sys_mem, 1, 0x12000000, 32 * MiB, 0x20000000, 512 * MiB, - get_cps_irq(s->cps, 1), false); + get_cps_irq(&s->cps, 1), false); pcie2 = xilinx_pcie_init(sys_mem, 2, 0x14000000, 32 * MiB, 0x16000000, 1 * MiB, - get_cps_irq(s->cps, 0), true); + get_cps_irq(&s->cps, 0), true); platreg = g_new(MemoryRegion, 1); memory_region_init_io(platreg, NULL, &boston_platreg_ops, s, @@ -505,7 +504,7 @@ static void boston_mach_init(MachineState *machine) memory_region_add_subregion_overlap(sys_mem, 0x17ffd000, platreg, 0); s->uart = serial_mm_init(sys_mem, 0x17ffe000, 2, - get_cps_irq(s->cps, 3), 10000000, + get_cps_irq(&s->cps, 3), 10000000, serial_hd(0), DEVICE_NATIVE_ENDIAN); lcd = g_new(MemoryRegion, 1); diff --git a/hw/mips/cps.c b/hw/mips/cps.c index fc97f59af4..649b35a76c 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -94,9 +94,8 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Inter-Thread Communication Unit */ if (itu_present) { - object_initialize(&s->itu, sizeof(s->itu), TYPE_MIPS_ITU); - qdev_set_parent_bus(DEVICE(&s->itu), sysbus_get_default()); - + sysbus_init_child_obj(OBJECT(dev), "itu", &s->itu, sizeof(s->itu), + TYPE_MIPS_ITU); object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err); object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err); object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present", @@ -115,9 +114,8 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) } /* Cluster Power Controller */ - object_initialize(&s->cpc, sizeof(s->cpc), TYPE_MIPS_CPC); - qdev_set_parent_bus(DEVICE(&s->cpc), sysbus_get_default()); - + sysbus_init_child_obj(OBJECT(dev), "cpc", &s->cpc, sizeof(s->cpc), + TYPE_MIPS_CPC); object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err); object_property_set_bool(OBJECT(&s->cpc), true, "realized", &err); @@ -130,9 +128,8 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0)); /* Global Interrupt Controller */ - object_initialize(&s->gic, sizeof(s->gic), TYPE_MIPS_GIC); - qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); - + sysbus_init_child_obj(OBJECT(dev), "gic", &s->gic, sizeof(s->gic), + TYPE_MIPS_GIC); object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->gic), 128, "num-irq", &err); object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); @@ -147,9 +144,8 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Global Configuration Registers */ gcr_base = env->CP0_CMGCRBase << 4; - object_initialize(&s->gcr, sizeof(s->gcr), TYPE_MIPS_GCR); - qdev_set_parent_bus(DEVICE(&s->gcr), sysbus_get_default()); - + sysbus_init_child_obj(OBJECT(dev), "gcr", &s->gcr, sizeof(s->gcr), + TYPE_MIPS_GCR); object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err); object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 3b009fda25..37ec89b07e 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -94,7 +94,7 @@ typedef struct { typedef struct { SysBusDevice parent_obj; - MIPSCPSState *cps; + MIPSCPSState cps; qemu_irq *i8259; } MaltaState; @@ -1151,20 +1151,19 @@ static void create_cps(MaltaState *s, const char *cpu_type, { Error *err = NULL; - s->cps = MIPS_CPS(object_new(TYPE_MIPS_CPS)); - qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default()); - - object_property_set_str(OBJECT(s->cps), cpu_type, "cpu-type", &err); - object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err); - object_property_set_bool(OBJECT(s->cps), true, "realized", &err); + sysbus_init_child_obj(OBJECT(s), "cps", OBJECT(&s->cps), sizeof(s->cps), + TYPE_MIPS_CPS); + object_property_set_str(OBJECT(&s->cps), cpu_type, "cpu-type", &err); + object_property_set_int(OBJECT(&s->cps), smp_cpus, "num-vp", &err); + object_property_set_bool(OBJECT(&s->cps), true, "realized", &err); if (err != NULL) { error_report("%s", error_get_pretty(err)); exit(1); } - sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1); + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); - *i8259_irq = get_cps_irq(s->cps, 3); + *i8259_irq = get_cps_irq(&s->cps, 3); *cbus_irq = NULL; } diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 94da85c8d7..b726c73022 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -346,12 +346,12 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) object_property_set_bool(OBJECT(&ns->gpio), true, "realized", &err); /* PMU */ - object_initialize(&s->pmu, sizeof(s->pmu), TYPE_VIA_PMU); + object_initialize_child(OBJECT(s), "pmu", &s->pmu, sizeof(s->pmu), + TYPE_VIA_PMU, &error_abort, NULL); object_property_set_link(OBJECT(&s->pmu), OBJECT(sysbus_dev), "gpio", &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); qdev_set_parent_bus(DEVICE(&s->pmu), BUS(&s->macio_bus)); - object_property_add_child(OBJECT(s), "pmu", OBJECT(&s->pmu), NULL); object_property_set_bool(OBJECT(&s->pmu), true, "realized", &err); if (err) { @@ -365,9 +365,9 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) sysbus_mmio_get_region(sysbus_dev, 0)); } else { /* CUDA */ - object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA); + object_initialize_child(OBJECT(s), "cuda", &s->cuda, sizeof(s->cuda), + TYPE_CUDA, &error_abort, NULL); qdev_set_parent_bus(DEVICE(&s->cuda), BUS(&s->macio_bus)); - object_property_add_child(OBJECT(s), "cuda", OBJECT(&s->cuda), NULL); qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index dfb4ea5742..31aa20ee25 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -994,14 +994,12 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize); int core_id = CPU_CORE(pnv_core)->core_id; - object_initialize(eq, sizeof(*eq), TYPE_PNV_QUAD); snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id); + object_initialize_child(OBJECT(chip), eq_name, eq, sizeof(*eq), + TYPE_PNV_QUAD, &error_fatal, NULL); - object_property_add_child(OBJECT(chip), eq_name, OBJECT(eq), - &error_fatal); object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal); object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal); - object_unref(OBJECT(eq)); pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id), &eq->xscom_regs); @@ -1165,10 +1163,9 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp) continue; } - object_initialize(pnv_core, typesize, typename); snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); - object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), - &error_fatal); + object_initialize_child(OBJECT(chip), core_name, pnv_core, typesize, + typename, &error_fatal, NULL); object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads", &error_fatal); object_property_set_int(OBJECT(pnv_core), core_hwid, @@ -1180,7 +1177,6 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp) OBJECT(chip), &error_fatal); object_property_set_bool(OBJECT(pnv_core), true, "realized", &error_fatal); - object_unref(OBJECT(pnv_core)); /* Each core has an XSCOM MMIO region */ if (!pnv_chip_is_power9(chip)) { diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs index 79bfb3abf9..a65027304a 100644 --- a/hw/riscv/Makefile.objs +++ b/hw/riscv/Makefile.objs @@ -2,6 +2,7 @@ obj-$(CONFIG_SPIKE) += riscv_htif.o obj-$(CONFIG_HART) += riscv_hart.o obj-$(CONFIG_SIFIVE_E) += sifive_e.o obj-$(CONFIG_SIFIVE) += sifive_clint.o +obj-$(CONFIG_SIFIVE) += sifive_gpio.o obj-$(CONFIG_SIFIVE) += sifive_prci.o obj-$(CONFIG_SIFIVE) += sifive_plic.o obj-$(CONFIG_SIFIVE) += sifive_test.o diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index b1cd11363c..80ac56fa7d 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -146,11 +146,15 @@ static void riscv_sifive_e_soc_init(Object *obj) &error_abort); object_property_set_int(OBJECT(&s->cpus), smp_cpus, "num-harts", &error_abort); + sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0", + &s->gpio, sizeof(s->gpio), + TYPE_SIFIVE_GPIO); } static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) { const struct MemmapEntry *memmap = sifive_e_memmap; + Error *err = NULL; SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); @@ -184,8 +188,28 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon", memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); sifive_prci_create(memmap[SIFIVE_E_PRCI].base); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.gpio0", - memmap[SIFIVE_E_GPIO0].base, memmap[SIFIVE_E_GPIO0].size); + + /* GPIO */ + + object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* Map GPIO registers */ + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_E_GPIO0].base); + + /* Pass all GPIOs to the SOC layer so they are available to the board */ + qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL); + + /* Connect GPIO interrupts to the PLIC */ + for (int i = 0; i < 32; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i, + qdev_get_gpio_in(DEVICE(s->plic), + SIFIVE_E_GPIO0_IRQ0 + i)); + } + sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base, serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ)); sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0", diff --git a/hw/riscv/sifive_gpio.c b/hw/riscv/sifive_gpio.c new file mode 100644 index 0000000000..06bd8112d7 --- /dev/null +++ b/hw/riscv/sifive_gpio.c @@ -0,0 +1,388 @@ +/* + * sifive System-on-Chip general purpose input/output register definition + * + * Copyright 2019 AdaCore + * + * Base on nrf51_gpio.c: + * + * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de> + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/riscv/sifive_gpio.h" +#include "trace.h" + +static void update_output_irq(SIFIVEGPIOState *s) +{ + + uint32_t pending; + uint32_t pin; + + pending = s->high_ip & s->high_ie; + pending |= s->low_ip & s->low_ie; + pending |= s->rise_ip & s->rise_ie; + pending |= s->fall_ip & s->fall_ie; + + for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { + pin = 1 << i; + qemu_set_irq(s->irq[i], (pending & pin) != 0); + trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0); + } +} + +static void update_state(SIFIVEGPIOState *s) +{ + size_t i; + bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en, + rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival; + + for (i = 0; i < SIFIVE_GPIO_PINS; i++) { + + prev_ival = extract32(s->value, i, 1); + in = extract32(s->in, i, 1); + in_mask = extract32(s->in_mask, i, 1); + port = extract32(s->port, i, 1); + out_xor = extract32(s->out_xor, i, 1); + pull = extract32(s->pue, i, 1); + output_en = extract32(s->output_en, i, 1); + input_en = extract32(s->input_en, i, 1); + rise_ip = extract32(s->rise_ip, i, 1); + fall_ip = extract32(s->fall_ip, i, 1); + low_ip = extract32(s->low_ip, i, 1); + high_ip = extract32(s->high_ip, i, 1); + + /* Output value (IOF not supported) */ + oval = output_en && (port ^ out_xor); + + /* Pin both driven externally and internally */ + if (output_en && in_mask) { + qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i); + } + + if (in_mask) { + /* The pin is driven by external device */ + actual_value = in; + } else if (output_en) { + /* The pin is driven by internal circuit */ + actual_value = oval; + } else { + /* Floating? Apply pull-up resistor */ + actual_value = pull; + } + + qemu_set_irq(s->output[i], actual_value); + + /* Input value */ + ival = input_en && actual_value; + + /* Interrupts */ + high_ip = high_ip || ival; + s->high_ip = deposit32(s->high_ip, i, 1, high_ip); + + low_ip = low_ip || !ival; + s->low_ip = deposit32(s->low_ip, i, 1, low_ip); + + rise_ip = rise_ip || (ival && !prev_ival); + s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip); + + fall_ip = fall_ip || (!ival && prev_ival); + s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip); + + /* Update value */ + s->value = deposit32(s->value, i, 1, ival); + } + update_output_irq(s); +} + +static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); + uint64_t r = 0; + + switch (offset) { + case SIFIVE_GPIO_REG_VALUE: + r = s->value; + break; + + case SIFIVE_GPIO_REG_INPUT_EN: + r = s->input_en; + break; + + case SIFIVE_GPIO_REG_OUTPUT_EN: + r = s->output_en; + break; + + case SIFIVE_GPIO_REG_PORT: + r = s->port; + break; + + case SIFIVE_GPIO_REG_PUE: + r = s->pue; + break; + + case SIFIVE_GPIO_REG_DS: + r = s->ds; + break; + + case SIFIVE_GPIO_REG_RISE_IE: + r = s->rise_ie; + break; + + case SIFIVE_GPIO_REG_RISE_IP: + r = s->rise_ip; + break; + + case SIFIVE_GPIO_REG_FALL_IE: + r = s->fall_ie; + break; + + case SIFIVE_GPIO_REG_FALL_IP: + r = s->fall_ip; + break; + + case SIFIVE_GPIO_REG_HIGH_IE: + r = s->high_ie; + break; + + case SIFIVE_GPIO_REG_HIGH_IP: + r = s->high_ip; + break; + + case SIFIVE_GPIO_REG_LOW_IE: + r = s->low_ie; + break; + + case SIFIVE_GPIO_REG_LOW_IP: + r = s->low_ip; + break; + + case SIFIVE_GPIO_REG_IOF_EN: + r = s->iof_en; + break; + + case SIFIVE_GPIO_REG_IOF_SEL: + r = s->iof_sel; + break; + + case SIFIVE_GPIO_REG_OUT_XOR: + r = s->out_xor; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bad read offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } + + trace_sifive_gpio_read(offset, r); + + return r; +} + +static void sifive_gpio_write(void *opaque, hwaddr offset, + uint64_t value, unsigned int size) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); + + trace_sifive_gpio_write(offset, value); + + switch (offset) { + + case SIFIVE_GPIO_REG_INPUT_EN: + s->input_en = value; + break; + + case SIFIVE_GPIO_REG_OUTPUT_EN: + s->output_en = value; + break; + + case SIFIVE_GPIO_REG_PORT: + s->port = value; + break; + + case SIFIVE_GPIO_REG_PUE: + s->pue = value; + break; + + case SIFIVE_GPIO_REG_DS: + s->ds = value; + break; + + case SIFIVE_GPIO_REG_RISE_IE: + s->rise_ie = value; + break; + + case SIFIVE_GPIO_REG_RISE_IP: + /* Write 1 to clear */ + s->rise_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_FALL_IE: + s->fall_ie = value; + break; + + case SIFIVE_GPIO_REG_FALL_IP: + /* Write 1 to clear */ + s->fall_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_HIGH_IE: + s->high_ie = value; + break; + + case SIFIVE_GPIO_REG_HIGH_IP: + /* Write 1 to clear */ + s->high_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_LOW_IE: + s->low_ie = value; + break; + + case SIFIVE_GPIO_REG_LOW_IP: + /* Write 1 to clear */ + s->low_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_IOF_EN: + s->iof_en = value; + break; + + case SIFIVE_GPIO_REG_IOF_SEL: + s->iof_sel = value; + break; + + case SIFIVE_GPIO_REG_OUT_XOR: + s->out_xor = value; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bad write offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } + + update_state(s); +} + +static const MemoryRegionOps gpio_ops = { + .read = sifive_gpio_read, + .write = sifive_gpio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static void sifive_gpio_set(void *opaque, int line, int value) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); + + trace_sifive_gpio_set(line, value); + + assert(line >= 0 && line < SIFIVE_GPIO_PINS); + + s->in_mask = deposit32(s->in_mask, line, 1, value >= 0); + if (value >= 0) { + s->in = deposit32(s->in, line, 1, value != 0); + } + + update_state(s); +} + +static void sifive_gpio_reset(DeviceState *dev) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(dev); + + s->value = 0; + s->input_en = 0; + s->output_en = 0; + s->port = 0; + s->pue = 0; + s->ds = 0; + s->rise_ie = 0; + s->rise_ip = 0; + s->fall_ie = 0; + s->fall_ip = 0; + s->high_ie = 0; + s->high_ip = 0; + s->low_ie = 0; + s->low_ip = 0; + s->iof_en = 0; + s->iof_sel = 0; + s->out_xor = 0; + s->in = 0; + s->in_mask = 0; + +} + +static const VMStateDescription vmstate_sifive_gpio = { + .name = TYPE_SIFIVE_GPIO, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(value, SIFIVEGPIOState), + VMSTATE_UINT32(input_en, SIFIVEGPIOState), + VMSTATE_UINT32(output_en, SIFIVEGPIOState), + VMSTATE_UINT32(port, SIFIVEGPIOState), + VMSTATE_UINT32(pue, SIFIVEGPIOState), + VMSTATE_UINT32(rise_ie, SIFIVEGPIOState), + VMSTATE_UINT32(rise_ip, SIFIVEGPIOState), + VMSTATE_UINT32(fall_ie, SIFIVEGPIOState), + VMSTATE_UINT32(fall_ip, SIFIVEGPIOState), + VMSTATE_UINT32(high_ie, SIFIVEGPIOState), + VMSTATE_UINT32(high_ip, SIFIVEGPIOState), + VMSTATE_UINT32(low_ie, SIFIVEGPIOState), + VMSTATE_UINT32(low_ip, SIFIVEGPIOState), + VMSTATE_UINT32(iof_en, SIFIVEGPIOState), + VMSTATE_UINT32(iof_sel, SIFIVEGPIOState), + VMSTATE_UINT32(out_xor, SIFIVEGPIOState), + VMSTATE_UINT32(in, SIFIVEGPIOState), + VMSTATE_UINT32(in_mask, SIFIVEGPIOState), + VMSTATE_END_OF_LIST() + } +}; + +static void sifive_gpio_init(Object *obj) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(obj); + + memory_region_init_io(&s->mmio, obj, &gpio_ops, s, + TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + + for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]); + } + + qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, SIFIVE_GPIO_PINS); + qdev_init_gpio_out(DEVICE(s), s->output, SIFIVE_GPIO_PINS); +} + +static void sifive_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_sifive_gpio; + dc->reset = sifive_gpio_reset; + dc->desc = "sifive GPIO"; +} + +static const TypeInfo sifive_gpio_info = { + .name = TYPE_SIFIVE_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SIFIVEGPIOState), + .instance_init = sifive_gpio_init, + .class_init = sifive_gpio_class_init +}; + +static void sifive_gpio_register_types(void) +{ + type_register_static(&sifive_gpio_info); +} + +type_init(sifive_gpio_register_types) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 2a000a5800..5b33d4be3b 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -39,6 +39,7 @@ #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" +#include "sysemu/qtest.h" #include "exec/address-spaces.h" #include "elf.h" @@ -160,7 +161,89 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } - } +} + +static void spike_board_init(MachineState *machine) +{ + const struct MemmapEntry *memmap = spike_memmap; + + SpikeState *s = g_new0(SpikeState, 1); + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *main_mem = g_new(MemoryRegion, 1); + MemoryRegion *mask_rom = g_new(MemoryRegion, 1); + int i; + + /* Initialize SOC */ + object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_RISCV_HART_ARRAY, &error_abort, NULL); + object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", + &error_abort); + object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", + &error_abort); + object_property_set_bool(OBJECT(&s->soc), true, "realized", + &error_abort); + + /* register system main memory (actual RAM) */ + memory_region_init_ram(main_mem, NULL, "riscv.spike.ram", + machine->ram_size, &error_fatal); + memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base, + main_mem); + + /* create device tree */ + create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); + + /* boot rom */ + memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom", + memmap[SPIKE_MROM].size, &error_fatal); + memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, + mask_rom); + + if (machine->kernel_filename) { + load_kernel(machine->kernel_filename); + } + + /* reset vector */ + uint32_t reset_vec[8] = { + 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ + 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ + 0xf1402573, /* csrr a0, mhartid */ +#if defined(TARGET_RISCV32) + 0x0182a283, /* lw t0, 24(t0) */ +#elif defined(TARGET_RISCV64) + 0x0182b283, /* ld t0, 24(t0) */ +#endif + 0x00028067, /* jr t0 */ + 0x00000000, + memmap[SPIKE_DRAM].base, /* start: .dword DRAM_BASE */ + 0x00000000, + /* dtb: */ + }; + + /* copy in the reset vector in little_endian byte order */ + for (i = 0; i < sizeof(reset_vec) >> 2; i++) { + reset_vec[i] = cpu_to_le32(reset_vec[i]); + } + rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), + memmap[SPIKE_MROM].base, &address_space_memory); + + /* copy in the device tree */ + if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) > + memmap[SPIKE_MROM].size - sizeof(reset_vec)) { + error_report("not enough space to store device-tree"); + exit(1); + } + qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt)); + rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt), + memmap[SPIKE_MROM].base + sizeof(reset_vec), + &address_space_memory); + + /* initialize HTIF using symbols found in load_kernel */ + htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0)); + + /* Core Local Interruptor (timer and IPI) */ + sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size, + smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); +} static void spike_v1_10_0_board_init(MachineState *machine) { @@ -172,6 +255,12 @@ static void spike_v1_10_0_board_init(MachineState *machine) MemoryRegion *mask_rom = g_new(MemoryRegion, 1); int i; + if (!qtest_enabled()) { + info_report("The Spike v1.10.0 machine has been deprecated. " + "Please use the generic spike machine and specify the ISA " + "versions using -cpu."); + } + /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY, &error_abort, NULL); @@ -254,6 +343,12 @@ static void spike_v1_09_1_board_init(MachineState *machine) MemoryRegion *mask_rom = g_new(MemoryRegion, 1); int i; + if (!qtest_enabled()) { + info_report("The Spike v1.09.1 machine has been deprecated. " + "Please use the generic spike machine and specify the ISA " + "versions using -cpu."); + } + /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY, &error_abort, NULL); @@ -359,8 +454,17 @@ static void spike_v1_10_0_machine_init(MachineClass *mc) mc->desc = "RISC-V Spike Board (Privileged ISA v1.10)"; mc->init = spike_v1_10_0_board_init; mc->max_cpus = 1; +} + +static void spike_machine_init(MachineClass *mc) +{ + mc->desc = "RISC-V Spike Board"; + mc->init = spike_board_init; + mc->max_cpus = 1; mc->is_default = 1; + mc->default_cpu_type = SPIKE_V1_10_0_CPU; } DEFINE_MACHINE("spike_v1.9.1", spike_v1_09_1_machine_init) DEFINE_MACHINE("spike_v1.10", spike_v1_10_0_machine_init) +DEFINE_MACHINE("spike", spike_machine_init) diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events new file mode 100644 index 0000000000..6d59233e23 --- /dev/null +++ b/hw/riscv/trace-events @@ -0,0 +1,7 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# hw/gpio/sifive_gpio.c +sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64 +sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 +sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 +sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index fc4c6b306e..84d94d0c42 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -29,7 +29,6 @@ #include "hw/sysbus.h" #include "hw/char/serial.h" #include "target/riscv/cpu.h" -#include "hw/riscv/riscv_htif.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_plic.h" #include "hw/riscv/sifive_clint.h" @@ -400,7 +399,7 @@ static void riscv_virt_board_init(MachineState *machine) /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY, &error_abort, NULL); - object_property_set_str(OBJECT(&s->soc), VIRT_CPU, "cpu-type", + object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", &error_abort); object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", &error_abort); @@ -526,6 +525,7 @@ static void riscv_virt_board_machine_init(MachineClass *mc) mc->desc = "RISC-V VirtIO Board (Privileged ISA v1.10)"; mc->init = riscv_virt_board_init; mc->max_cpus = 8; /* hardcoded limit in BBL */ + mc->default_cpu_type = VIRT_CPU; } DEFINE_MACHINE("virt", riscv_virt_board_machine_init) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 4805727b53..07f4a64b48 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2312,9 +2312,8 @@ void virtio_instance_init_common(Object *proxy_obj, void *data, { DeviceState *vdev = data; - object_initialize(vdev, vdev_size, vdev_name); - object_property_add_child(proxy_obj, "virtio-backend", OBJECT(vdev), NULL); - object_unref(OBJECT(vdev)); + object_initialize_child(proxy_obj, "virtio-backend", vdev, vdev_size, + vdev_name, &error_abort, NULL); qdev_alias_all_properties(vdev, proxy_obj); } diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index f5b193f670..e79c21771f 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -13,6 +13,7 @@ #include "qemu-common.h" #include "hw/sysbus.h" +#include "hw/char/pl011.h" #include "hw/char/bcm2835_aux.h" #include "hw/display/bcm2835_fb.h" #include "hw/dma/bcm2835_dma.h" @@ -37,7 +38,7 @@ typedef struct BCM2835PeripheralState { MemoryRegion ram_alias[4]; qemu_irq irq, fiq; - SysBusDevice *uart0; + PL011State uart0; BCM2835AuxState aux; BCM2835FBState fb; BCM2835DMAState dma; diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index f715f8606f..3b14eb7462 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -19,6 +19,8 @@ #ifndef HW_SIFIVE_E_H #define HW_SIFIVE_E_H +#include "hw/riscv/sifive_gpio.h" + #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" #define RISCV_E_SOC(obj) \ OBJECT_CHECK(SiFiveESoCState, (obj), TYPE_RISCV_E_SOC) @@ -30,6 +32,7 @@ typedef struct SiFiveESoCState { /*< public >*/ RISCVHartArrayState cpus; DeviceState *plic; + SIFIVEGPIOState gpio; } SiFiveESoCState; typedef struct SiFiveEState { @@ -63,8 +66,9 @@ enum { }; enum { - SIFIVE_E_UART0_IRQ = 3, - SIFIVE_E_UART1_IRQ = 4 + SIFIVE_E_UART0_IRQ = 3, + SIFIVE_E_UART1_IRQ = 4, + SIFIVE_E_GPIO0_IRQ0 = 8 }; #define SIFIVE_E_PLIC_HART_CONFIG "M" diff --git a/include/hw/riscv/sifive_gpio.h b/include/hw/riscv/sifive_gpio.h new file mode 100644 index 0000000000..fce03d6c41 --- /dev/null +++ b/include/hw/riscv/sifive_gpio.h @@ -0,0 +1,72 @@ +/* + * sifive System-on-Chip general purpose input/output register definition + * + * Copyright 2019 AdaCore + * + * Base on nrf51_gpio.c: + * + * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de> + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ +#ifndef SIFIVE_GPIO_H +#define SIFIVE_GPIO_H + +#include "hw/sysbus.h" +#define TYPE_SIFIVE_GPIO "sifive_soc.gpio" +#define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO) + +#define SIFIVE_GPIO_PINS 32 + +#define SIFIVE_GPIO_SIZE 0x100 + +#define SIFIVE_GPIO_REG_VALUE 0x000 +#define SIFIVE_GPIO_REG_INPUT_EN 0x004 +#define SIFIVE_GPIO_REG_OUTPUT_EN 0x008 +#define SIFIVE_GPIO_REG_PORT 0x00C +#define SIFIVE_GPIO_REG_PUE 0x010 +#define SIFIVE_GPIO_REG_DS 0x014 +#define SIFIVE_GPIO_REG_RISE_IE 0x018 +#define SIFIVE_GPIO_REG_RISE_IP 0x01C +#define SIFIVE_GPIO_REG_FALL_IE 0x020 +#define SIFIVE_GPIO_REG_FALL_IP 0x024 +#define SIFIVE_GPIO_REG_HIGH_IE 0x028 +#define SIFIVE_GPIO_REG_HIGH_IP 0x02C +#define SIFIVE_GPIO_REG_LOW_IE 0x030 +#define SIFIVE_GPIO_REG_LOW_IP 0x034 +#define SIFIVE_GPIO_REG_IOF_EN 0x038 +#define SIFIVE_GPIO_REG_IOF_SEL 0x03C +#define SIFIVE_GPIO_REG_OUT_XOR 0x040 + +typedef struct SIFIVEGPIOState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + + qemu_irq irq[SIFIVE_GPIO_PINS]; + qemu_irq output[SIFIVE_GPIO_PINS]; + + uint32_t value; /* Actual value of the pin */ + uint32_t input_en; + uint32_t output_en; + uint32_t port; /* Pin value requested by the user */ + uint32_t pue; + uint32_t ds; + uint32_t rise_ie; + uint32_t rise_ip; + uint32_t fall_ie; + uint32_t fall_ip; + uint32_t high_ie; + uint32_t high_ip; + uint32_t low_ie; + uint32_t low_ip; + uint32_t iof_en; + uint32_t iof_sel; + uint32_t out_xor; + uint32_t in; + uint32_t in_mask; + +} SIFIVEGPIOState; + +#endif diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 568764b570..d01a1a85c4 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -74,9 +74,9 @@ enum { FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS) #if defined(TARGET_RISCV32) -#define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0 +#define VIRT_CPU TYPE_RISCV_CPU_BASE32 #elif defined(TARGET_RISCV64) -#define VIRT_CPU TYPE_RISCV_CPU_RV64GCSU_V1_10_0 +#define VIRT_CPU TYPE_RISCV_CPU_BASE64 #endif #endif diff --git a/linux-user/riscv/target_elf.h b/linux-user/riscv/target_elf.h index a6716a6aac..9dd65652ee 100644 --- a/linux-user/riscv/target_elf.h +++ b/linux-user/riscv/target_elf.h @@ -9,6 +9,7 @@ #define RISCV_TARGET_ELF_H static inline const char *cpu_get_model(uint32_t eflags) { + /* TYPE_RISCV_CPU_ANY */ return "any"; } #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 55212585e0..5e29e675e9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -763,14 +763,7 @@ safe_syscall2(int, nanosleep, const struct timespec *, req, safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags, const struct timespec *, req, struct timespec *, rem) #endif -#ifdef __NR_msgsnd -safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz, - int, flags) -safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz, - long, msgtype, int, flags) -safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops, - unsigned, nsops, const struct timespec *, timeout) -#else +#if !defined(__NR_msgsnd) || !defined(__NR_msgrcv) || !defined(__NR_semtimedop) /* This host kernel architecture uses a single ipc syscall; fake up * wrappers for the sub-operations to hide this implementation detail. * Annoyingly we can't include linux/ipc.h to get the constant definitions @@ -785,14 +778,29 @@ safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops, safe_syscall6(int, ipc, int, call, long, first, long, second, long, third, void *, ptr, long, fifth) +#endif +#ifdef __NR_msgsnd +safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz, + int, flags) +#else static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags) { return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0); } +#endif +#ifdef __NR_msgrcv +safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz, + long, msgtype, int, flags) +#else static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags) { return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type); } +#endif +#ifdef __NR_semtimedop +safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops, + unsigned, nsops, const struct timespec *, timeout) +#else static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops, const struct timespec *timeout) { diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index 90cb677849..50292d820b 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -138,6 +138,21 @@ The ``acl_show'', ``acl_reset'', ``acl_policy'', ``acl_add'', and ``acl_remove'' commands are deprecated with no replacement. Authorization for VNC should be performed using the pluggable QAuthZ objects. +@section System emulator CPUS + +@subsection RISC-V ISA CPUs (since 4.1) + +The RISC-V cpus with the ISA version in the CPU name have been depcreated. The +four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and +``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec`` +option when using the ``rv32`` or ``rv64`` CPUs. + +@subsection RISC-V ISA CPUs (since 4.1) + +The RISC-V no MMU cpus have been depcreated. The two CPUs: ``rv32imacu-nommu`` and +``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified +via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. + @section System emulator devices @subsection bluetooth (since 3.1) @@ -160,6 +175,12 @@ This machine type uses an unmaintained firmware, broken in lots of ways, and unable to start post-2004 operating systems. 40p machine type should be used instead. +@subsection spike_v1.9.1 and spike_v1.10 (since 4.1) + +The version specific Spike machines have been deprecated in favour of the +generic ``spike`` machine. If you need to specify an older version of the RISC-V +spec you can use the ``-cpu rv64gcsu,priv_spec=v1.9.1`` command line argument. + @section Device options @subsection Block device options diff --git a/qom/object.c b/qom/object.c index 99c4fa707e..3966a3d461 100644 --- a/qom/object.c +++ b/qom/object.c @@ -28,6 +28,7 @@ #include "qapi/qmp/qbool.h" #include "qapi/qmp/qnum.h" #include "qapi/qmp/qstring.h" +#include "qemu/error-report.h" #define MAX_INTERFACES 32 @@ -448,7 +449,6 @@ static void object_initialize_with_type(void *data, size_t size, TypeImpl *type) { Object *obj = data; - g_assert(type != NULL); type_initialize(type); g_assert(type->instance_size >= sizeof(Object)); @@ -468,6 +468,11 @@ void object_initialize(void *data, size_t size, const char *typename) { TypeImpl *type = type_get_by_name(typename); + if (!type) { + error_report("missing object type '%s'", typename); + abort(); + } + object_initialize_with_type(data, size, type); } diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 1f41cf66d5..06a8ed4748 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -22,10 +22,10 @@ typedef struct CPUMIPSTLBContext CPUMIPSTLBContext; typedef union wr_t wr_t; union wr_t { - int8_t b[MSA_WRLEN/8]; - int16_t h[MSA_WRLEN/16]; - int32_t w[MSA_WRLEN/32]; - int64_t d[MSA_WRLEN/64]; + int8_t b[MSA_WRLEN / 8]; + int16_t h[MSA_WRLEN / 16]; + int32_t w[MSA_WRLEN / 32]; + int64_t d[MSA_WRLEN / 64]; }; typedef union fpr_t fpr_t; @@ -37,7 +37,8 @@ union fpr_t { /* FPU/MSA register mapping is not tested on big-endian hosts. */ wr_t wr; /* vector data */ }; -/* define FP_ENDIAN_IDX to access the same location +/* + *define FP_ENDIAN_IDX to access the same location * in the fpr_t union regardless of the host endianness */ #if defined(HOST_WORDS_BIGENDIAN) @@ -71,16 +72,29 @@ struct CPUMIPSFPUContext { #define FCR31_FS 24 #define FCR31_ABS2008 19 #define FCR31_NAN2008 18 -#define SET_FP_COND(num,env) do { ((env).fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) -#define CLEAR_FP_COND(num,env) do { ((env).fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) -#define GET_FP_COND(env) ((((env).fcr31 >> 24) & 0xfe) | (((env).fcr31 >> 23) & 0x1)) +#define SET_FP_COND(num, env) do { ((env).fcr31) |= \ + ((num) ? (1 << ((num) + 24)) : \ + (1 << 23)); \ + } while (0) +#define CLEAR_FP_COND(num, env) do { ((env).fcr31) &= \ + ~((num) ? (1 << ((num) + 24)) : \ + (1 << 23)); \ + } while (0) +#define GET_FP_COND(env) ((((env).fcr31 >> 24) & 0xfe) | \ + (((env).fcr31 >> 23) & 0x1)) #define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) #define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) #define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) -#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0) -#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v & 0x1f) << 7); } while(0) -#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v & 0x1f) << 2); } while(0) -#define UPDATE_FP_FLAGS(reg,v) do { (reg) |= ((v & 0x1f) << 2); } while(0) +#define SET_FP_CAUSE(reg, v) do { (reg) = ((reg) & ~(0x3f << 12)) | \ + ((v & 0x3f) << 12); \ + } while (0) +#define SET_FP_ENABLE(reg, v) do { (reg) = ((reg) & ~(0x1f << 7)) | \ + ((v & 0x1f) << 7); \ + } while (0) +#define SET_FP_FLAGS(reg, v) do { (reg) = ((reg) & ~(0x1f << 2)) | \ + ((v & 0x1f) << 2); \ + } while (0) +#define UPDATE_FP_FLAGS(reg, v) do { (reg) |= ((v & 0x1f) << 2); } while (0) #define FP_INEXACT 1 #define FP_UNDERFLOW 2 #define FP_OVERFLOW 4 @@ -95,25 +109,25 @@ struct CPUMIPSFPUContext { typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; struct CPUMIPSMVPContext { int32_t CP0_MVPControl; -#define CP0MVPCo_CPA 3 -#define CP0MVPCo_STLB 2 -#define CP0MVPCo_VPC 1 -#define CP0MVPCo_EVP 0 +#define CP0MVPCo_CPA 3 +#define CP0MVPCo_STLB 2 +#define CP0MVPCo_VPC 1 +#define CP0MVPCo_EVP 0 int32_t CP0_MVPConf0; -#define CP0MVPC0_M 31 -#define CP0MVPC0_TLBS 29 -#define CP0MVPC0_GS 28 -#define CP0MVPC0_PCP 27 -#define CP0MVPC0_PTLBE 16 -#define CP0MVPC0_TCA 15 -#define CP0MVPC0_PVPE 10 -#define CP0MVPC0_PTC 0 +#define CP0MVPC0_M 31 +#define CP0MVPC0_TLBS 29 +#define CP0MVPC0_GS 28 +#define CP0MVPC0_PCP 27 +#define CP0MVPC0_PTLBE 16 +#define CP0MVPC0_TCA 15 +#define CP0MVPC0_PVPE 10 +#define CP0MVPC0_PTC 0 int32_t CP0_MVPConf1; -#define CP0MVPC1_CIM 31 -#define CP0MVPC1_CIF 30 -#define CP0MVPC1_PCX 20 -#define CP0MVPC1_PCP2 10 -#define CP0MVPC1_PCP1 0 +#define CP0MVPC1_CIM 31 +#define CP0MVPC1_CIF 30 +#define CP0MVPC1_PCX 20 +#define CP0MVPC1_PCP2 10 +#define CP0MVPC1_PCP1 0 }; typedef struct mips_def_t mips_def_t; @@ -481,44 +495,44 @@ struct CPUMIPSState { */ int32_t CP0_Random; int32_t CP0_VPEControl; -#define CP0VPECo_YSI 21 -#define CP0VPECo_GSI 20 -#define CP0VPECo_EXCPT 16 -#define CP0VPECo_TE 15 -#define CP0VPECo_TargTC 0 +#define CP0VPECo_YSI 21 +#define CP0VPECo_GSI 20 +#define CP0VPECo_EXCPT 16 +#define CP0VPECo_TE 15 +#define CP0VPECo_TargTC 0 int32_t CP0_VPEConf0; -#define CP0VPEC0_M 31 -#define CP0VPEC0_XTC 21 -#define CP0VPEC0_TCS 19 -#define CP0VPEC0_SCS 18 -#define CP0VPEC0_DSC 17 -#define CP0VPEC0_ICS 16 -#define CP0VPEC0_MVP 1 -#define CP0VPEC0_VPA 0 +#define CP0VPEC0_M 31 +#define CP0VPEC0_XTC 21 +#define CP0VPEC0_TCS 19 +#define CP0VPEC0_SCS 18 +#define CP0VPEC0_DSC 17 +#define CP0VPEC0_ICS 16 +#define CP0VPEC0_MVP 1 +#define CP0VPEC0_VPA 0 int32_t CP0_VPEConf1; -#define CP0VPEC1_NCX 20 -#define CP0VPEC1_NCP2 10 -#define CP0VPEC1_NCP1 0 +#define CP0VPEC1_NCX 20 +#define CP0VPEC1_NCP2 10 +#define CP0VPEC1_NCP1 0 target_ulong CP0_YQMask; target_ulong CP0_VPESchedule; target_ulong CP0_VPEScheFBack; int32_t CP0_VPEOpt; -#define CP0VPEOpt_IWX7 15 -#define CP0VPEOpt_IWX6 14 -#define CP0VPEOpt_IWX5 13 -#define CP0VPEOpt_IWX4 12 -#define CP0VPEOpt_IWX3 11 -#define CP0VPEOpt_IWX2 10 -#define CP0VPEOpt_IWX1 9 -#define CP0VPEOpt_IWX0 8 -#define CP0VPEOpt_DWX7 7 -#define CP0VPEOpt_DWX6 6 -#define CP0VPEOpt_DWX5 5 -#define CP0VPEOpt_DWX4 4 -#define CP0VPEOpt_DWX3 3 -#define CP0VPEOpt_DWX2 2 -#define CP0VPEOpt_DWX1 1 -#define CP0VPEOpt_DWX0 0 +#define CP0VPEOpt_IWX7 15 +#define CP0VPEOpt_IWX6 14 +#define CP0VPEOpt_IWX5 13 +#define CP0VPEOpt_IWX4 12 +#define CP0VPEOpt_IWX3 11 +#define CP0VPEOpt_IWX2 10 +#define CP0VPEOpt_IWX1 9 +#define CP0VPEOpt_IWX0 8 +#define CP0VPEOpt_DWX7 7 +#define CP0VPEOpt_DWX6 6 +#define CP0VPEOpt_DWX5 5 +#define CP0VPEOpt_DWX4 4 +#define CP0VPEOpt_DWX3 3 +#define CP0VPEOpt_DWX2 2 +#define CP0VPEOpt_DWX1 1 +#define CP0VPEOpt_DWX0 0 /* * CP0 Register 2 */ @@ -625,33 +639,33 @@ struct CPUMIPSState { #define CP0PC_PSN 0 /* 5..0 */ int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0; -#define CP0SRSC0_M 31 -#define CP0SRSC0_SRS3 20 -#define CP0SRSC0_SRS2 10 -#define CP0SRSC0_SRS1 0 +#define CP0SRSC0_M 31 +#define CP0SRSC0_SRS3 20 +#define CP0SRSC0_SRS2 10 +#define CP0SRSC0_SRS1 0 int32_t CP0_SRSConf1_rw_bitmask; int32_t CP0_SRSConf1; -#define CP0SRSC1_M 31 -#define CP0SRSC1_SRS6 20 -#define CP0SRSC1_SRS5 10 -#define CP0SRSC1_SRS4 0 +#define CP0SRSC1_M 31 +#define CP0SRSC1_SRS6 20 +#define CP0SRSC1_SRS5 10 +#define CP0SRSC1_SRS4 0 int32_t CP0_SRSConf2_rw_bitmask; int32_t CP0_SRSConf2; -#define CP0SRSC2_M 31 -#define CP0SRSC2_SRS9 20 -#define CP0SRSC2_SRS8 10 -#define CP0SRSC2_SRS7 0 +#define CP0SRSC2_M 31 +#define CP0SRSC2_SRS9 20 +#define CP0SRSC2_SRS8 10 +#define CP0SRSC2_SRS7 0 int32_t CP0_SRSConf3_rw_bitmask; int32_t CP0_SRSConf3; -#define CP0SRSC3_M 31 -#define CP0SRSC3_SRS12 20 -#define CP0SRSC3_SRS11 10 -#define CP0SRSC3_SRS10 0 +#define CP0SRSC3_M 31 +#define CP0SRSC3_SRS12 20 +#define CP0SRSC3_SRS11 10 +#define CP0SRSC3_SRS10 0 int32_t CP0_SRSConf4_rw_bitmask; int32_t CP0_SRSConf4; -#define CP0SRSC4_SRS15 20 -#define CP0SRSC4_SRS14 10 -#define CP0SRSC4_SRS13 0 +#define CP0SRSC4_SRS15 20 +#define CP0SRSC4_SRS14 10 +#define CP0SRSC4_SRS13 0 /* * CP0 Register 7 */ @@ -963,9 +977,11 @@ struct CPUMIPSState { /* TMASK defines different execution modes */ #define MIPS_HFLAG_TMASK 0x1F5807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ - /* The KSU flags must be the lowest bits in hflags. The flag order - must be the same as defined for CP0 Status. This allows to use - the bits as the value of mmu_idx. */ + /* + * The KSU flags must be the lowest bits in hflags. The flag order + * must be the same as defined for CP0 Status. This allows to use + * the bits as the value of mmu_idx. + */ #define MIPS_HFLAG_KSU 0x00003 /* kernel/supervisor/user mode mask */ #define MIPS_HFLAG_UM 0x00002 /* user mode flag */ #define MIPS_HFLAG_SM 0x00001 /* supervisor mode flag */ @@ -975,18 +991,22 @@ struct CPUMIPSState { #define MIPS_HFLAG_CP0 0x00010 /* CP0 enabled */ #define MIPS_HFLAG_FPU 0x00020 /* FPU enabled */ #define MIPS_HFLAG_F64 0x00040 /* 64-bit FPU enabled */ - /* True if the MIPS IV COP1X instructions can be used. This also - controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S - and RSQRT.D. */ + /* + * True if the MIPS IV COP1X instructions can be used. This also + * controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S + * and RSQRT.D. + */ #define MIPS_HFLAG_COP1X 0x00080 /* COP1X instructions enabled */ #define MIPS_HFLAG_RE 0x00100 /* Reversed endianness */ #define MIPS_HFLAG_AWRAP 0x00200 /* 32-bit compatibility address wrapping */ #define MIPS_HFLAG_M16 0x00400 /* MIPS16 mode flag */ #define MIPS_HFLAG_M16_SHIFT 10 - /* If translation is interrupted between the branch instruction and + /* + * If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce - * this from three bits to two. */ + * this from three bits to two. + */ #define MIPS_HFLAG_BMASK_BASE 0x803800 #define MIPS_HFLAG_B 0x00800 /* Unconditional branch */ #define MIPS_HFLAG_BC 0x01000 /* Conditional branch */ @@ -1073,8 +1093,10 @@ void mips_cpu_list(void); extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env); extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env); -/* MMU modes definitions. We carefully match the indices with our - hflags layout. */ +/* + * MMU modes definitions. We carefully match the indices with our + * hflags layout. + */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _super #define MMU_MODE2_SUFFIX _user @@ -1090,14 +1112,15 @@ static inline int hflags_mmu_index(uint32_t hflags) } } -static inline int cpu_mmu_index (CPUMIPSState *env, bool ifetch) +static inline int cpu_mmu_index(CPUMIPSState *env, bool ifetch) { return hflags_mmu_index(env->hflags); } #include "exec/cpu-all.h" -/* Memory access type : +/* + * Memory access type : * may be needed for precise access rights control and precise exceptions. */ enum { @@ -1182,7 +1205,7 @@ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); void itc_reconfigure(struct MIPSITUState *tag); /* helper.c */ -target_ulong exception_resume_pc (CPUMIPSState *env); +target_ulong exception_resume_pc(CPUMIPSState *env); static inline void restore_snan_bit_mode(CPUMIPSState *env) { diff --git a/target/mips/helper.c b/target/mips/helper.c index 9799f2ede1..68e44df4da 100644 --- a/target/mips/helper.c +++ b/target/mips/helper.c @@ -43,7 +43,7 @@ int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type) { *physical = address; - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TLBRET_MATCH; } @@ -61,7 +61,7 @@ int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, else *physical = address; - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TLBRET_MATCH; } @@ -101,6 +101,9 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) *prot |= PAGE_WRITE; + if (!(n ? tlb->XI1 : tlb->XI0)) { + *prot |= PAGE_EXEC; + } return TLBRET_MATCH; } return TLBRET_DIRTY; @@ -182,7 +185,7 @@ static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical, } else { /* The segment is unmapped */ *physical = physical_base | (real_address & segmask); - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TLBRET_MATCH; } } @@ -907,7 +910,7 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } if (ret == TLBRET_MATCH) { tlb_set_page(cs, address & TARGET_PAGE_MASK, - physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + physical & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); return true; } @@ -927,7 +930,7 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, access_type, mips_access_type, mmu_idx); if (ret == TLBRET_MATCH) { tlb_set_page(cs, address & TARGET_PAGE_MASK, - physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + physical & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); return true; } diff --git a/target/mips/helper.h b/target/mips/helper.h index 90ab03b76e..51f0e1c183 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -878,9 +878,7 @@ DEF_HELPER_5(msa_hsub_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_sldi_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_splati_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_copy_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_copy_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_insert_df, void, env, i32, i32, i32, i32) + DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32) DEF_HELPER_3(msa_ctcmsa, void, env, tl, i32) DEF_HELPER_2(msa_cfcmsa, tl, env, i32) @@ -940,6 +938,18 @@ DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_copy_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_insert_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_insert_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_insert_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_insert_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_fclass_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ftrunc_s_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ftrunc_u_df, void, env, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index c74e3cdc65..ee1b1fa5f5 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -641,14 +641,15 @@ static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2) if (arg1 == DF_MIN_INT(df) && arg2 == -1) { return DF_MIN_INT(df); } - return arg2 ? arg1 / arg2 : 0; + return arg2 ? arg1 / arg2 + : arg1 >= 0 ? -1 : 1; } static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2) { uint64_t u_arg1 = UNSIGNED(arg1, df); uint64_t u_arg2 = UNSIGNED(arg2, df); - return u_arg2 ? u_arg1 / u_arg2 : 0; + return arg2 ? u_arg1 / u_arg2 : -1; } static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2) @@ -656,14 +657,14 @@ static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2) if (arg1 == DF_MIN_INT(df) && arg2 == -1) { return 0; } - return arg2 ? arg1 % arg2 : 0; + return arg2 ? arg1 % arg2 : arg1; } static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2) { uint64_t u_arg1 = UNSIGNED(arg1, df); uint64_t u_arg2 = UNSIGNED(arg2, df); - return u_arg2 ? u_arg1 % u_arg2 : 0; + return u_arg2 ? u_arg1 % u_arg2 : u_arg1; } #define SIGNED_EVEN(a, df) \ @@ -1248,78 +1249,152 @@ void helper_msa_splati_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_splat_df(df, pwd, pws, n); } -void helper_msa_copy_s_df(CPUMIPSState *env, uint32_t df, uint32_t rd, - uint32_t ws, uint32_t n) +void helper_msa_copy_s_b(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) { - n %= DF_ELEMENTS(df); + n %= 16; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 8) { + n = 8 - n - 1; + } else { + n = 24 - n - 1; + } +#endif + env->active_tc.gpr[rd] = (int8_t)env->active_fpu.fpr[ws].wr.b[n]; +} - switch (df) { - case DF_BYTE: - env->active_tc.gpr[rd] = (int8_t)env->active_fpu.fpr[ws].wr.b[n]; - break; - case DF_HALF: - env->active_tc.gpr[rd] = (int16_t)env->active_fpu.fpr[ws].wr.h[n]; - break; - case DF_WORD: - env->active_tc.gpr[rd] = (int32_t)env->active_fpu.fpr[ws].wr.w[n]; - break; -#ifdef TARGET_MIPS64 - case DF_DOUBLE: - env->active_tc.gpr[rd] = (int64_t)env->active_fpu.fpr[ws].wr.d[n]; - break; +void helper_msa_copy_s_h(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= 8; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 4) { + n = 4 - n - 1; + } else { + n = 12 - n - 1; + } #endif - default: - assert(0); + env->active_tc.gpr[rd] = (int16_t)env->active_fpu.fpr[ws].wr.h[n]; +} + +void helper_msa_copy_s_w(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= 4; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 2) { + n = 2 - n - 1; + } else { + n = 6 - n - 1; } +#endif + env->active_tc.gpr[rd] = (int32_t)env->active_fpu.fpr[ws].wr.w[n]; } -void helper_msa_copy_u_df(CPUMIPSState *env, uint32_t df, uint32_t rd, - uint32_t ws, uint32_t n) +void helper_msa_copy_s_d(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) { - n %= DF_ELEMENTS(df); + n %= 2; + env->active_tc.gpr[rd] = (int64_t)env->active_fpu.fpr[ws].wr.d[n]; +} - switch (df) { - case DF_BYTE: - env->active_tc.gpr[rd] = (uint8_t)env->active_fpu.fpr[ws].wr.b[n]; - break; - case DF_HALF: - env->active_tc.gpr[rd] = (uint16_t)env->active_fpu.fpr[ws].wr.h[n]; - break; - case DF_WORD: - env->active_tc.gpr[rd] = (uint32_t)env->active_fpu.fpr[ws].wr.w[n]; - break; -#ifdef TARGET_MIPS64 - case DF_DOUBLE: - env->active_tc.gpr[rd] = (uint64_t)env->active_fpu.fpr[ws].wr.d[n]; - break; +void helper_msa_copy_u_b(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= 16; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 8) { + n = 8 - n - 1; + } else { + n = 24 - n - 1; + } #endif - default: - assert(0); + env->active_tc.gpr[rd] = (uint8_t)env->active_fpu.fpr[ws].wr.b[n]; +} + +void helper_msa_copy_u_h(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= 8; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 4) { + n = 4 - n - 1; + } else { + n = 12 - n - 1; + } +#endif + env->active_tc.gpr[rd] = (uint16_t)env->active_fpu.fpr[ws].wr.h[n]; +} + +void helper_msa_copy_u_w(CPUMIPSState *env, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= 4; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 2) { + n = 2 - n - 1; + } else { + n = 6 - n - 1; } +#endif + env->active_tc.gpr[rd] = (uint32_t)env->active_fpu.fpr[ws].wr.w[n]; } -void helper_msa_insert_df(CPUMIPSState *env, uint32_t df, uint32_t wd, +void helper_msa_insert_b(CPUMIPSState *env, uint32_t wd, uint32_t rs_num, uint32_t n) { wr_t *pwd = &(env->active_fpu.fpr[wd].wr); target_ulong rs = env->active_tc.gpr[rs_num]; + n %= 16; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 8) { + n = 8 - n - 1; + } else { + n = 24 - n - 1; + } +#endif + pwd->b[n] = (int8_t)rs; +} - switch (df) { - case DF_BYTE: - pwd->b[n] = (int8_t)rs; - break; - case DF_HALF: - pwd->h[n] = (int16_t)rs; - break; - case DF_WORD: - pwd->w[n] = (int32_t)rs; - break; - case DF_DOUBLE: - pwd->d[n] = (int64_t)rs; - break; - default: - assert(0); +void helper_msa_insert_h(CPUMIPSState *env, uint32_t wd, + uint32_t rs_num, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + target_ulong rs = env->active_tc.gpr[rs_num]; + n %= 8; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 4) { + n = 4 - n - 1; + } else { + n = 12 - n - 1; } +#endif + pwd->h[n] = (int16_t)rs; +} + +void helper_msa_insert_w(CPUMIPSState *env, uint32_t wd, + uint32_t rs_num, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + target_ulong rs = env->active_tc.gpr[rs_num]; + n %= 4; +#if defined(HOST_WORDS_BIGENDIAN) + if (n < 2) { + n = 2 - n - 1; + } else { + n = 6 - n - 1; + } +#endif + pwd->w[n] = (int32_t)rs; +} + +void helper_msa_insert_d(CPUMIPSState *env, uint32_t wd, + uint32_t rs_num, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + target_ulong rs = env->active_tc.gpr[rs_num]; + n %= 2; + pwd->d[n] = (int64_t)rs; } void helper_msa_insve_df(CPUMIPSState *env, uint32_t df, uint32_t wd, diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 6d86912958..39180275b5 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -4356,31 +4356,179 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status) #define MEMOP_IDX(DF) #endif -#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \ -void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ - target_ulong addr) \ -{ \ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ - wr_t wx; \ - int i; \ - MEMOP_IDX(DF) \ - for (i = 0; i < DF_ELEMENTS(DF); i++) { \ - wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \ - } \ - memcpy(pwd, &wx, sizeof(wr_t)); \ +void helper_msa_ld_b(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + MEMOP_IDX(DF_BYTE) +#if !defined(CONFIG_USER_ONLY) +#if !defined(HOST_WORDS_BIGENDIAN) + pwd->b[0] = helper_ret_ldub_mmu(env, addr + (0 << DF_BYTE), oi, GETPC()); + pwd->b[1] = helper_ret_ldub_mmu(env, addr + (1 << DF_BYTE), oi, GETPC()); + pwd->b[2] = helper_ret_ldub_mmu(env, addr + (2 << DF_BYTE), oi, GETPC()); + pwd->b[3] = helper_ret_ldub_mmu(env, addr + (3 << DF_BYTE), oi, GETPC()); + pwd->b[4] = helper_ret_ldub_mmu(env, addr + (4 << DF_BYTE), oi, GETPC()); + pwd->b[5] = helper_ret_ldub_mmu(env, addr + (5 << DF_BYTE), oi, GETPC()); + pwd->b[6] = helper_ret_ldub_mmu(env, addr + (6 << DF_BYTE), oi, GETPC()); + pwd->b[7] = helper_ret_ldub_mmu(env, addr + (7 << DF_BYTE), oi, GETPC()); + pwd->b[8] = helper_ret_ldub_mmu(env, addr + (8 << DF_BYTE), oi, GETPC()); + pwd->b[9] = helper_ret_ldub_mmu(env, addr + (9 << DF_BYTE), oi, GETPC()); + pwd->b[10] = helper_ret_ldub_mmu(env, addr + (10 << DF_BYTE), oi, GETPC()); + pwd->b[11] = helper_ret_ldub_mmu(env, addr + (11 << DF_BYTE), oi, GETPC()); + pwd->b[12] = helper_ret_ldub_mmu(env, addr + (12 << DF_BYTE), oi, GETPC()); + pwd->b[13] = helper_ret_ldub_mmu(env, addr + (13 << DF_BYTE), oi, GETPC()); + pwd->b[14] = helper_ret_ldub_mmu(env, addr + (14 << DF_BYTE), oi, GETPC()); + pwd->b[15] = helper_ret_ldub_mmu(env, addr + (15 << DF_BYTE), oi, GETPC()); +#else + pwd->b[0] = helper_ret_ldub_mmu(env, addr + (7 << DF_BYTE), oi, GETPC()); + pwd->b[1] = helper_ret_ldub_mmu(env, addr + (6 << DF_BYTE), oi, GETPC()); + pwd->b[2] = helper_ret_ldub_mmu(env, addr + (5 << DF_BYTE), oi, GETPC()); + pwd->b[3] = helper_ret_ldub_mmu(env, addr + (4 << DF_BYTE), oi, GETPC()); + pwd->b[4] = helper_ret_ldub_mmu(env, addr + (3 << DF_BYTE), oi, GETPC()); + pwd->b[5] = helper_ret_ldub_mmu(env, addr + (2 << DF_BYTE), oi, GETPC()); + pwd->b[6] = helper_ret_ldub_mmu(env, addr + (1 << DF_BYTE), oi, GETPC()); + pwd->b[7] = helper_ret_ldub_mmu(env, addr + (0 << DF_BYTE), oi, GETPC()); + pwd->b[8] = helper_ret_ldub_mmu(env, addr + (15 << DF_BYTE), oi, GETPC()); + pwd->b[9] = helper_ret_ldub_mmu(env, addr + (14 << DF_BYTE), oi, GETPC()); + pwd->b[10] = helper_ret_ldub_mmu(env, addr + (13 << DF_BYTE), oi, GETPC()); + pwd->b[11] = helper_ret_ldub_mmu(env, addr + (12 << DF_BYTE), oi, GETPC()); + pwd->b[12] = helper_ret_ldub_mmu(env, addr + (11 << DF_BYTE), oi, GETPC()); + pwd->b[13] = helper_ret_ldub_mmu(env, addr + (10 << DF_BYTE), oi, GETPC()); + pwd->b[14] = helper_ret_ldub_mmu(env, addr + (9 << DF_BYTE), oi, GETPC()); + pwd->b[15] = helper_ret_ldub_mmu(env, addr + (8 << DF_BYTE), oi, GETPC()); +#endif +#else +#if !defined(HOST_WORDS_BIGENDIAN) + pwd->b[0] = cpu_ldub_data(env, addr + (0 << DF_BYTE)); + pwd->b[1] = cpu_ldub_data(env, addr + (1 << DF_BYTE)); + pwd->b[2] = cpu_ldub_data(env, addr + (2 << DF_BYTE)); + pwd->b[3] = cpu_ldub_data(env, addr + (3 << DF_BYTE)); + pwd->b[4] = cpu_ldub_data(env, addr + (4 << DF_BYTE)); + pwd->b[5] = cpu_ldub_data(env, addr + (5 << DF_BYTE)); + pwd->b[6] = cpu_ldub_data(env, addr + (6 << DF_BYTE)); + pwd->b[7] = cpu_ldub_data(env, addr + (7 << DF_BYTE)); + pwd->b[8] = cpu_ldub_data(env, addr + (8 << DF_BYTE)); + pwd->b[9] = cpu_ldub_data(env, addr + (9 << DF_BYTE)); + pwd->b[10] = cpu_ldub_data(env, addr + (10 << DF_BYTE)); + pwd->b[11] = cpu_ldub_data(env, addr + (11 << DF_BYTE)); + pwd->b[12] = cpu_ldub_data(env, addr + (12 << DF_BYTE)); + pwd->b[13] = cpu_ldub_data(env, addr + (13 << DF_BYTE)); + pwd->b[14] = cpu_ldub_data(env, addr + (14 << DF_BYTE)); + pwd->b[15] = cpu_ldub_data(env, addr + (15 << DF_BYTE)); +#else + pwd->b[0] = cpu_ldub_data(env, addr + (7 << DF_BYTE)); + pwd->b[1] = cpu_ldub_data(env, addr + (6 << DF_BYTE)); + pwd->b[2] = cpu_ldub_data(env, addr + (5 << DF_BYTE)); + pwd->b[3] = cpu_ldub_data(env, addr + (4 << DF_BYTE)); + pwd->b[4] = cpu_ldub_data(env, addr + (3 << DF_BYTE)); + pwd->b[5] = cpu_ldub_data(env, addr + (2 << DF_BYTE)); + pwd->b[6] = cpu_ldub_data(env, addr + (1 << DF_BYTE)); + pwd->b[7] = cpu_ldub_data(env, addr + (0 << DF_BYTE)); + pwd->b[8] = cpu_ldub_data(env, addr + (15 << DF_BYTE)); + pwd->b[9] = cpu_ldub_data(env, addr + (14 << DF_BYTE)); + pwd->b[10] = cpu_ldub_data(env, addr + (13 << DF_BYTE)); + pwd->b[11] = cpu_ldub_data(env, addr + (12 << DF_BYTE)); + pwd->b[12] = cpu_ldub_data(env, addr + (11 << DF_BYTE)); + pwd->b[13] = cpu_ldub_data(env, addr + (10 << DF_BYTE)); + pwd->b[14] = cpu_ldub_data(env, addr + (9 << DF_BYTE)); + pwd->b[15] = cpu_ldub_data(env, addr + (8 << DF_BYTE)); +#endif +#endif +} + +void helper_msa_ld_h(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + MEMOP_IDX(DF_HALF) +#if !defined(CONFIG_USER_ONLY) +#if !defined(HOST_WORDS_BIGENDIAN) + pwd->h[0] = helper_ret_lduw_mmu(env, addr + (0 << DF_HALF), oi, GETPC()); + pwd->h[1] = helper_ret_lduw_mmu(env, addr + (1 << DF_HALF), oi, GETPC()); + pwd->h[2] = helper_ret_lduw_mmu(env, addr + (2 << DF_HALF), oi, GETPC()); + pwd->h[3] = helper_ret_lduw_mmu(env, addr + (3 << DF_HALF), oi, GETPC()); + pwd->h[4] = helper_ret_lduw_mmu(env, addr + (4 << DF_HALF), oi, GETPC()); + pwd->h[5] = helper_ret_lduw_mmu(env, addr + (5 << DF_HALF), oi, GETPC()); + pwd->h[6] = helper_ret_lduw_mmu(env, addr + (6 << DF_HALF), oi, GETPC()); + pwd->h[7] = helper_ret_lduw_mmu(env, addr + (7 << DF_HALF), oi, GETPC()); +#else + pwd->h[0] = helper_ret_lduw_mmu(env, addr + (3 << DF_HALF), oi, GETPC()); + pwd->h[1] = helper_ret_lduw_mmu(env, addr + (2 << DF_HALF), oi, GETPC()); + pwd->h[2] = helper_ret_lduw_mmu(env, addr + (1 << DF_HALF), oi, GETPC()); + pwd->h[3] = helper_ret_lduw_mmu(env, addr + (0 << DF_HALF), oi, GETPC()); + pwd->h[4] = helper_ret_lduw_mmu(env, addr + (7 << DF_HALF), oi, GETPC()); + pwd->h[5] = helper_ret_lduw_mmu(env, addr + (6 << DF_HALF), oi, GETPC()); + pwd->h[6] = helper_ret_lduw_mmu(env, addr + (5 << DF_HALF), oi, GETPC()); + pwd->h[7] = helper_ret_lduw_mmu(env, addr + (4 << DF_HALF), oi, GETPC()); +#endif +#else +#if !defined(HOST_WORDS_BIGENDIAN) + pwd->h[0] = cpu_lduw_data(env, addr + (0 << DF_HALF)); + pwd->h[1] = cpu_lduw_data(env, addr + (1 << DF_HALF)); + pwd->h[2] = cpu_lduw_data(env, addr + (2 << DF_HALF)); + pwd->h[3] = cpu_lduw_data(env, addr + (3 << DF_HALF)); + pwd->h[4] = cpu_lduw_data(env, addr + (4 << DF_HALF)); + pwd->h[5] = cpu_lduw_data(env, addr + (5 << DF_HALF)); + pwd->h[6] = cpu_lduw_data(env, addr + (6 << DF_HALF)); + pwd->h[7] = cpu_lduw_data(env, addr + (7 << DF_HALF)); +#else + pwd->h[0] = cpu_lduw_data(env, addr + (3 << DF_HALF)); + pwd->h[1] = cpu_lduw_data(env, addr + (2 << DF_HALF)); + pwd->h[2] = cpu_lduw_data(env, addr + (1 << DF_HALF)); + pwd->h[3] = cpu_lduw_data(env, addr + (0 << DF_HALF)); + pwd->h[4] = cpu_lduw_data(env, addr + (7 << DF_HALF)); + pwd->h[5] = cpu_lduw_data(env, addr + (6 << DF_HALF)); + pwd->h[6] = cpu_lduw_data(env, addr + (5 << DF_HALF)); + pwd->h[7] = cpu_lduw_data(env, addr + (4 << DF_HALF)); +#endif +#endif } +void helper_msa_ld_w(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + MEMOP_IDX(DF_WORD) #if !defined(CONFIG_USER_ONLY) -MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETPC()) -MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETPC()) -MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETPC()) -MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETPC()) +#if !defined(HOST_WORDS_BIGENDIAN) + pwd->w[0] = helper_ret_ldul_mmu(env, addr + (0 << DF_WORD), oi, GETPC()); + pwd->w[1] = helper_ret_ldul_mmu(env, addr + (1 << DF_WORD), oi, GETPC()); + pwd->w[2] = helper_ret_ldul_mmu(env, addr + (2 << DF_WORD), oi, GETPC()); + pwd->w[3] = helper_ret_ldul_mmu(env, addr + (3 << DF_WORD), oi, GETPC()); #else -MSA_LD_DF(DF_BYTE, b, cpu_ldub_data) -MSA_LD_DF(DF_HALF, h, cpu_lduw_data) -MSA_LD_DF(DF_WORD, w, cpu_ldl_data) -MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data) + pwd->w[0] = helper_ret_ldul_mmu(env, addr + (1 << DF_WORD), oi, GETPC()); + pwd->w[1] = helper_ret_ldul_mmu(env, addr + (0 << DF_WORD), oi, GETPC()); + pwd->w[2] = helper_ret_ldul_mmu(env, addr + (3 << DF_WORD), oi, GETPC()); + pwd->w[3] = helper_ret_ldul_mmu(env, addr + (2 << DF_WORD), oi, GETPC()); #endif +#else +#if !defined(HOST_WORDS_BIGENDIAN) + pwd->w[0] = cpu_ldl_data(env, addr + (0 << DF_WORD)); + pwd->w[1] = cpu_ldl_data(env, addr + (1 << DF_WORD)); + pwd->w[2] = cpu_ldl_data(env, addr + (2 << DF_WORD)); + pwd->w[3] = cpu_ldl_data(env, addr + (3 << DF_WORD)); +#else + pwd->w[0] = cpu_ldl_data(env, addr + (1 << DF_WORD)); + pwd->w[1] = cpu_ldl_data(env, addr + (0 << DF_WORD)); + pwd->w[2] = cpu_ldl_data(env, addr + (3 << DF_WORD)); + pwd->w[3] = cpu_ldl_data(env, addr + (2 << DF_WORD)); +#endif +#endif +} + +void helper_msa_ld_d(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + MEMOP_IDX(DF_DOUBLE) +#if !defined(CONFIG_USER_ONLY) + pwd->d[0] = helper_ret_ldq_mmu(env, addr + (0 << DF_DOUBLE), oi, GETPC()); + pwd->d[1] = helper_ret_ldq_mmu(env, addr + (1 << DF_DOUBLE), oi, GETPC()); +#else + pwd->d[0] = cpu_ldq_data(env, addr + (0 << DF_DOUBLE)); + pwd->d[1] = cpu_ldq_data(env, addr + (1 << DF_DOUBLE)); +#endif +} #define MSA_PAGESPAN(x) \ ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE) @@ -4402,31 +4550,191 @@ static inline void ensure_writable_pages(CPUMIPSState *env, #endif } -#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \ -void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ - target_ulong addr) \ -{ \ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ - int mmu_idx = cpu_mmu_index(env, false); \ - int i; \ - MEMOP_IDX(DF) \ - ensure_writable_pages(env, addr, mmu_idx, GETPC()); \ - for (i = 0; i < DF_ELEMENTS(DF); i++) { \ - ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \ - } \ +void helper_msa_st_b(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + int mmu_idx = cpu_mmu_index(env, false); + + MEMOP_IDX(DF_BYTE) + ensure_writable_pages(env, addr, mmu_idx, GETPC()); +#if !defined(CONFIG_USER_ONLY) +#if !defined(HOST_WORDS_BIGENDIAN) + helper_ret_stb_mmu(env, addr + (0 << DF_BYTE), pwd->b[0], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (1 << DF_BYTE), pwd->b[1], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (2 << DF_BYTE), pwd->b[2], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (3 << DF_BYTE), pwd->b[3], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (4 << DF_BYTE), pwd->b[4], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (5 << DF_BYTE), pwd->b[5], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (6 << DF_BYTE), pwd->b[6], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (7 << DF_BYTE), pwd->b[7], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (8 << DF_BYTE), pwd->b[8], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (9 << DF_BYTE), pwd->b[9], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (10 << DF_BYTE), pwd->b[10], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (11 << DF_BYTE), pwd->b[11], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (12 << DF_BYTE), pwd->b[12], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (13 << DF_BYTE), pwd->b[13], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (14 << DF_BYTE), pwd->b[14], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (15 << DF_BYTE), pwd->b[15], oi, GETPC()); +#else + helper_ret_stb_mmu(env, addr + (7 << DF_BYTE), pwd->b[0], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (6 << DF_BYTE), pwd->b[1], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (5 << DF_BYTE), pwd->b[2], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (4 << DF_BYTE), pwd->b[3], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (3 << DF_BYTE), pwd->b[4], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (2 << DF_BYTE), pwd->b[5], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (1 << DF_BYTE), pwd->b[6], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (0 << DF_BYTE), pwd->b[7], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (15 << DF_BYTE), pwd->b[8], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (14 << DF_BYTE), pwd->b[9], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (13 << DF_BYTE), pwd->b[10], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (12 << DF_BYTE), pwd->b[11], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (11 << DF_BYTE), pwd->b[12], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (10 << DF_BYTE), pwd->b[13], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (9 << DF_BYTE), pwd->b[14], oi, GETPC()); + helper_ret_stb_mmu(env, addr + (8 << DF_BYTE), pwd->b[15], oi, GETPC()); +#endif +#else +#if !defined(HOST_WORDS_BIGENDIAN) + cpu_stb_data(env, addr + (0 << DF_BYTE), pwd->b[0]); + cpu_stb_data(env, addr + (1 << DF_BYTE), pwd->b[1]); + cpu_stb_data(env, addr + (2 << DF_BYTE), pwd->b[2]); + cpu_stb_data(env, addr + (3 << DF_BYTE), pwd->b[3]); + cpu_stb_data(env, addr + (4 << DF_BYTE), pwd->b[4]); + cpu_stb_data(env, addr + (5 << DF_BYTE), pwd->b[5]); + cpu_stb_data(env, addr + (6 << DF_BYTE), pwd->b[6]); + cpu_stb_data(env, addr + (7 << DF_BYTE), pwd->b[7]); + cpu_stb_data(env, addr + (8 << DF_BYTE), pwd->b[8]); + cpu_stb_data(env, addr + (9 << DF_BYTE), pwd->b[9]); + cpu_stb_data(env, addr + (10 << DF_BYTE), pwd->b[10]); + cpu_stb_data(env, addr + (11 << DF_BYTE), pwd->b[11]); + cpu_stb_data(env, addr + (12 << DF_BYTE), pwd->b[12]); + cpu_stb_data(env, addr + (13 << DF_BYTE), pwd->b[13]); + cpu_stb_data(env, addr + (14 << DF_BYTE), pwd->b[14]); + cpu_stb_data(env, addr + (15 << DF_BYTE), pwd->b[15]); +#else + cpu_stb_data(env, addr + (7 << DF_BYTE), pwd->b[0]); + cpu_stb_data(env, addr + (6 << DF_BYTE), pwd->b[1]); + cpu_stb_data(env, addr + (5 << DF_BYTE), pwd->b[2]); + cpu_stb_data(env, addr + (4 << DF_BYTE), pwd->b[3]); + cpu_stb_data(env, addr + (3 << DF_BYTE), pwd->b[4]); + cpu_stb_data(env, addr + (2 << DF_BYTE), pwd->b[5]); + cpu_stb_data(env, addr + (1 << DF_BYTE), pwd->b[6]); + cpu_stb_data(env, addr + (0 << DF_BYTE), pwd->b[7]); + cpu_stb_data(env, addr + (15 << DF_BYTE), pwd->b[8]); + cpu_stb_data(env, addr + (14 << DF_BYTE), pwd->b[9]); + cpu_stb_data(env, addr + (13 << DF_BYTE), pwd->b[10]); + cpu_stb_data(env, addr + (12 << DF_BYTE), pwd->b[11]); + cpu_stb_data(env, addr + (11 << DF_BYTE), pwd->b[12]); + cpu_stb_data(env, addr + (10 << DF_BYTE), pwd->b[13]); + cpu_stb_data(env, addr + (9 << DF_BYTE), pwd->b[14]); + cpu_stb_data(env, addr + (8 << DF_BYTE), pwd->b[15]); +#endif +#endif +} + +void helper_msa_st_h(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + int mmu_idx = cpu_mmu_index(env, false); + + MEMOP_IDX(DF_HALF) + ensure_writable_pages(env, addr, mmu_idx, GETPC()); +#if !defined(CONFIG_USER_ONLY) +#if !defined(HOST_WORDS_BIGENDIAN) + helper_ret_stw_mmu(env, addr + (0 << DF_HALF), pwd->h[0], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (1 << DF_HALF), pwd->h[1], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (2 << DF_HALF), pwd->h[2], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (3 << DF_HALF), pwd->h[3], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (4 << DF_HALF), pwd->h[4], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (5 << DF_HALF), pwd->h[5], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (6 << DF_HALF), pwd->h[6], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (7 << DF_HALF), pwd->h[7], oi, GETPC()); +#else + helper_ret_stw_mmu(env, addr + (3 << DF_HALF), pwd->h[0], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (2 << DF_HALF), pwd->h[1], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (1 << DF_HALF), pwd->h[2], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (0 << DF_HALF), pwd->h[3], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (7 << DF_HALF), pwd->h[4], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (6 << DF_HALF), pwd->h[5], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (5 << DF_HALF), pwd->h[6], oi, GETPC()); + helper_ret_stw_mmu(env, addr + (4 << DF_HALF), pwd->h[7], oi, GETPC()); +#endif +#else +#if !defined(HOST_WORDS_BIGENDIAN) + cpu_stw_data(env, addr + (0 << DF_HALF), pwd->h[0]); + cpu_stw_data(env, addr + (1 << DF_HALF), pwd->h[1]); + cpu_stw_data(env, addr + (2 << DF_HALF), pwd->h[2]); + cpu_stw_data(env, addr + (3 << DF_HALF), pwd->h[3]); + cpu_stw_data(env, addr + (4 << DF_HALF), pwd->h[4]); + cpu_stw_data(env, addr + (5 << DF_HALF), pwd->h[5]); + cpu_stw_data(env, addr + (6 << DF_HALF), pwd->h[6]); + cpu_stw_data(env, addr + (7 << DF_HALF), pwd->h[7]); +#else + cpu_stw_data(env, addr + (3 << DF_HALF), pwd->h[0]); + cpu_stw_data(env, addr + (2 << DF_HALF), pwd->h[1]); + cpu_stw_data(env, addr + (1 << DF_HALF), pwd->h[2]); + cpu_stw_data(env, addr + (0 << DF_HALF), pwd->h[3]); + cpu_stw_data(env, addr + (7 << DF_HALF), pwd->h[4]); + cpu_stw_data(env, addr + (6 << DF_HALF), pwd->h[5]); + cpu_stw_data(env, addr + (5 << DF_HALF), pwd->h[6]); + cpu_stw_data(env, addr + (4 << DF_HALF), pwd->h[7]); +#endif +#endif } +void helper_msa_st_w(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + int mmu_idx = cpu_mmu_index(env, false); + + MEMOP_IDX(DF_WORD) + ensure_writable_pages(env, addr, mmu_idx, GETPC()); #if !defined(CONFIG_USER_ONLY) -MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETPC()) -MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETPC()) -MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETPC()) -MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETPC()) +#if !defined(HOST_WORDS_BIGENDIAN) + helper_ret_stl_mmu(env, addr + (0 << DF_WORD), oi, GETPC(), pwd->w[0]); + helper_ret_stl_mmu(env, addr + (1 << DF_WORD), oi, GETPC(), pwd->w[1]); + helper_ret_stl_mmu(env, addr + (2 << DF_WORD), oi, GETPC(), pwd->w[2]); + helper_ret_stl_mmu(env, addr + (3 << DF_WORD), oi, GETPC(), pwd->w[3]); #else -MSA_ST_DF(DF_BYTE, b, cpu_stb_data) -MSA_ST_DF(DF_HALF, h, cpu_stw_data) -MSA_ST_DF(DF_WORD, w, cpu_stl_data) -MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data) + helper_ret_stl_mmu(env, addr + (1 << DF_WORD), oi, GETPC(), pwd->w[0]); + helper_ret_stl_mmu(env, addr + (0 << DF_WORD), oi, GETPC(), pwd->w[1]); + helper_ret_stl_mmu(env, addr + (3 << DF_WORD), oi, GETPC(), pwd->w[2]); + helper_ret_stl_mmu(env, addr + (2 << DF_WORD), oi, GETPC(), pwd->w[3]); +#endif +#else +#if !defined(HOST_WORDS_BIGENDIAN) + cpu_stl_data(env, addr + (0 << DF_WORD), pwd->w[0]); + cpu_stl_data(env, addr + (1 << DF_WORD), pwd->w[1]); + cpu_stl_data(env, addr + (2 << DF_WORD), pwd->w[2]); + cpu_stl_data(env, addr + (3 << DF_WORD), pwd->w[3]); +#else + cpu_stl_data(env, addr + (1 << DF_WORD), pwd->w[0]); + cpu_stl_data(env, addr + (0 << DF_WORD), pwd->w[1]); + cpu_stl_data(env, addr + (3 << DF_WORD), pwd->w[2]); + cpu_stl_data(env, addr + (2 << DF_WORD), pwd->w[3]); +#endif #endif +} + +void helper_msa_st_d(CPUMIPSState *env, uint32_t wd, + target_ulong addr) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + int mmu_idx = cpu_mmu_index(env, false); + + MEMOP_IDX(DF_DOUBLE) + ensure_writable_pages(env, addr, mmu_idx, GETPC()); +#if !defined(CONFIG_USER_ONLY) + helper_ret_stq_mmu(env, addr + (0 << DF_DOUBLE), pwd->d[0], oi, GETPC()); + helper_ret_stq_mmu(env, addr + (1 << DF_DOUBLE), pwd->d[1], oi, GETPC()); +#else + cpu_stq_data(env, addr + (0 << DF_DOUBLE), pwd->d[0]); + cpu_stq_data(env, addr + (1 << DF_DOUBLE), pwd->d[1]); +#endif +} void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) { diff --git a/target/mips/translate.c b/target/mips/translate.c index fb905c88b5..70552fe543 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -28305,20 +28305,73 @@ static void gen_msa_elm_df(CPUMIPSState *env, DisasContext *ctx, uint32_t df, generate_exception_end(ctx, EXCP_RI); break; } + if ((MASK_MSA_ELM(ctx->opcode) == OPC_COPY_U_df) && + (df == DF_WORD)) { + generate_exception_end(ctx, EXCP_RI); + break; + } #endif switch (MASK_MSA_ELM(ctx->opcode)) { case OPC_COPY_S_df: if (likely(wd != 0)) { - gen_helper_msa_copy_s_df(cpu_env, tdf, twd, tws, tn); + switch (df) { + case DF_BYTE: + gen_helper_msa_copy_s_b(cpu_env, twd, tws, tn); + break; + case DF_HALF: + gen_helper_msa_copy_s_h(cpu_env, twd, tws, tn); + break; + case DF_WORD: + gen_helper_msa_copy_s_w(cpu_env, twd, tws, tn); + break; +#if defined(TARGET_MIPS64) + case DF_DOUBLE: + gen_helper_msa_copy_s_d(cpu_env, twd, tws, tn); + break; +#endif + default: + assert(0); + } } break; case OPC_COPY_U_df: if (likely(wd != 0)) { - gen_helper_msa_copy_u_df(cpu_env, tdf, twd, tws, tn); + switch (df) { + case DF_BYTE: + gen_helper_msa_copy_u_b(cpu_env, twd, tws, tn); + break; + case DF_HALF: + gen_helper_msa_copy_u_h(cpu_env, twd, tws, tn); + break; +#if defined(TARGET_MIPS64) + case DF_WORD: + gen_helper_msa_copy_u_w(cpu_env, twd, tws, tn); + break; +#endif + default: + assert(0); + } } break; case OPC_INSERT_df: - gen_helper_msa_insert_df(cpu_env, tdf, twd, tws, tn); + switch (df) { + case DF_BYTE: + gen_helper_msa_insert_b(cpu_env, twd, tws, tn); + break; + case DF_HALF: + gen_helper_msa_insert_h(cpu_env, twd, tws, tn); + break; + case DF_WORD: + gen_helper_msa_insert_w(cpu_env, twd, tws, tn); + break; +#if defined(TARGET_MIPS64) + case DF_DOUBLE: + gen_helper_msa_insert_d(cpu_env, twd, tws, tn); + break; +#endif + default: + assert(0); + } break; } break; diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs index 9c6c109327..b1c79bc1d1 100644 --- a/target/riscv/Makefile.objs +++ b/target/riscv/Makefile.objs @@ -5,16 +5,19 @@ DECODETREE = $(SRC_PATH)/scripts/decodetree.py decode32-y = $(SRC_PATH)/target/riscv/insn32.decode decode32-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn32-64.decode +decode16-y = $(SRC_PATH)/target/riscv/insn16.decode +decode16-$(TARGET_RISCV32) += $(SRC_PATH)/target/riscv/insn16-32.decode +decode16-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn16-64.decode + target/riscv/decode_insn32.inc.c: $(decode32-y) $(DECODETREE) $(call quiet-command, \ - $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn32 $(decode32-y), \ - "GEN", $(TARGET_DIR)$@) + $(PYTHON) $(DECODETREE) -o $@ --static-decode decode_insn32 \ + $(decode32-y), "GEN", $(TARGET_DIR)$@) -target/riscv/decode_insn16.inc.c: \ - $(SRC_PATH)/target/riscv/insn16.decode $(DECODETREE) +target/riscv/decode_insn16.inc.c: $(decode16-y) $(DECODETREE) $(call quiet-command, \ - $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn16 --insnwidth 16 $<, \ - "GEN", $(TARGET_DIR)$@) + $(PYTHON) $(DECODETREE) -o $@ --static-decode decode_insn16 \ + --insnwidth 16 $(decode16-y), "GEN", $(TARGET_DIR)$@) target/riscv/translate.o: target/riscv/decode_insn32.inc.c \ target/riscv/decode_insn16.inc.c diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b7675707e0..e29879915f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "hw/qdev-properties.h" #include "migration/vmstate.h" /* RISC-V CPU definitions */ @@ -30,17 +31,17 @@ static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG"; const char * const riscv_int_regnames[] = { - "zero", "ra ", "sp ", "gp ", "tp ", "t0 ", "t1 ", "t2 ", - "s0 ", "s1 ", "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", - "a6 ", "a7 ", "s2 ", "s3 ", "s4 ", "s5 ", "s6 ", "s7 ", - "s8 ", "s9 ", "s10 ", "s11 ", "t3 ", "t4 ", "t5 ", "t6 " + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" }; const char * const riscv_fpr_regnames[] = { - "ft0 ", "ft1 ", "ft2 ", "ft3 ", "ft4 ", "ft5 ", "ft6 ", "ft7 ", - "fs0 ", "fs1 ", "fa0 ", "fa1 ", "fa2 ", "fa3 ", "fa4 ", "fa5 ", - "fa6 ", "fa7 ", "fs2 ", "fs3 ", "fs4 ", "fs5 ", "fs6 ", "fs7 ", - "fs8 ", "fs9 ", "fs10", "fs11", "ft8 ", "ft9 ", "ft10", "ft11" + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", + "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" }; const char * const riscv_excp_names[] = { @@ -114,6 +115,12 @@ static void riscv_any_cpu_init(Object *obj) #if defined(TARGET_RISCV32) +static void riscv_base32_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); +} + static void rv32gcsu_priv1_09_1_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -145,6 +152,12 @@ static void rv32imacu_nommu_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) +static void riscv_base64_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); +} + static void rv64gcsu_priv1_09_1_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -296,7 +309,11 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) static void riscv_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + RISCVCPU *cpu = RISCV_CPU(dev); + CPURISCVState *env = &cpu->env; RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); + int priv_version = PRIV_VERSION_1_10_0; + int user_version = USER_VERSION_2_02_0; Error *local_err = NULL; cpu_exec_realizefn(cs, &local_err); @@ -305,6 +322,41 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) return; } + if (cpu->cfg.priv_spec) { + if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { + priv_version = PRIV_VERSION_1_10_0; + } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) { + priv_version = PRIV_VERSION_1_09_1; + } else { + error_setg(errp, + "Unsupported privilege spec version '%s'", + cpu->cfg.priv_spec); + return; + } + } + + if (cpu->cfg.user_spec) { + if (!g_strcmp0(cpu->cfg.user_spec, "v2.02.0")) { + user_version = USER_VERSION_2_02_0; + } else { + error_setg(errp, + "Unsupported user spec version '%s'", + cpu->cfg.user_spec); + return; + } + } + + set_versions(env, user_version, priv_version); + set_resetvec(env, DEFAULT_RSTVEC); + + if (cpu->cfg.mmu) { + set_feature(env, RISCV_FEATURE_MMU); + } + + if (cpu->cfg.pmp) { + set_feature(env, RISCV_FEATURE_PMP); + } + riscv_cpu_register_gdb_regs_for_features(cs); qemu_init_vcpu(cs); @@ -326,6 +378,14 @@ static const VMStateDescription vmstate_riscv_cpu = { .unmigratable = 1, }; +static Property riscv_cpu_properties[] = { + DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), + DEFINE_PROP_STRING("user_spec", RISCVCPU, cfg.user_spec), + DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), + DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), + DEFINE_PROP_END_OF_LIST(), +}; + static void riscv_cpu_class_init(ObjectClass *c, void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); @@ -365,6 +425,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) #endif /* For now, mark unmigratable: */ cc->vmsd = &vmstate_riscv_cpu; + dc->props = riscv_cpu_properties; } char *riscv_isa_string(RISCVCPU *cpu) @@ -430,12 +491,14 @@ static const TypeInfo riscv_cpu_type_infos[] = { }, DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), #if defined(TARGET_RISCV32) + DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init) #elif defined(TARGET_RISCV64) + DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index c17184f4e4..74e726c1c9 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -48,6 +48,8 @@ #define CPU_RESOLVING_TYPE TYPE_RISCV_CPU #define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any") +#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") +#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1") #define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0") #define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu") @@ -224,6 +226,14 @@ typedef struct RISCVCPU { CPUState parent_obj; /*< public >*/ CPURISCVState env; + + /* Configuration Settings */ + struct { + char *priv_spec; + char *user_spec; + bool mmu; + bool pmp; + } cfg; } RISCVCPU; static inline RISCVCPU *riscv_env_get_cpu(CPURISCVState *env) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 7180fccf54..dc9d53d4be 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -202,6 +202,23 @@ #define CSR_DPC 0x7b1 #define CSR_DSCRATCH 0x7b2 +/* Hpervisor CSRs */ +#define CSR_HSTATUS 0xa00 +#define CSR_HEDELEG 0xa02 +#define CSR_HIDELEG 0xa03 +#define CSR_HGATP 0xa80 + +#if defined(TARGET_RISCV32) +#define HGATP_MODE SATP32_MODE +#define HGATP_ASID SATP32_ASID +#define HGATP_PPN SATP32_PPN +#endif +#if defined(TARGET_RISCV64) +#define HGATP_MODE SATP64_MODE +#define HGATP_ASID SATP64_ASID +#define HGATP_PPN SATP64_PPN +#endif + /* Performance Counters */ #define CSR_MHPMCOUNTER3 0xb03 #define CSR_MHPMCOUNTER4 0xb04 @@ -292,9 +309,6 @@ #define CSR_MHPMCOUNTER31H 0xb9f /* Legacy Hypervisor Trap Setup (priv v1.9.1) */ -#define CSR_HSTATUS 0x200 -#define CSR_HEDELEG 0x202 -#define CSR_HIDELEG 0x203 #define CSR_HIE 0x204 #define CSR_HTVEC 0x205 @@ -316,14 +330,11 @@ /* mstatus CSR bits */ #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 -#define MSTATUS_HIE 0x00000004 #define MSTATUS_MIE 0x00000008 #define MSTATUS_UPIE 0x00000010 #define MSTATUS_SPIE 0x00000020 -#define MSTATUS_HPIE 0x00000040 #define MSTATUS_MPIE 0x00000080 #define MSTATUS_SPP 0x00000100 -#define MSTATUS_HPP 0x00000600 #define MSTATUS_MPP 0x00001800 #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 @@ -335,6 +346,8 @@ #define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */ #define MSTATUS_TW 0x20000000 /* since: priv-1.10 */ #define MSTATUS_TSR 0x40000000 /* since: priv-1.10 */ +#define MSTATUS_MTL 0x4000000000ULL +#define MSTATUS_MPV 0x8000000000ULL #define MSTATUS64_UXL 0x0000000300000000ULL #define MSTATUS64_SXL 0x0000000C00000000ULL @@ -380,10 +393,28 @@ #define SSTATUS_SD SSTATUS64_SD #endif +/* hstatus CSR bits */ +#define HSTATUS_SPRV 0x00000001 +#define HSTATUS_STL 0x00000040 +#define HSTATUS_SPV 0x00000080 +#define HSTATUS_SP2P 0x00000100 +#define HSTATUS_SP2V 0x00000200 +#define HSTATUS_VTVM 0x00100000 +#define HSTATUS_VTSR 0x00400000 + +#define HSTATUS32_WPRI 0xFF8FF87E +#define HSTATUS64_WPRI 0xFFFFFFFFFF8FF87EULL + +#if defined(TARGET_RISCV32) +#define HSTATUS_WPRI HSTATUS32_WPRI +#elif defined(TARGET_RISCV64) +#define HSTATUS_WPRI HSTATUS64_WPRI +#endif + /* Privilege modes */ #define PRV_U 0 #define PRV_S 1 -#define PRV_H 2 +#define PRV_H 2 /* Reserved */ #define PRV_M 3 /* RV32 satp CSR field masks */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 41d6db41c3..c577a262b8 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -82,10 +82,31 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) } } -/* iothread_mutex must be held */ +struct CpuAsyncInfo { + uint32_t new_mip; +}; + +static void riscv_cpu_update_mip_irqs_async(CPUState *target_cpu_state, + run_on_cpu_data data) +{ + CPURISCVState *env = &RISCV_CPU(target_cpu_state)->env; + RISCVCPU *cpu = riscv_env_get_cpu(env); + struct CpuAsyncInfo *info = (struct CpuAsyncInfo *) data.host_ptr; + + if (info->new_mip) { + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + } + + g_free(info); +} + uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) { CPURISCVState *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct CpuAsyncInfo *info; uint32_t old, new, cmp = atomic_read(&env->mip); do { @@ -94,11 +115,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) cmp = atomic_cmpxchg(&env->mip, old, new); } while (old != cmp); - if (new) { - cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); - } + info = g_new(struct CpuAsyncInfo, 1); + info->new_mip = new; + + async_run_on_cpu(cs, riscv_cpu_update_mip_irqs_async, + RUN_ON_CPU_HOST_PTR(info)); return old; } @@ -494,7 +515,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) s = set_field(s, MSTATUS_SPP, env->priv); s = set_field(s, MSTATUS_SIE, 0); env->mstatus = s; - env->scause = cause | ~(((target_ulong)-1) >> async); + env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1)); env->sepc = env->pc; env->sbadaddr = tval; env->pc = (env->stvec >> 2 << 2) + diff --git a/target/riscv/csr.c b/target/riscv/csr.c index e1d91b6c60..f9e2910643 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -237,6 +237,7 @@ static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE | static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; +static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; #if defined(TARGET_RISCV32) static const char valid_vm_1_09[16] = { @@ -290,7 +291,6 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) { target_ulong mstatus = env->mstatus; target_ulong mask = 0; - target_ulong mpp = get_field(val, MSTATUS_MPP); /* flush tlb on mstatus fields that affect VM */ if (env->priv_ver <= PRIV_VERSION_1_09_1) { @@ -305,7 +305,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) MSTATUS_VM : 0); } if (env->priv_ver >= PRIV_VERSION_1_10_0) { - if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | + if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV | MSTATUS_MPRV | MSTATUS_SUM)) { tlb_flush(CPU(riscv_env_get_cpu(env))); } @@ -313,13 +313,13 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | MSTATUS_TW; - } - - /* silenty discard mstatus.mpp writes for unsupported modes */ - if (mpp == PRV_H || - (!riscv_has_ext(env, RVS) && mpp == PRV_S) || - (!riscv_has_ext(env, RVU) && mpp == PRV_U)) { - mask &= ~MSTATUS_MPP; +#if defined(TARGET_RISCV64) + /* + * RV32: MPV and MTL are not in mstatus. The current plan is to + * add them to mstatush. For now, we just don't support it. + */ + mask |= MSTATUS_MPP | MSTATUS_MPV; +#endif } mstatus = (mstatus & ~mask) | (val & mask); @@ -555,9 +555,7 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, uint32_t old_mip; if (mask) { - qemu_mutex_lock_iothread(); old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); - qemu_mutex_unlock_iothread(); } else { old_mip = atomic_read(&env->mip); } @@ -685,8 +683,10 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - return rmw_mip(env, CSR_MSTATUS, ret_value, new_value, - write_mask & env->mideleg); + int ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, + write_mask & env->mideleg & sip_writable_mask); + *ret_value &= env->mideleg; + return ret; } /* Supervisor Protection and Translation */ @@ -723,7 +723,9 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { return -1; } else { - tlb_flush(CPU(riscv_env_get_cpu(env))); + if((val ^ env->satp) & SATP_ASID) { + tlb_flush(CPU(riscv_env_get_cpu(env))); + } env->satp = val; } } diff --git a/target/riscv/insn16-32.decode b/target/riscv/insn16-32.decode new file mode 100644 index 0000000000..0819b17028 --- /dev/null +++ b/target/riscv/insn16-32.decode @@ -0,0 +1,28 @@ +# +# RISC-V translation routines for the RVXI Base Integer Instruction Set. +# +# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de +# Bastian Koppelmann, kbastian@mail.uni-paderborn.de +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2 or later, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +# *** RV32C Standard Extension (Quadrant 0) *** +flw 011 ... ... .. ... 00 @cl_w +fsw 111 ... ... .. ... 00 @cs_w + +# *** RV32C Standard Extension (Quadrant 1) *** +jal 001 ........... 01 @cj rd=1 # C.JAL + +# *** RV32C Standard Extension (Quadrant 2) *** +flw 011 . ..... ..... 10 @c_lwsp +fsw 111 . ..... ..... 10 @c_swsp diff --git a/target/riscv/insn16-64.decode b/target/riscv/insn16-64.decode new file mode 100644 index 0000000000..672e1e916f --- /dev/null +++ b/target/riscv/insn16-64.decode @@ -0,0 +1,36 @@ +# +# RISC-V translation routines for the RVXI Base Integer Instruction Set. +# +# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de +# Bastian Koppelmann, kbastian@mail.uni-paderborn.de +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2 or later, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +# *** RV64C Standard Extension (Quadrant 0) *** +ld 011 ... ... .. ... 00 @cl_d +sd 111 ... ... .. ... 00 @cs_d + +# *** RV64C Standard Extension (Quadrant 1) *** +{ + illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0 + addiw 001 . ..... ..... 01 @ci +} +subw 100 1 11 ... 00 ... 01 @cs_2 +addw 100 1 11 ... 01 ... 01 @cs_2 + +# *** RV64C Standard Extension (Quadrant 2) *** +{ + illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 + ld 011 . ..... ..... 10 @c_ldsp +} +sd 111 . ..... ..... 10 @c_sdsp diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index 17cc52cf2a..1cb93876fe 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -30,7 +30,7 @@ %imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1 %imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1 -%nzuimm_6bit 12:1 2:5 +%shimm_6bit 12:1 2:5 !function=ex_rvc_shifti %uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3 %uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2 %uimm_6bit_sd 7:3 10:3 !function=ex_shift_3 @@ -40,90 +40,93 @@ %imm_lui 12:s1 2:5 !function=ex_shift_12 +# Argument sets imported from insn32.decode: +&empty !extern +&r rd rs1 rs2 !extern +&i imm rs1 rd !extern +&s imm rs1 rs2 !extern +&j imm rd !extern +&b imm rs2 rs1 !extern +&u imm rd !extern +&shift shamt rs1 rd !extern -# Argument sets: -&cl rs1 rd -&cl_dw uimm rs1 rd -&ci imm rd -&ciw nzuimm rd -&cs rs1 rs2 -&cs_dw uimm rs1 rs2 -&cb imm rs1 -&cr rd rs2 -&cj imm -&c_shift shamt rd - -&c_ld uimm rd -&c_sd uimm rs2 - -&caddi16sp_lui imm_lui imm_addi16sp rd -&cflwsp_ldsp uimm_flwsp uimm_ldsp rd -&cfswsp_sdsp uimm_fswsp uimm_sdsp rs2 # Formats 16: -@cr .... ..... ..... .. &cr rs2=%rs2_5 %rd -@ci ... . ..... ..... .. &ci imm=%imm_ci %rd -@ciw ... ........ ... .. &ciw nzuimm=%nzuimm_ciw rd=%rs2_3 -@cl_d ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3 -@cl_w ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3 -@cl ... ... ... .. ... .. &cl rs1=%rs1_3 rd=%rs2_3 -@cs ... ... ... .. ... .. &cs rs1=%rs1_3 rs2=%rs2_3 -@cs_2 ... ... ... .. ... .. &cr rd=%rs1_3 rs2=%rs2_3 -@cs_d ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3 -@cs_w ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3 -@cb ... ... ... .. ... .. &cb imm=%imm_cb rs1=%rs1_3 -@cj ... ........... .. &cj imm=%imm_cj - -@c_ld ... . ..... ..... .. &c_ld uimm=%uimm_6bit_ld %rd -@c_lw ... . ..... ..... .. &c_ld uimm=%uimm_6bit_lw %rd -@c_sd ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sd rs2=%rs2_5 -@c_sw ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sw rs2=%rs2_5 - -@c_addi16sp_lui ... . ..... ..... .. &caddi16sp_lui %imm_lui %imm_addi16sp %rd -@c_flwsp_ldsp ... . ..... ..... .. &cflwsp_ldsp uimm_flwsp=%uimm_6bit_lw \ - uimm_ldsp=%uimm_6bit_ld %rd -@c_fswsp_sdsp ... . ..... ..... .. &cfswsp_sdsp uimm_fswsp=%uimm_6bit_sw \ - uimm_sdsp=%uimm_6bit_sd rs2=%rs2_5 - -@c_shift ... . .. ... ..... .. &c_shift rd=%rs1_3 shamt=%nzuimm_6bit -@c_shift2 ... . .. ... ..... .. &c_shift rd=%rd shamt=%nzuimm_6bit - -@c_andi ... . .. ... ..... .. &ci imm=%imm_ci rd=%rs1_3 - -# *** RV64C Standard Extension (Quadrant 0) *** -c_addi4spn 000 ........ ... 00 @ciw -c_fld 001 ... ... .. ... 00 @cl_d -c_lw 010 ... ... .. ... 00 @cl_w -c_flw_ld 011 --- ... -- ... 00 @cl #Note: Must parse uimm manually -c_fsd 101 ... ... .. ... 00 @cs_d -c_sw 110 ... ... .. ... 00 @cs_w -c_fsw_sd 111 --- ... -- ... 00 @cs #Note: Must parse uimm manually - -# *** RV64C Standard Extension (Quadrant 1) *** -c_addi 000 . ..... ..... 01 @ci -c_jal_addiw 001 . ..... ..... 01 @ci #Note: parse rd and/or imm manually -c_li 010 . ..... ..... 01 @ci -c_addi16sp_lui 011 . ..... ..... 01 @c_addi16sp_lui # shares opc with C.LUI -c_srli 100 . 00 ... ..... 01 @c_shift -c_srai 100 . 01 ... ..... 01 @c_shift -c_andi 100 . 10 ... ..... 01 @c_andi -c_sub 100 0 11 ... 00 ... 01 @cs_2 -c_xor 100 0 11 ... 01 ... 01 @cs_2 -c_or 100 0 11 ... 10 ... 01 @cs_2 -c_and 100 0 11 ... 11 ... 01 @cs_2 -c_subw 100 1 11 ... 00 ... 01 @cs_2 -c_addw 100 1 11 ... 01 ... 01 @cs_2 -c_j 101 ........... 01 @cj -c_beqz 110 ... ... ..... 01 @cb -c_bnez 111 ... ... ..... 01 @cb - -# *** RV64C Standard Extension (Quadrant 2) *** -c_slli 000 . ..... ..... 10 @c_shift2 -c_fldsp 001 . ..... ..... 10 @c_ld -c_lwsp 010 . ..... ..... 10 @c_lw -c_flwsp_ldsp 011 . ..... ..... 10 @c_flwsp_ldsp #C.LDSP:RV64;C.FLWSP:RV32 -c_jr_mv 100 0 ..... ..... 10 @cr -c_ebreak_jalr_add 100 1 ..... ..... 10 @cr -c_fsdsp 101 ...... ..... 10 @c_sd -c_swsp 110 . ..... ..... 10 @c_sw -c_fswsp_sdsp 111 . ..... ..... 10 @c_fswsp_sdsp #C.SDSP:RV64;C.FSWSP:RV32 +@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd +@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd +@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3 +@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3 +@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3 +@cs_d ... ... ... .. ... .. &s imm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3 +@cs_w ... ... ... .. ... .. &s imm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3 +@cj ... ........... .. &j imm=%imm_cj +@cb_z ... ... ... .. ... .. &b imm=%imm_cb rs1=%rs1_3 rs2=0 + +@c_ldsp ... . ..... ..... .. &i imm=%uimm_6bit_ld rs1=2 %rd +@c_lwsp ... . ..... ..... .. &i imm=%uimm_6bit_lw rs1=2 %rd +@c_sdsp ... . ..... ..... .. &s imm=%uimm_6bit_sd rs1=2 rs2=%rs2_5 +@c_swsp ... . ..... ..... .. &s imm=%uimm_6bit_sw rs1=2 rs2=%rs2_5 +@c_li ... . ..... ..... .. &i imm=%imm_ci rs1=0 %rd +@c_lui ... . ..... ..... .. &u imm=%imm_lui %rd +@c_jalr ... . ..... ..... .. &i imm=0 rs1=%rd +@c_mv ... . ..... ..... .. &i imm=0 rs1=%rs2_5 %rd + +@c_addi4spn ... . ..... ..... .. &i imm=%nzuimm_ciw rs1=2 rd=%rs2_3 +@c_addi16sp ... . ..... ..... .. &i imm=%imm_addi16sp rs1=2 rd=2 + +@c_shift ... . .. ... ..... .. \ + &shift rd=%rs1_3 rs1=%rs1_3 shamt=%shimm_6bit +@c_shift2 ... . .. ... ..... .. \ + &shift rd=%rd rs1=%rd shamt=%shimm_6bit + +@c_andi ... . .. ... ..... .. &i imm=%imm_ci rs1=%rs1_3 rd=%rs1_3 + +# *** RV32/64C Standard Extension (Quadrant 0) *** +{ + # Opcode of all zeros is illegal; rd != 0, nzuimm == 0 is reserved. + illegal 000 000 000 00 --- 00 + addi 000 ... ... .. ... 00 @c_addi4spn +} +fld 001 ... ... .. ... 00 @cl_d +lw 010 ... ... .. ... 00 @cl_w +fsd 101 ... ... .. ... 00 @cs_d +sw 110 ... ... .. ... 00 @cs_w + +# *** RV32/64C Standard Extension (Quadrant 1) *** +addi 000 . ..... ..... 01 @ci +addi 010 . ..... ..... 01 @c_li +{ + illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0 + addi 011 . 00010 ..... 01 @c_addi16sp + lui 011 . ..... ..... 01 @c_lui +} +srli 100 . 00 ... ..... 01 @c_shift +srai 100 . 01 ... ..... 01 @c_shift +andi 100 . 10 ... ..... 01 @c_andi +sub 100 0 11 ... 00 ... 01 @cs_2 +xor 100 0 11 ... 01 ... 01 @cs_2 +or 100 0 11 ... 10 ... 01 @cs_2 +and 100 0 11 ... 11 ... 01 @cs_2 +jal 101 ........... 01 @cj rd=0 # C.J +beq 110 ... ... ..... 01 @cb_z +bne 111 ... ... ..... 01 @cb_z + +# *** RV32/64C Standard Extension (Quadrant 2) *** +slli 000 . ..... ..... 10 @c_shift2 +fld 001 . ..... ..... 10 @c_ldsp +{ + illegal 010 - 00000 ----- 10 # c.lwsp, RES rd=0 + lw 010 . ..... ..... 10 @c_lwsp +} +{ + illegal 100 0 00000 00000 10 # c.jr, RES rs1=0 + jalr 100 0 ..... 00000 10 @c_jalr rd=0 # C.JR + addi 100 0 ..... ..... 10 @c_mv +} +{ + ebreak 100 1 00000 00000 10 + jalr 100 1 ..... 00000 10 @c_jalr rd=1 # C.JALR + add 100 1 ..... ..... 10 @cr +} +fsd 101 ...... ..... 10 @c_sdsp +sw 110 . ..... ..... 10 @c_swsp diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 6f3ab7aa52..77f794ed70 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -34,9 +34,13 @@ %imm_u 12:s20 !function=ex_shift_12 # Argument sets: +&empty &b imm rs2 rs1 &i imm rs1 rd +&j imm rd &r rd rs1 rs2 +&s imm rs1 rs2 +&u imm rd &shift shamt rs1 rd &atomic aq rl rs2 rs1 rd @@ -44,9 +48,9 @@ @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd @i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd @b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1 -@s ....... ..... ..... ... ..... ....... imm=%imm_s %rs2 %rs1 -@u .................... ..... ....... imm=%imm_u %rd -@j .................... ..... ....... imm=%imm_j %rd +@s ....... ..... ..... ... ..... ....... &s imm=%imm_s %rs2 %rs1 +@u .................... ..... ....... &u imm=%imm_u %rd +@j .................... ..... ....... &j imm=%imm_j %rd @sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd @csr ............ ..... ... ..... ....... %csr %rs1 %rd diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c index acb605923e..664d6ba3f2 100644 --- a/target/riscv/insn_trans/trans_privileged.inc.c +++ b/target/riscv/insn_trans/trans_privileged.inc.c @@ -22,7 +22,7 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a) { /* always generates U-level ECALL, fixed in do_interrupt handler */ generate_exception(ctx, RISCV_EXCP_U_ECALL); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ + exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; } @@ -30,7 +30,7 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a) static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) { generate_exception(ctx, RISCV_EXCP_BREAKPOINT); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ + exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; } @@ -47,7 +47,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) if (has_ext(ctx, RVS)) { gen_helper_sret(cpu_pc, cpu_env, cpu_pc); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ + exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; } else { return false; @@ -68,7 +68,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a) #ifndef CONFIG_USER_ONLY tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); gen_helper_mret(cpu_pc, cpu_env, cpu_pc); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ + exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; #else diff --git a/target/riscv/insn_trans/trans_rvc.inc.c b/target/riscv/insn_trans/trans_rvc.inc.c deleted file mode 100644 index 3e5d6fd5ea..0000000000 --- a/target/riscv/insn_trans/trans_rvc.inc.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * RISC-V translation routines for the RVC Compressed Instruction Set. - * - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu - * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de - * Bastian Koppelmann, kbastian@mail.uni-paderborn.de - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -static bool trans_c_addi4spn(DisasContext *ctx, arg_c_addi4spn *a) -{ - if (a->nzuimm == 0) { - /* Reserved in ISA */ - return false; - } - arg_addi arg = { .rd = a->rd, .rs1 = 2, .imm = a->nzuimm }; - return trans_addi(ctx, &arg); -} - -static bool trans_c_fld(DisasContext *ctx, arg_c_fld *a) -{ - arg_fld arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm }; - return trans_fld(ctx, &arg); -} - -static bool trans_c_lw(DisasContext *ctx, arg_c_lw *a) -{ - arg_lw arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm }; - return trans_lw(ctx, &arg); -} - -static bool trans_c_flw_ld(DisasContext *ctx, arg_c_flw_ld *a) -{ -#ifdef TARGET_RISCV32 - /* C.FLW ( RV32FC-only ) */ - REQUIRE_FPU; - REQUIRE_EXT(ctx, RVF); - - arg_c_lw tmp; - decode_insn16_extract_cl_w(ctx, &tmp, ctx->opcode); - arg_flw arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm }; - return trans_flw(ctx, &arg); -#else - /* C.LD ( RV64C/RV128C-only ) */ - arg_c_fld tmp; - decode_insn16_extract_cl_d(ctx, &tmp, ctx->opcode); - arg_ld arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm }; - return trans_ld(ctx, &arg); -#endif -} - -static bool trans_c_fsd(DisasContext *ctx, arg_c_fsd *a) -{ - arg_fsd arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm }; - return trans_fsd(ctx, &arg); -} - -static bool trans_c_sw(DisasContext *ctx, arg_c_sw *a) -{ - arg_sw arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm }; - return trans_sw(ctx, &arg); -} - -static bool trans_c_fsw_sd(DisasContext *ctx, arg_c_fsw_sd *a) -{ -#ifdef TARGET_RISCV32 - /* C.FSW ( RV32FC-only ) */ - REQUIRE_FPU; - REQUIRE_EXT(ctx, RVF); - - arg_c_sw tmp; - decode_insn16_extract_cs_w(ctx, &tmp, ctx->opcode); - arg_fsw arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm }; - return trans_fsw(ctx, &arg); -#else - /* C.SD ( RV64C/RV128C-only ) */ - arg_c_fsd tmp; - decode_insn16_extract_cs_d(ctx, &tmp, ctx->opcode); - arg_sd arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm }; - return trans_sd(ctx, &arg); -#endif -} - -static bool trans_c_addi(DisasContext *ctx, arg_c_addi *a) -{ - if (a->imm == 0) { - /* Hint: insn is valid but does not affect state */ - return true; - } - arg_addi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm }; - return trans_addi(ctx, &arg); -} - -static bool trans_c_jal_addiw(DisasContext *ctx, arg_c_jal_addiw *a) -{ -#ifdef TARGET_RISCV32 - /* C.JAL */ - arg_c_j tmp; - decode_insn16_extract_cj(ctx, &tmp, ctx->opcode); - arg_jal arg = { .rd = 1, .imm = tmp.imm }; - return trans_jal(ctx, &arg); -#else - /* C.ADDIW */ - arg_addiw arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm }; - return trans_addiw(ctx, &arg); -#endif -} - -static bool trans_c_li(DisasContext *ctx, arg_c_li *a) -{ - if (a->rd == 0) { - /* Hint: insn is valid but does not affect state */ - return true; - } - arg_addi arg = { .rd = a->rd, .rs1 = 0, .imm = a->imm }; - return trans_addi(ctx, &arg); -} - -static bool trans_c_addi16sp_lui(DisasContext *ctx, arg_c_addi16sp_lui *a) -{ - if (a->rd == 2) { - /* C.ADDI16SP */ - arg_addi arg = { .rd = 2, .rs1 = 2, .imm = a->imm_addi16sp }; - return trans_addi(ctx, &arg); - } else if (a->imm_lui != 0) { - /* C.LUI */ - if (a->rd == 0) { - /* Hint: insn is valid but does not affect state */ - return true; - } - arg_lui arg = { .rd = a->rd, .imm = a->imm_lui }; - return trans_lui(ctx, &arg); - } - return false; -} - -static bool trans_c_srli(DisasContext *ctx, arg_c_srli *a) -{ - int shamt = a->shamt; - if (shamt == 0) { - /* For RV128 a shamt of 0 means a shift by 64 */ - shamt = 64; - } - /* Ensure, that shamt[5] is zero for RV32 */ - if (shamt >= TARGET_LONG_BITS) { - return false; - } - - arg_srli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt }; - return trans_srli(ctx, &arg); -} - -static bool trans_c_srai(DisasContext *ctx, arg_c_srai *a) -{ - int shamt = a->shamt; - if (shamt == 0) { - /* For RV128 a shamt of 0 means a shift by 64 */ - shamt = 64; - } - /* Ensure, that shamt[5] is zero for RV32 */ - if (shamt >= TARGET_LONG_BITS) { - return false; - } - - arg_srai arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt }; - return trans_srai(ctx, &arg); -} - -static bool trans_c_andi(DisasContext *ctx, arg_c_andi *a) -{ - arg_andi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm }; - return trans_andi(ctx, &arg); -} - -static bool trans_c_sub(DisasContext *ctx, arg_c_sub *a) -{ - arg_sub arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_sub(ctx, &arg); -} - -static bool trans_c_xor(DisasContext *ctx, arg_c_xor *a) -{ - arg_xor arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_xor(ctx, &arg); -} - -static bool trans_c_or(DisasContext *ctx, arg_c_or *a) -{ - arg_or arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_or(ctx, &arg); -} - -static bool trans_c_and(DisasContext *ctx, arg_c_and *a) -{ - arg_and arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_and(ctx, &arg); -} - -static bool trans_c_subw(DisasContext *ctx, arg_c_subw *a) -{ -#ifdef TARGET_RISCV64 - arg_subw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_subw(ctx, &arg); -#else - return false; -#endif -} - -static bool trans_c_addw(DisasContext *ctx, arg_c_addw *a) -{ -#ifdef TARGET_RISCV64 - arg_addw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_addw(ctx, &arg); -#else - return false; -#endif -} - -static bool trans_c_j(DisasContext *ctx, arg_c_j *a) -{ - arg_jal arg = { .rd = 0, .imm = a->imm }; - return trans_jal(ctx, &arg); -} - -static bool trans_c_beqz(DisasContext *ctx, arg_c_beqz *a) -{ - arg_beq arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm }; - return trans_beq(ctx, &arg); -} - -static bool trans_c_bnez(DisasContext *ctx, arg_c_bnez *a) -{ - arg_bne arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm }; - return trans_bne(ctx, &arg); -} - -static bool trans_c_slli(DisasContext *ctx, arg_c_slli *a) -{ - int shamt = a->shamt; - if (shamt == 0) { - /* For RV128 a shamt of 0 means a shift by 64 */ - shamt = 64; - } - /* Ensure, that shamt[5] is zero for RV32 */ - if (shamt >= TARGET_LONG_BITS) { - return false; - } - - arg_slli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt }; - return trans_slli(ctx, &arg); -} - -static bool trans_c_fldsp(DisasContext *ctx, arg_c_fldsp *a) -{ - arg_fld arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm }; - return trans_fld(ctx, &arg); -} - -static bool trans_c_lwsp(DisasContext *ctx, arg_c_lwsp *a) -{ - arg_lw arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm }; - return trans_lw(ctx, &arg); -} - -static bool trans_c_flwsp_ldsp(DisasContext *ctx, arg_c_flwsp_ldsp *a) -{ -#ifdef TARGET_RISCV32 - /* C.FLWSP */ - arg_flw arg_flw = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_flwsp }; - return trans_flw(ctx, &arg_flw); -#else - /* C.LDSP */ - arg_ld arg_ld = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_ldsp }; - return trans_ld(ctx, &arg_ld); -#endif - return false; -} - -static bool trans_c_jr_mv(DisasContext *ctx, arg_c_jr_mv *a) -{ - if (a->rd != 0 && a->rs2 == 0) { - /* C.JR */ - arg_jalr arg = { .rd = 0, .rs1 = a->rd, .imm = 0 }; - return trans_jalr(ctx, &arg); - } else if (a->rd != 0 && a->rs2 != 0) { - /* C.MV */ - arg_add arg = { .rd = a->rd, .rs1 = 0, .rs2 = a->rs2 }; - return trans_add(ctx, &arg); - } - return false; -} - -static bool trans_c_ebreak_jalr_add(DisasContext *ctx, arg_c_ebreak_jalr_add *a) -{ - if (a->rd == 0 && a->rs2 == 0) { - /* C.EBREAK */ - arg_ebreak arg = { }; - return trans_ebreak(ctx, &arg); - } else if (a->rd != 0) { - if (a->rs2 == 0) { - /* C.JALR */ - arg_jalr arg = { .rd = 1, .rs1 = a->rd, .imm = 0 }; - return trans_jalr(ctx, &arg); - } else { - /* C.ADD */ - arg_add arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; - return trans_add(ctx, &arg); - } - } - return false; -} - -static bool trans_c_fsdsp(DisasContext *ctx, arg_c_fsdsp *a) -{ - arg_fsd arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm }; - return trans_fsd(ctx, &arg); -} - -static bool trans_c_swsp(DisasContext *ctx, arg_c_swsp *a) -{ - arg_sw arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm }; - return trans_sw(ctx, &arg); -} - -static bool trans_c_fswsp_sdsp(DisasContext *ctx, arg_c_fswsp_sdsp *a) -{ -#ifdef TARGET_RISCV32 - /* C.FSWSP */ - arg_fsw a_fsw = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_fswsp }; - return trans_fsw(ctx, &a_fsw); -#else - /* C.SDSP */ - arg_sd a_sd = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_sdsp }; - return trans_sd(ctx, &a_sd); -#endif -} diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c index d420a4d8b2..6cda078ed6 100644 --- a/target/riscv/insn_trans/trans_rvi.inc.c +++ b/target/riscv/insn_trans/trans_rvi.inc.c @@ -18,6 +18,12 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +static bool trans_illegal(DisasContext *ctx, arg_empty *a) +{ + gen_exception_illegal(ctx); + return true; +} + static bool trans_lui(DisasContext *ctx, arg_lui *a) { if (a->rd != 0) { @@ -60,7 +66,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a) if (a->rd != 0) { tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn); } - tcg_gen_lookup_and_goto_ptr(); + lookup_and_goto_ptr(ctx); if (misaligned) { gen_set_label(misaligned); @@ -217,7 +223,7 @@ static bool trans_sd(DisasContext *ctx, arg_sd *a) static bool trans_addi(DisasContext *ctx, arg_addi *a) { - return gen_arith_imm(ctx, a, &tcg_gen_add_tl); + return gen_arith_imm_fn(ctx, a, &tcg_gen_addi_tl); } static void gen_slt(TCGv ret, TCGv s1, TCGv s2) @@ -233,25 +239,25 @@ static void gen_sltu(TCGv ret, TCGv s1, TCGv s2) static bool trans_slti(DisasContext *ctx, arg_slti *a) { - return gen_arith_imm(ctx, a, &gen_slt); + return gen_arith_imm_tl(ctx, a, &gen_slt); } static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a) { - return gen_arith_imm(ctx, a, &gen_sltu); + return gen_arith_imm_tl(ctx, a, &gen_sltu); } static bool trans_xori(DisasContext *ctx, arg_xori *a) { - return gen_arith_imm(ctx, a, &tcg_gen_xor_tl); + return gen_arith_imm_fn(ctx, a, &tcg_gen_xori_tl); } static bool trans_ori(DisasContext *ctx, arg_ori *a) { - return gen_arith_imm(ctx, a, &tcg_gen_or_tl); + return gen_arith_imm_fn(ctx, a, &tcg_gen_ori_tl); } static bool trans_andi(DisasContext *ctx, arg_andi *a) { - return gen_arith_imm(ctx, a, &tcg_gen_and_tl); + return gen_arith_imm_fn(ctx, a, &tcg_gen_andi_tl); } static bool trans_slli(DisasContext *ctx, arg_slli *a) { @@ -358,7 +364,7 @@ static bool trans_and(DisasContext *ctx, arg_and *a) #ifdef TARGET_RISCV64 static bool trans_addiw(DisasContext *ctx, arg_addiw *a) { - return gen_arith_imm(ctx, a, &gen_addw); + return gen_arith_imm_tl(ctx, a, &gen_addw); } static bool trans_slliw(DisasContext *ctx, arg_slliw *a) @@ -483,7 +489,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) * however we need to end the translation block */ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); - tcg_gen_exit_tb(NULL, 0); + exit_tb(ctx); ctx->base.is_jmp = DISAS_NORETURN; return true; } @@ -504,7 +510,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) gen_io_end(); \ gen_set_gpr(a->rd, dest); \ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \ - tcg_gen_exit_tb(NULL, 0); \ + exit_tb(ctx); \ ctx->base.is_jmp = DISAS_NORETURN; \ tcg_temp_free(source1); \ tcg_temp_free(csr_store); \ diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index b7dc18a41e..644d0fb35f 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -145,9 +145,10 @@ void helper_tlb_flush(CPURISCVState *env) { RISCVCPU *cpu = riscv_env_get_cpu(env); CPUState *cs = CPU(cpu); - if (env->priv == PRV_S && - env->priv_ver >= PRIV_VERSION_1_10_0 && - get_field(env->mstatus, MSTATUS_TVM)) { + if (!(env->priv >= PRV_S) || + (env->priv == PRV_S && + env->priv_ver >= PRIV_VERSION_1_10_0 && + get_field(env->mstatus, MSTATUS_TVM))) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } else { tlb_flush(cs); diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 2ff6b49487..313c27b700 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -109,6 +109,26 @@ static void gen_exception_debug(void) tcg_temp_free_i32(helper_tmp); } +/* Wrapper around tcg_gen_exit_tb that handles single stepping */ +static void exit_tb(DisasContext *ctx) +{ + if (ctx->base.singlestep_enabled) { + gen_exception_debug(); + } else { + tcg_gen_exit_tb(NULL, 0); + } +} + +/* Wrapper around tcg_gen_lookup_and_goto_ptr that handles single stepping */ +static void lookup_and_goto_ptr(DisasContext *ctx) +{ + if (ctx->base.singlestep_enabled) { + gen_exception_debug(); + } else { + tcg_gen_lookup_and_goto_ptr(); + } +} + static void gen_exception_illegal(DisasContext *ctx) { generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); @@ -138,14 +158,14 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) /* chaining is only allowed when the jump is to the same page */ tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_pc, dest); + + /* No need to check for single stepping here as use_goto_tb() will + * return false in case of single stepping. + */ tcg_gen_exit_tb(ctx->base.tb, n); } else { tcg_gen_movi_tl(cpu_pc, dest); - if (ctx->base.singlestep_enabled) { - gen_exception_debug(); - } else { - tcg_gen_lookup_and_goto_ptr(); - } + lookup_and_goto_ptr(ctx); } } @@ -538,12 +558,32 @@ static int ex_rvc_register(DisasContext *ctx, int reg) return 8 + reg; } -bool decode_insn32(DisasContext *ctx, uint32_t insn); +static int ex_rvc_shifti(DisasContext *ctx, int imm) +{ + /* For RV128 a shamt of 0 means a shift by 64. */ + return imm ? imm : 64; +} + /* Include the auto-generated decoder for 32 bit insn */ #include "decode_insn32.inc.c" -static bool gen_arith_imm(DisasContext *ctx, arg_i *a, - void(*func)(TCGv, TCGv, TCGv)) +static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, + void (*func)(TCGv, TCGv, target_long)) +{ + TCGv source1; + source1 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + + (*func)(source1, source1, a->imm); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + return true; +} + +static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, + void (*func)(TCGv, TCGv, TCGv)) { TCGv source1, source2; source1 = tcg_temp_new(); @@ -667,10 +707,25 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, #include "insn_trans/trans_rvd.inc.c" #include "insn_trans/trans_privileged.inc.c" -bool decode_insn16(DisasContext *ctx, uint16_t insn); -/* auto-generated decoder*/ +/* + * Auto-generated decoder. + * Note that the 16-bit decoder reuses some of the trans_* functions + * initially declared by the 32-bit decoder, which results in duplicate + * declaration warnings. Suppress them. + */ +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wredundant-decls" +# ifdef __clang__ +# pragma GCC diagnostic ignored "-Wtypedef-redefinition" +# endif +#endif + #include "decode_insn16.inc.c" -#include "insn_trans/trans_rvc.inc.c" + +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif static void decode_opc(DisasContext *ctx) { diff --git a/tests/acceptance/linux_ssh_mips_malta.py b/tests/acceptance/linux_ssh_mips_malta.py new file mode 100644 index 0000000000..aafb0c39f6 --- /dev/null +++ b/tests/acceptance/linux_ssh_mips_malta.py @@ -0,0 +1,230 @@ +# Functional test that boots a VM and run commands via a SSH session +# +# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org> +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os +import re +import base64 +import logging +import paramiko +import time + +from avocado import skipIf +from avocado_qemu import Test +from avocado.utils import process +from avocado.utils import archive + + +class LinuxSSH(Test): + + timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg' + + KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' + VM_IP = '127.0.0.1' + + IMAGE_INFO = { + 'be': { + 'image_url': 'https://people.debian.org/~aurel32/qemu/mips/' + 'debian_wheezy_mips_standard.qcow2', + 'image_hash': '8987a63270df67345b2135a6b7a4885a35e392d5', + 'rsa_hostkey': b'AAAAB3NzaC1yc2EAAAADAQABAAABAQCca1VitiyLAdQOld' + b'zT43IOEVJZ0wHD78GJi8wDAjMiYWUzNSSn0rXGQsINHuH5' + b'IlF+kBZsHinb/FtKCAyS9a8uCHhQI4SuB4QhAb0+39MlUw' + b'Mm0CLkctgM2eUUZ6MQMQvDlqnue6CCkxN62EZYbaxmby7j' + b'CQa1125o1HRKBvdGm2zrJWxXAfA+f1v6jHLyE8Jnu83eQ+' + b'BFY25G+Vzx1PVc3zQBwJ8r0NGTRqy2//oWQP0h+bMsgeFe' + b'KH/J3RJM22vg6+I4JAdBFcxnK+l781h1FuRxOn4O/Xslbg' + b'go6WtB4V4TOsw2E/KfxI5IZ/icxF+swVcnvF46Hf3uQc/0' + b'BBqb', + }, + 'le': { + 'image_url': 'https://people.debian.org/~aurel32/qemu/mipsel/' + 'debian_wheezy_mipsel_standard.qcow2', + 'image_hash': '7866764d9de3ef536ffca24c9fb9f04ffdb45802', + 'rsa_hostkey': b'AAAAB3NzaC1yc2EAAAADAQABAAABAQClXJlBT71HL5yKvv' + b'gfC7jmxSWx5zSBCzET6CLZczwAafSIs7YKfNOy/dQTxhuk' + b'yIGFUugZFoF3E9PzdhunuyvyTd56MPoNIqFbb5rGokwU5I' + b'TOx3dBHZR0mClypL6MVrwe0bsiIb8GhF1zioNwcsaAZnAi' + b'KfXStVDtXvn/kLLq+xLABYt48CC5KYWoFaCoICskLAY+qo' + b'L+LWyAnQisj4jAH8VSaSKIImFpfkHWEXPhHcC4ZBlDKtnH' + b'po9vhfCHgnfW3Pzrqmk8BI4HysqPFVmJWkJGlGUL+sGeg3' + b'ZZolAYuDXGuBrw8ooPJq2v2dOH+z6dyD2q/ypmAbyPqj5C' + b'rc8H', + }, + } + + def wait_for_console_pattern(self, success_message, + failure_message='Oops'): + console = self.vm.console_socket.makefile() + console_logger = logging.getLogger('console') + while True: + msg = console.readline() + console_logger.debug(msg.strip()) + if success_message in msg: + break + if failure_message in msg: + fail = 'Failure message found in console: %s' % failure_message + self.fail(fail) + + def get_portfwd(self): + res = self.vm.command('human-monitor-command', + command_line='info usernet') + line = res.split('\r\n')[2] + port = re.split(r'.*TCP.HOST_FORWARD.*127\.0\.0\.1 (\d+)\s+10\..*', + line)[1] + self.log.debug("sshd listening on port:" + port) + return port + + def ssh_connect(self, username, password, rsa_hostkey_b64=None): + self.ssh_logger = logging.getLogger('ssh') + self.ssh_username = username + self.ssh_ps1 = '# ' if username is 'root' else '$ ' + self.ssh_client = paramiko.SSHClient() + port = self.get_portfwd() + if rsa_hostkey_b64: + rsa_hostkey_bin = base64.b64decode(rsa_hostkey_b64) + rsa_hostkey = paramiko.RSAKey(data = rsa_hostkey_bin) + ipport = '[%s]:%s' % (self.VM_IP, port) + self.ssh_logger.debug('ipport ' + ipport) + self.ssh_client.get_host_keys().add(ipport, 'ssh-rsa', rsa_hostkey) + for i in range(10): + try: + self.ssh_client.connect(self.VM_IP, int(port), + username, password, banner_timeout=90) + self.ssh_logger.info("Entering interactive session.") + return + except: + time.sleep(4) + pass + self.fail("sshd timeout") + + def ssh_disconnect_vm(self): + self.ssh_client.close() + + def ssh_command(self, command, is_root=True): + self.ssh_logger.info(self.ssh_ps1 + command) + stdin, stdout, stderr = self.ssh_client.exec_command(command) + stdout_lines = [line.strip('\n') for line in stdout] + for line in stdout_lines: + self.ssh_logger.info(line) + stderr_lines = [line.strip('\n') for line in stderr] + for line in stderr_lines: + self.ssh_logger.warning(line) + return stdout_lines, stderr_lines + + def boot_debian_wheezy_image_and_ssh_login(self, endianess, kernel_path): + image_url = self.IMAGE_INFO[endianess]['image_url'] + image_hash = self.IMAGE_INFO[endianess]['image_hash'] + image_path = self.fetch_asset(image_url, asset_hash=image_hash) + rsa_hostkey_b64 = self.IMAGE_INFO[endianess]['rsa_hostkey'] + + self.vm.set_machine('malta') + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 root=/dev/sda1') + self.vm.add_args('-no-reboot', + '-kernel', kernel_path, + '-append', kernel_command_line, + '-hda', image_path, + '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', + '-device', 'pcnet,netdev=vnet') + self.vm.launch() + + self.log.info('VM launched, waiting for sshd') + console_pattern = 'Starting OpenBSD Secure Shell server: sshd' + self.wait_for_console_pattern(console_pattern) + self.log.info('sshd ready') + + self.ssh_connect('root', 'root', rsa_hostkey_b64=rsa_hostkey_b64) + + def shutdown_via_ssh(self): + self.ssh_command('poweroff') + self.ssh_disconnect_vm() + self.wait_for_console_pattern('Power down') + + def run_common_commands(self): + stdout, stderr = self.ssh_command('lspci -d 11ab:4620') + self.assertIn(True, ["GT-64120" in line for line in stdout]) + + stdout, stderr = self.ssh_command('cat /sys/bus/i2c/devices/i2c-0/name') + self.assertIn(True, ["SMBus PIIX4 adapter" in line + for line in stdout]) + + stdout, stderr = self.ssh_command('cat /proc/mtd') + self.assertIn(True, ["YAMON" in line + for line in stdout]) + + # Empty 'Board Config' + stdout, stderr = self.ssh_command('md5sum /dev/mtd2ro') + self.assertIn(True, ["0dfbe8aa4c20b52e1b8bf3cb6cbdf193" in line + for line in stdout]) + + def do_test_mips_malta(self, endianess, kernel_path, uname_m): + self.boot_debian_wheezy_image_and_ssh_login(endianess, kernel_path) + + stdout, stderr = self.ssh_command('uname -a') + self.assertIn(True, [uname_m + " GNU/Linux" in line for line in stdout]) + + self.run_common_commands() + self.shutdown_via_ssh() + + @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') + def test_mips_malta32eb_kernel3_2_0(self): + """ + :avocado: tags=arch:mips + :avocado: tags=machine:malta + :avocado: tags=endian:big + :avocado: tags=device:pcnet32 + """ + kernel_url = ('https://people.debian.org/~aurel32/qemu/mips/' + 'vmlinux-3.2.0-4-4kc-malta') + kernel_hash = '592e384a4edc16dade52a6cd5c785c637bcbc9ad' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.do_test_mips_malta('be', kernel_path, 'mips') + + @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') + def test_mips_malta32el_kernel3_2_0(self): + """ + :avocado: tags=arch:mipsel + :avocado: tags=machine:malta + :avocado: tags=endian:little + :avocado: tags=device:pcnet32 + """ + kernel_url = ('https://people.debian.org/~aurel32/qemu/mipsel/' + 'vmlinux-3.2.0-4-4kc-malta') + kernel_hash = 'a66bea5a8adaa2cb3d36a1d4e0ccdb01be8f6c2a' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.do_test_mips_malta('le', kernel_path, 'mips') + + @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') + def test_mips_malta64eb_kernel3_2_0(self): + """ + :avocado: tags=arch:mips64 + :avocado: tags=machine:malta + :avocado: tags=endian:big + :avocado: tags=device:pcnet32 + """ + kernel_url = ('https://people.debian.org/~aurel32/qemu/mips/' + 'vmlinux-3.2.0-4-5kc-malta') + kernel_hash = 'db6eea7de35d36c77d8c165b6bcb222e16eb91db' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + self.do_test_mips_malta('be', kernel_path, 'mips64') + + @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') + def test_mips_malta64el_kernel3_2_0(self): + """ + :avocado: tags=arch:mips64el + :avocado: tags=machine:malta + :avocado: tags=endian:little + :avocado: tags=device:pcnet32 + """ + kernel_url = ('https://people.debian.org/~aurel32/qemu/mipsel/' + 'vmlinux-3.2.0-4-5kc-malta') + kernel_hash = '6a7f77245acf231415a0e8b725d91ed2f3487794' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + self.do_test_mips_malta('le', kernel_path, 'mips64') diff --git a/tests/requirements.txt b/tests/requirements.txt index 002ded6a22..3ae0e29ad7 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,3 +2,4 @@ # in the tests/venv Python virtual environment. For more info, # refer to: https://pip.pypa.io/en/stable/user_guide/#id1 avocado-framework==68.0 +paramiko |