Merge remote-tracking branch 'remotes/vivier2/tags/trivial-branch-for-6.1-pull-request' into staging
Trivial patches pull request 20210503
# gpg: Signature made Mon 03 May 2021 09:34:56 BST
# gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg: issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg: aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C
* remotes/vivier2/tags/trivial-branch-for-6.1-pull-request: (23 commits)
hw/rx/rx-gdbsim: Do not accept invalid memory size
docs: More precisely describe memory-backend-*::id's user
scripts: fix generation update-binfmts templates
docs/system: Document the removal of "compat" property for POWER CPUs
mc146818rtc: put it into the 'misc' category
Do not include exec/address-spaces.h if it's not really necessary
Do not include cpu.h if it's not really necessary
Do not include hw/boards.h if it's not really necessary
Do not include sysemu/sysemu.h if it's not really necessary
hw: Do not include qemu/log.h if it is not necessary
hw: Do not include hw/irq.h if it is not necessary
hw: Do not include hw/sysbus.h if it is not necessary
hw: Remove superfluous includes of hw/hw.h
ui: Fix memory leak in qemu_xkeymap_mapping_table()
hw/usb: Constify VMStateDescription
hw/display/qxl: Constify VMStateDescription
hw/arm: Constify VMStateDescription
vmstate: Constify some VMStateDescriptions
Fix typo in CFI build documentation
hw/pcmcia: Do not register PCMCIA type if not required
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml
index 2d95784..e44e4b4 100644
--- a/.gitlab-ci.d/crossbuilds.yml
+++ b/.gitlab-ci.d/crossbuilds.yml
@@ -176,6 +176,14 @@
IMAGE: debian-s390x-cross
ACCEL_CONFIGURE_OPTS: --disable-tcg
+cross-mips64el-kvm-only:
+ extends: .cross_accel_build_job
+ needs:
+ job: mips64el-debian-cross-container
+ variables:
+ IMAGE: debian-mips64el-cross
+ ACCEL_CONFIGURE_OPTS: --disable-tcg --target-list=mips64el-softmmu
+
cross-win32-system:
extends: .cross_system_build_job
needs:
diff --git a/MAINTAINERS b/MAINTAINERS
index 4c05ff8..6c5b569 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -404,7 +404,8 @@
MIPS KVM CPUs
M: Huacai Chen <chenhuacai@kernel.org>
S: Odd Fixes
-F: target/mips/kvm.c
+F: target/mips/kvm*
+F: target/mips/sysemu/
PPC KVM CPUs
M: David Gibson <david@gibson.dropbear.id.au>
@@ -1026,6 +1027,7 @@
F: hw/net/ftgmac100.c
F: include/hw/net/ftgmac100.h
F: docs/system/arm/aspeed.rst
+F: tests/qtest/*aspeed*
NRF51
M: Joel Stanley <joel@jms.id.au>
diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index f38c4fa..e1ed3b7 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -13,22 +13,23 @@
void *host_ptr;
host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
- if (!host_ptr)
+ if (!host_ptr) {
return -TARGET_EFAULT;
+ }
memcpy(host_ptr, src, len);
unlock_user(host_ptr, dest, 1);
return 0;
}
-static int count(char ** vec)
+static int count(char **vec)
{
int i;
- for(i = 0; *vec; i++) {
+ for (i = 0; *vec; i++) {
vec++;
}
- return(i);
+ return i;
}
static int prepare_binprm(struct linux_binprm *bprm)
@@ -37,23 +38,23 @@
int mode;
int retval;
- if(fstat(bprm->fd, &st) < 0) {
- return(-errno);
+ if (fstat(bprm->fd, &st) < 0) {
+ return -errno;
}
mode = st.st_mode;
- if(!S_ISREG(mode)) { /* Must be regular file */
- return(-EACCES);
+ if (!S_ISREG(mode)) { /* Must be regular file */
+ return -EACCES;
}
- if(!(mode & 0111)) { /* Must have at least one execute bit set */
- return(-EACCES);
+ if (!(mode & 0111)) { /* Must have at least one execute bit set */
+ return -EACCES;
}
bprm->e_uid = geteuid();
bprm->e_gid = getegid();
/* Set-uid? */
- if(mode & S_ISUID) {
+ if (mode & S_ISUID) {
bprm->e_uid = st.st_uid;
}
@@ -69,16 +70,14 @@
memset(bprm->buf, 0, sizeof(bprm->buf));
retval = lseek(bprm->fd, 0L, SEEK_SET);
- if(retval >= 0) {
+ if (retval >= 0) {
retval = read(bprm->fd, bprm->buf, 128);
}
- if(retval < 0) {
+ if (retval < 0) {
perror("prepare_binprm");
exit(-1);
- /* return(-errno); */
- }
- else {
- return(retval);
+ } else {
+ return retval;
}
}
@@ -125,19 +124,21 @@
return sp;
}
-int loader_exec(const char * filename, char ** argv, char ** envp,
- struct target_pt_regs * regs, struct image_info *infop)
+int loader_exec(const char *filename, char **argv, char **envp,
+ struct target_pt_regs *regs, struct image_info *infop)
{
struct linux_binprm bprm;
int retval;
int i;
- bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
+ bprm.p = TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(unsigned int);
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) { /* clear page-table */
bprm.page[i] = NULL;
+ }
retval = open(filename, O_RDONLY);
- if (retval < 0)
+ if (retval < 0) {
return retval;
+ }
bprm.fd = retval;
bprm.filename = (char *)filename;
bprm.argc = count(argv);
@@ -147,27 +148,27 @@
retval = prepare_binprm(&bprm);
- if(retval>=0) {
+ if (retval >= 0) {
if (bprm.buf[0] == 0x7f
&& bprm.buf[1] == 'E'
&& bprm.buf[2] == 'L'
&& bprm.buf[3] == 'F') {
- retval = load_elf_binary(&bprm,regs,infop);
+ retval = load_elf_binary(&bprm, regs, infop);
} else {
fprintf(stderr, "Unknown binary format\n");
return -1;
}
}
- if(retval>=0) {
+ if (retval >= 0) {
/* success. Initialize important registers */
do_init_thread(regs, infop);
return retval;
}
/* Something went wrong, return the inode and free the argument pages*/
- for (i=0 ; i<MAX_ARG_PAGES ; i++) {
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
g_free(bprm.page[i]);
}
- return(retval);
+ return retval;
}
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index d2bcaab..b836b60 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -233,7 +233,7 @@
#define __put_user(x, hptr)\
({\
int size = sizeof(*hptr);\
- switch(size) {\
+ switch (size) {\
case 1:\
*(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\
break;\
@@ -255,7 +255,7 @@
#define __get_user(x, hptr) \
({\
int size = sizeof(*hptr);\
- switch(size) {\
+ switch (size) {\
case 1:\
x = (typeof(*hptr))*(uint8_t *)(hptr);\
break;\
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index adc3d21..4abff79 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -199,6 +199,7 @@
#else
case CTLTYPE_LONG:
*(uint64_t *)holdp = tswap64(*(long *)holdp);
+ break;
case CTLTYPE_ULONG:
*(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
break;
diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
index d1fb8f2..a1911f9 100644
--- a/docs/system/arm/aspeed.rst
+++ b/docs/system/arm/aspeed.rst
@@ -49,6 +49,7 @@
* Ethernet controllers
* Front LEDs (PCA9552 on I2C bus)
* LPC Peripheral Controller (a subset of subdevices are supported)
+ * Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA
Missing devices
@@ -59,7 +60,6 @@
* PWM and Fan Controller
* Slave GPIO Controller
* Super I/O Controller
- * Hash/Crypto Engine
* PCI-Express 1 Controller
* Graphic Display Controller
* PECI Controller
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 80cae86..f916907 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -245,6 +245,13 @@
to distinguish which model QEMU is implementing, the ``raspi2`` and ``raspi3``
machines have been renamed ``raspi2b`` and ``raspi3b``.
+Aspeed ``swift-bmc`` machine (since 6.1)
+''''''''''''''''''''''''''''''''''''''''
+
+This machine is deprecated because we have enough AST2500 based OpenPOWER
+machines. It can be easily replaced by the ``witherspoon-bmc`` or the
+``romulus-bmc`` machines.
+
Device options
--------------
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
index c2f87ad..9ea318f 100644
--- a/fpu/softfloat-specialize.c.inc
+++ b/fpu/softfloat-specialize.c.inc
@@ -145,6 +145,9 @@
#elif defined(TARGET_HPPA)
/* snan_bit_is_one, set msb-1. */
frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2);
+#elif defined(TARGET_HEXAGON)
+ sign = 1;
+ frac = ~0ULL;
#else
/* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
* S390, SH4, TriCore, and Xtensa. I cannot find documentation
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index b623226..3fe6c55 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -133,6 +133,19 @@
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
+/* Quanta-Q71l hardware value */
+#define QUANTA_Q71L_BMC_HW_STRAP1 ( \
+ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_128MB) | \
+ SCU_AST2400_HW_STRAP_DRAM_CONFIG(2/* DDR3 with CL=6, CWL=5 */) | \
+ SCU_AST2400_HW_STRAP_ACPI_DIS | \
+ SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_24M_IN) | \
+ SCU_HW_STRAP_VGA_CLASS_CODE | \
+ SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_PASS_THROUGH) | \
+ SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \
+ SCU_HW_STRAP_SPI_WIDTH | \
+ SCU_HW_STRAP_VGA_SIZE_SET(VGA_8M_DRAM) | \
+ SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT))
+
/* AST2600 evb hardware value */
#define AST2600_EVB_HW_STRAP1 0x000000C0
#define AST2600_EVB_HW_STRAP2 0x00000003
@@ -141,6 +154,10 @@
#define TACOMA_BMC_HW_STRAP1 0x00000000
#define TACOMA_BMC_HW_STRAP2 0x00000040
+/* Rainier hardware value: (QEMU prototype) */
+#define RAINIER_BMC_HW_STRAP1 0x00000000
+#define RAINIER_BMC_HW_STRAP2 0x00000000
+
/*
* The max ram region is for firmwares that scan the address space
* with load/store to guess how much RAM the SoC has.
@@ -322,7 +339,7 @@
object_property_set_int(OBJECT(&bmc->soc), "num-cs", amc->num_cs,
&error_abort);
object_property_set_link(OBJECT(&bmc->soc), "dram",
- OBJECT(&bmc->ram_container), &error_abort);
+ OBJECT(machine->ram), &error_abort);
if (machine->kernel_filename) {
/*
* When booting with a -kernel command line there is no u-boot
@@ -428,6 +445,34 @@
object_property_set_int(OBJECT(dev), "temperature3", 110000, &error_abort);
}
+static void quanta_q71l_bmc_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+
+ /*
+ * The quanta-q71l platform expects tmp75s which are compatible with
+ * tmp105s.
+ */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4c);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4e);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4f);
+
+ /* TODO: i2c-1: Add baseboard FRU eeprom@54 24c64 */
+ /* TODO: i2c-1: Add Frontpanel FRU eeprom@57 24c64 */
+ /* TODO: Add Memory Riser i2c mux and eeproms. */
+
+ /* TODO: i2c-2: pca9546@74 */
+ /* TODO: i2c-2: pca9548@77 */
+ /* TODO: i2c-3: Add BIOS FRU eeprom@56 24c64 */
+ /* TODO: i2c-7: Add pca9546@70 */
+ /* - i2c@0: pmbus@59 */
+ /* - i2c@1: pmbus@58 */
+ /* - i2c@2: pmbus@58 */
+ /* - i2c@3: pmbus@59 */
+ /* TODO: i2c-7: Add PDB FRU eeprom@52 */
+ /* TODO: i2c-8: Add BMC FRU eeprom@50 */
+}
+
static void ast2500_evb_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
@@ -624,6 +669,58 @@
eeprom_buf);
}
+static void rainier_bmc_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+
+ /* The rainier expects a TMP275 but a TMP105 is compatible */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105,
+ 0x49);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105,
+ 0x4a);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105,
+ 0x49);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105,
+ 0x4a);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105,
+ 0x4b);
+
+ /* Bus 7: TODO dps310@76 */
+ /* Bus 7: TODO max31785@52 */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 0x61);
+ /* Bus 7: TODO si7021-a20@20 */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105,
+ 0x48);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105,
+ 0x4a);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61);
+ /* Bus 8: ucd90320@11 */
+ /* Bus 8: ucd90320@b */
+ /* Bus 8: ucd90320@c */
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4d);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4d);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105,
+ 0x49);
+}
+
static bool aspeed_get_mmio_exec(Object *obj, Error **errp)
{
return ASPEED_MACHINE(obj)->mmio_exec;
@@ -723,6 +820,23 @@
aspeed_soc_num_cpus(amc->soc_name);
};
+static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+ mc->desc = "Quanta-Q71l BMC (ARM926EJ-S)";
+ amc->soc_name = "ast2400-a1";
+ amc->hw_strap1 = QUANTA_Q71L_BMC_HW_STRAP1;
+ amc->fmc_model = "n25q256a";
+ amc->spi_model = "mx25l25635e";
+ amc->num_cs = 1;
+ amc->i2c_init = quanta_q71l_bmc_i2c_init;
+ mc->default_ram_size = 128 * MiB;
+ mc->default_cpus = mc->min_cpus = mc->max_cpus =
+ aspeed_soc_num_cpus(amc->soc_name);
+}
+
static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc,
void *data)
{
@@ -806,6 +920,9 @@
mc->default_ram_size = 512 * MiB;
mc->default_cpus = mc->min_cpus = mc->max_cpus =
aspeed_soc_num_cpus(amc->soc_name);
+
+ mc->deprecation_reason = "redundant system. Please use a similar "
+ "OpenPOWER BMC, Witherspoon or Romulus.";
};
static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data)
@@ -881,6 +998,25 @@
aspeed_soc_num_cpus(amc->soc_name);
};
+static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+ mc->desc = "IBM Rainier BMC (Cortex A7)";
+ amc->soc_name = "ast2600-a1";
+ amc->hw_strap1 = RAINIER_BMC_HW_STRAP1;
+ amc->hw_strap2 = RAINIER_BMC_HW_STRAP2;
+ amc->fmc_model = "mx66l1g45g";
+ amc->spi_model = "mx66l1g45g";
+ amc->num_cs = 2;
+ amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
+ amc->i2c_init = rainier_bmc_i2c_init;
+ mc->default_ram_size = 1 * GiB;
+ mc->default_cpus = mc->min_cpus = mc->max_cpus =
+ aspeed_soc_num_cpus(amc->soc_name);
+};
+
static const TypeInfo aspeed_machine_types[] = {
{
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
@@ -923,6 +1059,14 @@
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_g220a_class_init,
}, {
+ .name = MACHINE_TYPE_NAME("quanta-q71l-bmc"),
+ .parent = TYPE_ASPEED_MACHINE,
+ .class_init = aspeed_machine_quanta_q71l_class_init,
+ }, {
+ .name = MACHINE_TYPE_NAME("rainier-bmc"),
+ .parent = TYPE_ASPEED_MACHINE,
+ .class_init = aspeed_machine_rainier_class_init,
+ }, {
.name = TYPE_ASPEED_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(AspeedMachineState),
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 8202b4f..e301312 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -39,6 +39,7 @@
[ASPEED_DEV_ETH2] = 0x1E680000,
[ASPEED_DEV_ETH4] = 0x1E690000,
[ASPEED_DEV_VIC] = 0x1E6C0000,
+ [ASPEED_DEV_HACE] = 0x1E6D0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
@@ -99,6 +100,7 @@
[ASPEED_DEV_I2C] = 110, /* 110 -> 125 */
[ASPEED_DEV_ETH1] = 2,
[ASPEED_DEV_ETH2] = 3,
+ [ASPEED_DEV_HACE] = 4,
[ASPEED_DEV_ETH3] = 32,
[ASPEED_DEV_ETH4] = 33,
[ASPEED_DEV_KCS] = 138, /* 138 -> 142 */
@@ -182,7 +184,8 @@
object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
}
- object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA);
+ snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
+ object_initialize_child(obj, "xdma", &s->xdma, typename);
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
@@ -210,6 +213,9 @@
TYPE_SYSBUS_SDHCI);
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
+
+ snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
+ object_initialize_child(obj, "hace", &s->hace, typename);
}
/*
@@ -341,10 +347,6 @@
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
- if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base",
- sc->memmap[ASPEED_DEV_SDRAM], errp)) {
- return;
- }
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
@@ -495,6 +497,16 @@
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4));
+
+ /* HACE */
+ object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
}
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index abc90ed..3ad6c56 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -31,6 +31,7 @@
[ASPEED_DEV_VIC] = 0x1E6C0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
+ [ASPEED_DEV_HACE] = 0x1E6E3000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
[ASPEED_DEV_VIDEO] = 0x1E700000,
[ASPEED_DEV_ADC] = 0x1E6E9000,
@@ -62,6 +63,7 @@
[ASPEED_DEV_VIC] = 0x1E6C0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
+ [ASPEED_DEV_HACE] = 0x1E6E3000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
[ASPEED_DEV_ADC] = 0x1E6E9000,
[ASPEED_DEV_VIDEO] = 0x1E700000,
@@ -114,6 +116,7 @@
[ASPEED_DEV_ETH2] = 3,
[ASPEED_DEV_XDMA] = 6,
[ASPEED_DEV_SDHCI] = 26,
+ [ASPEED_DEV_HACE] = 4,
};
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
@@ -193,7 +196,8 @@
TYPE_FTGMAC100);
}
- object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA);
+ snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
+ object_initialize_child(obj, "xdma", &s->xdma, typename);
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
@@ -209,6 +213,9 @@
}
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
+
+ snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
+ object_initialize_child(obj, "hace", &s->hace, typename);
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@@ -298,10 +305,6 @@
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
- if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base",
- sc->memmap[ASPEED_DEV_SDRAM], errp)) {
- return;
- }
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
@@ -422,6 +425,16 @@
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4,
qdev_get_gpio_in(DEVICE(&s->lpc), aspeed_lpc_kcs_4));
+
+ /* HACE */
+ object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
}
static Property aspeed_soc_properties[] = {
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 183d3f4..b77503d 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -259,6 +259,8 @@
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
{ INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
+ { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 518a3f5..8d276d9 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -601,7 +601,7 @@
break;
}
- bus->dma_addr = value & 0xfffffffc;
+ bus->dma_addr = value & 0x3ffffffc;
break;
case I2CD_DMA_LEN:
@@ -816,7 +816,8 @@
return;
}
- address_space_init(&s->dram_as, s->dram_mr, "dma-dram");
+ address_space_init(&s->dram_as, s->dram_mr,
+ TYPE_ASPEED_I2C "-dma-dram");
}
}
diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index 48c5dda..0fe7b69 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -267,8 +267,9 @@
pci_create_simple(pci_bus, devfn + 2, "piix4-usb-uhci");
if (smbus) {
*smbus = piix4_pm_init(pci_bus, devfn + 3, 0x1100,
- isa_get_irq(NULL, 9), NULL, 0, NULL);
- }
+ qdev_get_gpio_in_named(dev, "isa", 9),
+ NULL, 0, NULL);
+ }
return dev;
}
diff --git a/hw/mips/meson.build b/hw/mips/meson.build
index 1195716..dd0101a 100644
--- a/hw/mips/meson.build
+++ b/hw/mips/meson.build
@@ -1,12 +1,15 @@
mips_ss = ss.source_set()
mips_ss.add(files('bootloader.c', 'mips_int.c'))
mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c'))
-mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
-mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
-mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
-mips_ss.add(when: 'CONFIG_MIPS_BOSTON', if_true: [files('boston.c'), fdt])
mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c'))
+if 'CONFIG_TCG' in config_all
+mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
+mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
+mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
+mips_ss.add(when: 'CONFIG_MIPS_BOSTON', if_true: [files('boston.c'), fdt])
+endif
+
hw_arch += {'mips': mips_ss}
diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
new file mode 100644
index 0000000..10f00e6
--- /dev/null
+++ b/hw/misc/aspeed_hace.c
@@ -0,0 +1,389 @@
+/*
+ * ASPEED Hash and Crypto Engine
+ *
+ * Copyright (C) 2021 IBM Corp.
+ *
+ * Joel Stanley <joel@jms.id.au>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/misc/aspeed_hace.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "crypto/hash.h"
+#include "hw/qdev-properties.h"
+#include "hw/irq.h"
+
+#define R_CRYPT_CMD (0x10 / 4)
+
+#define R_STATUS (0x1c / 4)
+#define HASH_IRQ BIT(9)
+#define CRYPT_IRQ BIT(12)
+#define TAG_IRQ BIT(15)
+
+#define R_HASH_SRC (0x20 / 4)
+#define R_HASH_DEST (0x24 / 4)
+#define R_HASH_SRC_LEN (0x2c / 4)
+
+#define R_HASH_CMD (0x30 / 4)
+/* Hash algorithm selection */
+#define HASH_ALGO_MASK (BIT(4) | BIT(5) | BIT(6))
+#define HASH_ALGO_MD5 0
+#define HASH_ALGO_SHA1 BIT(5)
+#define HASH_ALGO_SHA224 BIT(6)
+#define HASH_ALGO_SHA256 (BIT(4) | BIT(6))
+#define HASH_ALGO_SHA512_SERIES (BIT(5) | BIT(6))
+/* SHA512 algorithm selection */
+#define SHA512_HASH_ALGO_MASK (BIT(10) | BIT(11) | BIT(12))
+#define HASH_ALGO_SHA512_SHA512 0
+#define HASH_ALGO_SHA512_SHA384 BIT(10)
+#define HASH_ALGO_SHA512_SHA256 BIT(11)
+#define HASH_ALGO_SHA512_SHA224 (BIT(10) | BIT(11))
+/* HMAC modes */
+#define HASH_HMAC_MASK (BIT(7) | BIT(8))
+#define HASH_DIGEST 0
+#define HASH_DIGEST_HMAC BIT(7)
+#define HASH_DIGEST_ACCUM BIT(8)
+#define HASH_HMAC_KEY (BIT(7) | BIT(8))
+/* Cascaded operation modes */
+#define HASH_ONLY 0
+#define HASH_ONLY2 BIT(0)
+#define HASH_CRYPT_THEN_HASH BIT(1)
+#define HASH_HASH_THEN_CRYPT (BIT(0) | BIT(1))
+/* Other cmd bits */
+#define HASH_IRQ_EN BIT(9)
+#define HASH_SG_EN BIT(18)
+/* Scatter-gather data list */
+#define SG_LIST_LEN_SIZE 4
+#define SG_LIST_LEN_MASK 0x0FFFFFFF
+#define SG_LIST_LEN_LAST BIT(31)
+#define SG_LIST_ADDR_SIZE 4
+#define SG_LIST_ADDR_MASK 0x7FFFFFFF
+#define SG_LIST_ENTRY_SIZE (SG_LIST_LEN_SIZE + SG_LIST_ADDR_SIZE)
+#define ASPEED_HACE_MAX_SG 256 /* max number of entries */
+
+static const struct {
+ uint32_t mask;
+ QCryptoHashAlgorithm algo;
+} hash_algo_map[] = {
+ { HASH_ALGO_MD5, QCRYPTO_HASH_ALG_MD5 },
+ { HASH_ALGO_SHA1, QCRYPTO_HASH_ALG_SHA1 },
+ { HASH_ALGO_SHA224, QCRYPTO_HASH_ALG_SHA224 },
+ { HASH_ALGO_SHA256, QCRYPTO_HASH_ALG_SHA256 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALG_SHA512 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALG_SHA384 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALG_SHA256 },
+};
+
+static int hash_algo_lookup(uint32_t reg)
+{
+ int i;
+
+ reg &= HASH_ALGO_MASK | SHA512_HASH_ALGO_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(hash_algo_map); i++) {
+ if (reg == hash_algo_map[i].mask) {
+ return hash_algo_map[i].algo;
+ }
+ }
+
+ return -1;
+}
+
+static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode)
+{
+ struct iovec iov[ASPEED_HACE_MAX_SG];
+ g_autofree uint8_t *digest_buf;
+ size_t digest_len = 0;
+ int i;
+
+ if (sg_mode) {
+ uint32_t len = 0;
+
+ for (i = 0; !(len & SG_LIST_LEN_LAST); i++) {
+ uint32_t addr, src;
+ hwaddr plen;
+
+ if (i == ASPEED_HACE_MAX_SG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "aspeed_hace: guest failed to set end of sg list marker\n");
+ break;
+ }
+
+ src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE);
+
+ len = address_space_ldl_le(&s->dram_as, src,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+
+ addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ addr &= SG_LIST_ADDR_MASK;
+
+ iov[i].iov_len = len & SG_LIST_LEN_MASK;
+ plen = iov[i].iov_len;
+ iov[i].iov_base = address_space_map(&s->dram_as, addr, &plen, false,
+ MEMTXATTRS_UNSPECIFIED);
+ }
+ } else {
+ hwaddr len = s->regs[R_HASH_SRC_LEN];
+
+ iov[0].iov_len = len;
+ iov[0].iov_base = address_space_map(&s->dram_as, s->regs[R_HASH_SRC],
+ &len, false,
+ MEMTXATTRS_UNSPECIFIED);
+ i = 1;
+ }
+
+ if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
+ return;
+ }
+
+ if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST],
+ MEMTXATTRS_UNSPECIFIED,
+ digest_buf, digest_len)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "aspeed_hace: address space write failed\n");
+ }
+
+ for (; i > 0; i--) {
+ address_space_unmap(&s->dram_as, iov[i - 1].iov_base,
+ iov[i - 1].iov_len, false,
+ iov[i - 1].iov_len);
+ }
+
+ /*
+ * Set status bits to indicate completion. Testing shows hardware sets
+ * these irrespective of HASH_IRQ_EN.
+ */
+ s->regs[R_STATUS] |= HASH_IRQ;
+}
+
+static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ AspeedHACEState *s = ASPEED_HACE(opaque);
+
+ addr >>= 2;
+
+ if (addr >= ASPEED_HACE_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr << 2);
+ return 0;
+ }
+
+ return s->regs[addr];
+}
+
+static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ AspeedHACEState *s = ASPEED_HACE(opaque);
+ AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s);
+
+ addr >>= 2;
+
+ if (addr >= ASPEED_HACE_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr << 2);
+ return;
+ }
+
+ switch (addr) {
+ case R_STATUS:
+ if (data & HASH_IRQ) {
+ data &= ~HASH_IRQ;
+
+ if (s->regs[addr] & HASH_IRQ) {
+ qemu_irq_lower(s->irq);
+ }
+ }
+ break;
+ case R_HASH_SRC:
+ data &= ahc->src_mask;
+ break;
+ case R_HASH_DEST:
+ data &= ahc->dest_mask;
+ break;
+ case R_HASH_SRC_LEN:
+ data &= 0x0FFFFFFF;
+ break;
+ case R_HASH_CMD: {
+ int algo;
+ data &= ahc->hash_mask;
+
+ if ((data & HASH_HMAC_MASK)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: HMAC engine command mode %"PRIx64" not implemented",
+ __func__, (data & HASH_HMAC_MASK) >> 8);
+ }
+ if (data & BIT(1)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Cascaded mode not implemented",
+ __func__);
+ }
+ algo = hash_algo_lookup(data);
+ if (algo < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid hash algorithm selection 0x%"PRIx64"\n",
+ __func__, data & ahc->hash_mask);
+ break;
+ }
+ do_hash_operation(s, algo, data & HASH_SG_EN);
+
+ if (data & HASH_IRQ_EN) {
+ qemu_irq_raise(s->irq);
+ }
+ break;
+ }
+ case R_CRYPT_CMD:
+ qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n",
+ __func__);
+ break;
+ default:
+ break;
+ }
+
+ s->regs[addr] = data;
+}
+
+static const MemoryRegionOps aspeed_hace_ops = {
+ .read = aspeed_hace_read,
+ .write = aspeed_hace_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static void aspeed_hace_reset(DeviceState *dev)
+{
+ struct AspeedHACEState *s = ASPEED_HACE(dev);
+
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static void aspeed_hace_realize(DeviceState *dev, Error **errp)
+{
+ AspeedHACEState *s = ASPEED_HACE(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s,
+ TYPE_ASPEED_HACE, 0x1000);
+
+ if (!s->dram_mr) {
+ error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set");
+ return;
+ }
+
+ address_space_init(&s->dram_as, s->dram_mr, "dram");
+
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static Property aspeed_hace_properties[] = {
+ DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr,
+ TYPE_MEMORY_REGION, MemoryRegion *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+
+static const VMStateDescription vmstate_aspeed_hace = {
+ .name = TYPE_ASPEED_HACE,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void aspeed_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = aspeed_hace_realize;
+ dc->reset = aspeed_hace_reset;
+ device_class_set_props(dc, aspeed_hace_properties);
+ dc->vmsd = &vmstate_aspeed_hace;
+}
+
+static const TypeInfo aspeed_hace_info = {
+ .name = TYPE_ASPEED_HACE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedHACEState),
+ .class_init = aspeed_hace_class_init,
+ .class_size = sizeof(AspeedHACEClass)
+};
+
+static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2400 Hash and Crypto Engine";
+
+ ahc->src_mask = 0x0FFFFFFF;
+ ahc->dest_mask = 0x0FFFFFF8;
+ ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */
+}
+
+static const TypeInfo aspeed_ast2400_hace_info = {
+ .name = TYPE_ASPEED_AST2400_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2400_hace_class_init,
+};
+
+static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2500 Hash and Crypto Engine";
+
+ ahc->src_mask = 0x3fffffff;
+ ahc->dest_mask = 0x3ffffff8;
+ ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */
+}
+
+static const TypeInfo aspeed_ast2500_hace_info = {
+ .name = TYPE_ASPEED_AST2500_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2500_hace_class_init,
+};
+
+static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2600 Hash and Crypto Engine";
+
+ ahc->src_mask = 0x7FFFFFFF;
+ ahc->dest_mask = 0x7FFFFFF8;
+ ahc->hash_mask = 0x00147FFF;
+}
+
+static const TypeInfo aspeed_ast2600_hace_info = {
+ .name = TYPE_ASPEED_AST2600_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2600_hace_class_init,
+};
+
+static void aspeed_hace_register_types(void)
+{
+ type_register_static(&aspeed_ast2400_hace_info);
+ type_register_static(&aspeed_ast2500_hace_info);
+ type_register_static(&aspeed_ast2600_hace_info);
+ type_register_static(&aspeed_hace_info);
+}
+
+type_init(aspeed_hace_register_types);
diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c
index 533d237..1c21577 100644
--- a/hw/misc/aspeed_xdma.c
+++ b/hw/misc/aspeed_xdma.c
@@ -30,6 +30,19 @@
#define XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
#define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
#define XDMA_IRQ_ENG_STAT_RESET 0xF8000000
+
+#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14
+#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18
+#define XDMA_AST2600_BMC_CMDQ_WRP 0x1c
+#define XDMA_AST2600_BMC_CMDQ_RDP 0x20
+#define XDMA_AST2600_IRQ_CTRL 0x38
+#define XDMA_AST2600_IRQ_CTRL_US_COMP BIT(16)
+#define XDMA_AST2600_IRQ_CTRL_DS_COMP BIT(17)
+#define XDMA_AST2600_IRQ_CTRL_W_MASK 0x017003FF
+#define XDMA_AST2600_IRQ_STATUS 0x3c
+#define XDMA_AST2600_IRQ_STATUS_US_COMP BIT(16)
+#define XDMA_AST2600_IRQ_STATUS_DS_COMP BIT(17)
+
#define XDMA_MEM_SIZE 0x1000
#define TO_REG(addr) ((addr) / sizeof(uint32_t))
@@ -52,56 +65,48 @@
unsigned int idx;
uint32_t val32 = (uint32_t)val;
AspeedXDMAState *xdma = opaque;
+ AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma);
if (addr >= ASPEED_XDMA_REG_SIZE) {
return;
}
- switch (addr) {
- case XDMA_BMC_CMDQ_ENDP:
+ if (addr == axc->cmdq_endp) {
xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
- break;
- case XDMA_BMC_CMDQ_WRP:
+ } else if (addr == axc->cmdq_wrp) {
idx = TO_REG(addr);
xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
- xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
+ xdma->regs[TO_REG(axc->cmdq_rdp)] = xdma->regs[idx];
trace_aspeed_xdma_write(addr, val);
if (xdma->bmc_cmdq_readp_set) {
xdma->bmc_cmdq_readp_set = 0;
} else {
- xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
- XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+ xdma->regs[TO_REG(axc->intr_status)] |= axc->intr_complete;
- if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
- (XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
+ if (xdma->regs[TO_REG(axc->intr_ctrl)] & axc->intr_complete) {
qemu_irq_raise(xdma->irq);
+ }
}
- break;
- case XDMA_BMC_CMDQ_RDP:
+ } else if (addr == axc->cmdq_rdp) {
trace_aspeed_xdma_write(addr, val);
if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
xdma->bmc_cmdq_readp_set = 1;
}
- break;
- case XDMA_IRQ_ENG_CTRL:
- xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
- break;
- case XDMA_IRQ_ENG_STAT:
+ } else if (addr == axc->intr_ctrl) {
+ xdma->regs[TO_REG(addr)] = val32 & axc->intr_ctrl_mask;
+ } else if (addr == axc->intr_status) {
trace_aspeed_xdma_write(addr, val);
idx = TO_REG(addr);
- if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
- xdma->regs[idx] &=
- ~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
+ if (val32 & axc->intr_complete) {
+ xdma->regs[idx] &= ~axc->intr_complete;
qemu_irq_lower(xdma->irq);
}
- break;
- default:
+ } else {
xdma->regs[TO_REG(addr)] = val32;
- break;
}
}
@@ -127,10 +132,11 @@
static void aspeed_xdma_reset(DeviceState *dev)
{
AspeedXDMAState *xdma = ASPEED_XDMA(dev);
+ AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma);
xdma->bmc_cmdq_readp_set = 0;
memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
- xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
+ xdma->regs[TO_REG(axc->intr_status)] = XDMA_IRQ_ENG_STAT_RESET;
qemu_irq_lower(xdma->irq);
}
@@ -144,6 +150,73 @@
},
};
+static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 XDMA Controller";
+
+ axc->cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP;
+ axc->cmdq_wrp = XDMA_AST2600_BMC_CMDQ_WRP;
+ axc->cmdq_rdp = XDMA_AST2600_BMC_CMDQ_RDP;
+ axc->intr_ctrl = XDMA_AST2600_IRQ_CTRL;
+ axc->intr_ctrl_mask = XDMA_AST2600_IRQ_CTRL_W_MASK;
+ axc->intr_status = XDMA_AST2600_IRQ_STATUS;
+ axc->intr_complete = XDMA_AST2600_IRQ_STATUS_US_COMP |
+ XDMA_AST2600_IRQ_STATUS_DS_COMP;
+}
+
+static const TypeInfo aspeed_2600_xdma_info = {
+ .name = TYPE_ASPEED_2600_XDMA,
+ .parent = TYPE_ASPEED_XDMA,
+ .class_init = aspeed_2600_xdma_class_init,
+};
+
+static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 XDMA Controller";
+
+ axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP;
+ axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP;
+ axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP;
+ axc->intr_ctrl = XDMA_IRQ_ENG_CTRL;
+ axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK;
+ axc->intr_status = XDMA_IRQ_ENG_STAT;
+ axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+};
+
+static const TypeInfo aspeed_2500_xdma_info = {
+ .name = TYPE_ASPEED_2500_XDMA,
+ .parent = TYPE_ASPEED_XDMA,
+ .class_init = aspeed_2500_xdma_class_init,
+};
+
+static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 XDMA Controller";
+
+ axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP;
+ axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP;
+ axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP;
+ axc->intr_ctrl = XDMA_IRQ_ENG_CTRL;
+ axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK;
+ axc->intr_status = XDMA_IRQ_ENG_STAT;
+ axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+};
+
+static const TypeInfo aspeed_2400_xdma_info = {
+ .name = TYPE_ASPEED_2400_XDMA,
+ .parent = TYPE_ASPEED_XDMA,
+ .class_init = aspeed_2400_xdma_class_init,
+};
+
static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
@@ -158,10 +231,15 @@
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedXDMAState),
.class_init = aspeed_xdma_class_init,
+ .class_size = sizeof(AspeedXDMAClass),
+ .abstract = true,
};
static void aspeed_xdma_register_type(void)
{
type_register_static(&aspeed_xdma_info);
+ type_register_static(&aspeed_2400_xdma_info);
+ type_register_static(&aspeed_2500_xdma_info);
+ type_register_static(&aspeed_2600_xdma_info);
}
type_init(aspeed_xdma_register_type);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 21034dc..1e7b8b0 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -109,6 +109,7 @@
softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
+ 'aspeed_hace.c',
'aspeed_lpc.c',
'aspeed_scu.c',
'aspeed_sdmc.c',
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 72cb217..331a2c5 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -126,6 +126,8 @@
/* DMA Control/Status Register */
#define R_DMA_CTRL (0x80 / 4)
+#define DMA_CTRL_REQUEST (1 << 31)
+#define DMA_CTRL_GRANT (1 << 30)
#define DMA_CTRL_DELAY_MASK 0xf
#define DMA_CTRL_DELAY_SHIFT 8
#define DMA_CTRL_FREQ_MASK 0xf
@@ -177,10 +179,8 @@
* 0: 4 bytes
* 0x7FFFFF: 32M bytes
*/
-#define DMA_DRAM_ADDR(s, val) ((s)->sdram_base | \
- ((val) & (s)->ctrl->dma_dram_mask))
-#define DMA_FLASH_ADDR(s, val) ((s)->ctrl->flash_window_base | \
- ((val) & (s)->ctrl->dma_flash_mask))
+#define DMA_DRAM_ADDR(s, val) ((val) & (s)->ctrl->dma_dram_mask)
+#define DMA_FLASH_ADDR(s, val) ((val) & (s)->ctrl->dma_flash_mask)
#define DMA_LENGTH(val) ((val) & 0x01FFFFFC)
/* Flash opcodes. */
@@ -229,6 +229,7 @@
const AspeedSegments *seg);
static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg,
AspeedSegments *seg);
+static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t value);
/*
* AST2600 definitions
@@ -258,6 +259,15 @@
const AspeedSegments *seg);
static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s,
uint32_t reg, AspeedSegments *seg);
+static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t value);
+
+#define ASPEED_SMC_FEATURE_DMA 0x1
+#define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
+
+static inline bool aspeed_smc_has_dma(const AspeedSMCState *s)
+{
+ return !!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA);
+}
static const AspeedSMCController controllers[] = {
{
@@ -272,10 +282,11 @@
.segments = aspeed_segments_legacy,
.flash_window_base = ASPEED_SOC_SMC_FLASH_BASE,
.flash_window_size = 0x6000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_SMC_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.fmc-ast2400",
.r_conf = R_CONF,
@@ -288,12 +299,13 @@
.segments = aspeed_segments_fmc,
.flash_window_base = ASPEED_SOC_FMC_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x1FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.spi1-ast2400",
.r_conf = R_SPI_CONF,
@@ -306,10 +318,11 @@
.segments = aspeed_segments_spi,
.flash_window_base = ASPEED_SOC_SPI_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_SPI_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.fmc-ast2500",
.r_conf = R_CONF,
@@ -322,12 +335,13 @@
.segments = aspeed_segments_ast2500_fmc,
.flash_window_base = ASPEED_SOC_FMC_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.spi1-ast2500",
.r_conf = R_CONF,
@@ -340,10 +354,11 @@
.segments = aspeed_segments_ast2500_spi1,
.flash_window_base = ASPEED_SOC_SPI_FLASH_BASE,
.flash_window_size = 0x8000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.spi2-ast2500",
.r_conf = R_CONF,
@@ -356,10 +371,11 @@
.segments = aspeed_segments_ast2500_spi2,
.flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE,
.flash_window_size = 0x8000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.fmc-ast2600",
.r_conf = R_CONF,
@@ -372,12 +388,13 @@
.segments = aspeed_segments_ast2600_fmc,
.flash_window_base = ASPEED26_SOC_FMC_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_2600_smc_segment_to_reg,
.reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ .dma_ctrl = aspeed_2600_smc_dma_ctrl,
}, {
.name = "aspeed.spi1-ast2600",
.r_conf = R_CONF,
@@ -390,12 +407,14 @@
.segments = aspeed_segments_ast2600_spi1,
.flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA |
+ ASPEED_SMC_FEATURE_DMA_GRANT,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_2600_smc_segment_to_reg,
.reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ .dma_ctrl = aspeed_2600_smc_dma_ctrl,
}, {
.name = "aspeed.spi2-ast2600",
.r_conf = R_CONF,
@@ -408,12 +427,14 @@
.segments = aspeed_segments_ast2600_spi2,
.flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA |
+ ASPEED_SMC_FEATURE_DMA_GRANT,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_2600_smc_segment_to_reg,
.reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ .dma_ctrl = aspeed_2600_smc_dma_ctrl,
},
};
@@ -998,11 +1019,11 @@
addr == R_CE_CMD_CTRL ||
addr == R_INTR_CTRL ||
addr == R_DUMMY_DATA ||
- (s->ctrl->has_dma && addr == R_DMA_CTRL) ||
- (s->ctrl->has_dma && addr == R_DMA_FLASH_ADDR) ||
- (s->ctrl->has_dma && addr == R_DMA_DRAM_ADDR) ||
- (s->ctrl->has_dma && addr == R_DMA_LEN) ||
- (s->ctrl->has_dma && addr == R_DMA_CHECKSUM) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_CHECKSUM) ||
(addr >= R_SEG_ADDR0 &&
addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) ||
(addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_peripherals)) {
@@ -1235,7 +1256,7 @@
}
}
-static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint64_t dma_ctrl)
+static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl)
{
if (!(dma_ctrl & DMA_CTRL_ENABLE)) {
s->regs[R_DMA_CTRL] = dma_ctrl;
@@ -1260,6 +1281,46 @@
aspeed_smc_dma_done(s);
}
+static inline bool aspeed_smc_dma_granted(AspeedSMCState *s)
+{
+ if (!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA_GRANT)) {
+ return true;
+ }
+
+ if (!(s->regs[R_DMA_CTRL] & DMA_CTRL_GRANT)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl)
+{
+ /* Preserve DMA bits */
+ dma_ctrl |= s->regs[R_DMA_CTRL] & (DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+
+ if (dma_ctrl == 0xAEED0000) {
+ /* automatically grant request */
+ s->regs[R_DMA_CTRL] |= (DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+ return;
+ }
+
+ /* clear request */
+ if (dma_ctrl == 0xDEEA0000) {
+ s->regs[R_DMA_CTRL] &= ~(DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+ return;
+ }
+
+ if (!aspeed_smc_dma_granted(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__);
+ return;
+ }
+
+ aspeed_smc_dma_ctrl(s, dma_ctrl);
+ s->regs[R_DMA_CTRL] &= ~(DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+}
+
static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
@@ -1291,13 +1352,16 @@
s->regs[addr] = value & 0xff;
} else if (addr == R_INTR_CTRL) {
s->regs[addr] = value;
- } else if (s->ctrl->has_dma && addr == R_DMA_CTRL) {
- aspeed_smc_dma_ctrl(s, value);
- } else if (s->ctrl->has_dma && addr == R_DMA_DRAM_ADDR) {
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) {
+ s->ctrl->dma_ctrl(s, value);
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR &&
+ aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_DRAM_ADDR(s, value);
- } else if (s->ctrl->has_dma && addr == R_DMA_FLASH_ADDR) {
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR &&
+ aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_FLASH_ADDR(s, value);
- } else if (s->ctrl->has_dma && addr == R_DMA_LEN) {
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN &&
+ aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_LENGTH(value);
} else {
qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
@@ -1385,7 +1449,9 @@
memory_region_init_io(&s->mmio_flash, OBJECT(s),
&aspeed_smc_flash_default_ops, s, name,
s->ctrl->flash_window_size);
- sysbus_init_mmio(sbd, &s->mmio_flash);
+ memory_region_init_alias(&s->mmio_flash_alias, OBJECT(s), name,
+ &s->mmio_flash, 0, s->ctrl->flash_window_size);
+ sysbus_init_mmio(sbd, &s->mmio_flash_alias);
s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_peripherals);
@@ -1411,7 +1477,7 @@
}
/* DMA support */
- if (s->ctrl->has_dma) {
+ if (aspeed_smc_has_dma(s)) {
aspeed_smc_dma_setup(s, errp);
}
}
@@ -1431,7 +1497,6 @@
static Property aspeed_smc_properties[] = {
DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false),
- DEFINE_PROP_UINT64("sdram-base", AspeedSMCState, sdram_base, 0),
DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 9359d6d..d9161d2 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -21,6 +21,7 @@
#include "hw/rtc/aspeed_rtc.h"
#include "hw/i2c/aspeed_i2c.h"
#include "hw/ssi/aspeed_smc.h"
+#include "hw/misc/aspeed_hace.h"
#include "hw/watchdog/wdt_aspeed.h"
#include "hw/net/ftgmac100.h"
#include "target/arm/cpu.h"
@@ -50,6 +51,7 @@
AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c;
AspeedSCUState scu;
+ AspeedHACEState hace;
AspeedXDMAState xdma;
AspeedSMCState fmc;
AspeedSMCState spi[ASPEED_SPIS_NUM];
@@ -133,6 +135,7 @@
ASPEED_DEV_XDMA,
ASPEED_DEV_EMMC,
ASPEED_DEV_KCS,
+ ASPEED_DEV_HACE,
};
#endif /* ASPEED_SOC_H */
diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h
new file mode 100644
index 0000000..94d5ada
--- /dev/null
+++ b/include/hw/misc/aspeed_hace.h
@@ -0,0 +1,43 @@
+/*
+ * ASPEED Hash and Crypto Engine
+ *
+ * Copyright (C) 2021 IBM Corp.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ASPEED_HACE_H
+#define ASPEED_HACE_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_ASPEED_HACE "aspeed.hace"
+#define TYPE_ASPEED_AST2400_HACE TYPE_ASPEED_HACE "-ast2400"
+#define TYPE_ASPEED_AST2500_HACE TYPE_ASPEED_HACE "-ast2500"
+#define TYPE_ASPEED_AST2600_HACE TYPE_ASPEED_HACE "-ast2600"
+OBJECT_DECLARE_TYPE(AspeedHACEState, AspeedHACEClass, ASPEED_HACE)
+
+#define ASPEED_HACE_NR_REGS (0x64 >> 2)
+
+struct AspeedHACEState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ uint32_t regs[ASPEED_HACE_NR_REGS];
+
+ MemoryRegion *dram_mr;
+ AddressSpace dram_as;
+};
+
+
+struct AspeedHACEClass {
+ SysBusDeviceClass parent_class;
+
+ uint32_t src_mask;
+ uint32_t dest_mask;
+ uint32_t hash_mask;
+};
+
+#endif /* _ASPEED_HACE_H_ */
diff --git a/include/hw/misc/aspeed_xdma.h b/include/hw/misc/aspeed_xdma.h
index a2dea96..b1478fd 100644
--- a/include/hw/misc/aspeed_xdma.h
+++ b/include/hw/misc/aspeed_xdma.h
@@ -13,7 +13,10 @@
#include "qom/object.h"
#define TYPE_ASPEED_XDMA "aspeed.xdma"
-OBJECT_DECLARE_SIMPLE_TYPE(AspeedXDMAState, ASPEED_XDMA)
+#define TYPE_ASPEED_2400_XDMA TYPE_ASPEED_XDMA "-ast2400"
+#define TYPE_ASPEED_2500_XDMA TYPE_ASPEED_XDMA "-ast2500"
+#define TYPE_ASPEED_2600_XDMA TYPE_ASPEED_XDMA "-ast2600"
+OBJECT_DECLARE_TYPE(AspeedXDMAState, AspeedXDMAClass, ASPEED_XDMA)
#define ASPEED_XDMA_NUM_REGS (ASPEED_XDMA_REG_SIZE / sizeof(uint32_t))
#define ASPEED_XDMA_REG_SIZE 0x7C
@@ -28,4 +31,16 @@
uint32_t regs[ASPEED_XDMA_NUM_REGS];
};
+struct AspeedXDMAClass {
+ SysBusDeviceClass parent_class;
+
+ uint8_t cmdq_endp;
+ uint8_t cmdq_wrp;
+ uint8_t cmdq_rdp;
+ uint8_t intr_ctrl;
+ uint32_t intr_ctrl_mask;
+ uint8_t intr_status;
+ uint32_t intr_complete;
+};
+
#endif /* ASPEED_XDMA_H */
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 16c03fe..cdaf165 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -47,7 +47,7 @@
const AspeedSegments *segments;
hwaddr flash_window_base;
uint32_t flash_window_size;
- bool has_dma;
+ uint32_t features;
hwaddr dma_flash_mask;
hwaddr dma_dram_mask;
uint32_t nregs;
@@ -55,6 +55,7 @@
const AspeedSegments *seg);
void (*reg_to_segment)(const struct AspeedSMCState *s, uint32_t reg,
AspeedSegments *seg);
+ void (*dma_ctrl)(struct AspeedSMCState *s, uint32_t value);
} AspeedSMCController;
typedef struct AspeedSMCFlash {
@@ -84,6 +85,7 @@
MemoryRegion mmio;
MemoryRegion mmio_flash;
+ MemoryRegion mmio_flash_alias;
qemu_irq irq;
int irqline;
@@ -103,9 +105,6 @@
uint8_t r_timings;
uint8_t conf_enable_w0;
- /* for DMA support */
- uint64_t sdram_base;
-
AddressSpace flash_as;
MemoryRegion *dram_mr;
AddressSpace dram_as;
diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index 9a68ca0..bc34f5d 100644
--- a/linux-user/hexagon/cpu_loop.c
+++ b/linux-user/hexagon/cpu_loop.c
@@ -25,7 +25,7 @@
void cpu_loop(CPUHexagonState *env)
{
- CPUState *cs = CPU(hexagon_env_get_cpu(env));
+ CPUState *cs = env_cpu(env);
int trapnr, signum, sigcode;
target_ulong sigaddr;
target_ulong syscallnum;
diff --git a/meson.build b/meson.build
index d8bb1ec..1ffdc9e 100644
--- a/meson.build
+++ b/meson.build
@@ -1751,6 +1751,7 @@
hw_arch = {}
target_arch = {}
target_softmmu_arch = {}
+target_user_arch = {}
###############
# Trace files #
@@ -2168,6 +2169,11 @@
abi = config_target['TARGET_ABI_DIR']
target_type='user'
qemu_target_name = 'qemu-' + target_name
+ if arch in target_user_arch
+ t = target_user_arch[arch].apply(config_target, strict: false)
+ arch_srcs += t.sources()
+ arch_deps += t.dependencies()
+ endif
if 'CONFIG_LINUX_USER' in config_target
base_dir = 'linux-user'
target_inc += include_directories('linux-user/host/' / config_host['ARCH'])
diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c
index 09de124..68a55b3 100644
--- a/target/hexagon/arch.c
+++ b/target/hexagon/arch.c
@@ -27,6 +27,97 @@
#define SF_MANTBITS 23
#define float32_nan make_float32(0xffffffff)
+/*
+ * These three tables are used by the cabacdecbin instruction
+ */
+const uint8_t rLPS_table_64x4[64][4] = {
+ {128, 176, 208, 240},
+ {128, 167, 197, 227},
+ {128, 158, 187, 216},
+ {123, 150, 178, 205},
+ {116, 142, 169, 195},
+ {111, 135, 160, 185},
+ {105, 128, 152, 175},
+ {100, 122, 144, 166},
+ {95, 116, 137, 158},
+ {90, 110, 130, 150},
+ {85, 104, 123, 142},
+ {81, 99, 117, 135},
+ {77, 94, 111, 128},
+ {73, 89, 105, 122},
+ {69, 85, 100, 116},
+ {66, 80, 95, 110},
+ {62, 76, 90, 104},
+ {59, 72, 86, 99},
+ {56, 69, 81, 94},
+ {53, 65, 77, 89},
+ {51, 62, 73, 85},
+ {48, 59, 69, 80},
+ {46, 56, 66, 76},
+ {43, 53, 63, 72},
+ {41, 50, 59, 69},
+ {39, 48, 56, 65},
+ {37, 45, 54, 62},
+ {35, 43, 51, 59},
+ {33, 41, 48, 56},
+ {32, 39, 46, 53},
+ {30, 37, 43, 50},
+ {29, 35, 41, 48},
+ {27, 33, 39, 45},
+ {26, 31, 37, 43},
+ {24, 30, 35, 41},
+ {23, 28, 33, 39},
+ {22, 27, 32, 37},
+ {21, 26, 30, 35},
+ {20, 24, 29, 33},
+ {19, 23, 27, 31},
+ {18, 22, 26, 30},
+ {17, 21, 25, 28},
+ {16, 20, 23, 27},
+ {15, 19, 22, 25},
+ {14, 18, 21, 24},
+ {14, 17, 20, 23},
+ {13, 16, 19, 22},
+ {12, 15, 18, 21},
+ {12, 14, 17, 20},
+ {11, 14, 16, 19},
+ {11, 13, 15, 18},
+ {10, 12, 15, 17},
+ {10, 12, 14, 16},
+ {9, 11, 13, 15},
+ {9, 11, 12, 14},
+ {8, 10, 12, 14},
+ {8, 9, 11, 13},
+ {7, 9, 11, 12},
+ {7, 9, 10, 12},
+ {7, 8, 10, 11},
+ {6, 8, 9, 11},
+ {6, 7, 9, 10},
+ {6, 7, 8, 9},
+ {2, 2, 2, 2}
+};
+
+const uint8_t AC_next_state_MPS_64[64] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 62, 63
+};
+
+
+const uint8_t AC_next_state_LPS_64[64] = {
+ 0, 0, 1, 2, 2, 4, 4, 5, 6, 7,
+ 8, 9, 9, 11, 11, 12, 13, 13, 15, 15,
+ 16, 16, 18, 18, 19, 19, 21, 21, 22, 22,
+ 23, 24, 24, 25, 26, 26, 27, 27, 28, 29,
+ 29, 30, 30, 30, 31, 32, 32, 33, 33, 33,
+ 34, 34, 35, 35, 35, 36, 36, 36, 37, 37,
+ 37, 38, 38, 63
+};
+
#define BITS_MASK_8 0x5555555555555555ULL
#define PAIR_MASK_8 0x3333333333333333ULL
#define NYBL_MASK_8 0x0f0f0f0f0f0f0f0fULL
@@ -76,19 +167,6 @@
return myeven | (myodd << 32);
}
-uint32_t carry_from_add64(uint64_t a, uint64_t b, uint32_t c)
-{
- uint64_t tmpa, tmpb, tmpc;
- tmpa = fGETUWORD(0, a);
- tmpb = fGETUWORD(0, b);
- tmpc = tmpa + tmpb + c;
- tmpa = fGETUWORD(1, a);
- tmpb = fGETUWORD(1, b);
- tmpc = tmpa + tmpb + fGETUWORD(1, tmpc);
- tmpc = fGETUWORD(1, tmpc);
- return tmpc;
-}
-
int32_t conv_round(int32_t a, int n)
{
int64_t val;
@@ -108,7 +186,7 @@
/* Floating Point Stuff */
-static const int softfloat_roundingmodes[] = {
+static const FloatRoundMode softfloat_roundingmodes[] = {
float_round_nearest_even,
float_round_to_zero,
float_round_down,
@@ -156,12 +234,6 @@
}
}
-static float32 float32_mul_pow2(float32 a, uint32_t p, float_status *fp_status)
-{
- float32 b = make_float32((SF_BIAS + p) << SF_MANTBITS);
- return float32_mul(a, b, fp_status);
-}
-
int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust,
float_status *fp_status)
{
@@ -200,12 +272,13 @@
/* or put Inf in num fixup? */
uint8_t RsV_sign = float32_is_neg(RsV);
uint8_t RtV_sign = float32_is_neg(RtV);
+ /* Check that RsV is NOT infinite before we overwrite it */
+ if (!float32_is_infinity(RsV)) {
+ float_raise(float_flag_divbyzero, fp_status);
+ }
RsV = infinite_float32(RsV_sign ^ RtV_sign);
RtV = float32_one;
RdV = float32_one;
- if (float32_is_infinity(RsV)) {
- float_raise(float_flag_divbyzero, fp_status);
- }
} else if (float32_is_infinity(RtV)) {
RsV = make_float32(0x80000000 & (RsV ^ RtV));
RtV = float32_one;
@@ -230,22 +303,22 @@
if ((n_exp - d_exp + SF_BIAS) <= SF_MANTBITS) {
/* Near quotient underflow / inexact Q */
PeV = 0x80;
- RtV = float32_mul_pow2(RtV, -64, fp_status);
- RsV = float32_mul_pow2(RsV, 64, fp_status);
+ RtV = float32_scalbn(RtV, -64, fp_status);
+ RsV = float32_scalbn(RsV, 64, fp_status);
} else if ((n_exp - d_exp + SF_BIAS) > (SF_MAXEXP - 24)) {
/* Near quotient overflow */
PeV = 0x40;
- RtV = float32_mul_pow2(RtV, 32, fp_status);
- RsV = float32_mul_pow2(RsV, -32, fp_status);
+ RtV = float32_scalbn(RtV, 32, fp_status);
+ RsV = float32_scalbn(RsV, -32, fp_status);
} else if (n_exp <= SF_MANTBITS + 2) {
- RtV = float32_mul_pow2(RtV, 64, fp_status);
- RsV = float32_mul_pow2(RsV, 64, fp_status);
+ RtV = float32_scalbn(RtV, 64, fp_status);
+ RsV = float32_scalbn(RsV, 64, fp_status);
} else if (d_exp <= 1) {
- RtV = float32_mul_pow2(RtV, 32, fp_status);
- RsV = float32_mul_pow2(RsV, 32, fp_status);
+ RtV = float32_scalbn(RtV, 32, fp_status);
+ RsV = float32_scalbn(RsV, 32, fp_status);
} else if (d_exp > 252) {
- RtV = float32_mul_pow2(RtV, -32, fp_status);
- RsV = float32_mul_pow2(RsV, -32, fp_status);
+ RtV = float32_scalbn(RtV, -32, fp_status);
+ RsV = float32_scalbn(RsV, -32, fp_status);
}
RdV = 0;
ret = 1;
@@ -265,7 +338,7 @@
int r_exp;
int ret = 0;
RsV = *Rs;
- if (float32_is_infinity(RsV)) {
+ if (float32_is_any_nan(RsV)) {
if (extract32(RsV, 22, 1) == 0) {
float_raise(float_flag_invalid, fp_status);
}
@@ -287,7 +360,7 @@
/* Basic checks passed */
r_exp = float32_getexp(RsV);
if (r_exp <= 24) {
- RsV = float32_mul_pow2(RsV, 64, fp_status);
+ RsV = float32_scalbn(RsV, 64, fp_status);
PeV = 0xe0;
}
RdV = 0;
@@ -298,3 +371,41 @@
*adjust = PeV;
return ret;
}
+
+const uint8_t recip_lookup_table[128] = {
+ 0x0fe, 0x0fa, 0x0f6, 0x0f2, 0x0ef, 0x0eb, 0x0e7, 0x0e4,
+ 0x0e0, 0x0dd, 0x0d9, 0x0d6, 0x0d2, 0x0cf, 0x0cc, 0x0c9,
+ 0x0c6, 0x0c2, 0x0bf, 0x0bc, 0x0b9, 0x0b6, 0x0b3, 0x0b1,
+ 0x0ae, 0x0ab, 0x0a8, 0x0a5, 0x0a3, 0x0a0, 0x09d, 0x09b,
+ 0x098, 0x096, 0x093, 0x091, 0x08e, 0x08c, 0x08a, 0x087,
+ 0x085, 0x083, 0x080, 0x07e, 0x07c, 0x07a, 0x078, 0x075,
+ 0x073, 0x071, 0x06f, 0x06d, 0x06b, 0x069, 0x067, 0x065,
+ 0x063, 0x061, 0x05f, 0x05e, 0x05c, 0x05a, 0x058, 0x056,
+ 0x054, 0x053, 0x051, 0x04f, 0x04e, 0x04c, 0x04a, 0x049,
+ 0x047, 0x045, 0x044, 0x042, 0x040, 0x03f, 0x03d, 0x03c,
+ 0x03a, 0x039, 0x037, 0x036, 0x034, 0x033, 0x032, 0x030,
+ 0x02f, 0x02d, 0x02c, 0x02b, 0x029, 0x028, 0x027, 0x025,
+ 0x024, 0x023, 0x021, 0x020, 0x01f, 0x01e, 0x01c, 0x01b,
+ 0x01a, 0x019, 0x017, 0x016, 0x015, 0x014, 0x013, 0x012,
+ 0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00b, 0x00a, 0x009,
+ 0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x000,
+};
+
+const uint8_t invsqrt_lookup_table[128] = {
+ 0x069, 0x066, 0x063, 0x061, 0x05e, 0x05b, 0x059, 0x057,
+ 0x054, 0x052, 0x050, 0x04d, 0x04b, 0x049, 0x047, 0x045,
+ 0x043, 0x041, 0x03f, 0x03d, 0x03b, 0x039, 0x037, 0x036,
+ 0x034, 0x032, 0x030, 0x02f, 0x02d, 0x02c, 0x02a, 0x028,
+ 0x027, 0x025, 0x024, 0x022, 0x021, 0x01f, 0x01e, 0x01d,
+ 0x01b, 0x01a, 0x019, 0x017, 0x016, 0x015, 0x014, 0x012,
+ 0x011, 0x010, 0x00f, 0x00d, 0x00c, 0x00b, 0x00a, 0x009,
+ 0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x001,
+ 0x0fe, 0x0fa, 0x0f6, 0x0f3, 0x0ef, 0x0eb, 0x0e8, 0x0e4,
+ 0x0e1, 0x0de, 0x0db, 0x0d7, 0x0d4, 0x0d1, 0x0ce, 0x0cb,
+ 0x0c9, 0x0c6, 0x0c3, 0x0c0, 0x0be, 0x0bb, 0x0b8, 0x0b6,
+ 0x0b3, 0x0b1, 0x0af, 0x0ac, 0x0aa, 0x0a8, 0x0a5, 0x0a3,
+ 0x0a1, 0x09f, 0x09d, 0x09b, 0x099, 0x097, 0x095, 0x093,
+ 0x091, 0x08f, 0x08d, 0x08b, 0x089, 0x087, 0x086, 0x084,
+ 0x082, 0x080, 0x07f, 0x07d, 0x07b, 0x07a, 0x078, 0x077,
+ 0x075, 0x074, 0x072, 0x071, 0x06f, 0x06e, 0x06c, 0x06b,
+};
diff --git a/target/hexagon/arch.h b/target/hexagon/arch.h
index 1f7f036..7091806 100644
--- a/target/hexagon/arch.h
+++ b/target/hexagon/arch.h
@@ -20,9 +20,12 @@
#include "qemu/int128.h"
+extern const uint8_t rLPS_table_64x4[64][4];
+extern const uint8_t AC_next_state_MPS_64[64];
+extern const uint8_t AC_next_state_LPS_64[64];
+
uint64_t interleave(uint32_t odd, uint32_t even);
uint64_t deinterleave(uint64_t src);
-uint32_t carry_from_add64(uint64_t a, uint64_t b, uint32_t c);
int32_t conv_round(int32_t a, int n);
void arch_fpop_start(CPUHexagonState *env);
void arch_fpop_end(CPUHexagonState *env);
@@ -31,4 +34,8 @@
int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust,
float_status *fp_status);
+extern const uint8_t recip_lookup_table[128];
+
+extern const uint8_t invsqrt_lookup_table[128];
+
#endif
diff --git a/target/hexagon/conv_emu.c b/target/hexagon/conv_emu.c
deleted file mode 100644
index 3985b10..0000000
--- a/target/hexagon/conv_emu.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that 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/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/host-utils.h"
-#include "fpu/softfloat.h"
-#include "macros.h"
-#include "conv_emu.h"
-
-#define LL_MAX_POS 0x7fffffffffffffffULL
-#define MAX_POS 0x7fffffffU
-
-static uint64_t conv_f64_to_8u_n(float64 in, int will_negate,
- float_status *fp_status)
-{
- uint8_t sign = float64_is_neg(in);
- if (float64_is_infinity(in)) {
- float_raise(float_flag_invalid, fp_status);
- if (float64_is_neg(in)) {
- return 0ULL;
- } else {
- return ~0ULL;
- }
- }
- if (float64_is_any_nan(in)) {
- float_raise(float_flag_invalid, fp_status);
- return ~0ULL;
- }
- if (float64_is_zero(in)) {
- return 0;
- }
- if (sign) {
- float_raise(float_flag_invalid, fp_status);
- return 0;
- }
- if (float64_lt(in, float64_half, fp_status)) {
- /* Near zero, captures large fracshifts, denorms, etc */
- float_raise(float_flag_inexact, fp_status);
- switch (get_float_rounding_mode(fp_status)) {
- case float_round_down:
- if (will_negate) {
- return 1;
- } else {
- return 0;
- }
- case float_round_up:
- if (!will_negate) {
- return 1;
- } else {
- return 0;
- }
- default:
- return 0; /* nearest or towards zero */
- }
- }
- return float64_to_uint64(in, fp_status);
-}
-
-static void clr_float_exception_flags(uint8_t flag, float_status *fp_status)
-{
- uint8_t flags = fp_status->float_exception_flags;
- flags &= ~flag;
- set_float_exception_flags(flags, fp_status);
-}
-
-static uint32_t conv_df_to_4u_n(float64 fp64, int will_negate,
- float_status *fp_status)
-{
- uint64_t tmp;
- tmp = conv_f64_to_8u_n(fp64, will_negate, fp_status);
- if (tmp > 0x00000000ffffffffULL) {
- clr_float_exception_flags(float_flag_inexact, fp_status);
- float_raise(float_flag_invalid, fp_status);
- return ~0U;
- }
- return (uint32_t)tmp;
-}
-
-uint64_t conv_df_to_8u(float64 in, float_status *fp_status)
-{
- return conv_f64_to_8u_n(in, 0, fp_status);
-}
-
-uint32_t conv_df_to_4u(float64 in, float_status *fp_status)
-{
- return conv_df_to_4u_n(in, 0, fp_status);
-}
-
-int64_t conv_df_to_8s(float64 in, float_status *fp_status)
-{
- uint8_t sign = float64_is_neg(in);
- uint64_t tmp;
- if (float64_is_any_nan(in)) {
- float_raise(float_flag_invalid, fp_status);
- return -1;
- }
- if (sign) {
- float64 minus_fp64 = float64_abs(in);
- tmp = conv_f64_to_8u_n(minus_fp64, 1, fp_status);
- } else {
- tmp = conv_f64_to_8u_n(in, 0, fp_status);
- }
- if (tmp > (LL_MAX_POS + sign)) {
- clr_float_exception_flags(float_flag_inexact, fp_status);
- float_raise(float_flag_invalid, fp_status);
- tmp = (LL_MAX_POS + sign);
- }
- if (sign) {
- return -tmp;
- } else {
- return tmp;
- }
-}
-
-int32_t conv_df_to_4s(float64 in, float_status *fp_status)
-{
- uint8_t sign = float64_is_neg(in);
- uint64_t tmp;
- if (float64_is_any_nan(in)) {
- float_raise(float_flag_invalid, fp_status);
- return -1;
- }
- if (sign) {
- float64 minus_fp64 = float64_abs(in);
- tmp = conv_f64_to_8u_n(minus_fp64, 1, fp_status);
- } else {
- tmp = conv_f64_to_8u_n(in, 0, fp_status);
- }
- if (tmp > (MAX_POS + sign)) {
- clr_float_exception_flags(float_flag_inexact, fp_status);
- float_raise(float_flag_invalid, fp_status);
- tmp = (MAX_POS + sign);
- }
- if (sign) {
- return -tmp;
- } else {
- return tmp;
- }
-}
-
-uint64_t conv_sf_to_8u(float32 in, float_status *fp_status)
-{
- float64 fp64 = float32_to_float64(in, fp_status);
- return conv_df_to_8u(fp64, fp_status);
-}
-
-uint32_t conv_sf_to_4u(float32 in, float_status *fp_status)
-{
- float64 fp64 = float32_to_float64(in, fp_status);
- return conv_df_to_4u(fp64, fp_status);
-}
-
-int64_t conv_sf_to_8s(float32 in, float_status *fp_status)
-{
- float64 fp64 = float32_to_float64(in, fp_status);
- return conv_df_to_8s(fp64, fp_status);
-}
-
-int32_t conv_sf_to_4s(float32 in, float_status *fp_status)
-{
- float64 fp64 = float32_to_float64(in, fp_status);
- return conv_df_to_4s(fp64, fp_status);
-}
diff --git a/target/hexagon/conv_emu.h b/target/hexagon/conv_emu.h
deleted file mode 100644
index cade9de..0000000
--- a/target/hexagon/conv_emu.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that 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/>.
- */
-
-#ifndef HEXAGON_CONV_EMU_H
-#define HEXAGON_CONV_EMU_H
-
-uint64_t conv_sf_to_8u(float32 in, float_status *fp_status);
-uint32_t conv_sf_to_4u(float32 in, float_status *fp_status);
-int64_t conv_sf_to_8s(float32 in, float_status *fp_status);
-int32_t conv_sf_to_4s(float32 in, float_status *fp_status);
-
-uint64_t conv_df_to_8u(float64 in, float_status *fp_status);
-uint32_t conv_df_to_4u(float64 in, float_status *fp_status);
-int64_t conv_df_to_8s(float64 in, float_status *fp_status);
-int32_t conv_df_to_4s(float64 in, float_status *fp_status);
-
-#endif
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 543fceb..ebe60a6 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -22,6 +22,7 @@
#include "exec/exec-all.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
+#include "fpu/softfloat-helpers.h"
static void hexagon_v67_cpu_init(Object *obj)
{
@@ -68,10 +69,9 @@
* stacks at different locations. This is used to compensate so the diff is
* cleaner.
*/
-static inline target_ulong adjust_stack_ptrs(CPUHexagonState *env,
- target_ulong addr)
+static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr)
{
- HexagonCPU *cpu = container_of(env, HexagonCPU, env);
+ HexagonCPU *cpu = env_archcpu(env);
target_ulong stack_adjust = cpu->lldb_stack_adjust;
target_ulong stack_start = env->stack_start;
target_ulong stack_size = 0x10000;
@@ -87,7 +87,7 @@
}
/* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */
-static inline target_ulong read_p3_0(CPUHexagonState *env)
+static target_ulong read_p3_0(CPUHexagonState *env)
{
int32_t control_reg = 0;
int i;
@@ -115,7 +115,7 @@
static void hexagon_dump(CPUHexagonState *env, FILE *f)
{
- HexagonCPU *cpu = container_of(env, HexagonCPU, env);
+ HexagonCPU *cpu = env_archcpu(env);
if (cpu->lldb_compat) {
/*
@@ -205,8 +205,12 @@
CPUState *cs = CPU(dev);
HexagonCPU *cpu = HEXAGON_CPU(cs);
HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(cpu);
+ CPUHexagonState *env = &cpu->env;
mcc->parent_reset(dev);
+
+ set_default_nan_mode(1, &env->fp_status);
+ set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
}
static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index e04eac5..2855dd3 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -127,11 +127,6 @@
target_ulong lldb_stack_adjust;
} HexagonCPU;
-static inline HexagonCPU *hexagon_env_get_cpu(CPUHexagonState *env)
-{
- return container_of(env, HexagonCPU, env);
-}
-
#include "cpu_bits.h"
#define cpu_signal_handler cpu_hexagon_signal_handler
diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h
index 96af834..96fef71 100644
--- a/target/hexagon/cpu_bits.h
+++ b/target/hexagon/cpu_bits.h
@@ -47,7 +47,7 @@
return iclass;
}
-static inline int is_packet_end(uint32_t endocing)
+static inline bool is_packet_end(uint32_t endocing)
{
uint32_t bits = parse_bits(endocing);
return ((bits == 0x3) || (bits == 0x0));
diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index 9bcc8c9..d424245 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -47,8 +47,8 @@
DEF_REGMAP(R_16, 16, 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23)
DEF_REGMAP(R__8, 8, 0, 2, 4, 6, 16, 18, 20, 22)
-#define DECODE_MAPPED_REG(REGNO, NAME) \
- insn->regno[REGNO] = DECODE_REGISTER_##NAME[insn->regno[REGNO]];
+#define DECODE_MAPPED_REG(OPNUM, NAME) \
+ insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
typedef struct {
const struct DectreeTable *table_link;
@@ -339,8 +339,8 @@
if (GET_ATTRIB(pkt->insn[i].opcode, A_NEWCMPJUMP)) {
last = pkt->num_insns;
pkt->insn[last] = pkt->insn[i]; /* copy the instruction */
- pkt->insn[last].part1 = 1; /* last instruction does the CMP */
- pkt->insn[i].part1 = 0; /* existing instruction does the JUMP */
+ pkt->insn[last].part1 = true; /* last insn does the CMP */
+ pkt->insn[i].part1 = false; /* existing insn does the JUMP */
pkt->num_insns++;
}
}
@@ -353,7 +353,7 @@
}
}
-static inline int decode_opcode_can_jump(int opcode)
+static bool decode_opcode_can_jump(int opcode)
{
if ((GET_ATTRIB(opcode, A_JUMP)) ||
(GET_ATTRIB(opcode, A_CALL)) ||
@@ -361,15 +361,15 @@
(opcode == J2_pause)) {
/* Exception to A_JUMP attribute */
if (opcode == J4_hintjumpr) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-static inline int decode_opcode_ends_loop(int opcode)
+static bool decode_opcode_ends_loop(int opcode)
{
return GET_ATTRIB(opcode, A_HWLOOP0_END) ||
GET_ATTRIB(opcode, A_HWLOOP1_END);
@@ -382,9 +382,9 @@
int numinsns = pkt->num_insns;
uint16_t opcode;
- pkt->pkt_has_cof = 0;
- pkt->pkt_has_endloop = 0;
- pkt->pkt_has_dczeroa = 0;
+ pkt->pkt_has_cof = false;
+ pkt->pkt_has_endloop = false;
+ pkt->pkt_has_dczeroa = false;
for (i = 0; i < numinsns; i++) {
opcode = pkt->insn[i].opcode;
@@ -393,14 +393,14 @@
}
if (GET_ATTRIB(opcode, A_DCZEROA)) {
- pkt->pkt_has_dczeroa = 1;
+ pkt->pkt_has_dczeroa = true;
}
if (GET_ATTRIB(opcode, A_STORE)) {
if (pkt->insn[i].slot == 0) {
- pkt->pkt_has_store_s0 = 1;
+ pkt->pkt_has_store_s0 = true;
} else {
- pkt->pkt_has_store_s1 = 1;
+ pkt->pkt_has_store_s1 = true;
}
}
@@ -421,9 +421,9 @@
*/
static void decode_shuffle_for_execution(Packet *packet)
{
- int changed = 0;
+ bool changed = false;
int i;
- int flag; /* flag means we've seen a non-memory instruction */
+ bool flag; /* flag means we've seen a non-memory instruction */
int n_mems;
int last_insn = packet->num_insns - 1;
@@ -436,7 +436,7 @@
}
do {
- changed = 0;
+ changed = false;
/*
* Stores go last, must not reorder.
* Cannot shuffle stores past loads, either.
@@ -444,13 +444,13 @@
* then a store, shuffle the store to the front. Don't shuffle
* stores wrt each other or a load.
*/
- for (flag = n_mems = 0, i = last_insn; i >= 0; i--) {
+ for (flag = false, n_mems = 0, i = last_insn; i >= 0; i--) {
int opcode = packet->insn[i].opcode;
if (flag && GET_ATTRIB(opcode, A_STORE)) {
decode_send_insn_to(packet, i, last_insn - n_mems);
n_mems++;
- changed = 1;
+ changed = true;
} else if (GET_ATTRIB(opcode, A_STORE)) {
n_mems++;
} else if (GET_ATTRIB(opcode, A_LOAD)) {
@@ -465,7 +465,7 @@
* a .new value
*/
} else {
- flag = 1;
+ flag = true;
}
}
@@ -473,7 +473,7 @@
continue;
}
/* Compares go first, may be reordered wrt each other */
- for (flag = 0, i = 0; i < last_insn + 1; i++) {
+ for (flag = false, i = 0; i < last_insn + 1; i++) {
int opcode = packet->insn[i].opcode;
if ((strstr(opcode_wregs[opcode], "Pd4") ||
@@ -482,7 +482,7 @@
/* This should be a compare (not a store conditional) */
if (flag) {
decode_send_insn_to(packet, i, 0);
- changed = 1;
+ changed = true;
continue;
}
} else if (GET_ATTRIB(opcode, A_IMPLICIT_WRITES_P3) &&
@@ -494,18 +494,18 @@
*/
if (flag) {
decode_send_insn_to(packet, i, 0);
- changed = 1;
+ changed = true;
continue;
}
} else if (GET_ATTRIB(opcode, A_IMPLICIT_WRITES_P0) &&
!GET_ATTRIB(opcode, A_NEWCMPJUMP)) {
if (flag) {
decode_send_insn_to(packet, i, 0);
- changed = 1;
+ changed = true;
continue;
}
} else {
- flag = 1;
+ flag = true;
}
}
if (changed) {
@@ -542,7 +542,7 @@
int i;
for (i = 0; i < packet->num_insns; i++) {
if (GET_ATTRIB(packet->insn[i].opcode, A_IT_EXTENDER)) {
- packet->insn[i + 1].extension_valid = 1;
+ packet->insn[i + 1].extension_valid = true;
apply_extender(packet, i + 1, packet->insn[i].immed[0]);
}
}
@@ -763,7 +763,7 @@
}
}
-static inline int decode_parsebits_is_loopend(uint32_t encoding32)
+static bool decode_parsebits_is_loopend(uint32_t encoding32)
{
uint32_t bits = parse_bits(encoding32);
return bits == 0x2;
@@ -774,8 +774,11 @@
{
int slot;
int i;
- int hit_mem_insn = 0;
- int hit_duplex = 0;
+ bool hit_mem_insn = false;
+ bool hit_duplex = false;
+ bool slot0_found = false;
+ bool slot1_found = false;
+ int slot1_iidx = 0;
/*
* The slots are encoded in reverse order
@@ -800,7 +803,7 @@
if ((GET_ATTRIB(pkt->insn[i].opcode, A_MEMLIKE) ||
GET_ATTRIB(pkt->insn[i].opcode, A_MEMLIKE_PACKET_RULES)) &&
!hit_mem_insn) {
- hit_mem_insn = 1;
+ hit_mem_insn = true;
pkt->insn[i].slot = 0;
continue;
}
@@ -817,7 +820,7 @@
for (i = pkt->num_insns - 1; i >= 0; i--) {
/* First subinsn always goes to slot 0 */
if (GET_ATTRIB(pkt->insn[i].opcode, A_SUBINSN) && !hit_duplex) {
- hit_duplex = 1;
+ hit_duplex = true;
pkt->insn[i].slot = 0;
continue;
}
@@ -829,13 +832,10 @@
}
/* Fix the exceptions - slot 1 is never empty, always aligns to slot 0 */
- int slot0_found = 0;
- int slot1_found = 0;
- int slot1_iidx = 0;
for (i = pkt->num_insns - 1; i >= 0; i--) {
/* Is slot0 used? */
if (pkt->insn[i].slot == 0) {
- int is_endloop = (pkt->insn[i].opcode == J2_endloop01);
+ bool is_endloop = (pkt->insn[i].opcode == J2_endloop01);
is_endloop |= (pkt->insn[i].opcode == J2_endloop0);
is_endloop |= (pkt->insn[i].opcode == J2_endloop1);
@@ -844,17 +844,17 @@
* slot0 for endloop
*/
if (!is_endloop) {
- slot0_found = 1;
+ slot0_found = true;
}
}
/* Is slot1 used? */
if (pkt->insn[i].slot == 1) {
- slot1_found = 1;
+ slot1_found = true;
slot1_iidx = i;
}
}
/* Is slot0 empty and slot1 used? */
- if ((slot0_found == 0) && (slot1_found == 1)) {
+ if ((!slot0_found) && slot1_found) {
/* Then push it to slot0 */
pkt->insn[slot1_iidx].slot = 0;
}
@@ -872,7 +872,7 @@
{
int num_insns = 0;
int words_read = 0;
- int end_of_packet = 0;
+ bool end_of_packet = false;
int new_insns = 0;
uint32_t encoding32;
@@ -889,7 +889,7 @@
* decode works
*/
if (pkt->insn[num_insns].opcode == A4_ext) {
- pkt->insn[num_insns + 1].extension_valid = 1;
+ pkt->insn[num_insns + 1].extension_valid = true;
}
num_insns += new_insns;
words_read++;
@@ -912,7 +912,7 @@
decode_add_endloop_insn(&pkt->insn[pkt->num_insns++], 0);
}
if (words_read >= 3) {
- uint32_t has_loop0, has_loop1;
+ bool has_loop0, has_loop1;
has_loop0 = decode_parsebits_is_loopend(words[0]);
has_loop1 = decode_parsebits_is_loopend(words[1]);
if (has_loop0 && has_loop1) {
diff --git a/target/hexagon/fma_emu.c b/target/hexagon/fma_emu.c
index 842d903..d3b45d4 100644
--- a/target/hexagon/fma_emu.c
+++ b/target/hexagon/fma_emu.c
@@ -19,7 +19,6 @@
#include "qemu/int128.h"
#include "fpu/softfloat.h"
#include "macros.h"
-#include "conv_emu.h"
#include "fma_emu.h"
#define DF_INF_EXP 0x7ff
@@ -64,7 +63,7 @@
};
} Float;
-static inline uint64_t float64_getmant(float64 f64)
+static uint64_t float64_getmant(float64 f64)
{
Double a = { .i = f64 };
if (float64_is_normal(f64)) {
@@ -91,7 +90,7 @@
return -1;
}
-static inline uint64_t float32_getmant(float32 f32)
+static uint64_t float32_getmant(float32 f32)
{
Float a = { .i = f32 };
if (float32_is_normal(f32)) {
@@ -118,17 +117,17 @@
return -1;
}
-static inline uint32_t int128_getw0(Int128 x)
+static uint32_t int128_getw0(Int128 x)
{
return int128_getlo(x);
}
-static inline uint32_t int128_getw1(Int128 x)
+static uint32_t int128_getw1(Int128 x)
{
return int128_getlo(x) >> 32;
}
-static inline Int128 int128_mul_6464(uint64_t ai, uint64_t bi)
+static Int128 int128_mul_6464(uint64_t ai, uint64_t bi)
{
Int128 a, b;
uint64_t pp0, pp1a, pp1b, pp1s, pp2;
@@ -152,7 +151,7 @@
return int128_make128(ret_low, pp2 + (pp1s >> 32));
}
-static inline Int128 int128_sub_borrow(Int128 a, Int128 b, int borrow)
+static Int128 int128_sub_borrow(Int128 a, Int128 b, int borrow)
{
Int128 ret = int128_sub(a, b);
if (borrow != 0) {
@@ -170,7 +169,7 @@
uint8_t sticky;
} Accum;
-static inline void accum_init(Accum *p)
+static void accum_init(Accum *p)
{
p->mant = int128_zero();
p->exp = 0;
@@ -180,7 +179,7 @@
p->sticky = 0;
}
-static inline Accum accum_norm_left(Accum a)
+static Accum accum_norm_left(Accum a)
{
a.exp--;
a.mant = int128_lshift(a.mant, 1);
@@ -190,6 +189,7 @@
return a;
}
+/* This function is marked inline for performance reasons */
static inline Accum accum_norm_right(Accum a, int amt)
{
if (amt > 130) {
@@ -226,7 +226,7 @@
*/
static Accum accum_add(Accum a, Accum b);
-static inline Accum accum_sub(Accum a, Accum b, int negate)
+static Accum accum_sub(Accum a, Accum b, int negate)
{
Accum ret;
accum_init(&ret);
@@ -329,7 +329,7 @@
}
/* Return an infinity with requested sign */
-static inline float64 infinite_float64(uint8_t sign)
+static float64 infinite_float64(uint8_t sign)
{
if (sign) {
return make_float64(DF_MINUS_INF);
@@ -339,7 +339,7 @@
}
/* Return a maximum finite value with requested sign */
-static inline float64 maxfinite_float64(uint8_t sign)
+static float64 maxfinite_float64(uint8_t sign)
{
if (sign) {
return make_float64(DF_MINUS_MAXF);
@@ -349,7 +349,7 @@
}
/* Return a zero value with requested sign */
-static inline float64 zero_float64(uint8_t sign)
+static float64 zero_float64(uint8_t sign)
{
if (sign) {
return make_float64(0x8000000000000000);
@@ -369,7 +369,7 @@
}
/* Return a maximum finite value with the requested sign */
-static inline float32 maxfinite_float32(uint8_t sign)
+static float32 maxfinite_float32(uint8_t sign)
{
if (sign) {
return make_float32(SF_MINUS_MAXF);
@@ -379,7 +379,7 @@
}
/* Return a zero value with requested sign */
-static inline float32 zero_float32(uint8_t sign)
+static float32 zero_float32(uint8_t sign)
{
if (sign) {
return make_float32(0x80000000);
@@ -389,7 +389,7 @@
}
#define GEN_XF_ROUND(SUFFIX, MANTBITS, INF_EXP, INTERNAL_TYPE) \
-static inline SUFFIX accum_round_##SUFFIX(Accum a, float_status * fp_status) \
+static SUFFIX accum_round_##SUFFIX(Accum a, float_status * fp_status) \
{ \
if ((int128_gethi(a.mant) == 0) && (int128_getlo(a.mant) == 0) \
&& ((a.guard | a.round | a.sticky) == 0)) { \
@@ -526,8 +526,8 @@
(float64_is_infinity(b) && is_finite(a) && (!float64_is_zero(a))));
}
-static inline float64 special_fma(float64 a, float64 b, float64 c,
- float_status *fp_status)
+static float64 special_fma(float64 a, float64 b, float64 c,
+ float_status *fp_status)
{
float64 ret = make_float64(0);
@@ -586,8 +586,8 @@
g_assert_not_reached();
}
-static inline float32 special_fmaf(float32 a, float32 b, float32 c,
- float_status *fp_status)
+static float32 special_fmaf(float32 a, float32 b, float32 c,
+ float_status *fp_status)
{
float64 aa, bb, cc;
aa = float32_to_float64(a, fp_status);
diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
index e044dea..18fcdbc 100644
--- a/target/hexagon/gen_tcg.h
+++ b/target/hexagon/gen_tcg.h
@@ -37,7 +37,10 @@
* _sp stack pointer relative r0 = memw(r29+#12)
* _ap absolute set r0 = memw(r1=##variable)
* _pr post increment register r0 = memw(r1++m1)
+ * _pbr post increment bit reverse r0 = memw(r1++m1:brev)
* _pi post increment immediate r0 = memb(r1++#1)
+ * _pci post increment circular immediate r0 = memw(r1++#4:circ(m0))
+ * _pcr post increment circular register r0 = memw(r1++I:circ(m0))
*/
/* Macros for complex addressing modes */
@@ -51,12 +54,32 @@
fEA_REG(RxV); \
fPM_M(RxV, MuV); \
} while (0)
+#define GET_EA_pbr \
+ do { \
+ gen_helper_fbrev(EA, RxV); \
+ tcg_gen_add_tl(RxV, RxV, MuV); \
+ } while (0)
#define GET_EA_pi \
do { \
fEA_REG(RxV); \
fPM_I(RxV, siV); \
} while (0)
-
+#define GET_EA_pci \
+ do { \
+ TCGv tcgv_siV = tcg_const_tl(siV); \
+ tcg_gen_mov_tl(EA, RxV); \
+ gen_helper_fcircadd(RxV, RxV, tcgv_siV, MuV, \
+ hex_gpr[HEX_REG_CS0 + MuN]); \
+ tcg_temp_free(tcgv_siV); \
+ } while (0)
+#define GET_EA_pcr(SHIFT) \
+ do { \
+ TCGv ireg = tcg_temp_new(); \
+ tcg_gen_mov_tl(EA, RxV); \
+ gen_read_ireg(ireg, MuV, (SHIFT)); \
+ gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
+ tcg_temp_free(ireg); \
+ } while (0)
/* Instructions with multiple definitions */
#define fGEN_TCG_LOAD_AP(RES, SIZE, SIGN) \
@@ -80,20 +103,230 @@
#define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \
fGEN_TCG_LOAD_AP(RddV, 8, u)
+#define fGEN_TCG_L2_loadrub_pci(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrb_pci(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadruh_pci(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrh_pci(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadri_pci(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrd_pci(SHORTCODE) SHORTCODE
+
+#define fGEN_TCG_LOAD_pcr(SHIFT, LOAD) \
+ do { \
+ TCGv ireg = tcg_temp_new(); \
+ tcg_gen_mov_tl(EA, RxV); \
+ gen_read_ireg(ireg, MuV, SHIFT); \
+ gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
+ LOAD; \
+ tcg_temp_free(ireg); \
+ } while (0)
+
+#define fGEN_TCG_L2_loadrub_pcr(SHORTCODE) \
+ fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, u, EA, RdV))
+#define fGEN_TCG_L2_loadrb_pcr(SHORTCODE) \
+ fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, s, EA, RdV))
+#define fGEN_TCG_L2_loadruh_pcr(SHORTCODE) \
+ fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, u, EA, RdV))
+#define fGEN_TCG_L2_loadrh_pcr(SHORTCODE) \
+ fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, s, EA, RdV))
+#define fGEN_TCG_L2_loadri_pcr(SHORTCODE) \
+ fGEN_TCG_LOAD_pcr(2, fLOAD(1, 4, u, EA, RdV))
+#define fGEN_TCG_L2_loadrd_pcr(SHORTCODE) \
+ fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV))
+
#define fGEN_TCG_L2_loadrub_pr(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrub_pbr(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadrub_pi(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadrb_pr(SHORTCODE) SHORTCODE
-#define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE;
+#define fGEN_TCG_L2_loadrb_pbr(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadruh_pr(SHORTCODE) SHORTCODE
-#define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE;
+#define fGEN_TCG_L2_loadruh_pbr(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadrh_pr(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrh_pbr(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadrh_pi(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadri_pr(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadri_pbr(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadri_pi(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadrd_pr(SHORTCODE) SHORTCODE
+#define fGEN_TCG_L2_loadrd_pbr(SHORTCODE) SHORTCODE
#define fGEN_TCG_L2_loadrd_pi(SHORTCODE) SHORTCODE
/*
+ * These instructions load 2 bytes and places them in
+ * two halves of the destination register.
+ * The GET_EA macro determines the addressing mode.
+ * The SIGN argument determines whether to zero-extend or
+ * sign-extend.
+ */
+#define fGEN_TCG_loadbXw2(GET_EA, SIGN) \
+ do { \
+ TCGv tmp = tcg_temp_new(); \
+ TCGv byte = tcg_temp_new(); \
+ GET_EA; \
+ fLOAD(1, 2, u, EA, tmp); \
+ tcg_gen_movi_tl(RdV, 0); \
+ for (int i = 0; i < 2; i++) { \
+ gen_set_half(i, RdV, gen_get_byte(byte, i, tmp, (SIGN))); \
+ } \
+ tcg_temp_free(tmp); \
+ tcg_temp_free(byte); \
+ } while (0)
+
+#define fGEN_TCG_L2_loadbzw2_io(SHORTCODE) \
+ fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), false)
+#define fGEN_TCG_L4_loadbzw2_ur(SHORTCODE) \
+ fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), false)
+#define fGEN_TCG_L2_loadbsw2_io(SHORTCODE) \
+ fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), true)
+#define fGEN_TCG_L4_loadbsw2_ur(SHORTCODE) \
+ fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), true)
+#define fGEN_TCG_L4_loadbzw2_ap(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_ap, false)
+#define fGEN_TCG_L2_loadbzw2_pr(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pr, false)
+#define fGEN_TCG_L2_loadbzw2_pbr(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pbr, false)
+#define fGEN_TCG_L2_loadbzw2_pi(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pi, false)
+#define fGEN_TCG_L4_loadbsw2_ap(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_ap, true)
+#define fGEN_TCG_L2_loadbsw2_pr(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pr, true)
+#define fGEN_TCG_L2_loadbsw2_pbr(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pbr, true)
+#define fGEN_TCG_L2_loadbsw2_pi(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pi, true)
+#define fGEN_TCG_L2_loadbzw2_pci(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pci, false)
+#define fGEN_TCG_L2_loadbsw2_pci(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pci, true)
+#define fGEN_TCG_L2_loadbzw2_pcr(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pcr(1), false)
+#define fGEN_TCG_L2_loadbsw2_pcr(SHORTCODE) \
+ fGEN_TCG_loadbXw2(GET_EA_pcr(1), true)
+
+/*
+ * These instructions load 4 bytes and places them in
+ * four halves of the destination register pair.
+ * The GET_EA macro determines the addressing mode.
+ * The SIGN argument determines whether to zero-extend or
+ * sign-extend.
+ */
+#define fGEN_TCG_loadbXw4(GET_EA, SIGN) \
+ do { \
+ TCGv tmp = tcg_temp_new(); \
+ TCGv byte = tcg_temp_new(); \
+ GET_EA; \
+ fLOAD(1, 4, u, EA, tmp); \
+ tcg_gen_movi_i64(RddV, 0); \
+ for (int i = 0; i < 4; i++) { \
+ gen_set_half_i64(i, RddV, gen_get_byte(byte, i, tmp, (SIGN))); \
+ } \
+ tcg_temp_free(tmp); \
+ tcg_temp_free(byte); \
+ } while (0)
+
+#define fGEN_TCG_L2_loadbzw4_io(SHORTCODE) \
+ fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), false)
+#define fGEN_TCG_L4_loadbzw4_ur(SHORTCODE) \
+ fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), false)
+#define fGEN_TCG_L2_loadbsw4_io(SHORTCODE) \
+ fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), true)
+#define fGEN_TCG_L4_loadbsw4_ur(SHORTCODE) \
+ fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), true)
+#define fGEN_TCG_L2_loadbzw4_pci(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pci, false)
+#define fGEN_TCG_L2_loadbsw4_pci(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pci, true)
+#define fGEN_TCG_L2_loadbzw4_pcr(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pcr(2), false)
+#define fGEN_TCG_L2_loadbsw4_pcr(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pcr(2), true)
+#define fGEN_TCG_L4_loadbzw4_ap(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_ap, false)
+#define fGEN_TCG_L2_loadbzw4_pr(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pr, false)
+#define fGEN_TCG_L2_loadbzw4_pbr(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pbr, false)
+#define fGEN_TCG_L2_loadbzw4_pi(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pi, false)
+#define fGEN_TCG_L4_loadbsw4_ap(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_ap, true)
+#define fGEN_TCG_L2_loadbsw4_pr(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pr, true)
+#define fGEN_TCG_L2_loadbsw4_pbr(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pbr, true)
+#define fGEN_TCG_L2_loadbsw4_pi(SHORTCODE) \
+ fGEN_TCG_loadbXw4(GET_EA_pi, true)
+
+/*
+ * These instructions load a half word, shift the destination right by 16 bits
+ * and place the loaded value in the high half word of the destination pair.
+ * The GET_EA macro determines the addressing mode.
+ */
+#define fGEN_TCG_loadalignh(GET_EA) \
+ do { \
+ TCGv tmp = tcg_temp_new(); \
+ TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
+ GET_EA; \
+ fLOAD(1, 2, u, EA, tmp); \
+ tcg_gen_extu_i32_i64(tmp_i64, tmp); \
+ tcg_gen_shri_i64(RyyV, RyyV, 16); \
+ tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 48, 16); \
+ tcg_temp_free(tmp); \
+ tcg_temp_free_i64(tmp_i64); \
+ } while (0)
+
+#define fGEN_TCG_L4_loadalignh_ur(SHORTCODE) \
+ fGEN_TCG_loadalignh(fEA_IRs(UiV, RtV, uiV))
+#define fGEN_TCG_L2_loadalignh_io(SHORTCODE) \
+ fGEN_TCG_loadalignh(fEA_RI(RsV, siV))
+#define fGEN_TCG_L2_loadalignh_pci(SHORTCODE) \
+ fGEN_TCG_loadalignh(GET_EA_pci)
+#define fGEN_TCG_L2_loadalignh_pcr(SHORTCODE) \
+ fGEN_TCG_loadalignh(GET_EA_pcr(1))
+#define fGEN_TCG_L4_loadalignh_ap(SHORTCODE) \
+ fGEN_TCG_loadalignh(GET_EA_ap)
+#define fGEN_TCG_L2_loadalignh_pr(SHORTCODE) \
+ fGEN_TCG_loadalignh(GET_EA_pr)
+#define fGEN_TCG_L2_loadalignh_pbr(SHORTCODE) \
+ fGEN_TCG_loadalignh(GET_EA_pbr)
+#define fGEN_TCG_L2_loadalignh_pi(SHORTCODE) \
+ fGEN_TCG_loadalignh(GET_EA_pi)
+
+/* Same as above, but loads a byte instead of half word */
+#define fGEN_TCG_loadalignb(GET_EA) \
+ do { \
+ TCGv tmp = tcg_temp_new(); \
+ TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
+ GET_EA; \
+ fLOAD(1, 1, u, EA, tmp); \
+ tcg_gen_extu_i32_i64(tmp_i64, tmp); \
+ tcg_gen_shri_i64(RyyV, RyyV, 8); \
+ tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 56, 8); \
+ tcg_temp_free(tmp); \
+ tcg_temp_free_i64(tmp_i64); \
+ } while (0)
+
+#define fGEN_TCG_L2_loadalignb_io(SHORTCODE) \
+ fGEN_TCG_loadalignb(fEA_RI(RsV, siV))
+#define fGEN_TCG_L4_loadalignb_ur(SHORTCODE) \
+ fGEN_TCG_loadalignb(fEA_IRs(UiV, RtV, uiV))
+#define fGEN_TCG_L2_loadalignb_pci(SHORTCODE) \
+ fGEN_TCG_loadalignb(GET_EA_pci)
+#define fGEN_TCG_L2_loadalignb_pcr(SHORTCODE) \
+ fGEN_TCG_loadalignb(GET_EA_pcr(0))
+#define fGEN_TCG_L4_loadalignb_ap(SHORTCODE) \
+ fGEN_TCG_loadalignb(GET_EA_ap)
+#define fGEN_TCG_L2_loadalignb_pr(SHORTCODE) \
+ fGEN_TCG_loadalignb(GET_EA_pr)
+#define fGEN_TCG_L2_loadalignb_pbr(SHORTCODE) \
+ fGEN_TCG_loadalignb(GET_EA_pbr)
+#define fGEN_TCG_L2_loadalignb_pi(SHORTCODE) \
+ fGEN_TCG_loadalignb(GET_EA_pi)
+
+/*
* Predicated loads
* Here is a primer to understand the tag names
*
@@ -195,6 +428,191 @@
#define fGEN_TCG_S4_stored_locked(SHORTCODE) \
do { SHORTCODE; READ_PREG(PdV, PdN); } while (0)
+#define fGEN_TCG_STORE(SHORTCODE) \
+ do { \
+ TCGv HALF = tcg_temp_new(); \
+ TCGv BYTE = tcg_temp_new(); \
+ SHORTCODE; \
+ tcg_temp_free(HALF); \
+ tcg_temp_free(BYTE); \
+ } while (0)
+
+#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \
+ do { \
+ TCGv ireg = tcg_temp_new(); \
+ TCGv HALF = tcg_temp_new(); \
+ TCGv BYTE = tcg_temp_new(); \
+ tcg_gen_mov_tl(EA, RxV); \
+ gen_read_ireg(ireg, MuV, SHIFT); \
+ gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
+ STORE; \
+ tcg_temp_free(ireg); \
+ tcg_temp_free(HALF); \
+ tcg_temp_free(BYTE); \
+ } while (0)
+
+#define fGEN_TCG_S2_storerb_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerb_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV)))
+
+#define fGEN_TCG_S2_storerh_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerh_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV)))
+
+#define fGEN_TCG_S2_storerf_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerf_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV)))
+
+#define fGEN_TCG_S2_storeri_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storeri_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV))
+
+#define fGEN_TCG_S2_storerd_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerd_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV))
+
+#define fGEN_TCG_S2_storerbnew_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN)))
+
+#define fGEN_TCG_S2_storerhnew_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN)))
+
+#define fGEN_TCG_S2_storerinew_pbr(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \
+ fGEN_TCG_STORE(SHORTCODE)
+#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \
+ fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN))
+
+/*
+ * Mathematical operations with more than one definition require
+ * special handling
+ */
+#define fGEN_TCG_A5_ACS(SHORTCODE) \
+ do { \
+ gen_helper_vacsh_pred(PeV, cpu_env, RxxV, RssV, RttV); \
+ gen_helper_vacsh_val(RxxV, cpu_env, RxxV, RssV, RttV); \
+ } while (0)
+
+/*
+ * Approximate reciprocal
+ * r3,p1 = sfrecipa(r0, r1)
+ *
+ * The helper packs the 2 32-bit results into a 64-bit value,
+ * so unpack them into the proper results.
+ */
+#define fGEN_TCG_F2_sfrecipa(SHORTCODE) \
+ do { \
+ TCGv_i64 tmp = tcg_temp_new_i64(); \
+ gen_helper_sfrecipa(tmp, cpu_env, RsV, RtV); \
+ tcg_gen_extrh_i64_i32(RdV, tmp); \
+ tcg_gen_extrl_i64_i32(PeV, tmp); \
+ tcg_temp_free_i64(tmp); \
+ } while (0)
+
+/*
+ * Approximation of the reciprocal square root
+ * r1,p0 = sfinvsqrta(r0)
+ *
+ * The helper packs the 2 32-bit results into a 64-bit value,
+ * so unpack them into the proper results.
+ */
+#define fGEN_TCG_F2_sfinvsqrta(SHORTCODE) \
+ do { \
+ TCGv_i64 tmp = tcg_temp_new_i64(); \
+ gen_helper_sfinvsqrta(tmp, cpu_env, RsV); \
+ tcg_gen_extrh_i64_i32(RdV, tmp); \
+ tcg_gen_extrl_i64_i32(PeV, tmp); \
+ tcg_temp_free_i64(tmp); \
+ } while (0)
+
+/*
+ * Add or subtract with carry.
+ * Predicate register is used as an extra input and output.
+ * r5:4 = add(r1:0, r3:2, p1):carry
+ */
+#define fGEN_TCG_A4_addp_c(SHORTCODE) \
+ do { \
+ TCGv_i64 carry = tcg_temp_new_i64(); \
+ TCGv_i64 zero = tcg_const_i64(0); \
+ tcg_gen_extu_i32_i64(carry, PxV); \
+ tcg_gen_andi_i64(carry, carry, 1); \
+ tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
+ tcg_gen_add2_i64(RddV, carry, RddV, carry, RttV, zero); \
+ tcg_gen_extrl_i64_i32(PxV, carry); \
+ gen_8bitsof(PxV, PxV); \
+ tcg_temp_free_i64(carry); \
+ tcg_temp_free_i64(zero); \
+ } while (0)
+
+/* r5:4 = sub(r1:0, r3:2, p1):carry */
+#define fGEN_TCG_A4_subp_c(SHORTCODE) \
+ do { \
+ TCGv_i64 carry = tcg_temp_new_i64(); \
+ TCGv_i64 zero = tcg_const_i64(0); \
+ TCGv_i64 not_RttV = tcg_temp_new_i64(); \
+ tcg_gen_extu_i32_i64(carry, PxV); \
+ tcg_gen_andi_i64(carry, carry, 1); \
+ tcg_gen_not_i64(not_RttV, RttV); \
+ tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
+ tcg_gen_add2_i64(RddV, carry, RddV, carry, not_RttV, zero); \
+ tcg_gen_extrl_i64_i32(PxV, carry); \
+ gen_8bitsof(PxV, PxV); \
+ tcg_temp_free_i64(carry); \
+ tcg_temp_free_i64(zero); \
+ tcg_temp_free_i64(not_RttV); \
+ } while (0)
+
+/*
+ * Compare each of the 8 unsigned bytes
+ * The minimum is placed in each byte of the destination.
+ * Each bit of the predicate is set true if the bit from the first operand
+ * is greater than the bit from the second operand.
+ * r5:4,p1 = vminub(r1:0, r3:2)
+ */
+#define fGEN_TCG_A6_vminub_RdP(SHORTCODE) \
+ do { \
+ TCGv left = tcg_temp_new(); \
+ TCGv right = tcg_temp_new(); \
+ TCGv tmp = tcg_temp_new(); \
+ tcg_gen_movi_tl(PeV, 0); \
+ tcg_gen_movi_i64(RddV, 0); \
+ for (int i = 0; i < 8; i++) { \
+ gen_get_byte_i64(left, i, RttV, false); \
+ gen_get_byte_i64(right, i, RssV, false); \
+ tcg_gen_setcond_tl(TCG_COND_GT, tmp, left, right); \
+ tcg_gen_deposit_tl(PeV, PeV, tmp, i, 1); \
+ tcg_gen_umin_tl(tmp, left, right); \
+ gen_set_byte_i64(i, RddV, tmp); \
+ } \
+ tcg_temp_free(left); \
+ tcg_temp_free(right); \
+ tcg_temp_free(tmp); \
+ } while (0)
+
/* Floating point */
#define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \
gen_helper_conv_sf2df(RddV, cpu_env, RsV)
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index db9f663..7ceb25b 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -316,7 +316,7 @@ def genptr_dst_write(f, tag, regtype, regid):
print("Bad register parse: ", regtype, regid)
elif (regtype == "P"):
if (regid in {"d", "e", "x"}):
- f.write(" gen_log_pred_write(%s%sN, %s%sV);\n" % \
+ f.write(" gen_log_pred_write(ctx, %s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
f.write(" ctx_log_pred_write(ctx, %s%sN);\n" % \
(regtype, regid))
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index cea1f22..797a6c0 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -15,7 +15,6 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#define QEMU_GENERATE
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
@@ -23,7 +22,9 @@
#include "insn.h"
#include "opcodes.h"
#include "translate.h"
+#define QEMU_GENERATE /* Used internally by macros.h */
#include "macros.h"
+#undef QEMU_GENERATE
#include "gen_tcg.h"
static inline TCGv gen_read_preg(TCGv pred, uint8_t num)
@@ -34,20 +35,24 @@
static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
{
- TCGv one = tcg_const_tl(1);
TCGv zero = tcg_const_tl(0);
TCGv slot_mask = tcg_temp_new();
tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero,
val, hex_new_value[rnum]);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum], slot_mask, zero,
- one, hex_reg_written[rnum]);
-#endif
+ if (HEX_DEBUG) {
+ /*
+ * Do this so HELPER(debug_commit_end) will know
+ *
+ * Note that slot_mask indicates the value is not written
+ * (i.e., slot was cancelled), so we create a true/false value before
+ * or'ing with hex_reg_written[rnum].
+ */
+ tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero);
+ tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask);
+ }
- tcg_temp_free(one);
tcg_temp_free(zero);
tcg_temp_free(slot_mask);
}
@@ -55,45 +60,44 @@
static inline void gen_log_reg_write(int rnum, TCGv val)
{
tcg_gen_mov_tl(hex_new_value[rnum], val);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_movi_tl(hex_reg_written[rnum], 1);
-#endif
+ if (HEX_DEBUG) {
+ /* Do this so HELPER(debug_commit_end) will know */
+ tcg_gen_movi_tl(hex_reg_written[rnum], 1);
+ }
}
static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
{
TCGv val32 = tcg_temp_new();
- TCGv one = tcg_const_tl(1);
TCGv zero = tcg_const_tl(0);
TCGv slot_mask = tcg_temp_new();
tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
/* Low word */
tcg_gen_extrl_i64_i32(val32, val);
- tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero,
- val32, hex_new_value[rnum]);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum],
+ tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum],
slot_mask, zero,
- one, hex_reg_written[rnum]);
-#endif
-
+ val32, hex_new_value[rnum]);
/* High word */
tcg_gen_extrh_i64_i32(val32, val);
tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1],
slot_mask, zero,
val32, hex_new_value[rnum + 1]);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum + 1],
- slot_mask, zero,
- one, hex_reg_written[rnum + 1]);
-#endif
+ if (HEX_DEBUG) {
+ /*
+ * Do this so HELPER(debug_commit_end) will know
+ *
+ * Note that slot_mask indicates the value is not written
+ * (i.e., slot was cancelled), so we create a true/false value before
+ * or'ing with hex_reg_written[rnum].
+ */
+ tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero);
+ tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask);
+ tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1],
+ slot_mask);
+ }
tcg_temp_free(val32);
- tcg_temp_free(one);
tcg_temp_free(zero);
tcg_temp_free(slot_mask);
}
@@ -102,33 +106,41 @@
{
/* Low word */
tcg_gen_extrl_i64_i32(hex_new_value[rnum], val);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_movi_tl(hex_reg_written[rnum], 1);
-#endif
+ if (HEX_DEBUG) {
+ /* Do this so HELPER(debug_commit_end) will know */
+ tcg_gen_movi_tl(hex_reg_written[rnum], 1);
+ }
/* High word */
tcg_gen_extrh_i64_i32(hex_new_value[rnum + 1], val);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1);
-#endif
+ if (HEX_DEBUG) {
+ /* Do this so HELPER(debug_commit_end) will know */
+ tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1);
+ }
}
-static inline void gen_log_pred_write(int pnum, TCGv val)
+static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
{
TCGv zero = tcg_const_tl(0);
TCGv base_val = tcg_temp_new();
TCGv and_val = tcg_temp_new();
TCGv pred_written = tcg_temp_new();
- /* Multiple writes to the same preg are and'ed together */
tcg_gen_andi_tl(base_val, val, 0xff);
- tcg_gen_and_tl(and_val, base_val, hex_new_pred_value[pnum]);
- tcg_gen_andi_tl(pred_written, hex_pred_written, 1 << pnum);
- tcg_gen_movcond_tl(TCG_COND_NE, hex_new_pred_value[pnum],
- pred_written, zero,
- and_val, base_val);
+
+ /*
+ * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual
+ *
+ * Multiple writes to the same preg are and'ed together
+ * If this is the first predicate write in the packet, do a
+ * straight assignment. Otherwise, do an and.
+ */
+ if (!test_bit(pnum, ctx->pregs_written)) {
+ tcg_gen_mov_tl(hex_new_pred_value[pnum], base_val);
+ } else {
+ tcg_gen_and_tl(hex_new_pred_value[pnum],
+ hex_new_pred_value[pnum], base_val);
+ }
tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pnum);
tcg_temp_free(zero);
@@ -253,6 +265,61 @@
}
}
+static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
+{
+ if (sign) {
+ tcg_gen_sextract_tl(result, src, N * 8, 8);
+ } else {
+ tcg_gen_extract_tl(result, src, N * 8, 8);
+ }
+ return result;
+}
+
+static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
+{
+ TCGv_i64 res64 = tcg_temp_new_i64();
+ if (sign) {
+ tcg_gen_sextract_i64(res64, src, N * 8, 8);
+ } else {
+ tcg_gen_extract_i64(res64, src, N * 8, 8);
+ }
+ tcg_gen_extrl_i64_i32(result, res64);
+ tcg_temp_free_i64(res64);
+
+ return result;
+}
+
+static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
+{
+ if (sign) {
+ tcg_gen_sextract_tl(result, src, N * 16, 16);
+ } else {
+ tcg_gen_extract_tl(result, src, N * 16, 16);
+ }
+ return result;
+}
+
+static inline void gen_set_half(int N, TCGv result, TCGv src)
+{
+ tcg_gen_deposit_tl(result, result, src, N * 16, 16);
+}
+
+static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
+{
+ TCGv_i64 src64 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(src64, src);
+ tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
+ tcg_temp_free_i64(src64);
+}
+
+static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
+{
+ TCGv_i64 src64 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(src64, src);
+ tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
+ tcg_temp_free_i64(src64);
+}
+
static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
{
tcg_gen_qemu_ld32u(dest, vaddr, mem_index);
@@ -326,5 +393,85 @@
tcg_gen_movi_tl(hex_llsc_addr, ~0);
}
+static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
+{
+ tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
+ tcg_gen_movi_tl(hex_store_width[slot], width);
+ tcg_gen_mov_tl(hex_store_val32[slot], src);
+}
+
+static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
+ DisasContext *ctx, int slot)
+{
+ gen_store32(vaddr, src, 1, slot);
+ ctx->store_width[slot] = 1;
+}
+
+static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
+ DisasContext *ctx, int slot)
+{
+ TCGv tmp = tcg_const_tl(src);
+ gen_store1(cpu_env, vaddr, tmp, ctx, slot);
+ tcg_temp_free(tmp);
+}
+
+static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
+ DisasContext *ctx, int slot)
+{
+ gen_store32(vaddr, src, 2, slot);
+ ctx->store_width[slot] = 2;
+}
+
+static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
+ DisasContext *ctx, int slot)
+{
+ TCGv tmp = tcg_const_tl(src);
+ gen_store2(cpu_env, vaddr, tmp, ctx, slot);
+ tcg_temp_free(tmp);
+}
+
+static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
+ DisasContext *ctx, int slot)
+{
+ gen_store32(vaddr, src, 4, slot);
+ ctx->store_width[slot] = 4;
+}
+
+static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
+ DisasContext *ctx, int slot)
+{
+ TCGv tmp = tcg_const_tl(src);
+ gen_store4(cpu_env, vaddr, tmp, ctx, slot);
+ tcg_temp_free(tmp);
+}
+
+static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
+ DisasContext *ctx, int slot)
+{
+ tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
+ tcg_gen_movi_tl(hex_store_width[slot], 8);
+ tcg_gen_mov_i64(hex_store_val64[slot], src);
+ ctx->store_width[slot] = 8;
+}
+
+static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
+ DisasContext *ctx, int slot)
+{
+ TCGv_i64 tmp = tcg_const_i64(src);
+ gen_store8(cpu_env, vaddr, tmp, ctx, slot);
+ tcg_temp_free_i64(tmp);
+}
+
+static TCGv gen_8bitsof(TCGv result, TCGv value)
+{
+ TCGv zero = tcg_const_tl(0);
+ TCGv ones = tcg_const_tl(0xff);
+ tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
+ tcg_temp_free(zero);
+ tcg_temp_free(ones);
+
+ return result;
+}
+
#include "tcg_funcs_generated.c.inc"
#include "tcg_func_table_generated.c.inc"
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index a5f340c..ca201fb 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -19,13 +19,16 @@
#include "helper_protos_generated.h.inc"
DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32)
-#if HEX_DEBUG
DEF_HELPER_1(debug_start_packet, void, env)
DEF_HELPER_FLAGS_3(debug_check_store_width, TCG_CALL_NO_WG, void, env, int, int)
DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int)
-#endif
DEF_HELPER_2(commit_store, void, env, int)
DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32)
+DEF_HELPER_FLAGS_1(fbrev, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_3(sfrecipa, i64, env, f32, f32)
+DEF_HELPER_2(sfinvsqrta, i64, env, f32)
+DEF_HELPER_4(vacsh_val, s64, env, s64, s64, s64)
+DEF_HELPER_FLAGS_4(vacsh_pred, TCG_CALL_NO_RWG_SE, s32, env, s64, s64, s64)
/* Floating point */
DEF_HELPER_2(conv_sf2df, f64, env, f32)
@@ -38,21 +41,21 @@
DEF_HELPER_2(conv_ud2df, f64, env, s64)
DEF_HELPER_2(conv_d2sf, f32, env, s64)
DEF_HELPER_2(conv_d2df, f64, env, s64)
-DEF_HELPER_2(conv_sf2uw, s32, env, f32)
+DEF_HELPER_2(conv_sf2uw, i32, env, f32)
DEF_HELPER_2(conv_sf2w, s32, env, f32)
-DEF_HELPER_2(conv_sf2ud, s64, env, f32)
+DEF_HELPER_2(conv_sf2ud, i64, env, f32)
DEF_HELPER_2(conv_sf2d, s64, env, f32)
-DEF_HELPER_2(conv_df2uw, s32, env, f64)
+DEF_HELPER_2(conv_df2uw, i32, env, f64)
DEF_HELPER_2(conv_df2w, s32, env, f64)
-DEF_HELPER_2(conv_df2ud, s64, env, f64)
+DEF_HELPER_2(conv_df2ud, i64, env, f64)
DEF_HELPER_2(conv_df2d, s64, env, f64)
-DEF_HELPER_2(conv_sf2uw_chop, s32, env, f32)
+DEF_HELPER_2(conv_sf2uw_chop, i32, env, f32)
DEF_HELPER_2(conv_sf2w_chop, s32, env, f32)
-DEF_HELPER_2(conv_sf2ud_chop, s64, env, f32)
+DEF_HELPER_2(conv_sf2ud_chop, i64, env, f32)
DEF_HELPER_2(conv_sf2d_chop, s64, env, f32)
-DEF_HELPER_2(conv_df2uw_chop, s32, env, f64)
+DEF_HELPER_2(conv_df2uw_chop, i32, env, f64)
DEF_HELPER_2(conv_df2w_chop, s32, env, f64)
-DEF_HELPER_2(conv_df2ud_chop, s64, env, f64)
+DEF_HELPER_2(conv_df2ud_chop, i64, env, f64)
DEF_HELPER_2(conv_df2d_chop, s64, env, f64)
DEF_HELPER_3(sfadd, f32, env, f32, f32)
DEF_HELPER_3(sfsub, f32, env, f32, f32)
diff --git a/target/hexagon/iclass.c b/target/hexagon/iclass.c
index 378d8a6..6091286 100644
--- a/target/hexagon/iclass.c
+++ b/target/hexagon/iclass.c
@@ -53,10 +53,6 @@
(opcode == Y2_isync) ||
(opcode == J2_pause) || (opcode == J4_hintjumpr)) {
return SLOTS_2;
- } else if ((itype == ICLASS_V2LDST) && (GET_ATTRIB(opcode, A_STORE))) {
- return SLOTS_01;
- } else if ((itype == ICLASS_V2LDST) && (!GET_ATTRIB(opcode, A_STORE))) {
- return SLOTS_01;
} else if (GET_ATTRIB(opcode, A_CRSLOT23)) {
return SLOTS_23;
} else if (GET_ATTRIB(opcode, A_RESTRICT_PREFERSLOT0)) {
diff --git a/target/hexagon/imported/alu.idef b/target/hexagon/imported/alu.idef
index 45cc529..58477ae 100644
--- a/target/hexagon/imported/alu.idef
+++ b/target/hexagon/imported/alu.idef
@@ -153,6 +153,21 @@
"Sub",
{ RddV=RttV-RssV;})
+/* 64-bit with carry */
+
+Q6INSN(A4_addp_c,"Rdd32=add(Rss32,Rtt32,Px4):carry",ATTRIBS(),"Add with Carry",
+{
+ RddV = RssV + RttV + fLSBOLD(PxV);
+ PxV = f8BITSOF(fCARRY_FROM_ADD(RssV,RttV,fLSBOLD(PxV)));
+})
+
+Q6INSN(A4_subp_c,"Rdd32=sub(Rss32,Rtt32,Px4):carry",ATTRIBS(),"Sub with Carry",
+{
+ RddV = RssV + ~RttV + fLSBOLD(PxV);
+ PxV = f8BITSOF(fCARRY_FROM_ADD(RssV,~RttV,fLSBOLD(PxV)));
+})
+
+
/* NEG and ABS */
Q6INSN(A2_negsat,"Rd32=neg(Rs32):sat",ATTRIBS(),
@@ -1240,6 +1255,35 @@
#undef VMINORMAX3
+Q6INSN(A5_ACS,"Rxx32,Pe4=vacsh(Rss32,Rtt32)",ATTRIBS(),
+"Add Compare and Select elements of two vectors, record the maximums and the decisions ",
+{
+ fHIDE(int i;)
+ fHIDE(int xv;)
+ fHIDE(int sv;)
+ fHIDE(int tv;)
+ for (i = 0; i < 4; i++) {
+ xv = (int) fGETHALF(i,RxxV);
+ sv = (int) fGETHALF(i,RssV);
+ tv = (int) fGETHALF(i,RttV);
+ xv = xv + tv; //assumes 17bit datapath
+ sv = sv - tv; //assumes 17bit datapath
+ fSETBIT(i*2, PeV, (xv > sv));
+ fSETBIT(i*2+1,PeV, (xv > sv));
+ fSETHALF(i, RxxV, fSATH(fMAX(xv,sv)));
+ }
+})
+
+Q6INSN(A6_vminub_RdP,"Rdd32,Pe4=vminub(Rtt32,Rss32)",ATTRIBS(),
+"Vector minimum of bytes, records minimum and decision vector",
+{
+ fHIDE(int i;)
+ for (i = 0; i < 8; i++) {
+ fSETBIT(i, PeV, (fGETUBYTE(i,RttV) > fGETUBYTE(i,RssV)));
+ fSETBYTE(i,RddV,fMIN(fGETUBYTE(i,RttV),fGETUBYTE(i,RssV)));
+ }
+})
+
/**********************************************/
/* Vector Min/Max */
/**********************************************/
diff --git a/target/hexagon/imported/compare.idef b/target/hexagon/imported/compare.idef
index 3551467..abd016f 100644
--- a/target/hexagon/imported/compare.idef
+++ b/target/hexagon/imported/compare.idef
@@ -198,11 +198,11 @@
Q6INSN(C2_any8,"Pd4=any8(Ps4)",ATTRIBS(A_CRSLOT23),
"Logical ANY of low 8 predicate bits",
-{ PsV ? (PdV=0xff) : (PdV=0x00); })
+{ PdV = (PsV ? 0xff : 0x00); })
Q6INSN(C2_all8,"Pd4=all8(Ps4)",ATTRIBS(A_CRSLOT23),
"Logical ALL of low 8 predicate bits",
-{ (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); })
+{ PdV = (PsV == 0xff ? 0xff : 0x00); })
Q6INSN(C2_vitpack,"Rd32=vitpack(Ps4,Pt4)",ATTRIBS(),
"Pack the odd and even bits of two predicate registers",
@@ -212,7 +212,7 @@
Q6INSN(C2_mux,"Rd32=mux(Pu4,Rs32,Rt32)",ATTRIBS(),
"Scalar MUX",
-{ (fLSBOLD(PuV)) ? (RdV=RsV):(RdV=RtV); })
+{ RdV = (fLSBOLD(PuV) ? RsV : RtV); })
Q6INSN(C2_cmovenewit,"if (Pu4.new) Rd32=#s12",ATTRIBS(A_ARCHV2),
@@ -269,18 +269,18 @@
Q6INSN(C2_muxii,"Rd32=mux(Pu4,#s8,#S8)",ATTRIBS(A_ARCHV2),
"Scalar MUX immediates",
-{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=siV):(RdV=SiV); })
+{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? siV : SiV); })
Q6INSN(C2_muxir,"Rd32=mux(Pu4,Rs32,#s8)",ATTRIBS(A_ARCHV2),
"Scalar MUX register immediate",
-{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=RsV):(RdV=siV); })
+{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? RsV : siV); })
Q6INSN(C2_muxri,"Rd32=mux(Pu4,#s8,Rs32)",ATTRIBS(A_ARCHV2),
"Scalar MUX register immediate",
-{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=siV):(RdV=RsV); })
+{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? siV : RsV); })
diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def
index c21cb73..35ae3d2 100644
--- a/target/hexagon/imported/encode_pp.def
+++ b/target/hexagon/imported/encode_pp.def
@@ -294,12 +294,14 @@
DEF_CLASS32(ICLASS_LD" 0--- -------- PP------ --------",LD_ADDR_ROFFSET)
+DEF_CLASS32(ICLASS_LD" 100- -------- PP----0- --------",LD_ADDR_POST_CIRC_IMMED)
DEF_CLASS32(ICLASS_LD" 101- -------- PP00---- --------",LD_ADDR_POST_IMMED)
DEF_CLASS32(ICLASS_LD" 101- -------- PP01---- --------",LD_ADDR_ABS_UPDATE_V4)
DEF_CLASS32(ICLASS_LD" 101- -------- PP1----- --------",LD_ADDR_POST_IMMED_PRED_V2)
DEF_CLASS32(ICLASS_LD" 110- -------- PP-0---- 0-------",LD_ADDR_POST_REG)
DEF_CLASS32(ICLASS_LD" 110- -------- PP-1---- --------",LD_ADDR_ABS_PLUS_REG_V4)
DEF_CLASS32(ICLASS_LD" 100- -------- PP----1- --------",LD_ADDR_POST_CREG_V2)
+DEF_CLASS32(ICLASS_LD" 111- -------- PP------ 0-------",LD_ADDR_POST_BREV_REG)
DEF_CLASS32(ICLASS_LD" 111- -------- PP------ 1-------",LD_ADDR_PRED_ABS_V4)
DEF_FIELD32(ICLASS_LD" !!!- -------- PP------ --------",LD_Amode,"Amode")
@@ -308,18 +310,24 @@
#define STD_LD_ENC(TAG,OPC) \
DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiddddd")\
+DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiddddd")\
DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiddddd")\
DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIddddd")\
DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--ddddd")\
DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIddddd")\
+DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--ddddd")\
+DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--ddddd")
#define STD_LDX_ENC(TAG,OPC) \
DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiyyyyy")\
+DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiyyyyy")\
DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiyyyyy")\
DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIyyyyy")\
DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--yyyyy")\
DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIyyyyy")\
+DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--yyyyy")\
+DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--yyyyy")
#define STD_PLD_ENC(TAG,OPC) \
@@ -334,6 +342,15 @@
/* 0 000 misc: dealloc,loadw_locked,dcfetch */
+STD_LD_ENC(bzw4,"0 101")
+STD_LD_ENC(bzw2,"0 011")
+
+STD_LD_ENC(bsw4,"0 111")
+STD_LD_ENC(bsw2,"0 001")
+
+STD_LDX_ENC(alignh,"0 010")
+STD_LDX_ENC(alignb,"0 100")
+
STD_LD_ENC(rb, "1 000")
STD_LD_ENC(rub, "1 001")
STD_LD_ENC(rh, "1 010")
@@ -351,6 +368,7 @@
DEF_CLASS32( ICLASS_LD" 0--0 000----- PP------ --------",LD_MISC)
DEF_ANTICLASS32(ICLASS_LD" 0--0 000----- PP------ --------",LD_ADDR_ROFFSET)
+DEF_ANTICLASS32(ICLASS_LD" 1000 000----- PP------ --------",LD_ADDR_POST_CIRC_IMMED)
DEF_ANTICLASS32(ICLASS_LD" 1010 000----- PP------ --------",LD_ADDR_POST_IMMED)
DEF_ANTICLASS32(ICLASS_LD" 1100 000----- PP------ --------",LD_ADDR_POST_REG)
DEF_ANTICLASS32(ICLASS_LD" 1110 000----- PP------ --------",LD_ADDR_POST_REG)
@@ -397,6 +415,7 @@
DEF_FIELD32(ICLASS_ST" ---- --!----- PP------ --------",ST_UN,"Unsigned")
DEF_CLASS32(ICLASS_ST" 0--1 -------- PP------ --------",ST_ADDR_ROFFSET)
+DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------0-",ST_ADDR_POST_CIRC_IMMED)
DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 0-----0-",ST_ADDR_POST_IMMED)
DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 1-------",ST_ADDR_ABS_UPDATE_V4)
DEF_CLASS32(ICLASS_ST" 1011 -------- PP1----- --------",ST_ADDR_POST_IMMED_PRED_V2)
@@ -404,6 +423,7 @@
DEF_CLASS32(ICLASS_ST" 1101 -------- PP------ 0-------",ST_ADDR_POST_REG)
DEF_CLASS32(ICLASS_ST" 1101 -------- PP------ 1-------",ST_ADDR_ABS_PLUS_REG_V4)
DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------1-",ST_ADDR_POST_CREG_V2)
+DEF_CLASS32(ICLASS_ST" 1111 -------- PP------ 0-------",ST_ADDR_POST_BREV_REG)
DEF_CLASS32(ICLASS_ST" 0--0 1------- PP------ --------",ST_MISC_STORELIKE)
DEF_CLASS32(ICLASS_ST" 1--0 0------- PP------ --------",ST_MISC_BUSOP)
DEF_CLASS32(ICLASS_ST" 0--0 0------- PP------ --------",ST_MISC_CACHEOP)
@@ -411,10 +431,13 @@
#define STD_ST_ENC(TAG,OPC,SRC) \
DEF_ENC32(S2_store##TAG##_io, ICLASS_ST" 0 ii "OPC" sssss PPi"SRC" iiiiiiii")\
+DEF_ENC32(S2_store##TAG##_pci, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0iiii-0-")\
DEF_ENC32(S2_store##TAG##_pi, ICLASS_ST" 1 01 "OPC" xxxxx PP0"SRC" 0iiii-0-")\
DEF_ENC32(S4_store##TAG##_ap, ICLASS_ST" 1 01 "OPC" eeeee PP0"SRC" 1-IIIIII")\
DEF_ENC32(S2_store##TAG##_pr, ICLASS_ST" 1 10 "OPC" xxxxx PPu"SRC" 0-------")\
DEF_ENC32(S4_store##TAG##_ur, ICLASS_ST" 1 10 "OPC" uuuuu PPi"SRC" 1iIIIIII")\
+DEF_ENC32(S2_store##TAG##_pcr, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0-----1-")\
+DEF_ENC32(S2_store##TAG##_pbr, ICLASS_ST" 1 11 "OPC" xxxxx PPu"SRC" 0-------")
#define STD_PST_ENC(TAG,OPC,SRC) \
@@ -1017,6 +1040,8 @@
+MPY_ENC(A5_ACS, "1010","xxxxx","0","1","0","1","ee")
+MPY_ENC(A6_vminub_RdP, "1010","ddddd","0","1","1","1","ee")
/*
*/
@@ -1028,6 +1053,7 @@
MPY_ENC(F2_sfmpy, "1011","ddddd","0","0","1","0","00")
MPY_ENC(F2_sffixupn, "1011","ddddd","0","0","1","1","00")
MPY_ENC(F2_sffixupd, "1011","ddddd","0","0","1","1","01")
+MPY_ENC(F2_sfrecipa, "1011","ddddd","1","1","1","1","ee")
DEF_FIELDROW_DESC32(ICLASS_M" 1100 -------- PP------ --------","[#12] Rd=(Rs,Rt)")
DEF_FIELD32(ICLASS_M" 1100 -------- PP------ --!-----",Mc_tH,"Rt is High") /*Rt high */
@@ -1641,6 +1667,7 @@
SH2_RR_ENC(F2_conv_sf2uw_chop, "1011","011","-","001","ddddd")
SH2_RR_ENC(F2_conv_sf2w_chop, "1011","100","-","001","ddddd")
SH2_RR_ENC(F2_sffixupr, "1011","101","-","000","ddddd")
+SH2_RR_ENC(F2_sfinvsqrta, "1011","111","-","0ee","ddddd")
DEF_FIELDROW_DESC32(ICLASS_S2op" 1100 -------- PP------ --------","[#12] Rd=(Rs,#u6)")
@@ -1740,11 +1767,14 @@
SH_RRR_ENC(S4_vxaddsubhr, "0001","11-","-","00-","ddddd")
SH_RRR_ENC(S4_vxsubaddhr, "0001","11-","-","01-","ddddd")
SH_RRR_ENC(S4_extractp_rp, "0001","11-","-","10-","ddddd")
+SH_RRR_ENC(S2_cabacdecbin, "0001","11-","-","11-","ddddd") /* implicit P0 write */
DEF_FIELDROW_DESC32(ICLASS_S3op" 0010 -------- PP------ --------","[#2] Rdd=(Rss,Rtt,Pu)")
SH_RRR_ENC(S2_valignrb, "0010","0--","-","-uu","ddddd")
SH_RRR_ENC(S2_vsplicerb, "0010","100","-","-uu","ddddd")
+SH_RRR_ENC(A4_addp_c, "0010","110","-","-xx","ddddd")
+SH_RRR_ENC(A4_subp_c, "0010","111","-","-xx","ddddd")
DEF_FIELDROW_DESC32(ICLASS_S3op" 0011 -------- PP------ --------","[#3] Rdd=(Rss,Rt)")
diff --git a/target/hexagon/imported/float.idef b/target/hexagon/imported/float.idef
index 76cecfe..3e75bc4 100644
--- a/target/hexagon/imported/float.idef
+++ b/target/hexagon/imported/float.idef
@@ -146,6 +146,22 @@
})
+Q6INSN(F2_sfrecipa,"Rd32,Pe4=sfrecipa(Rs32,Rt32)",ATTRIBS(),
+"Reciprocal Approximation for Division",
+{
+ fHIDE(int idx;)
+ fHIDE(int adjust;)
+ fHIDE(int mant;)
+ fHIDE(int exp;)
+ if (fSF_RECIP_COMMON(RsV,RtV,RdV,adjust)) {
+ PeV = adjust;
+ idx = (RtV >> 16) & 0x7f;
+ mant = (fSF_RECIP_LOOKUP(idx) << 15) | 1;
+ exp = fSF_BIAS() - (fSF_GETEXP(RtV) - fSF_BIAS()) - 1;
+ RdV = fMAKESF(fGETBIT(31,RtV),exp,mant);
+ }
+})
+
Q6INSN(F2_sffixupn,"Rd32=sffixupn(Rs32,Rt32)",ATTRIBS(),
"Fix Up Numerator",
{
@@ -162,6 +178,22 @@
RdV = RtV;
})
+Q6INSN(F2_sfinvsqrta,"Rd32,Pe4=sfinvsqrta(Rs32)",ATTRIBS(),
+"Reciprocal Square Root Approximation",
+{
+ fHIDE(int idx;)
+ fHIDE(int adjust;)
+ fHIDE(int mant;)
+ fHIDE(int exp;)
+ if (fSF_INVSQRT_COMMON(RsV,RdV,adjust)) {
+ PeV = adjust;
+ idx = (RsV >> 17) & 0x7f;
+ mant = (fSF_INVSQRT_LOOKUP(idx) << 15);
+ exp = fSF_BIAS() - ((fSF_GETEXP(RsV) - fSF_BIAS()) >> 1) - 1;
+ RdV = fMAKESF(fGETBIT(31,RsV),exp,mant);
+ }
+})
+
Q6INSN(F2_sffixupr,"Rd32=sffixupr(Rs32)",ATTRIBS(),
"Fix Up Radicand",
{
diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef
index 78a2ea4..359d3b7 100644
--- a/target/hexagon/imported/ldst.idef
+++ b/target/hexagon/imported/ldst.idef
@@ -25,7 +25,10 @@
Q6INSN(L4_##TAG##_ur, OPER"(Rt32<<#u2+#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IRs(UiV,RtV,uiV); SEMANTICS;})\
Q6INSN(L4_##TAG##_ap, OPER"(Re32=#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\
Q6INSN(L2_##TAG##_pr, OPER"(Rx32++Mu2)", ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS;})\
+Q6INSN(L2_##TAG##_pbr, OPER"(Rx32++Mu2:brev)", ATTRIB,DESCR,{fEA_BREVR(RxV); fPM_M(RxV,MuV); SEMANTICS;})\
Q6INSN(L2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")", ATTRIB,DESCR,{fEA_REG(RxV); fPM_I(RxV,siV); SEMANTICS;})\
+Q6INSN(L2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))",ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\
+Q6INSN(L2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))", ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<<SCALE,MuV); SEMANTICS;})
/* The set of 32-bit load instructions */
STD_LD_AMODES(loadrub,"Rd32=memub","Load Unsigned Byte",ATTRIBS(A_LOAD),"0",fLOAD(1,1,u,EA,RdV),0)
@@ -35,6 +38,68 @@
STD_LD_AMODES(loadri, "Rd32=memw", "Load Word",ATTRIBS(A_LOAD),"2",fLOAD(1,4,u,EA,RdV),2)
STD_LD_AMODES(loadrd, "Rdd32=memd","Load Double integer",ATTRIBS(A_LOAD),"3",fLOAD(1,8,u,EA,RddV),3)
+/* These instructions do a load an unpack */
+STD_LD_AMODES(loadbzw2, "Rd32=memubh", "Load Bytes and Vector Zero-Extend (unpack)",
+ATTRIBS(A_LOAD),"1",
+{fHIDE(size2u_t tmpV; int i;)
+ fLOAD(1,2,u,EA,tmpV);
+ for (i=0;i<2;i++) {
+ fSETHALF(i,RdV,fGETUBYTE(i,tmpV));
+ }
+},1)
+
+STD_LD_AMODES(loadbzw4, "Rdd32=memubh", "Load Bytes and Vector Zero-Extend (unpack)",
+ATTRIBS(A_LOAD),"2",
+{fHIDE(size4u_t tmpV; int i;)
+ fLOAD(1,4,u,EA,tmpV);
+ for (i=0;i<4;i++) {
+ fSETHALF(i,RddV,fGETUBYTE(i,tmpV));
+ }
+},2)
+
+
+
+/* These instructions do a load an unpack */
+STD_LD_AMODES(loadbsw2, "Rd32=membh", "Load Bytes and Vector Sign-Extend (unpack)",
+ATTRIBS(A_LOAD),"1",
+{fHIDE(size2u_t tmpV; int i;)
+ fLOAD(1,2,u,EA,tmpV);
+ for (i=0;i<2;i++) {
+ fSETHALF(i,RdV,fGETBYTE(i,tmpV));
+ }
+},1)
+
+STD_LD_AMODES(loadbsw4, "Rdd32=membh", "Load Bytes and Vector Sign-Extend (unpack)",
+ATTRIBS(A_LOAD),"2",
+{fHIDE(size4u_t tmpV; int i;)
+ fLOAD(1,4,u,EA,tmpV);
+ for (i=0;i<4;i++) {
+ fSETHALF(i,RddV,fGETBYTE(i,tmpV));
+ }
+},2)
+
+
+
+STD_LD_AMODES(loadalignh, "Ryy32=memh_fifo", "Load Half-word into shifted vector",
+ATTRIBS(A_LOAD),"1",
+{
+ fHIDE(size8u_t tmpV;)
+ fLOAD(1,2,u,EA,tmpV);
+ RyyV = (((size8u_t)RyyV)>>16)|(tmpV<<48);
+},1)
+
+
+STD_LD_AMODES(loadalignb, "Ryy32=memb_fifo", "Load byte into shifted vector",
+ATTRIBS(A_LOAD),"0",
+{
+ fHIDE(size8u_t tmpV;)
+ fLOAD(1,1,u,EA,tmpV);
+ RyyV = (((size8u_t)RyyV)>>8)|(tmpV<<56);
+},0)
+
+
+
+
/* The set of addressing modes standard to all Store instructions */
#define STD_ST_AMODES(TAG,DEST,OPER,DESCR,ATTRIB,SHFT,SEMANTICS,SCALE)\
Q6INSN(S2_##TAG##_io, OPER"(Rs32+#s11:"SHFT")="DEST, ATTRIB,DESCR,{fIMMEXT(siV); fEA_RI(RsV,siV); SEMANTICS; })\
@@ -42,6 +107,9 @@
Q6INSN(S4_##TAG##_ap, OPER"(Re32=#U6)="DEST, ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\
Q6INSN(S2_##TAG##_pr, OPER"(Rx32++Mu2)="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS; })\
Q6INSN(S4_##TAG##_ur, OPER"(Ru32<<#u2+#U6)="DEST, ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IRs(UiV,RuV,uiV); SEMANTICS;})\
+Q6INSN(S2_##TAG##_pbr, OPER"(Rx32++Mu2:brev)="DEST, ATTRIB,DESCR,{fEA_BREVR(RxV); fPM_M(RxV,MuV); SEMANTICS; })\
+Q6INSN(S2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\
+Q6INSN(S2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<<SCALE,MuV); SEMANTICS;})
/* The set of 32-bit store instructions */
diff --git a/target/hexagon/imported/macros.def b/target/hexagon/imported/macros.def
index 65292c7..32ed3bf 100755
--- a/target/hexagon/imported/macros.def
+++ b/target/hexagon/imported/macros.def
@@ -92,6 +92,21 @@
/* attribs */
)
+
+DEF_MACRO(
+ fINSERT_RANGE,
+ {
+ int offset=LOWBIT;
+ int width=HIBIT-LOWBIT+1;
+ /* clear bits where new bits go */
+ INREG &= ~(((fCONSTLL(1)<<width)-1)<<offset);
+ /* OR in new bits */
+ INREG |= ((INVAL & ((fCONSTLL(1)<<width)-1)) << offset);
+ },
+ /* attribs */
+)
+
+
DEF_MACRO(
f8BITSOF,
( (VAL) ? 0xff : 0x00),
@@ -277,6 +292,12 @@
/*************************************/
DEF_MACRO(
+ fREAD_IREG, /* read modifier register */
+ (fSXTN(11,64,(((VAL) & 0xf0000000)>>21) | ((VAL>>17)&0x7f) )), /* behavior */
+ ()
+)
+
+DEF_MACRO(
fREAD_LR, /* read link register */
(READ_RREG(REG_LR)), /* behavior */
()
@@ -307,6 +328,12 @@
)
DEF_MACRO(
+ fREAD_CSREG, /* read CS register */
+ (READ_RREG(REG_CSA+N)), /* behavior */
+ ()
+)
+
+DEF_MACRO(
fREAD_LC0, /* read loop count */
(READ_RREG(REG_LC0)), /* behavior */
()
@@ -807,6 +834,12 @@
)
DEF_MACRO(
+ fEA_BREVR, /* Calculate EA with bit reversed bottom of REGISTER */
+ EA=fbrev(REG),
+ ()
+)
+
+DEF_MACRO(
fEA_GPI, /* Calculate EA with Global Poitner + Immediate */
do { EA=fREAD_GP()+IMM; fGP_DOCHKPAGECROSS(fREAD_GP(),EA); } while (0),
()
@@ -825,6 +858,20 @@
)
DEF_MACRO(
+ fPM_CIRI, /* Post Modify Register using Circular arithmetic by Immediate */
+ do { fcirc_add(REG,siV,MuV); } while (0),
+ ()
+)
+
+DEF_MACRO(
+ fPM_CIRR, /* Post Modify Register using Circular arithmetic by register */
+ do { fcirc_add(REG,VAL,MuV); } while (0),
+ ()
+)
+
+
+
+DEF_MACRO(
fSCALE, /* scale by N */
(((size8s_t)(A))<<N),
/* optional attributes */
diff --git a/target/hexagon/imported/shift.idef b/target/hexagon/imported/shift.idef
index e328ab7..b32c4e0 100644
--- a/target/hexagon/imported/shift.idef
+++ b/target/hexagon/imported/shift.idef
@@ -1029,6 +1029,53 @@
{ RdV = (fMAX(fCL1_8(RssV),fCL1_8(~RssV)))+siV;})
+
+Q6INSN(S2_cabacdecbin,"Rdd32=decbin(Rss32,Rtt32)",ATTRIBS(A_ARCHV3),"CABAC decode bin",
+{
+ fHIDE(size4u_t state;)
+ fHIDE(size4u_t valMPS;)
+ fHIDE(size4u_t bitpos;)
+ fHIDE(size4u_t range;)
+ fHIDE(size4u_t offset;)
+ fHIDE(size4u_t rLPS;)
+ fHIDE(size4u_t rMPS;)
+
+ state = fEXTRACTU_RANGE( fGETWORD(1,RttV) ,5,0);
+ valMPS = fEXTRACTU_RANGE( fGETWORD(1,RttV) ,8,8);
+ bitpos = fEXTRACTU_RANGE( fGETWORD(0,RttV) ,4,0);
+ range = fGETWORD(0,RssV);
+ offset = fGETWORD(1,RssV);
+
+ /* calculate rLPS */
+ range <<= bitpos;
+ offset <<= bitpos;
+ rLPS = rLPS_table_64x4[state][ (range >>29)&3];
+ rLPS = rLPS << 23; /* left aligned */
+
+ /* calculate rMPS */
+ rMPS= (range&0xff800000) - rLPS;
+
+ /* most probable region */
+ if (offset < rMPS) {
+ RddV = AC_next_state_MPS_64[state];
+ fINSERT_RANGE(RddV,8,8,valMPS);
+ fINSERT_RANGE(RddV,31,23,(rMPS>>23));
+ fSETWORD(1,RddV,offset);
+ fWRITE_P0(valMPS);
+
+
+ }
+ /* least probable region */
+ else {
+ RddV = AC_next_state_LPS_64[state];
+ fINSERT_RANGE(RddV,8,8,((!state)?(1-valMPS):(valMPS)));
+ fINSERT_RANGE(RddV,31,23,(rLPS>>23));
+ fSETWORD(1,RddV,(offset-rMPS));
+ fWRITE_P0((valMPS^1));
+ }
+})
+
+
Q6INSN(S2_clb,"Rd32=clb(Rs32)",ATTRIBS(),
"Count leading bits", {RdV = fMAX(fCL1_4(RsV),fCL1_4(~RsV));})
diff --git a/target/hexagon/insn.h b/target/hexagon/insn.h
index 5756a1d..2e34591 100644
--- a/target/hexagon/insn.h
+++ b/target/hexagon/insn.h
@@ -40,14 +40,15 @@
uint32_t iclass:6;
uint32_t slot:3;
- uint32_t part1:1; /*
+ uint32_t which_extended:1; /* If has an extender, which immediate */
+ uint32_t new_value_producer_slot:4;
+
+ bool part1; /*
* cmp-jumps are split into two insns.
* set for the compare and clear for the jump
*/
- uint32_t extension_valid:1; /* Has a constant extender attached */
- uint32_t which_extended:1; /* If has an extender, which immediate */
- uint32_t is_endloop:1; /* This is an end of loop */
- uint32_t new_value_producer_slot:4;
+ bool extension_valid; /* Has a constant extender attached */
+ bool is_endloop; /* This is an end of loop */
int32_t immed[IMMEDS_MAX]; /* immediate field */
};
@@ -58,13 +59,13 @@
uint16_t encod_pkt_size_in_bytes;
/* Pre-decodes about COF */
- uint32_t pkt_has_cof:1; /* Has any change-of-flow */
- uint32_t pkt_has_endloop:1;
+ bool pkt_has_cof; /* Has any change-of-flow */
+ bool pkt_has_endloop;
- uint32_t pkt_has_dczeroa:1;
+ bool pkt_has_dczeroa;
- uint32_t pkt_has_store_s0:1;
- uint32_t pkt_has_store_s1:1;
+ bool pkt_has_store_s0;
+ bool pkt_has_store_s1;
Insn insn[INSTRUCTIONS_MAX];
};
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 2da85c8..6b20aff 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -22,11 +22,12 @@
* Change HEX_DEBUG to 1 to turn on debugging output
*/
#define HEX_DEBUG 0
-#if HEX_DEBUG
-#define HEX_DEBUG_LOG(...) qemu_log(__VA_ARGS__)
-#else
-#define HEX_DEBUG_LOG(...) do { } while (0)
-#endif
+#define HEX_DEBUG_LOG(...) \
+ do { \
+ if (HEX_DEBUG) { \
+ qemu_log(__VA_ARGS__); \
+ } \
+ } while (0)
int hexagon_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index cfcb817..b726c3b 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -133,6 +133,38 @@
CHECK_NOSHUF; \
tcg_gen_qemu_ld64(DST, VA, ctx->mem_idx); \
} while (0)
+
+#define MEM_STORE1_FUNC(X) \
+ __builtin_choose_expr(TYPE_INT(X), \
+ gen_store1i, \
+ __builtin_choose_expr(TYPE_TCGV(X), \
+ gen_store1, (void)0))
+#define MEM_STORE1(VA, DATA, SLOT) \
+ MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
+
+#define MEM_STORE2_FUNC(X) \
+ __builtin_choose_expr(TYPE_INT(X), \
+ gen_store2i, \
+ __builtin_choose_expr(TYPE_TCGV(X), \
+ gen_store2, (void)0))
+#define MEM_STORE2(VA, DATA, SLOT) \
+ MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
+
+#define MEM_STORE4_FUNC(X) \
+ __builtin_choose_expr(TYPE_INT(X), \
+ gen_store4i, \
+ __builtin_choose_expr(TYPE_TCGV(X), \
+ gen_store4, (void)0))
+#define MEM_STORE4(VA, DATA, SLOT) \
+ MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
+
+#define MEM_STORE8_FUNC(X) \
+ __builtin_choose_expr(TYPE_INT(X), \
+ gen_store8i, \
+ __builtin_choose_expr(TYPE_TCGV_I64(X), \
+ gen_store8, (void)0))
+#define MEM_STORE8(VA, DATA, SLOT) \
+ MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
#else
#define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA))
#define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA))
@@ -190,6 +222,13 @@
(((HIBIT) - (LOWBIT) + 1) ? \
extract64((INREG), (LOWBIT), ((HIBIT) - (LOWBIT) + 1)) : \
0LL)
+#define fINSERT_RANGE(INREG, HIBIT, LOWBIT, INVAL) \
+ do { \
+ int width = ((HIBIT) - (LOWBIT) + 1); \
+ INREG = (width >= 0 ? \
+ deposit64((INREG), (LOWBIT), width, (INVAL)) : \
+ INREG); \
+ } while (0)
#define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00)
@@ -285,6 +324,39 @@
#define fPCALIGN(IMM) IMM = (IMM & ~PCALIGN_MASK)
+#ifdef QEMU_GENERATE
+static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
+{
+ /*
+ * Section 2.2.4 of the Hexagon V67 Programmer's Reference Manual
+ *
+ * The "I" value from a modifier register is divided into two pieces
+ * LSB bits 23:17
+ * MSB bits 31:28
+ * The value is signed
+ *
+ * At the end we shift the result according to the shift argument
+ */
+ TCGv msb = tcg_temp_new();
+ TCGv lsb = tcg_temp_new();
+
+ tcg_gen_extract_tl(lsb, val, 17, 7);
+ tcg_gen_sari_tl(msb, val, 21);
+ tcg_gen_deposit_tl(result, msb, lsb, 0, 7);
+
+ tcg_gen_shli_tl(result, result, shift);
+
+ tcg_temp_free(msb);
+ tcg_temp_free(lsb);
+
+ return result;
+}
+#define fREAD_IREG(VAL, SHIFT) gen_read_ireg(ireg, (VAL), (SHIFT))
+#else
+#define fREAD_IREG(VAL) \
+ (fSXTN(11, 64, (((VAL) & 0xf0000000) >> 21) | ((VAL >> 17) & 0x7f)))
+#endif
+
#define fREAD_LR() (READ_REG(HEX_REG_LR))
#define fWRITE_LR(A) WRITE_RREG(HEX_REG_LR, A)
@@ -341,8 +413,6 @@
#define fWRITE_LC0(VAL) WRITE_RREG(HEX_REG_LC0, VAL)
#define fWRITE_LC1(VAL) WRITE_RREG(HEX_REG_LC1, VAL)
-#define fCARRY_FROM_ADD(A, B, C) carry_from_add64(A, B, C)
-
#define fSET_OVERFLOW() SET_USR_FIELD(USR_OVF, 1)
#define fSET_LPCFG(VAL) SET_USR_FIELD(USR_LPCFG, (VAL))
#define fGET_LPCFG (GET_USR_FIELD(USR_LPCFG))
@@ -402,6 +472,21 @@
#define fCAST8S_16S(A) (int128_exts64(A))
#define fCAST16S_8S(A) (int128_getlo(A))
+#ifdef QEMU_GENERATE
+#define fEA_RI(REG, IMM) tcg_gen_addi_tl(EA, REG, IMM)
+#define fEA_RRs(REG, REG2, SCALE) \
+ do { \
+ TCGv tmp = tcg_temp_new(); \
+ tcg_gen_shli_tl(tmp, REG2, SCALE); \
+ tcg_gen_add_tl(EA, REG, tmp); \
+ tcg_temp_free(tmp); \
+ } while (0)
+#define fEA_IRs(IMM, REG, SCALE) \
+ do { \
+ tcg_gen_shli_tl(EA, REG, SCALE); \
+ tcg_gen_addi_tl(EA, EA, IMM); \
+ } while (0)
+#else
#define fEA_RI(REG, IMM) \
do { \
EA = REG + IMM; \
@@ -414,12 +499,21 @@
do { \
EA = IMM + (REG << SCALE); \
} while (0)
+#endif
#ifdef QEMU_GENERATE
#define fEA_IMM(IMM) tcg_gen_movi_tl(EA, IMM)
#define fEA_REG(REG) tcg_gen_mov_tl(EA, REG)
+#define fEA_BREVR(REG) gen_helper_fbrev(EA, REG)
#define fPM_I(REG, IMM) tcg_gen_addi_tl(REG, REG, IMM)
#define fPM_M(REG, MVAL) tcg_gen_add_tl(REG, REG, MVAL)
+#define fPM_CIRI(REG, IMM, MVAL) \
+ do { \
+ TCGv tcgv_siV = tcg_const_tl(siV); \
+ gen_helper_fcircadd(REG, REG, tcgv_siV, MuV, \
+ hex_gpr[HEX_REG_CS0 + MuN]); \
+ tcg_temp_free(tcgv_siV); \
+ } while (0)
#else
#define fEA_IMM(IMM) do { EA = (IMM); } while (0)
#define fEA_REG(REG) do { EA = (REG); } while (0)
@@ -496,23 +590,43 @@
gen_load_locked##SIZE##SIGN(DST, EA, ctx->mem_idx);
#endif
+#ifdef QEMU_GENERATE
+#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, insn->slot)
+#else
#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, slot)
+#endif
#ifdef QEMU_GENERATE
#define fSTORE_LOCKED(NUM, SIZE, EA, SRC, PRED) \
gen_store_conditional##SIZE(env, ctx, PdN, PRED, EA, SRC);
#endif
+#ifdef QEMU_GENERATE
+#define GETBYTE_FUNC(X) \
+ __builtin_choose_expr(TYPE_TCGV(X), \
+ gen_get_byte, \
+ __builtin_choose_expr(TYPE_TCGV_I64(X), \
+ gen_get_byte_i64, (void)0))
+#define fGETBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, true)
+#define fGETUBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, false)
+#else
#define fGETBYTE(N, SRC) ((int8_t)((SRC >> ((N) * 8)) & 0xff))
#define fGETUBYTE(N, SRC) ((uint8_t)((SRC >> ((N) * 8)) & 0xff))
+#endif
#define fSETBYTE(N, DST, VAL) \
do { \
DST = (DST & ~(0x0ffLL << ((N) * 8))) | \
(((uint64_t)((VAL) & 0x0ffLL)) << ((N) * 8)); \
} while (0)
+
+#ifdef QEMU_GENERATE
+#define fGETHALF(N, SRC) gen_get_half(HALF, N, SRC, true)
+#define fGETUHALF(N, SRC) gen_get_half(HALF, N, SRC, false)
+#else
#define fGETHALF(N, SRC) ((int16_t)((SRC >> ((N) * 16)) & 0xffff))
#define fGETUHALF(N, SRC) ((uint16_t)((SRC >> ((N) * 16)) & 0xffff))
+#endif
#define fSETHALF(N, DST, VAL) \
do { \
DST = (DST & ~(0x0ffffLL << ((N) * 16))) | \
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index bb0b4fb..6fd9360 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -173,7 +173,6 @@
'printinsn.c',
'arch.c',
'fma_emu.c',
- 'conv_emu.c',
))
target_arch += {'hexagon': hexagon_ss}
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 2c6d718..63dd685 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -25,7 +25,6 @@
#include "arch.h"
#include "hex_arch_types.h"
#include "fma_emu.h"
-#include "conv_emu.h"
#define SF_BIAS 127
#define SF_MANTBITS 23
@@ -35,7 +34,7 @@
uint32_t exception,
uintptr_t pc)
{
- CPUState *cs = CPU(hexagon_env_get_cpu(env));
+ CPUState *cs = env_cpu(env);
qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
cs->exception_index = exception;
cpu_loop_exit_restore(cs, pc);
@@ -46,8 +45,8 @@
do_raise_exception_err(env, excp, 0);
}
-static inline void log_reg_write(CPUHexagonState *env, int rnum,
- target_ulong val, uint32_t slot)
+static void log_reg_write(CPUHexagonState *env, int rnum,
+ target_ulong val, uint32_t slot)
{
HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
rnum, val, val);
@@ -57,14 +56,13 @@
HEX_DEBUG_LOG("\n");
env->new_value[rnum] = val;
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- env->reg_written[rnum] = 1;
-#endif
+ if (HEX_DEBUG) {
+ /* Do this so HELPER(debug_commit_end) will know */
+ env->reg_written[rnum] = 1;
+ }
}
-static inline void log_pred_write(CPUHexagonState *env, int pnum,
- target_ulong val)
+static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
{
HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx ")\n",
@@ -79,8 +77,8 @@
}
}
-static inline void log_store32(CPUHexagonState *env, target_ulong addr,
- target_ulong val, int width, int slot)
+static void log_store32(CPUHexagonState *env, target_ulong addr,
+ target_ulong val, int width, int slot)
{
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
", %" PRId32 " [0x08%" PRIx32 "])\n",
@@ -90,8 +88,8 @@
env->mem_log_stores[slot].data32 = val;
}
-static inline void log_store64(CPUHexagonState *env, target_ulong addr,
- int64_t val, int width, int slot)
+static void log_store64(CPUHexagonState *env, target_ulong addr,
+ int64_t val, int width, int slot)
{
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
", %" PRId64 " [0x016%" PRIx64 "])\n",
@@ -101,7 +99,7 @@
env->mem_log_stores[slot].data64 = val;
}
-static inline void write_new_pc(CPUHexagonState *env, target_ulong addr)
+static void write_new_pc(CPUHexagonState *env, target_ulong addr)
{
HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
@@ -119,7 +117,6 @@
}
}
-#if HEX_DEBUG
/* Handy place to set a breakpoint */
void HELPER(debug_start_packet)(CPUHexagonState *env)
{
@@ -130,14 +127,12 @@
env->reg_written[i] = 0;
}
}
-#endif
-static inline int32_t new_pred_value(CPUHexagonState *env, int pnum)
+static int32_t new_pred_value(CPUHexagonState *env, int pnum)
{
return env->new_pred_value[pnum];
}
-#if HEX_DEBUG
/* Checks for bookkeeping errors between disassembly context and runtime */
void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
{
@@ -147,7 +142,6 @@
g_assert_not_reached();
}
}
-#endif
void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
{
@@ -173,7 +167,6 @@
}
}
-#if HEX_DEBUG
static void print_store(CPUHexagonState *env, int slot)
{
if (!(env->slot_cancelled & (1 << slot))) {
@@ -257,35 +250,26 @@
env->gpr[HEX_REG_QEMU_INSN_CNT]);
}
-#endif
-
-static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
-{
- int32_t length = M & 0x0001ffff;
- uint32_t new_ptr = RxV + offset;
- uint32_t start_addr = CS;
- uint32_t end_addr = start_addr + length;
-
- if (new_ptr >= end_addr) {
- new_ptr -= length;
- } else if (new_ptr < start_addr) {
- new_ptr += length;
- }
-
- return new_ptr;
-}
int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
{
- int32_t K_const = (M >> 24) & 0xf;
- int32_t length = M & 0x1ffff;
- int32_t mask = (1 << (K_const + 2)) - 1;
+ int32_t K_const = sextract32(M, 24, 4);
+ int32_t length = sextract32(M, 0, 17);
uint32_t new_ptr = RxV + offset;
- uint32_t start_addr = RxV & (~mask);
- uint32_t end_addr = start_addr | length;
+ uint32_t start_addr;
+ uint32_t end_addr;
if (K_const == 0 && length >= 4) {
- return fcircadd_v4(RxV, offset, M, CS);
+ start_addr = CS;
+ end_addr = start_addr + length;
+ } else {
+ /*
+ * Versions v3 and earlier used the K value to specify a power-of-2 size
+ * 2^(K+2) that is greater than the buffer length
+ */
+ int32_t mask = (1 << (K_const + 2)) - 1;
+ start_addr = RxV & (~mask);
+ end_addr = start_addr | length;
}
if (new_ptr >= end_addr) {
@@ -297,24 +281,103 @@
return new_ptr;
}
-/*
- * Hexagon FP operations return ~0 insteat of NaN
- * The hex_check_sfnan/hex_check_dfnan functions perform this check
- */
-static float32 hex_check_sfnan(float32 x)
+uint32_t HELPER(fbrev)(uint32_t addr)
{
- if (float32_is_any_nan(x)) {
- return make_float32(0xFFFFFFFFU);
- }
- return x;
+ /*
+ * Bit reverse the low 16 bits of the address
+ */
+ return deposit32(addr, 0, 16, revbit16(addr));
}
-static float64 hex_check_dfnan(float64 x)
+static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
{
- if (float64_is_any_nan(x)) {
- return make_float64(0xFFFFFFFFFFFFFFFFULL);
+ return make_float32(
+ ((sign & 1) << 31) |
+ ((exp & 0xff) << SF_MANTBITS) |
+ (mant & ((1 << SF_MANTBITS) - 1)));
+}
+
+/*
+ * sfrecipa, sfinvsqrta have two 32-bit results
+ * r0,p0=sfrecipa(r1,r2)
+ * r0,p0=sfinvsqrta(r1)
+ *
+ * Since helpers can only return a single value, we pack the two results
+ * into a 64-bit value.
+ */
+uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
+{
+ int32_t PeV = 0;
+ float32 RdV;
+ int idx;
+ int adjust;
+ int mant;
+ int exp;
+
+ arch_fpop_start(env);
+ if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
+ PeV = adjust;
+ idx = (RtV >> 16) & 0x7f;
+ mant = (recip_lookup_table[idx] << 15) | 1;
+ exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
+ RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
}
- return x;
+ arch_fpop_end(env);
+ return ((uint64_t)RdV << 32) | PeV;
+}
+
+uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
+{
+ int PeV = 0;
+ float32 RdV;
+ int idx;
+ int adjust;
+ int mant;
+ int exp;
+
+ arch_fpop_start(env);
+ if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
+ PeV = adjust;
+ idx = (RsV >> 17) & 0x7f;
+ mant = (invsqrt_lookup_table[idx] << 15);
+ exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
+ RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
+ }
+ arch_fpop_end(env);
+ return ((uint64_t)RdV << 32) | PeV;
+}
+
+int64_t HELPER(vacsh_val)(CPUHexagonState *env,
+ int64_t RxxV, int64_t RssV, int64_t RttV)
+{
+ for (int i = 0; i < 4; i++) {
+ int xv = sextract64(RxxV, i * 16, 16);
+ int sv = sextract64(RssV, i * 16, 16);
+ int tv = sextract64(RttV, i * 16, 16);
+ int max;
+ xv = xv + tv;
+ sv = sv - tv;
+ max = xv > sv ? xv : sv;
+ /* Note that fSATH can set the OVF bit in usr */
+ RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
+ }
+ return RxxV;
+}
+
+int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
+ int64_t RxxV, int64_t RssV, int64_t RttV)
+{
+ int32_t PeV = 0;
+ for (int i = 0; i < 4; i++) {
+ int xv = sextract64(RxxV, i * 16, 16);
+ int sv = sextract64(RssV, i * 16, 16);
+ int tv = sextract64(RttV, i * 16, 16);
+ xv = xv + tv;
+ sv = sv - tv;
+ PeV = deposit32(PeV, i * 2, 1, (xv > sv));
+ PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
+ }
+ return PeV;
}
/*
@@ -332,8 +395,8 @@
}
}
-static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint8_t retval;
check_noshuf(env, slot);
@@ -341,8 +404,8 @@
return retval;
}
-static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint16_t retval;
check_noshuf(env, slot);
@@ -350,8 +413,8 @@
return retval;
}
-static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint32_t retval;
check_noshuf(env, slot);
@@ -359,8 +422,8 @@
return retval;
}
-static inline uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint64_t retval;
check_noshuf(env, slot);
@@ -374,7 +437,6 @@
float64 out_f64;
arch_fpop_start(env);
out_f64 = float32_to_float64(RsV, &env->fp_status);
- out_f64 = hex_check_dfnan(out_f64);
arch_fpop_end(env);
return out_f64;
}
@@ -384,7 +446,6 @@
float32 out_f32;
arch_fpop_start(env);
out_f32 = float64_to_float32(RssV, &env->fp_status);
- out_f32 = hex_check_sfnan(out_f32);
arch_fpop_end(env);
return out_f32;
}
@@ -394,7 +455,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = uint32_to_float32(RsV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -404,7 +464,6 @@
float64 RddV;
arch_fpop_start(env);
RddV = uint32_to_float64(RsV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -414,7 +473,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = int32_to_float32(RsV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -424,7 +482,6 @@
float64 RddV;
arch_fpop_start(env);
RddV = int32_to_float64(RsV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -434,7 +491,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = uint64_to_float32(RssV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -444,7 +500,6 @@
float64 RddV;
arch_fpop_start(env);
RddV = uint64_to_float64(RssV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -454,7 +509,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = int64_to_float32(RssV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -464,16 +518,21 @@
float64 RddV;
arch_fpop_start(env);
RddV = int64_to_float64(RssV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
+uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- RdV = conv_sf_to_4u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float32_to_uint32(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -482,16 +541,28 @@
{
int32_t RdV;
arch_fpop_start(env);
- RdV = conv_sf_to_4s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float32_to_int32(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
+uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- RddV = conv_sf_to_8u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float32_to_uint64(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -500,16 +571,28 @@
{
int64_t RddV;
arch_fpop_start(env);
- RddV = conv_sf_to_8s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float32_to_int64(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
+uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- RdV = conv_df_to_4u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float64_to_uint32(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -518,16 +601,28 @@
{
int32_t RdV;
arch_fpop_start(env);
- RdV = conv_df_to_4s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float64_to_int32(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
+uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- RddV = conv_df_to_8u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float64_to_uint64(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -536,17 +631,28 @@
{
int64_t RddV;
arch_fpop_start(env);
- RddV = conv_df_to_8s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float64_to_int64(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
+uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_sf_to_4u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -555,18 +661,28 @@
{
int32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_sf_to_4s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
+uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_sf_to_8u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -575,18 +691,28 @@
{
int64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_sf_to_8s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
+uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_df_to_4u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -595,18 +721,28 @@
{
int32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_df_to_4s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
+uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_df_to_8u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -615,8 +751,13 @@
{
int64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_df_to_8s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -626,7 +767,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = float32_add(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -636,7 +776,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = float32_sub(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -688,7 +827,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = float32_maxnum(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -698,7 +836,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = float32_minnum(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -765,7 +902,6 @@
float64 RddV;
arch_fpop_start(env);
RddV = float64_add(RssV, RttV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -775,7 +911,6 @@
float64 RddV;
arch_fpop_start(env);
RddV = float64_sub(RssV, RttV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -788,7 +923,6 @@
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
float_raise(float_flag_invalid, &env->fp_status);
}
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -801,7 +935,6 @@
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
float_raise(float_flag_invalid, &env->fp_status);
}
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -877,7 +1010,6 @@
float32 RdV;
arch_fpop_start(env);
RdV = internal_mpyf(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -887,7 +1019,6 @@
{
arch_fpop_start(env);
RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
- RxV = hex_check_sfnan(RxV);
arch_fpop_end(env);
return RxV;
}
@@ -919,7 +1050,6 @@
RxV = check_nan(RxV, RsV, &env->fp_status);
RxV = check_nan(RxV, RtV, &env->fp_status);
tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
- tmp = hex_check_sfnan(tmp);
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
RxV = tmp;
}
@@ -934,12 +1064,11 @@
arch_fpop_start(env);
neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
- RxV = hex_check_sfnan(RxV);
arch_fpop_end(env);
return RxV;
}
-static inline bool is_inf_prod(int32_t a, int32_t b)
+static bool is_inf_prod(int32_t a, int32_t b)
{
return (float32_is_infinity(a) && float32_is_infinity(b)) ||
(float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
@@ -949,8 +1078,8 @@
float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
float32 RsV, float32 RtV)
{
- int infinp;
- int infminusinf;
+ bool infinp;
+ bool infminusinf;
float32 tmp;
arch_fpop_start(env);
@@ -965,7 +1094,6 @@
RxV = check_nan(RxV, RsV, &env->fp_status);
RxV = check_nan(RxV, RtV, &env->fp_status);
tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
- tmp = hex_check_sfnan(tmp);
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
RxV = tmp;
}
@@ -983,8 +1111,8 @@
float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
float32 RsV, float32 RtV)
{
- int infinp;
- int infminusinf;
+ bool infinp;
+ bool infminusinf;
float32 tmp;
arch_fpop_start(env);
@@ -1000,7 +1128,6 @@
RxV = check_nan(RxV, RtV, &env->fp_status);
float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
- tmp = hex_check_sfnan(tmp);
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
RxV = tmp;
}
@@ -1024,13 +1151,11 @@
float64_is_normal(RttV)) {
RddV = float64_mul(RssV, make_float64(0x4330000000000000),
&env->fp_status);
- RddV = hex_check_dfnan(RddV);
} else if (float64_is_denormal(RttV) &&
(float64_getexp(RssV) >= 512) &&
float64_is_normal(RssV)) {
RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
&env->fp_status);
- RddV = hex_check_dfnan(RddV);
} else {
RddV = RssV;
}
@@ -1043,7 +1168,6 @@
{
arch_fpop_start(env);
RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
- RxxV = hex_check_dfnan(RxxV);
arch_fpop_end(env);
return RxxV;
}
diff --git a/target/hexagon/reg_fields.c b/target/hexagon/reg_fields.c
index bdcab79..6713203 100644
--- a/target/hexagon/reg_fields.c
+++ b/target/hexagon/reg_fields.c
@@ -18,10 +18,9 @@
#include "qemu/osdep.h"
#include "reg_fields.h"
-const RegField reg_field_info[] = {
+const RegField reg_field_info[NUM_REG_FIELDS] = {
#define DEF_REG_FIELD(TAG, START, WIDTH) \
{ START, WIDTH },
#include "reg_fields_def.h.inc"
- { 0, 0 }
#undef DEF_REG_FIELD
};
diff --git a/target/hexagon/reg_fields.h b/target/hexagon/reg_fields.h
index d3c86c94..9e2ad5d 100644
--- a/target/hexagon/reg_fields.h
+++ b/target/hexagon/reg_fields.h
@@ -23,8 +23,6 @@
int width;
} RegField;
-extern const RegField reg_field_info[];
-
enum {
#define DEF_REG_FIELD(TAG, START, WIDTH) \
TAG,
@@ -33,4 +31,6 @@
#undef DEF_REG_FIELD
};
+extern const RegField reg_field_info[NUM_REG_FIELDS];
+
#endif
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index eeaad5f..9a37644 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -35,9 +35,7 @@
TCGv hex_slot_cancelled;
TCGv hex_branch_taken;
TCGv hex_new_value[TOTAL_PER_THREAD_REGS];
-#if HEX_DEBUG
TCGv hex_reg_written[TOTAL_PER_THREAD_REGS];
-#endif
TCGv hex_new_pred_value[NUM_PREGS];
TCGv hex_pred_written;
TCGv hex_store_addr[STORES_MAX];
@@ -54,19 +52,42 @@
"p0", "p1", "p2", "p3"
};
-void gen_exception(int excp)
+static void gen_exception_raw(int excp)
{
TCGv_i32 helper_tmp = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, helper_tmp);
tcg_temp_free_i32(helper_tmp);
}
-void gen_exception_debug(void)
+static void gen_exec_counters(DisasContext *ctx)
{
- gen_exception(EXCP_DEBUG);
+ tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
+ hex_gpr[HEX_REG_QEMU_PKT_CNT], ctx->num_packets);
+ tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_INSN_CNT],
+ hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns);
}
-#if HEX_DEBUG
+static void gen_end_tb(DisasContext *ctx)
+{
+ gen_exec_counters(ctx);
+ tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
+ if (ctx->base.singlestep_enabled) {
+ gen_exception_raw(EXCP_DEBUG);
+ } else {
+ tcg_gen_exit_tb(NULL, 0);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+static void gen_exception_end_tb(DisasContext *ctx, int excp)
+{
+ gen_exec_counters(ctx);
+ tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
+ gen_exception_raw(excp);
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+}
+
#define PACKET_BUFFER_LEN 1028
static void print_pkt(Packet *pkt)
{
@@ -75,10 +96,12 @@
HEX_DEBUG_LOG("%s", buf->str);
g_string_free(buf, true);
}
-#define HEX_DEBUG_PRINT_PKT(pkt) print_pkt(pkt)
-#else
-#define HEX_DEBUG_PRINT_PKT(pkt) /* nothing */
-#endif
+#define HEX_DEBUG_PRINT_PKT(pkt) \
+ do { \
+ if (HEX_DEBUG) { \
+ print_pkt(pkt); \
+ } \
+ } while (0)
static int read_packet_words(CPUHexagonState *env, DisasContext *ctx,
uint32_t words[])
@@ -88,8 +111,8 @@
memset(words, 0, PACKET_WORDS_MAX * sizeof(uint32_t));
for (nwords = 0; !found_end && nwords < PACKET_WORDS_MAX; nwords++) {
- words[nwords] = cpu_ldl_code(env,
- ctx->base.pc_next + nwords * sizeof(uint32_t));
+ words[nwords] =
+ translator_ldl(env, ctx->base.pc_next + nwords * sizeof(uint32_t));
found_end = is_packet_end(words[nwords]);
}
if (!found_end) {
@@ -148,17 +171,18 @@
ctx->reg_log_idx = 0;
bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS);
ctx->preg_log_idx = 0;
+ bitmap_zero(ctx->pregs_written, NUM_PREGS);
for (i = 0; i < STORES_MAX; i++) {
ctx->store_width[i] = 0;
}
tcg_gen_movi_tl(hex_pkt_has_store_s1, pkt->pkt_has_store_s1);
- ctx->s1_store_processed = 0;
+ ctx->s1_store_processed = false;
-#if HEX_DEBUG
- /* Handy place to set a breakpoint before the packet executes */
- gen_helper_debug_start_packet(cpu_env);
- tcg_gen_movi_tl(hex_this_PC, ctx->base.pc_next);
-#endif
+ if (HEX_DEBUG) {
+ /* Handy place to set a breakpoint before the packet executes */
+ gen_helper_debug_start_packet(cpu_env);
+ tcg_gen_movi_tl(hex_this_PC, ctx->base.pc_next);
+ }
/* Initialize the runtime state for packet semantics */
if (need_pc(pkt)) {
@@ -185,7 +209,7 @@
int attrib, int rnum)
{
if (GET_ATTRIB(insn->opcode, attrib)) {
- int is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC);
+ bool is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC);
if (is_predicated && !is_preloaded(ctx, rnum)) {
tcg_gen_mov_tl(hex_new_value[rnum], hex_gpr[rnum]);
}
@@ -202,7 +226,7 @@
}
}
-static void mark_implicit_writes(DisasContext *ctx, Insn *insn)
+static void mark_implicit_reg_writes(DisasContext *ctx, Insn *insn)
{
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_FP, HEX_REG_FP);
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SP, HEX_REG_SP);
@@ -211,7 +235,10 @@
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0);
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1);
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1);
+}
+static void mark_implicit_pred_writes(DisasContext *ctx, Insn *insn)
+{
mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P0, 0);
mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P1, 1);
mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P2, 2);
@@ -222,11 +249,11 @@
Insn *insn, Packet *pkt)
{
if (insn->generate) {
- mark_implicit_writes(ctx, insn);
+ mark_implicit_reg_writes(ctx, insn);
insn->generate(env, ctx, insn, pkt);
+ mark_implicit_pred_writes(ctx, insn);
} else {
- gen_exception(HEX_EXCP_INVALID_OPCODE);
- ctx->base.is_jmp = DISAS_NORETURN;
+ gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE);
}
}
@@ -280,10 +307,11 @@
for (i = 0; i < ctx->preg_log_idx; i++) {
int pred_num = ctx->preg_log[i];
tcg_gen_mov_tl(hex_pred[pred_num], hex_new_pred_value[pred_num]);
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pred_num);
-#endif
+ if (HEX_DEBUG) {
+ /* Do this so HELPER(debug_commit_end) will know */
+ tcg_gen_ori_tl(hex_pred_written, hex_pred_written,
+ 1 << pred_num);
+ }
}
}
@@ -292,20 +320,16 @@
tcg_temp_free(pval);
}
-#if HEX_DEBUG
-static inline void gen_check_store_width(DisasContext *ctx, int slot_num)
+static void gen_check_store_width(DisasContext *ctx, int slot_num)
{
- TCGv slot = tcg_const_tl(slot_num);
- TCGv check = tcg_const_tl(ctx->store_width[slot_num]);
- gen_helper_debug_check_store_width(cpu_env, slot, check);
- tcg_temp_free(slot);
- tcg_temp_free(check);
+ if (HEX_DEBUG) {
+ TCGv slot = tcg_const_tl(slot_num);
+ TCGv check = tcg_const_tl(ctx->store_width[slot_num]);
+ gen_helper_debug_check_store_width(cpu_env, slot, check);
+ tcg_temp_free(slot);
+ tcg_temp_free(check);
+ }
}
-#define HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num) \
- gen_check_store_width(ctx, slot_num)
-#else
-#define HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num) /* nothing */
-#endif
static bool slot_is_predicated(Packet *pkt, int slot_num)
{
@@ -330,7 +354,7 @@
if (slot_num == 1 && ctx->s1_store_processed) {
return;
}
- ctx->s1_store_processed = 1;
+ ctx->s1_store_processed = true;
if (is_predicated) {
TCGv cancelled = tcg_temp_new();
@@ -355,25 +379,25 @@
*/
switch (ctx->store_width[slot_num]) {
case 1:
- HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
+ gen_check_store_width(ctx, slot_num);
tcg_gen_qemu_st8(hex_store_val32[slot_num],
hex_store_addr[slot_num],
ctx->mem_idx);
break;
case 2:
- HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
+ gen_check_store_width(ctx, slot_num);
tcg_gen_qemu_st16(hex_store_val32[slot_num],
hex_store_addr[slot_num],
ctx->mem_idx);
break;
case 4:
- HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
+ gen_check_store_width(ctx, slot_num);
tcg_gen_qemu_st32(hex_store_val32[slot_num],
hex_store_addr[slot_num],
ctx->mem_idx);
break;
case 8:
- HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
+ gen_check_store_width(ctx, slot_num);
tcg_gen_qemu_st64(hex_store_val64[slot_num],
hex_store_addr[slot_num],
ctx->mem_idx);
@@ -451,14 +475,6 @@
ctx->num_insns += num_real_insns;
}
-static void gen_exec_counters(DisasContext *ctx)
-{
- tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
- hex_gpr[HEX_REG_QEMU_PKT_CNT], ctx->num_packets);
- tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_INSN_CNT],
- hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns);
-}
-
static void gen_commit_packet(DisasContext *ctx, Packet *pkt)
{
gen_reg_writes(ctx);
@@ -466,8 +482,7 @@
process_store_log(ctx, pkt);
process_dczeroa(ctx, pkt);
update_exec_counters(ctx, pkt);
-#if HEX_DEBUG
- {
+ if (HEX_DEBUG) {
TCGv has_st0 =
tcg_const_tl(pkt->pkt_has_store_s0 && !pkt->pkt_has_dczeroa);
TCGv has_st1 =
@@ -479,10 +494,9 @@
tcg_temp_free(has_st0);
tcg_temp_free(has_st1);
}
-#endif
if (pkt->pkt_has_cof) {
- ctx->base.is_jmp = DISAS_NORETURN;
+ gen_end_tb(ctx);
}
}
@@ -495,8 +509,7 @@
nwords = read_packet_words(env, ctx, words);
if (!nwords) {
- gen_exception(HEX_EXCP_INVALID_PACKET);
- ctx->base.is_jmp = DISAS_NORETURN;
+ gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
return;
}
@@ -509,8 +522,7 @@
gen_commit_packet(ctx, &pkt);
ctx->base.pc_next += pkt.encod_pkt_size_in_bytes;
} else {
- gen_exception(HEX_EXCP_INVALID_PACKET);
- ctx->base.is_jmp = DISAS_NORETURN;
+ gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
}
}
@@ -540,9 +552,7 @@
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
- tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);
- ctx->base.is_jmp = DISAS_NORETURN;
- gen_exception_debug();
+ gen_exception_end_tb(ctx, EXCP_DEBUG);
/*
* The address covered by the breakpoint must be included in
* [tb->pc, tb->pc + tb->size) in order to for it to be
@@ -589,14 +599,10 @@
* The CPU log is used to compare against LLDB single stepping,
* so end the TLB after every packet.
*/
- HexagonCPU *hex_cpu = container_of(env, HexagonCPU, env);
+ HexagonCPU *hex_cpu = env_archcpu(env);
if (hex_cpu->lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
ctx->base.is_jmp = DISAS_TOO_MANY;
}
-#if HEX_DEBUG
- /* When debugging, only put one packet per TB */
- ctx->base.is_jmp = DISAS_TOO_MANY;
-#endif
}
}
@@ -609,19 +615,12 @@
gen_exec_counters(ctx);
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);
if (ctx->base.singlestep_enabled) {
- gen_exception_debug();
+ gen_exception_raw(EXCP_DEBUG);
} else {
tcg_gen_exit_tb(NULL, 0);
}
break;
case DISAS_NORETURN:
- gen_exec_counters(ctx);
- tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
- if (ctx->base.singlestep_enabled) {
- gen_exception_debug();
- } else {
- tcg_gen_exit_tb(NULL, 0);
- }
break;
default:
g_assert_not_reached();
@@ -654,9 +653,7 @@
#define NAME_LEN 64
static char new_value_names[TOTAL_PER_THREAD_REGS][NAME_LEN];
-#if HEX_DEBUG
static char reg_written_names[TOTAL_PER_THREAD_REGS][NAME_LEN];
-#endif
static char new_pred_value_names[NUM_PREGS][NAME_LEN];
static char store_addr_names[STORES_MAX][NAME_LEN];
static char store_width_names[STORES_MAX][NAME_LEN];
@@ -669,11 +666,11 @@
opcode_init();
-#if HEX_DEBUG
- if (!qemu_logfile) {
- qemu_set_log(qemu_loglevel);
+ if (HEX_DEBUG) {
+ if (!qemu_logfile) {
+ qemu_set_log(qemu_loglevel);
+ }
}
-#endif
for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
hex_gpr[i] = tcg_global_mem_new(cpu_env,
@@ -685,13 +682,13 @@
offsetof(CPUHexagonState, new_value[i]),
new_value_names[i]);
-#if HEX_DEBUG
- snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s",
- hexagon_regnames[i]);
- hex_reg_written[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPUHexagonState, reg_written[i]),
- reg_written_names[i]);
-#endif
+ if (HEX_DEBUG) {
+ snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s",
+ hexagon_regnames[i]);
+ hex_reg_written[i] = tcg_global_mem_new(cpu_env,
+ offsetof(CPUHexagonState, reg_written[i]),
+ reg_written_names[i]);
+ }
}
for (i = 0; i < NUM_PREGS; i++) {
hex_pred[i] = tcg_global_mem_new(cpu_env,
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 938f7fb..703fd13 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -34,17 +34,16 @@
DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS);
int preg_log[PRED_WRITES_MAX];
int preg_log_idx;
+ DECLARE_BITMAP(pregs_written, NUM_PREGS);
uint8_t store_width[STORES_MAX];
- uint8_t s1_store_processed;
+ bool s1_store_processed;
} DisasContext;
static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
{
-#if HEX_DEBUG
if (test_bit(rnum, ctx->regs_written)) {
HEX_DEBUG_LOG("WARNING: Multiple writes to r%d\n", rnum);
}
-#endif
ctx->reg_log[ctx->reg_log_idx] = rnum;
ctx->reg_log_idx++;
set_bit(rnum, ctx->regs_written);
@@ -60,6 +59,7 @@
{
ctx->preg_log[ctx->preg_log_idx] = pnum;
ctx->preg_log_idx++;
+ set_bit(pnum, ctx->pregs_written);
}
static inline bool is_preloaded(DisasContext *ctx, int num)
@@ -86,8 +86,5 @@
extern TCGv hex_llsc_val;
extern TCGv_i64 hex_llsc_val_i64;
-void gen_exception(int excp);
-void gen_exception_debug(void);
-
void process_store(DisasContext *ctx, Packet *pkt, int slot_num);
#endif
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index dce1e16..1ad2fe4 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -35,155 +35,84 @@
#include "qapi/qapi-commands-machine-target.h"
#include "fpu_helper.h"
-#if !defined(CONFIG_USER_ONLY)
-
-/* Called for updates to CP0_Status. */
-void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
-{
- int32_t tcstatus, *tcst;
- uint32_t v = cpu->CP0_Status;
- uint32_t cu, mx, asid, ksu;
- uint32_t mask = ((1 << CP0TCSt_TCU3)
- | (1 << CP0TCSt_TCU2)
- | (1 << CP0TCSt_TCU1)
- | (1 << CP0TCSt_TCU0)
- | (1 << CP0TCSt_TMX)
- | (3 << CP0TCSt_TKSU)
- | (0xff << CP0TCSt_TASID));
-
- cu = (v >> CP0St_CU0) & 0xf;
- mx = (v >> CP0St_MX) & 0x1;
- ksu = (v >> CP0St_KSU) & 0x3;
- asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
-
- tcstatus = cu << CP0TCSt_TCU0;
- tcstatus |= mx << CP0TCSt_TMX;
- tcstatus |= ksu << CP0TCSt_TKSU;
- tcstatus |= asid;
-
- if (tc == cpu->current_tc) {
- tcst = &cpu->active_tc.CP0_TCStatus;
- } else {
- tcst = &cpu->tcs[tc].CP0_TCStatus;
- }
-
- *tcst &= ~mask;
- *tcst |= tcstatus;
- compute_hflags(cpu);
-}
-
-void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
-{
- uint32_t mask = env->CP0_Status_rw_bitmask;
- target_ulong old = env->CP0_Status;
-
- if (env->insn_flags & ISA_MIPS_R6) {
- bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
-#if defined(TARGET_MIPS64)
- uint32_t ksux = (1 << CP0St_KX) & val;
- ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */
- ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */
- val = (val & ~(7 << CP0St_UX)) | ksux;
-#endif
- if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
- mask &= ~(3 << CP0St_KSU);
- }
- mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val);
- }
-
- env->CP0_Status = (old & ~mask) | (val & mask);
-#if defined(TARGET_MIPS64)
- if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
- /* Access to at least one of the 64-bit segments has been disabled */
- tlb_flush(env_cpu(env));
- }
-#endif
- if (ase_mt_available(env)) {
- sync_c0_status(env, env, env->current_tc);
- } else {
- compute_hflags(env);
- }
-}
-
-void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val)
-{
- uint32_t mask = 0x00C00300;
- uint32_t old = env->CP0_Cause;
- int i;
-
- if (env->insn_flags & ISA_MIPS_R2) {
- mask |= 1 << CP0Ca_DC;
- }
- if (env->insn_flags & ISA_MIPS_R6) {
- mask &= ~((1 << CP0Ca_WP) & val);
- }
-
- env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask);
-
- if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
- if (env->CP0_Cause & (1 << CP0Ca_DC)) {
- cpu_mips_stop_count(env);
- } else {
- cpu_mips_start_count(env);
- }
- }
-
- /* Set/reset software interrupts */
- for (i = 0 ; i < 2 ; i++) {
- if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
- cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
- }
- }
-}
-
-#endif /* !CONFIG_USER_ONLY */
-
-static const char * const excp_names[EXCP_LAST + 1] = {
- [EXCP_RESET] = "reset",
- [EXCP_SRESET] = "soft reset",
- [EXCP_DSS] = "debug single step",
- [EXCP_DINT] = "debug interrupt",
- [EXCP_NMI] = "non-maskable interrupt",
- [EXCP_MCHECK] = "machine check",
- [EXCP_EXT_INTERRUPT] = "interrupt",
- [EXCP_DFWATCH] = "deferred watchpoint",
- [EXCP_DIB] = "debug instruction breakpoint",
- [EXCP_IWATCH] = "instruction fetch watchpoint",
- [EXCP_AdEL] = "address error load",
- [EXCP_AdES] = "address error store",
- [EXCP_TLBF] = "TLB refill",
- [EXCP_IBE] = "instruction bus error",
- [EXCP_DBp] = "debug breakpoint",
- [EXCP_SYSCALL] = "syscall",
- [EXCP_BREAK] = "break",
- [EXCP_CpU] = "coprocessor unusable",
- [EXCP_RI] = "reserved instruction",
- [EXCP_OVERFLOW] = "arithmetic overflow",
- [EXCP_TRAP] = "trap",
- [EXCP_FPE] = "floating point",
- [EXCP_DDBS] = "debug data break store",
- [EXCP_DWATCH] = "data watchpoint",
- [EXCP_LTLBL] = "TLB modify",
- [EXCP_TLBL] = "TLB load",
- [EXCP_TLBS] = "TLB store",
- [EXCP_DBE] = "data bus error",
- [EXCP_DDBL] = "debug data break load",
- [EXCP_THREAD] = "thread",
- [EXCP_MDMX] = "MDMX",
- [EXCP_C2E] = "precise coprocessor 2",
- [EXCP_CACHE] = "cache error",
- [EXCP_TLBXI] = "TLB execute-inhibit",
- [EXCP_TLBRI] = "TLB read-inhibit",
- [EXCP_MSADIS] = "MSA disabled",
- [EXCP_MSAFPE] = "MSA floating point",
+const char regnames[32][4] = {
+ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
};
-const char *mips_exception_name(int32_t exception)
+static void fpu_dump_fpr(fpr_t *fpr, FILE *f, bool is_fpu64)
{
- if (exception < 0 || exception > EXCP_LAST) {
- return "unknown";
+ if (is_fpu64) {
+ qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu: %13g\n",
+ fpr->w[FP_ENDIAN_IDX], fpr->d,
+ (double)fpr->fd,
+ (double)fpr->fs[FP_ENDIAN_IDX],
+ (double)fpr->fs[!FP_ENDIAN_IDX]);
+ } else {
+ fpr_t tmp;
+
+ tmp.w[FP_ENDIAN_IDX] = fpr->w[FP_ENDIAN_IDX];
+ tmp.w[!FP_ENDIAN_IDX] = (fpr + 1)->w[FP_ENDIAN_IDX];
+ qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu:%13g\n",
+ tmp.w[FP_ENDIAN_IDX], tmp.d,
+ (double)tmp.fd,
+ (double)tmp.fs[FP_ENDIAN_IDX],
+ (double)tmp.fs[!FP_ENDIAN_IDX]);
}
- return excp_names[exception];
+}
+
+static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags)
+{
+ int i;
+ bool is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
+
+ qemu_fprintf(f,
+ "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n",
+ env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
+ get_float_exception_flags(&env->active_fpu.fp_status));
+ for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
+ qemu_fprintf(f, "%3s: ", fregnames[i]);
+ fpu_dump_fpr(&env->active_fpu.fpr[i], f, is_fpu64);
+ }
+}
+
+static void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+ int i;
+
+ qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
+ " LO=0x" TARGET_FMT_lx " ds %04x "
+ TARGET_FMT_lx " " TARGET_FMT_ld "\n",
+ env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0],
+ env->hflags, env->btarget, env->bcond);
+ for (i = 0; i < 32; i++) {
+ if ((i & 3) == 0) {
+ qemu_fprintf(f, "GPR%02d:", i);
+ }
+ qemu_fprintf(f, " %s " TARGET_FMT_lx,
+ regnames[i], env->active_tc.gpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+
+ qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x"
+ TARGET_FMT_lx "\n",
+ env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
+ qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016"
+ PRIx64 "\n",
+ env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
+ qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n",
+ env->CP0_Config2, env->CP0_Config3);
+ qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n",
+ env->CP0_Config4, env->CP0_Config5);
+ if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) {
+ fpu_dump_state(env, f, flags);
+ }
}
void cpu_set_exception_base(int vp_index, target_ulong address)
@@ -192,101 +121,13 @@
vp->env.exception_base = address;
}
-target_ulong exception_resume_pc(CPUMIPSState *env)
-{
- target_ulong bad_pc;
- target_ulong isa_mode;
-
- isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
- bad_pc = env->active_tc.PC | isa_mode;
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /*
- * If the exception was raised from a delay slot, come back to
- * the jump.
- */
- bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
- }
-
- return bad_pc;
-}
-
-bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
-
- if (cpu_mips_hw_interrupts_enabled(env) &&
- cpu_mips_hw_interrupts_pending(env)) {
- /* Raise it */
- cs->exception_index = EXCP_EXT_INTERRUPT;
- env->error_code = 0;
- mips_cpu_do_interrupt(cs);
- return true;
- }
- }
- return false;
-}
-
-void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
- uint32_t exception,
- int error_code,
- uintptr_t pc)
-{
- CPUState *cs = env_cpu(env);
-
- qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n",
- __func__, exception, mips_exception_name(exception),
- error_code);
- cs->exception_index = exception;
- env->error_code = error_code;
-
- cpu_loop_exit_restore(cs, pc);
-}
-
static void mips_cpu_set_pc(CPUState *cs, vaddr value)
{
MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
- env->active_tc.PC = value & ~(target_ulong)1;
- if (value & 1) {
- env->hflags |= MIPS_HFLAG_M16;
- } else {
- env->hflags &= ~(MIPS_HFLAG_M16);
- }
+ mips_env_set_pc(&cpu->env, value);
}
-#ifdef CONFIG_TCG
-static void mips_cpu_synchronize_from_tb(CPUState *cs,
- const TranslationBlock *tb)
-{
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
-
- env->active_tc.PC = tb->pc;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
-}
-
-# ifndef CONFIG_USER_ONLY
-static bool mips_io_recompile_replay_branch(CPUState *cs,
- const TranslationBlock *tb)
-{
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
-
- if ((env->hflags & MIPS_HFLAG_BMASK) != 0
- && env->active_tc.PC != tb->pc) {
- env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
- env->hflags &= ~MIPS_HFLAG_BMASK;
- return true;
- }
- return false;
-}
-# endif /* !CONFIG_USER_ONLY */
-#endif /* CONFIG_TCG */
-
static bool mips_cpu_has_work(CPUState *cs)
{
MIPSCPU *cpu = MIPS_CPU(cs);
@@ -634,7 +475,7 @@
env->exception_base = (int32_t)0xBFC00000;
-#ifndef CONFIG_USER_ONLY
+#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
mmu_init(env, env->cpu_model);
#endif
fpu_init(env, env->cpu_model);
diff --git a/target/mips/fpu.c b/target/mips/fpu.c
new file mode 100644
index 0000000..c7c487c
--- /dev/null
+++ b/target/mips/fpu.c
@@ -0,0 +1,25 @@
+/*
+ * Helpers for emulation of FPU-related MIPS instructions.
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+#include "qemu/osdep.h"
+#include "fpu/softfloat-helpers.h"
+#include "fpu_helper.h"
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+const FloatRoundMode ieee_rm[4] = {
+ float_round_nearest_even,
+ float_round_to_zero,
+ float_round_up,
+ float_round_down
+};
+
+const char fregnames[32][4] = {
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+};
diff --git a/target/mips/helper.h b/target/mips/helper.h
index 7094944..a9c6c7d 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -2,10 +2,6 @@
DEF_HELPER_2(raise_exception, noreturn, env, i32)
DEF_HELPER_1(raise_exception_debug, noreturn, env)
-#ifndef CONFIG_USER_ONLY
-DEF_HELPER_1(do_semihosting, void, env)
-#endif
-
#ifdef TARGET_MIPS64
DEF_HELPER_4(sdl, void, env, tl, tl, int)
DEF_HELPER_4(sdr, void, env, tl, tl, int)
@@ -42,164 +38,6 @@
DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32)
-#ifndef CONFIG_USER_ONLY
-/* CP0 helpers */
-DEF_HELPER_1(mfc0_mvpcontrol, tl, env)
-DEF_HELPER_1(mfc0_mvpconf0, tl, env)
-DEF_HELPER_1(mfc0_mvpconf1, tl, env)
-DEF_HELPER_1(mftc0_vpecontrol, tl, env)
-DEF_HELPER_1(mftc0_vpeconf0, tl, env)
-DEF_HELPER_1(mfc0_random, tl, env)
-DEF_HELPER_1(mfc0_tcstatus, tl, env)
-DEF_HELPER_1(mftc0_tcstatus, tl, env)
-DEF_HELPER_1(mfc0_tcbind, tl, env)
-DEF_HELPER_1(mftc0_tcbind, tl, env)
-DEF_HELPER_1(mfc0_tcrestart, tl, env)
-DEF_HELPER_1(mftc0_tcrestart, tl, env)
-DEF_HELPER_1(mfc0_tchalt, tl, env)
-DEF_HELPER_1(mftc0_tchalt, tl, env)
-DEF_HELPER_1(mfc0_tccontext, tl, env)
-DEF_HELPER_1(mftc0_tccontext, tl, env)
-DEF_HELPER_1(mfc0_tcschedule, tl, env)
-DEF_HELPER_1(mftc0_tcschedule, tl, env)
-DEF_HELPER_1(mfc0_tcschefback, tl, env)
-DEF_HELPER_1(mftc0_tcschefback, tl, env)
-DEF_HELPER_1(mfc0_count, tl, env)
-DEF_HELPER_1(mfc0_saar, tl, env)
-DEF_HELPER_1(mfhc0_saar, tl, env)
-DEF_HELPER_1(mftc0_entryhi, tl, env)
-DEF_HELPER_1(mftc0_status, tl, env)
-DEF_HELPER_1(mftc0_cause, tl, env)
-DEF_HELPER_1(mftc0_epc, tl, env)
-DEF_HELPER_1(mftc0_ebase, tl, env)
-DEF_HELPER_2(mftc0_configx, tl, env, tl)
-DEF_HELPER_1(mfc0_lladdr, tl, env)
-DEF_HELPER_1(mfc0_maar, tl, env)
-DEF_HELPER_1(mfhc0_maar, tl, env)
-DEF_HELPER_2(mfc0_watchlo, tl, env, i32)
-DEF_HELPER_2(mfc0_watchhi, tl, env, i32)
-DEF_HELPER_2(mfhc0_watchhi, tl, env, i32)
-DEF_HELPER_1(mfc0_debug, tl, env)
-DEF_HELPER_1(mftc0_debug, tl, env)
-#ifdef TARGET_MIPS64
-DEF_HELPER_1(dmfc0_tcrestart, tl, env)
-DEF_HELPER_1(dmfc0_tchalt, tl, env)
-DEF_HELPER_1(dmfc0_tccontext, tl, env)
-DEF_HELPER_1(dmfc0_tcschedule, tl, env)
-DEF_HELPER_1(dmfc0_tcschefback, tl, env)
-DEF_HELPER_1(dmfc0_lladdr, tl, env)
-DEF_HELPER_1(dmfc0_maar, tl, env)
-DEF_HELPER_2(dmfc0_watchlo, tl, env, i32)
-DEF_HELPER_2(dmfc0_watchhi, tl, env, i32)
-DEF_HELPER_1(dmfc0_saar, tl, env)
-#endif /* TARGET_MIPS64 */
-
-DEF_HELPER_2(mtc0_index, void, env, tl)
-DEF_HELPER_2(mtc0_mvpcontrol, void, env, tl)
-DEF_HELPER_2(mtc0_vpecontrol, void, env, tl)
-DEF_HELPER_2(mttc0_vpecontrol, void, env, tl)
-DEF_HELPER_2(mtc0_vpeconf0, void, env, tl)
-DEF_HELPER_2(mttc0_vpeconf0, void, env, tl)
-DEF_HELPER_2(mtc0_vpeconf1, void, env, tl)
-DEF_HELPER_2(mtc0_yqmask, void, env, tl)
-DEF_HELPER_2(mtc0_vpeopt, void, env, tl)
-DEF_HELPER_2(mtc0_entrylo0, void, env, tl)
-DEF_HELPER_2(mtc0_tcstatus, void, env, tl)
-DEF_HELPER_2(mttc0_tcstatus, void, env, tl)
-DEF_HELPER_2(mtc0_tcbind, void, env, tl)
-DEF_HELPER_2(mttc0_tcbind, void, env, tl)
-DEF_HELPER_2(mtc0_tcrestart, void, env, tl)
-DEF_HELPER_2(mttc0_tcrestart, void, env, tl)
-DEF_HELPER_2(mtc0_tchalt, void, env, tl)
-DEF_HELPER_2(mttc0_tchalt, void, env, tl)
-DEF_HELPER_2(mtc0_tccontext, void, env, tl)
-DEF_HELPER_2(mttc0_tccontext, void, env, tl)
-DEF_HELPER_2(mtc0_tcschedule, void, env, tl)
-DEF_HELPER_2(mttc0_tcschedule, void, env, tl)
-DEF_HELPER_2(mtc0_tcschefback, void, env, tl)
-DEF_HELPER_2(mttc0_tcschefback, void, env, tl)
-DEF_HELPER_2(mtc0_entrylo1, void, env, tl)
-DEF_HELPER_2(mtc0_context, void, env, tl)
-DEF_HELPER_2(mtc0_memorymapid, void, env, tl)
-DEF_HELPER_2(mtc0_pagemask, void, env, tl)
-DEF_HELPER_2(mtc0_pagegrain, void, env, tl)
-DEF_HELPER_2(mtc0_segctl0, void, env, tl)
-DEF_HELPER_2(mtc0_segctl1, void, env, tl)
-DEF_HELPER_2(mtc0_segctl2, void, env, tl)
-DEF_HELPER_2(mtc0_pwfield, void, env, tl)
-DEF_HELPER_2(mtc0_pwsize, void, env, tl)
-DEF_HELPER_2(mtc0_wired, void, env, tl)
-DEF_HELPER_2(mtc0_srsconf0, void, env, tl)
-DEF_HELPER_2(mtc0_srsconf1, void, env, tl)
-DEF_HELPER_2(mtc0_srsconf2, void, env, tl)
-DEF_HELPER_2(mtc0_srsconf3, void, env, tl)
-DEF_HELPER_2(mtc0_srsconf4, void, env, tl)
-DEF_HELPER_2(mtc0_hwrena, void, env, tl)
-DEF_HELPER_2(mtc0_pwctl, void, env, tl)
-DEF_HELPER_2(mtc0_count, void, env, tl)
-DEF_HELPER_2(mtc0_saari, void, env, tl)
-DEF_HELPER_2(mtc0_saar, void, env, tl)
-DEF_HELPER_2(mthc0_saar, void, env, tl)
-DEF_HELPER_2(mtc0_entryhi, void, env, tl)
-DEF_HELPER_2(mttc0_entryhi, void, env, tl)
-DEF_HELPER_2(mtc0_compare, void, env, tl)
-DEF_HELPER_2(mtc0_status, void, env, tl)
-DEF_HELPER_2(mttc0_status, void, env, tl)
-DEF_HELPER_2(mtc0_intctl, void, env, tl)
-DEF_HELPER_2(mtc0_srsctl, void, env, tl)
-DEF_HELPER_2(mtc0_cause, void, env, tl)
-DEF_HELPER_2(mttc0_cause, void, env, tl)
-DEF_HELPER_2(mtc0_ebase, void, env, tl)
-DEF_HELPER_2(mttc0_ebase, void, env, tl)
-DEF_HELPER_2(mtc0_config0, void, env, tl)
-DEF_HELPER_2(mtc0_config2, void, env, tl)
-DEF_HELPER_2(mtc0_config3, void, env, tl)
-DEF_HELPER_2(mtc0_config4, void, env, tl)
-DEF_HELPER_2(mtc0_config5, void, env, tl)
-DEF_HELPER_2(mtc0_lladdr, void, env, tl)
-DEF_HELPER_2(mtc0_maar, void, env, tl)
-DEF_HELPER_2(mthc0_maar, void, env, tl)
-DEF_HELPER_2(mtc0_maari, void, env, tl)
-DEF_HELPER_3(mtc0_watchlo, void, env, tl, i32)
-DEF_HELPER_3(mtc0_watchhi, void, env, tl, i32)
-DEF_HELPER_3(mthc0_watchhi, void, env, tl, i32)
-DEF_HELPER_2(mtc0_xcontext, void, env, tl)
-DEF_HELPER_2(mtc0_framemask, void, env, tl)
-DEF_HELPER_2(mtc0_debug, void, env, tl)
-DEF_HELPER_2(mttc0_debug, void, env, tl)
-DEF_HELPER_2(mtc0_performance0, void, env, tl)
-DEF_HELPER_2(mtc0_errctl, void, env, tl)
-DEF_HELPER_2(mtc0_taglo, void, env, tl)
-DEF_HELPER_2(mtc0_datalo, void, env, tl)
-DEF_HELPER_2(mtc0_taghi, void, env, tl)
-DEF_HELPER_2(mtc0_datahi, void, env, tl)
-
-#if defined(TARGET_MIPS64)
-DEF_HELPER_2(dmtc0_entrylo0, void, env, i64)
-DEF_HELPER_2(dmtc0_entrylo1, void, env, i64)
-#endif
-
-/* MIPS MT functions */
-DEF_HELPER_2(mftgpr, tl, env, i32)
-DEF_HELPER_2(mftlo, tl, env, i32)
-DEF_HELPER_2(mfthi, tl, env, i32)
-DEF_HELPER_2(mftacx, tl, env, i32)
-DEF_HELPER_1(mftdsp, tl, env)
-DEF_HELPER_3(mttgpr, void, env, tl, i32)
-DEF_HELPER_3(mttlo, void, env, tl, i32)
-DEF_HELPER_3(mtthi, void, env, tl, i32)
-DEF_HELPER_3(mttacx, void, env, tl, i32)
-DEF_HELPER_2(mttdsp, void, env, tl)
-DEF_HELPER_0(dmt, tl)
-DEF_HELPER_0(emt, tl)
-DEF_HELPER_1(dvpe, tl, env)
-DEF_HELPER_1(evpe, tl, env)
-
-/* R6 Multi-threading */
-DEF_HELPER_1(dvp, tl, env)
-DEF_HELPER_1(evp, tl, env)
-#endif /* !CONFIG_USER_ONLY */
-
/* microMIPS functions */
DEF_HELPER_4(lwm, void, env, tl, tl, i32)
DEF_HELPER_4(swm, void, env, tl, tl, i32)
@@ -364,21 +202,6 @@
FOP_PROTO(sne)
#undef FOP_PROTO
-/* Special functions */
-#ifndef CONFIG_USER_ONLY
-DEF_HELPER_1(tlbwi, void, env)
-DEF_HELPER_1(tlbwr, void, env)
-DEF_HELPER_1(tlbp, void, env)
-DEF_HELPER_1(tlbr, void, env)
-DEF_HELPER_1(tlbinv, void, env)
-DEF_HELPER_1(tlbinvf, void, env)
-DEF_HELPER_1(di, tl, env)
-DEF_HELPER_1(ei, tl, env)
-DEF_HELPER_1(eret, void, env)
-DEF_HELPER_1(eretnc, void, env)
-DEF_HELPER_1(deret, void, env)
-DEF_HELPER_3(ginvt, void, env, tl, i32)
-#endif /* !CONFIG_USER_ONLY */
DEF_HELPER_1(rdhwr_cpunum, tl, env)
DEF_HELPER_1(rdhwr_synci_step, tl, env)
DEF_HELPER_1(rdhwr_cc, tl, env)
@@ -781,6 +604,8 @@
DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
-DEF_HELPER_3(cache, void, env, tl, i32)
+#ifndef CONFIG_USER_ONLY
+#include "tcg/sysemu_helper.h.inc"
+#endif /* !CONFIG_USER_ONLY */
-#include "msa_helper.h.inc"
+#include "tcg/msa_helper.h.inc"
diff --git a/target/mips/internal.h b/target/mips/internal.h
index 99264b8..18d5da6 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -9,6 +9,9 @@
#define MIPS_INTERNAL_H
#include "exec/memattrs.h"
+#ifdef CONFIG_TCG
+#include "tcg/tcg-internal.h"
+#endif
/*
* MMU types, the first four entries have the same layout as the
@@ -71,21 +74,41 @@
int32_t SAARP;
};
+extern const char regnames[32][4];
+extern const char fregnames[32][4];
+
extern const struct mips_def_t mips_defs[];
extern const int mips_defs_number;
-void mips_cpu_do_interrupt(CPUState *cpu);
-bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
-void mips_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
- MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr);
+
+#define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL)
+#define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL)
+#define KSEG1_BASE ((target_ulong)(int32_t)0xA0000000UL)
+#define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL)
+#define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL)
+
+#define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL)
+#define KVM_KSEG2_BASE ((target_ulong)(int32_t)0x60000000UL)
#if !defined(CONFIG_USER_ONLY)
+enum {
+ TLBRET_XI = -6,
+ TLBRET_RI = -5,
+ TLBRET_DIRTY = -4,
+ TLBRET_INVALID = -3,
+ TLBRET_NOMATCH = -2,
+ TLBRET_BADADDR = -1,
+ TLBRET_MATCH = 0
+};
+
+int get_physical_address(CPUMIPSState *env, hwaddr *physical,
+ int *prot, target_ulong real_address,
+ MMUAccessType access_type, int mmu_idx);
+hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+
typedef struct r4k_tlb_t r4k_tlb_t;
struct r4k_tlb_t {
target_ulong VPN;
@@ -125,36 +148,16 @@
} mmu;
};
-int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, MMUAccessType access_type);
-int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, MMUAccessType access_type);
-int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, MMUAccessType access_type);
-void r4k_helper_tlbwi(CPUMIPSState *env);
-void r4k_helper_tlbwr(CPUMIPSState *env);
-void r4k_helper_tlbp(CPUMIPSState *env);
-void r4k_helper_tlbr(CPUMIPSState *env);
-void r4k_helper_tlbinv(CPUMIPSState *env);
-void r4k_helper_tlbinvf(CPUMIPSState *env);
-void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
-uint32_t cpu_mips_get_random(CPUMIPSState *env);
+void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc);
+void cpu_mips_store_status(CPUMIPSState *env, target_ulong val);
+void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val);
-void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
- vaddr addr, unsigned size,
- MMUAccessType access_type,
- int mmu_idx, MemTxAttrs attrs,
- MemTxResult response, uintptr_t retaddr);
-hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
- MMUAccessType access_type);
-#endif
+extern const VMStateDescription vmstate_mips_cpu;
+
+#endif /* !CONFIG_USER_ONLY */
#define cpu_signal_handler cpu_mips_signal_handler
-#ifndef CONFIG_USER_ONLY
-extern const VMStateDescription vmstate_mips_cpu;
-#endif
-
static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
{
return (env->CP0_Status & (1 << CP0St_IE)) &&
@@ -197,8 +200,6 @@
return r;
}
-void mips_tcg_init(void);
-
void msa_reset(CPUMIPSState *env);
/* cp0_timer.c */
@@ -208,14 +209,15 @@
void cpu_mips_start_count(CPUMIPSState *env);
void cpu_mips_stop_count(CPUMIPSState *env);
-/* helper.c */
-void mmu_init(CPUMIPSState *env, const mips_def_t *def);
-bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
-
-/* op_helper.c */
-void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
+static inline void mips_env_set_pc(CPUMIPSState *env, target_ulong value)
+{
+ env->active_tc.PC = value & ~(target_ulong)1;
+ if (value & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ } else {
+ env->hflags &= ~(MIPS_HFLAG_M16);
+ }
+}
static inline void restore_pamask(CPUMIPSState *env)
{
@@ -397,21 +399,4 @@
}
}
-void cpu_mips_tlb_flush(CPUMIPSState *env);
-void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc);
-void cpu_mips_store_status(CPUMIPSState *env, target_ulong val);
-void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val);
-
-const char *mips_exception_name(int32_t exception);
-
-void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
- int error_code, uintptr_t pc);
-
-static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
- uint32_t exception,
- uintptr_t pc)
-{
- do_raise_exception_err(env, exception, 0, pc);
-}
-
#endif
diff --git a/target/mips/meson.build b/target/mips/meson.build
index 3b131c4..2407a05 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -1,52 +1,23 @@
-gen = [
- decodetree.process('mips32r6.decode', extra_args: '--static-decode=decode_mips32r6'),
- decodetree.process('mips64r6.decode', extra_args: '--static-decode=decode_mips64r6'),
- decodetree.process('msa32.decode', extra_args: '--static-decode=decode_msa32'),
- decodetree.process('msa64.decode', extra_args: '--static-decode=decode_msa64'),
- decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'),
-]
-
+mips_user_ss = ss.source_set()
+mips_softmmu_ss = ss.source_set()
mips_ss = ss.source_set()
mips_ss.add(files(
'cpu.c',
+ 'fpu.c',
'gdbstub.c',
+ 'msa.c',
))
-mips_tcg_ss = ss.source_set()
-mips_tcg_ss.add(gen)
-mips_tcg_ss.add(files(
- 'dsp_helper.c',
- 'fpu_helper.c',
- 'lmmi_helper.c',
- 'msa_helper.c',
- 'msa_translate.c',
- 'op_helper.c',
- 'rel6_translate.c',
- 'tlb_helper.c',
- 'translate.c',
- 'translate_addr_const.c',
- 'txx9_translate.c',
-))
-mips_ss.add(when: ['CONFIG_TCG', 'TARGET_MIPS64'], if_true: files(
- 'tx79_translate.c',
-))
-mips_tcg_ss.add(when: 'TARGET_MIPS64', if_false: files(
- 'mxu_translate.c',
-))
+
+if have_system
+ subdir('sysemu')
+endif
+
+if 'CONFIG_TCG' in config_all
+ subdir('tcg')
+endif
mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'))
-mips_softmmu_ss = ss.source_set()
-mips_softmmu_ss.add(files(
- 'addr.c',
- 'cp0_timer.c',
- 'machine.c',
-))
-mips_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files(
- 'cp0_helper.c',
- 'mips-semi.c',
-))
-
-mips_ss.add_all(when: 'CONFIG_TCG', if_true: [mips_tcg_ss])
-
target_arch += {'mips': mips_ss}
target_softmmu_arch += {'mips': mips_softmmu_ss}
+target_user_arch += {'mips': mips_user_ss}
diff --git a/target/mips/msa.c b/target/mips/msa.c
new file mode 100644
index 0000000..61f1a9a
--- /dev/null
+++ b/target/mips/msa.c
@@ -0,0 +1,60 @@
+/*
+ * MIPS SIMD Architecture Module Instruction emulation helpers for QEMU.
+ *
+ * Copyright (c) 2014 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internal.h"
+#include "fpu/softfloat.h"
+#include "fpu_helper.h"
+
+void msa_reset(CPUMIPSState *env)
+{
+ if (!ase_msa_available(env)) {
+ return;
+ }
+
+#ifdef CONFIG_USER_ONLY
+ /* MSA access enabled */
+ env->CP0_Config5 |= 1 << CP0C5_MSAEn;
+ env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR);
+#endif
+
+ /*
+ * MSA CSR:
+ * - non-signaling floating point exception mode off (NX bit is 0)
+ * - Cause, Enables, and Flags are all 0
+ * - round to nearest / ties to even (RM bits are 0)
+ */
+ env->active_tc.msacsr = 0;
+
+ restore_msa_fp_status(env);
+
+ /* tininess detected after rounding.*/
+ set_float_detect_tininess(float_tininess_after_rounding,
+ &env->active_tc.msa_fp_status);
+
+ /* clear float_status exception flags */
+ set_float_exception_flags(0, &env->active_tc.msa_fp_status);
+
+ /* clear float_status nan mode */
+ set_default_nan_mode(0, &env->active_tc.msa_fp_status);
+
+ /* set proper signanling bit meaning ("1" means "quiet") */
+ set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
+}
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
deleted file mode 100644
index b80e8f7..0000000
--- a/target/mips/op_helper.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/*
- * MIPS emulation helpers for qemu.
- *
- * Copyright (c) 2004-2005 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
-#include "exec/memop.h"
-#include "fpu_helper.h"
-
-/*****************************************************************************/
-/* Exceptions processing helpers */
-
-void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
- int error_code)
-{
- do_raise_exception_err(env, exception, error_code, 0);
-}
-
-void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
-{
- do_raise_exception(env, exception, GETPC());
-}
-
-void helper_raise_exception_debug(CPUMIPSState *env)
-{
- do_raise_exception(env, EXCP_DEBUG, 0);
-}
-
-static void raise_exception(CPUMIPSState *env, uint32_t exception)
-{
- do_raise_exception(env, exception, 0);
-}
-
-/* 64 bits arithmetic for 32 bits hosts */
-static inline uint64_t get_HILO(CPUMIPSState *env)
-{
- return ((uint64_t)(env->active_tc.HI[0]) << 32) |
- (uint32_t)env->active_tc.LO[0];
-}
-
-static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
-{
- env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
- return env->active_tc.HI[0] = (int32_t)(HILO >> 32);
-}
-
-static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
-{
- target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
- env->active_tc.HI[0] = (int32_t)(HILO >> 32);
- return tmp;
-}
-
-/* Multiplication variants of the vr54xx. */
-target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2));
-}
-
-target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
- (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
- (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
- (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
- (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
- (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
- (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
- return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
- (uint64_t)(uint32_t)arg2);
-}
-
-static inline target_ulong bitswap(target_ulong v)
-{
- v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
- ((v & (target_ulong)0x5555555555555555ULL) << 1);
- v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
- ((v & (target_ulong)0x3333333333333333ULL) << 2);
- v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
- ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
- return v;
-}
-
-#ifdef TARGET_MIPS64
-target_ulong helper_dbitswap(target_ulong rt)
-{
- return bitswap(rt);
-}
-#endif
-
-target_ulong helper_bitswap(target_ulong rt)
-{
- return (int32_t)bitswap(rt);
-}
-
-target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
- uint32_t stripe)
-{
- int i;
- uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff);
- uint64_t tmp1 = tmp0;
- for (i = 0; i <= 46; i++) {
- int s;
- if (i & 0x8) {
- s = shift;
- } else {
- s = shiftx;
- }
-
- if (stripe != 0 && !(i & 0x4)) {
- s = ~s;
- }
- if (s & 0x10) {
- if (tmp0 & (1LL << (i + 16))) {
- tmp1 |= 1LL << i;
- } else {
- tmp1 &= ~(1LL << i);
- }
- }
- }
-
- uint64_t tmp2 = tmp1;
- for (i = 0; i <= 38; i++) {
- int s;
- if (i & 0x4) {
- s = shift;
- } else {
- s = shiftx;
- }
-
- if (s & 0x8) {
- if (tmp1 & (1LL << (i + 8))) {
- tmp2 |= 1LL << i;
- } else {
- tmp2 &= ~(1LL << i);
- }
- }
- }
-
- uint64_t tmp3 = tmp2;
- for (i = 0; i <= 34; i++) {
- int s;
- if (i & 0x2) {
- s = shift;
- } else {
- s = shiftx;
- }
- if (s & 0x4) {
- if (tmp2 & (1LL << (i + 4))) {
- tmp3 |= 1LL << i;
- } else {
- tmp3 &= ~(1LL << i);
- }
- }
- }
-
- uint64_t tmp4 = tmp3;
- for (i = 0; i <= 32; i++) {
- int s;
- if (i & 0x1) {
- s = shift;
- } else {
- s = shiftx;
- }
- if (s & 0x2) {
- if (tmp3 & (1LL << (i + 2))) {
- tmp4 |= 1LL << i;
- } else {
- tmp4 &= ~(1LL << i);
- }
- }
- }
-
- uint64_t tmp5 = tmp4;
- for (i = 0; i <= 31; i++) {
- int s;
- s = shift;
- if (s & 0x1) {
- if (tmp4 & (1LL << (i + 1))) {
- tmp5 |= 1LL << i;
- } else {
- tmp5 &= ~(1LL << i);
- }
- }
- }
-
- return (int64_t)(int32_t)(uint32_t)tmp5;
-}
-
-#ifndef CONFIG_USER_ONLY
-
-static inline hwaddr do_translate_address(CPUMIPSState *env,
- target_ulong address,
- MMUAccessType access_type,
- uintptr_t retaddr)
-{
- hwaddr paddr;
- CPUState *cs = env_cpu(env);
-
- paddr = cpu_mips_translate_address(env, address, access_type);
-
- if (paddr == -1LL) {
- cpu_loop_exit_restore(cs, retaddr);
- } else {
- return paddr;
- }
-}
-
-#define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \
-target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
-{ \
- if (arg & almask) { \
- if (!(env->hflags & MIPS_HFLAG_DM)) { \
- env->CP0_BadVAddr = arg; \
- } \
- do_raise_exception(env, EXCP_AdEL, GETPC()); \
- } \
- env->CP0_LLAddr = do_translate_address(env, arg, MMU_DATA_LOAD, GETPC()); \
- env->lladdr = arg; \
- env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \
- return env->llval; \
-}
-HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t))
-#ifdef TARGET_MIPS64
-HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
-#endif
-#undef HELPER_LD_ATOMIC
-#endif
-
-#ifdef TARGET_WORDS_BIGENDIAN
-#define GET_LMASK(v) ((v) & 3)
-#define GET_OFFSET(addr, offset) (addr + (offset))
-#else
-#define GET_LMASK(v) (((v) & 3) ^ 3)
-#define GET_OFFSET(addr, offset) (addr - (offset))
-#endif
-
-void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
- int mem_idx)
-{
- cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
-
- if (GET_LMASK(arg2) <= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK(arg2) <= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK(arg2) == 0) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)arg1,
- mem_idx, GETPC());
- }
-}
-
-void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
- int mem_idx)
-{
- cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
-
- if (GET_LMASK(arg2) >= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK(arg2) >= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK(arg2) == 3) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
- mem_idx, GETPC());
- }
-}
-
-#if defined(TARGET_MIPS64)
-/*
- * "half" load and stores. We must do the memory access inline,
- * or fault handling won't work.
- */
-#ifdef TARGET_WORDS_BIGENDIAN
-#define GET_LMASK64(v) ((v) & 7)
-#else
-#define GET_LMASK64(v) (((v) & 7) ^ 7)
-#endif
-
-void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
- int mem_idx)
-{
- cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
-
- if (GET_LMASK64(arg2) <= 6) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) <= 5) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) <= 4) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) <= 3) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) <= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) <= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) <= 0) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 7), (uint8_t)arg1,
- mem_idx, GETPC());
- }
-}
-
-void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
- int mem_idx)
-{
- cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
-
- if (GET_LMASK64(arg2) >= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) >= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) >= 3) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) >= 4) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) >= 5) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) >= 6) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48),
- mem_idx, GETPC());
- }
-
- if (GET_LMASK64(arg2) == 7) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56),
- mem_idx, GETPC());
- }
-}
-#endif /* TARGET_MIPS64 */
-
-static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
-
-void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
- uint32_t mem_idx)
-{
- target_ulong base_reglist = reglist & 0xf;
- target_ulong do_r31 = reglist & 0x10;
-
- if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
- target_ulong i;
-
- for (i = 0; i < base_reglist; i++) {
- env->active_tc.gpr[multiple_regs[i]] =
- (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
- addr += 4;
- }
- }
-
- if (do_r31) {
- env->active_tc.gpr[31] =
- (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
- }
-}
-
-void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
- uint32_t mem_idx)
-{
- target_ulong base_reglist = reglist & 0xf;
- target_ulong do_r31 = reglist & 0x10;
-
- if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
- target_ulong i;
-
- for (i = 0; i < base_reglist; i++) {
- cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
- mem_idx, GETPC());
- addr += 4;
- }
- }
-
- if (do_r31) {
- cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
- }
-}
-
-#if defined(TARGET_MIPS64)
-void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
- uint32_t mem_idx)
-{
- target_ulong base_reglist = reglist & 0xf;
- target_ulong do_r31 = reglist & 0x10;
-
- if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
- target_ulong i;
-
- for (i = 0; i < base_reglist; i++) {
- env->active_tc.gpr[multiple_regs[i]] =
- cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
- addr += 8;
- }
- }
-
- if (do_r31) {
- env->active_tc.gpr[31] =
- cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
- }
-}
-
-void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
- uint32_t mem_idx)
-{
- target_ulong base_reglist = reglist & 0xf;
- target_ulong do_r31 = reglist & 0x10;
-
- if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
- target_ulong i;
-
- for (i = 0; i < base_reglist; i++) {
- cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
- mem_idx, GETPC());
- addr += 8;
- }
- }
-
- if (do_r31) {
- cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
- }
-}
-#endif
-
-
-void helper_fork(target_ulong arg1, target_ulong arg2)
-{
- /*
- * arg1 = rt, arg2 = rs
- * TODO: store to TC register
- */
-}
-
-target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
-{
- target_long arg1 = arg;
-
- if (arg1 < 0) {
- /* No scheduling policy implemented. */
- if (arg1 != -2) {
- if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
- env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
- env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
- env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
- do_raise_exception(env, EXCP_THREAD, GETPC());
- }
- }
- } else if (arg1 == 0) {
- if (0) {
- /* TODO: TC underflow */
- env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
- do_raise_exception(env, EXCP_THREAD, GETPC());
- } else {
- /* TODO: Deallocate TC */
- }
- } else if (arg1 > 0) {
- /* Yield qualifier inputs not implemented. */
- env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
- env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
- do_raise_exception(env, EXCP_THREAD, GETPC());
- }
- return env->CP0_YQMask;
-}
-
-#ifndef CONFIG_USER_ONLY
-/* TLB management */
-static void r4k_mips_tlb_flush_extra(CPUMIPSState *env, int first)
-{
- /* Discard entries from env->tlb[first] onwards. */
- while (env->tlb->tlb_in_use > first) {
- r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
- }
-}
-
-static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
-{
-#if defined(TARGET_MIPS64)
- return extract64(entrylo, 6, 54);
-#else
- return extract64(entrylo, 6, 24) | /* PFN */
- (extract64(entrylo, 32, 32) << 24); /* PFNX */
-#endif
-}
-
-static void r4k_fill_tlb(CPUMIPSState *env, int idx)
-{
- r4k_tlb_t *tlb;
- uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
-
- /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
- tlb = &env->tlb->mmu.r4k.tlb[idx];
- if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
- tlb->EHINV = 1;
- return;
- }
- tlb->EHINV = 0;
- tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
-#if defined(TARGET_MIPS64)
- tlb->VPN &= env->SEGMask;
-#endif
- tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
- tlb->MMID = env->CP0_MemoryMapID;
- tlb->PageMask = env->CP0_PageMask;
- tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
- tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
- tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
- tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
- tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
- tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
- tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
- tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
- tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
- tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
- tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
- tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
- tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
-}
-
-void r4k_helper_tlbinv(CPUMIPSState *env)
-{
- bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
- uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
- uint32_t MMID = env->CP0_MemoryMapID;
- uint32_t tlb_mmid;
- r4k_tlb_t *tlb;
- int idx;
-
- MMID = mi ? MMID : (uint32_t) ASID;
- for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
- tlb = &env->tlb->mmu.r4k.tlb[idx];
- tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
- if (!tlb->G && tlb_mmid == MMID) {
- tlb->EHINV = 1;
- }
- }
- cpu_mips_tlb_flush(env);
-}
-
-void r4k_helper_tlbinvf(CPUMIPSState *env)
-{
- int idx;
-
- for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
- env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
- }
- cpu_mips_tlb_flush(env);
-}
-
-void r4k_helper_tlbwi(CPUMIPSState *env)
-{
- bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
- target_ulong VPN;
- uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
- uint32_t MMID = env->CP0_MemoryMapID;
- uint32_t tlb_mmid;
- bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
- r4k_tlb_t *tlb;
- int idx;
-
- MMID = mi ? MMID : (uint32_t) ASID;
-
- idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
- tlb = &env->tlb->mmu.r4k.tlb[idx];
- VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
-#if defined(TARGET_MIPS64)
- VPN &= env->SEGMask;
-#endif
- EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
- G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
- V0 = (env->CP0_EntryLo0 & 2) != 0;
- D0 = (env->CP0_EntryLo0 & 4) != 0;
- XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
- RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
- V1 = (env->CP0_EntryLo1 & 2) != 0;
- D1 = (env->CP0_EntryLo1 & 4) != 0;
- XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
- RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
-
- tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
- /*
- * Discard cached TLB entries, unless tlbwi is just upgrading access
- * permissions on the current entry.
- */
- if (tlb->VPN != VPN || tlb_mmid != MMID || tlb->G != G ||
- (!tlb->EHINV && EHINV) ||
- (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
- (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
- (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
- (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
- r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
- }
-
- r4k_invalidate_tlb(env, idx, 0);
- r4k_fill_tlb(env, idx);
-}
-
-void r4k_helper_tlbwr(CPUMIPSState *env)
-{
- int r = cpu_mips_get_random(env);
-
- r4k_invalidate_tlb(env, r, 1);
- r4k_fill_tlb(env, r);
-}
-
-void r4k_helper_tlbp(CPUMIPSState *env)
-{
- bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
- r4k_tlb_t *tlb;
- target_ulong mask;
- target_ulong tag;
- target_ulong VPN;
- uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
- uint32_t MMID = env->CP0_MemoryMapID;
- uint32_t tlb_mmid;
- int i;
-
- MMID = mi ? MMID : (uint32_t) ASID;
- for (i = 0; i < env->tlb->nb_tlb; i++) {
- tlb = &env->tlb->mmu.r4k.tlb[i];
- /* 1k pages are not supported. */
- mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
- tag = env->CP0_EntryHi & ~mask;
- VPN = tlb->VPN & ~mask;
-#if defined(TARGET_MIPS64)
- tag &= env->SEGMask;
-#endif
- tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
- /* Check ASID/MMID, virtual page number & size */
- if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag && !tlb->EHINV) {
- /* TLB match */
- env->CP0_Index = i;
- break;
- }
- }
- if (i == env->tlb->nb_tlb) {
- /* No match. Discard any shadow entries, if any of them match. */
- for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
- tlb = &env->tlb->mmu.r4k.tlb[i];
- /* 1k pages are not supported. */
- mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
- tag = env->CP0_EntryHi & ~mask;
- VPN = tlb->VPN & ~mask;
-#if defined(TARGET_MIPS64)
- tag &= env->SEGMask;
-#endif
- tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
- /* Check ASID/MMID, virtual page number & size */
- if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag) {
- r4k_mips_tlb_flush_extra(env, i);
- break;
- }
- }
-
- env->CP0_Index |= 0x80000000;
- }
-}
-
-static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
-{
-#if defined(TARGET_MIPS64)
- return tlb_pfn << 6;
-#else
- return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
- (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
-#endif
-}
-
-void r4k_helper_tlbr(CPUMIPSState *env)
-{
- bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
- uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
- uint32_t MMID = env->CP0_MemoryMapID;
- uint32_t tlb_mmid;
- r4k_tlb_t *tlb;
- int idx;
-
- MMID = mi ? MMID : (uint32_t) ASID;
- idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
- tlb = &env->tlb->mmu.r4k.tlb[idx];
-
- tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
- /* If this will change the current ASID/MMID, flush qemu's TLB. */
- if (MMID != tlb_mmid) {
- cpu_mips_tlb_flush(env);
- }
-
- r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
-
- if (tlb->EHINV) {
- env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
- env->CP0_PageMask = 0;
- env->CP0_EntryLo0 = 0;
- env->CP0_EntryLo1 = 0;
- } else {
- env->CP0_EntryHi = mi ? tlb->VPN : tlb->VPN | tlb->ASID;
- env->CP0_MemoryMapID = tlb->MMID;
- env->CP0_PageMask = tlb->PageMask;
- env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
- ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
- ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
- get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
- env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
- ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
- ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
- get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
- }
-}
-
-void helper_tlbwi(CPUMIPSState *env)
-{
- env->tlb->helper_tlbwi(env);
-}
-
-void helper_tlbwr(CPUMIPSState *env)
-{
- env->tlb->helper_tlbwr(env);
-}
-
-void helper_tlbp(CPUMIPSState *env)
-{
- env->tlb->helper_tlbp(env);
-}
-
-void helper_tlbr(CPUMIPSState *env)
-{
- env->tlb->helper_tlbr(env);
-}
-
-void helper_tlbinv(CPUMIPSState *env)
-{
- env->tlb->helper_tlbinv(env);
-}
-
-void helper_tlbinvf(CPUMIPSState *env)
-{
- env->tlb->helper_tlbinvf(env);
-}
-
-static void global_invalidate_tlb(CPUMIPSState *env,
- uint32_t invMsgVPN2,
- uint8_t invMsgR,
- uint32_t invMsgMMid,
- bool invAll,
- bool invVAMMid,
- bool invMMid,
- bool invVA)
-{
-
- int idx;
- r4k_tlb_t *tlb;
- bool VAMatch;
- bool MMidMatch;
-
- for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
- tlb = &env->tlb->mmu.r4k.tlb[idx];
- VAMatch =
- (((tlb->VPN & ~tlb->PageMask) == (invMsgVPN2 & ~tlb->PageMask))
-#ifdef TARGET_MIPS64
- &&
- (extract64(env->CP0_EntryHi, 62, 2) == invMsgR)
-#endif
- );
- MMidMatch = tlb->MMID == invMsgMMid;
- if ((invAll && (idx > env->CP0_Wired)) ||
- (VAMatch && invVAMMid && (tlb->G || MMidMatch)) ||
- (VAMatch && invVA) ||
- (MMidMatch && !(tlb->G) && invMMid)) {
- tlb->EHINV = 1;
- }
- }
- cpu_mips_tlb_flush(env);
-}
-
-void helper_ginvt(CPUMIPSState *env, target_ulong arg, uint32_t type)
-{
- bool invAll = type == 0;
- bool invVA = type == 1;
- bool invMMid = type == 2;
- bool invVAMMid = type == 3;
- uint32_t invMsgVPN2 = arg & (TARGET_PAGE_MASK << 1);
- uint8_t invMsgR = 0;
- uint32_t invMsgMMid = env->CP0_MemoryMapID;
- CPUState *other_cs = first_cpu;
-
-#ifdef TARGET_MIPS64
- invMsgR = extract64(arg, 62, 2);
-#endif
-
- CPU_FOREACH(other_cs) {
- MIPSCPU *other_cpu = MIPS_CPU(other_cs);
- global_invalidate_tlb(&other_cpu->env, invMsgVPN2, invMsgR, invMsgMMid,
- invAll, invVAMMid, invMMid, invVA);
- }
-}
-
-/* Specials */
-target_ulong helper_di(CPUMIPSState *env)
-{
- target_ulong t0 = env->CP0_Status;
-
- env->CP0_Status = t0 & ~(1 << CP0St_IE);
- return t0;
-}
-
-target_ulong helper_ei(CPUMIPSState *env)
-{
- target_ulong t0 = env->CP0_Status;
-
- env->CP0_Status = t0 | (1 << CP0St_IE);
- return t0;
-}
-
-static void debug_pre_eret(CPUMIPSState *env)
-{
- if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
- qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
- env->active_tc.PC, env->CP0_EPC);
- if (env->CP0_Status & (1 << CP0St_ERL)) {
- qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
- }
- if (env->hflags & MIPS_HFLAG_DM) {
- qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
- }
- qemu_log("\n");
- }
-}
-
-static void debug_post_eret(CPUMIPSState *env)
-{
- if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
- qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
- env->active_tc.PC, env->CP0_EPC);
- if (env->CP0_Status & (1 << CP0St_ERL)) {
- qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
- }
- if (env->hflags & MIPS_HFLAG_DM) {
- qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
- }
- switch (cpu_mmu_index(env, false)) {
- case 3:
- qemu_log(", ERL\n");
- break;
- case MIPS_HFLAG_UM:
- qemu_log(", UM\n");
- break;
- case MIPS_HFLAG_SM:
- qemu_log(", SM\n");
- break;
- case MIPS_HFLAG_KM:
- qemu_log("\n");
- break;
- default:
- cpu_abort(env_cpu(env), "Invalid MMU mode!\n");
- break;
- }
- }
-}
-
-static void set_pc(CPUMIPSState *env, target_ulong error_pc)
-{
- env->active_tc.PC = error_pc & ~(target_ulong)1;
- if (error_pc & 1) {
- env->hflags |= MIPS_HFLAG_M16;
- } else {
- env->hflags &= ~(MIPS_HFLAG_M16);
- }
-}
-
-static inline void exception_return(CPUMIPSState *env)
-{
- debug_pre_eret(env);
- if (env->CP0_Status & (1 << CP0St_ERL)) {
- set_pc(env, env->CP0_ErrorEPC);
- env->CP0_Status &= ~(1 << CP0St_ERL);
- } else {
- set_pc(env, env->CP0_EPC);
- env->CP0_Status &= ~(1 << CP0St_EXL);
- }
- compute_hflags(env);
- debug_post_eret(env);
-}
-
-void helper_eret(CPUMIPSState *env)
-{
- exception_return(env);
- env->CP0_LLAddr = 1;
- env->lladdr = 1;
-}
-
-void helper_eretnc(CPUMIPSState *env)
-{
- exception_return(env);
-}
-
-void helper_deret(CPUMIPSState *env)
-{
- debug_pre_eret(env);
-
- env->hflags &= ~MIPS_HFLAG_DM;
- compute_hflags(env);
-
- set_pc(env, env->CP0_DEPC);
-
- debug_post_eret(env);
-}
-#endif /* !CONFIG_USER_ONLY */
-
-static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
-{
- if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
- return;
- }
- do_raise_exception(env, EXCP_RI, pc);
-}
-
-target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
-{
- check_hwrena(env, 0, GETPC());
- return env->CP0_EBase & 0x3ff;
-}
-
-target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
-{
- check_hwrena(env, 1, GETPC());
- return env->SYNCI_Step;
-}
-
-target_ulong helper_rdhwr_cc(CPUMIPSState *env)
-{
- check_hwrena(env, 2, GETPC());
-#ifdef CONFIG_USER_ONLY
- return env->CP0_Count;
-#else
- return (int32_t)cpu_mips_get_count(env);
-#endif
-}
-
-target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
-{
- check_hwrena(env, 3, GETPC());
- return env->CCRes;
-}
-
-target_ulong helper_rdhwr_performance(CPUMIPSState *env)
-{
- check_hwrena(env, 4, GETPC());
- return env->CP0_Performance0;
-}
-
-target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
-{
- check_hwrena(env, 5, GETPC());
- return (env->CP0_Config5 >> CP0C5_XNP) & 1;
-}
-
-void helper_pmon(CPUMIPSState *env, int function)
-{
- function /= 2;
- switch (function) {
- case 2: /* TODO: char inbyte(int waitflag); */
- if (env->active_tc.gpr[4] == 0) {
- env->active_tc.gpr[2] = -1;
- }
- /* Fall through */
- case 11: /* TODO: char inbyte (void); */
- env->active_tc.gpr[2] = -1;
- break;
- case 3:
- case 12:
- printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
- break;
- case 17:
- break;
- case 158:
- {
- unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
- printf("%s", fmt);
- }
- break;
- }
-}
-
-void helper_wait(CPUMIPSState *env)
-{
- CPUState *cs = env_cpu(env);
-
- cs->halted = 1;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
- /*
- * Last instruction in the block, PC was updated before
- * - no need to recover PC and icount.
- */
- raise_exception(env, EXCP_HLT);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-
-void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
- MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr)
-{
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
- int error_code = 0;
- int excp;
-
- if (!(env->hflags & MIPS_HFLAG_DM)) {
- env->CP0_BadVAddr = addr;
- }
-
- if (access_type == MMU_DATA_STORE) {
- excp = EXCP_AdES;
- } else {
- excp = EXCP_AdEL;
- if (access_type == MMU_INST_FETCH) {
- error_code |= EXCP_INST_NOTAVAIL;
- }
- }
-
- do_raise_exception_err(env, excp, error_code, retaddr);
-}
-
-void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
- vaddr addr, unsigned size,
- MMUAccessType access_type,
- int mmu_idx, MemTxAttrs attrs,
- MemTxResult response, uintptr_t retaddr)
-{
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
-
- if (access_type == MMU_INST_FETCH) {
- do_raise_exception(env, EXCP_IBE, retaddr);
- } else {
- do_raise_exception(env, EXCP_DBE, retaddr);
- }
-}
-#endif /* !CONFIG_USER_ONLY */
-
-void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
-{
-#ifndef CONFIG_USER_ONLY
- static const char *const type_name[] = {
- "Primary Instruction",
- "Primary Data or Unified Primary",
- "Tertiary",
- "Secondary"
- };
- uint32_t cache_type = extract32(op, 0, 2);
- uint32_t cache_operation = extract32(op, 2, 3);
- target_ulong index = addr & 0x1fffffff;
-
- switch (cache_operation) {
- case 0b010: /* Index Store Tag */
- memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
- MO_64, MEMTXATTRS_UNSPECIFIED);
- break;
- case 0b001: /* Index Load Tag */
- memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
- MO_64, MEMTXATTRS_UNSPECIFIED);
- break;
- case 0b000: /* Index Invalidate */
- case 0b100: /* Hit Invalidate */
- case 0b110: /* Hit Writeback */
- /* no-op */
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n",
- cache_operation, type_name[cache_type]);
- break;
- }
-#endif
-}
diff --git a/target/mips/addr.c b/target/mips/sysemu/addr.c
similarity index 100%
rename from target/mips/addr.c
rename to target/mips/sysemu/addr.c
diff --git a/target/mips/sysemu/cp0.c b/target/mips/sysemu/cp0.c
new file mode 100644
index 0000000..bae37f5
--- /dev/null
+++ b/target/mips/sysemu/cp0.c
@@ -0,0 +1,123 @@
+/*
+ * QEMU MIPS CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internal.h"
+#include "exec/exec-all.h"
+
+/* Called for updates to CP0_Status. */
+void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
+{
+ int32_t tcstatus, *tcst;
+ uint32_t v = cpu->CP0_Status;
+ uint32_t cu, mx, asid, ksu;
+ uint32_t mask = ((1 << CP0TCSt_TCU3)
+ | (1 << CP0TCSt_TCU2)
+ | (1 << CP0TCSt_TCU1)
+ | (1 << CP0TCSt_TCU0)
+ | (1 << CP0TCSt_TMX)
+ | (3 << CP0TCSt_TKSU)
+ | (0xff << CP0TCSt_TASID));
+
+ cu = (v >> CP0St_CU0) & 0xf;
+ mx = (v >> CP0St_MX) & 0x1;
+ ksu = (v >> CP0St_KSU) & 0x3;
+ asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+
+ tcstatus = cu << CP0TCSt_TCU0;
+ tcstatus |= mx << CP0TCSt_TMX;
+ tcstatus |= ksu << CP0TCSt_TKSU;
+ tcstatus |= asid;
+
+ if (tc == cpu->current_tc) {
+ tcst = &cpu->active_tc.CP0_TCStatus;
+ } else {
+ tcst = &cpu->tcs[tc].CP0_TCStatus;
+ }
+
+ *tcst &= ~mask;
+ *tcst |= tcstatus;
+ compute_hflags(cpu);
+}
+
+void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
+{
+ uint32_t mask = env->CP0_Status_rw_bitmask;
+ target_ulong old = env->CP0_Status;
+
+ if (env->insn_flags & ISA_MIPS_R6) {
+ bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
+#if defined(TARGET_MIPS64)
+ uint32_t ksux = (1 << CP0St_KX) & val;
+ ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */
+ ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */
+ val = (val & ~(7 << CP0St_UX)) | ksux;
+#endif
+ if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
+ mask &= ~(3 << CP0St_KSU);
+ }
+ mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val);
+ }
+
+ env->CP0_Status = (old & ~mask) | (val & mask);
+#if defined(TARGET_MIPS64)
+ if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
+ /* Access to at least one of the 64-bit segments has been disabled */
+ tlb_flush(env_cpu(env));
+ }
+#endif
+ if (ase_mt_available(env)) {
+ sync_c0_status(env, env, env->current_tc);
+ } else {
+ compute_hflags(env);
+ }
+}
+
+void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val)
+{
+ uint32_t mask = 0x00C00300;
+ uint32_t old = env->CP0_Cause;
+ int i;
+
+ if (env->insn_flags & ISA_MIPS_R2) {
+ mask |= 1 << CP0Ca_DC;
+ }
+ if (env->insn_flags & ISA_MIPS_R6) {
+ mask &= ~((1 << CP0Ca_WP) & val);
+ }
+
+ env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask);
+
+ if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
+ if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+ cpu_mips_stop_count(env);
+ } else {
+ cpu_mips_start_count(env);
+ }
+ }
+
+ /* Set/reset software interrupts */
+ for (i = 0 ; i < 2 ; i++) {
+ if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
+ cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
+ }
+ }
+}
diff --git a/target/mips/cp0_timer.c b/target/mips/sysemu/cp0_timer.c
similarity index 100%
rename from target/mips/cp0_timer.c
rename to target/mips/sysemu/cp0_timer.c
diff --git a/target/mips/machine.c b/target/mips/sysemu/machine.c
similarity index 94%
rename from target/mips/machine.c
rename to target/mips/sysemu/machine.c
index b5fda6a..80d37f9 100644
--- a/target/mips/machine.c
+++ b/target/mips/sysemu/machine.c
@@ -81,6 +81,9 @@
static VMStateField vmstate_tc_fields[] = {
VMSTATE_UINTTL_ARRAY(gpr, TCState, 32),
+#if defined(TARGET_MIPS64)
+ VMSTATE_UINT64_ARRAY(gpr_hi, TCState, 32),
+#endif /* TARGET_MIPS64 */
VMSTATE_UINTTL(PC, TCState),
VMSTATE_UINTTL_ARRAY(HI, TCState, MIPS_DSP_ACC),
VMSTATE_UINTTL_ARRAY(LO, TCState, MIPS_DSP_ACC),
@@ -95,20 +98,22 @@
VMSTATE_INT32(CP0_Debug_tcstatus, TCState),
VMSTATE_UINTTL(CP0_UserLocal, TCState),
VMSTATE_INT32(msacsr, TCState),
+ VMSTATE_UINTTL_ARRAY(mxu_gpr, TCState, NUMBER_OF_MXU_REGISTERS - 1),
+ VMSTATE_UINTTL(mxu_cr, TCState),
VMSTATE_END_OF_LIST()
};
const VMStateDescription vmstate_tc = {
.name = "cpu/tc",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = vmstate_tc_fields
};
const VMStateDescription vmstate_inactive_tc = {
.name = "cpu/inactive_tc",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = vmstate_tc_fields
};
@@ -213,8 +218,8 @@
const VMStateDescription vmstate_mips_cpu = {
.name = "cpu",
- .version_id = 20,
- .minimum_version_id = 20,
+ .version_id = 21,
+ .minimum_version_id = 21,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
/* Active TC */
@@ -241,6 +246,7 @@
/* Remaining CP0 registers */
VMSTATE_INT32(env.CP0_Index, MIPSCPU),
+ VMSTATE_INT32(env.CP0_VPControl, MIPSCPU),
VMSTATE_INT32(env.CP0_Random, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEControl, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEConf0, MIPSCPU),
@@ -251,6 +257,7 @@
VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU),
VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU),
VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU),
+ VMSTATE_INT32(env.CP0_GlobalNumber, MIPSCPU),
VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
VMSTATE_INT32(env.CP0_MemoryMapID, MIPSCPU),
VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
@@ -286,6 +293,7 @@
VMSTATE_UINTTL(env.CP0_EPC, MIPSCPU),
VMSTATE_INT32(env.CP0_PRid, MIPSCPU),
VMSTATE_UINTTL(env.CP0_EBase, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_CMGCRBase, MIPSCPU),
VMSTATE_INT32(env.CP0_Config0, MIPSCPU),
VMSTATE_INT32(env.CP0_Config1, MIPSCPU),
VMSTATE_INT32(env.CP0_Config2, MIPSCPU),
@@ -305,6 +313,7 @@
VMSTATE_INT32(env.CP0_Debug, MIPSCPU),
VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU),
VMSTATE_INT32(env.CP0_Performance0, MIPSCPU),
+ VMSTATE_INT32(env.CP0_ErrCtl, MIPSCPU),
VMSTATE_UINT64(env.CP0_TagLo, MIPSCPU),
VMSTATE_INT32(env.CP0_DataLo, MIPSCPU),
VMSTATE_INT32(env.CP0_TagHi, MIPSCPU),
diff --git a/target/mips/sysemu/meson.build b/target/mips/sysemu/meson.build
new file mode 100644
index 0000000..cefc227
--- /dev/null
+++ b/target/mips/sysemu/meson.build
@@ -0,0 +1,7 @@
+mips_softmmu_ss.add(files(
+ 'addr.c',
+ 'cp0.c',
+ 'cp0_timer.c',
+ 'machine.c',
+ 'physaddr.c',
+))
diff --git a/target/mips/sysemu/physaddr.c b/target/mips/sysemu/physaddr.c
new file mode 100644
index 0000000..1918633
--- /dev/null
+++ b/target/mips/sysemu/physaddr.c
@@ -0,0 +1,257 @@
+/*
+ * MIPS TLB (Translation lookaside buffer) helpers.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "../internal.h"
+
+static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx)
+{
+ /*
+ * Interpret access control mode and mmu_idx.
+ * AdE? TLB?
+ * AM K S U E K S U E
+ * UK 0 0 1 1 0 0 - - 0
+ * MK 1 0 1 1 0 1 - - !eu
+ * MSK 2 0 0 1 0 1 1 - !eu
+ * MUSK 3 0 0 0 0 1 1 1 !eu
+ * MUSUK 4 0 0 0 0 0 1 1 0
+ * USK 5 0 0 1 0 0 0 - 0
+ * - 6 - - - - - - - -
+ * UUSK 7 0 0 0 0 0 0 0 0
+ */
+ int32_t adetlb_mask;
+
+ switch (mmu_idx) {
+ case 3: /* ERL */
+ /* If EU is set, always unmapped */
+ if (eu) {
+ return 0;
+ }
+ /* fall through */
+ case MIPS_HFLAG_KM:
+ /* Never AdE, TLB mapped if AM={1,2,3} */
+ adetlb_mask = 0x70000000;
+ goto check_tlb;
+
+ case MIPS_HFLAG_SM:
+ /* AdE if AM={0,1}, TLB mapped if AM={2,3,4} */
+ adetlb_mask = 0xc0380000;
+ goto check_ade;
+
+ case MIPS_HFLAG_UM:
+ /* AdE if AM={0,1,2,5}, TLB mapped if AM={3,4} */
+ adetlb_mask = 0xe4180000;
+ /* fall through */
+ check_ade:
+ /* does this AM cause AdE in current execution mode */
+ if ((adetlb_mask << am) < 0) {
+ return TLBRET_BADADDR;
+ }
+ adetlb_mask <<= 8;
+ /* fall through */
+ check_tlb:
+ /* is this AM mapped in current execution mode */
+ return ((adetlb_mask << am) < 0);
+ default:
+ assert(0);
+ return TLBRET_BADADDR;
+ };
+}
+
+static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical,
+ int *prot, target_ulong real_address,
+ MMUAccessType access_type, int mmu_idx,
+ unsigned int am, bool eu,
+ target_ulong segmask,
+ hwaddr physical_base)
+{
+ int mapped = is_seg_am_mapped(am, eu, mmu_idx);
+
+ if (mapped < 0) {
+ /* is_seg_am_mapped can report TLBRET_BADADDR */
+ return mapped;
+ } else if (mapped) {
+ /* The segment is TLB mapped */
+ return env->tlb->map_address(env, physical, prot, real_address,
+ access_type);
+ } else {
+ /* The segment is unmapped */
+ *physical = physical_base | (real_address & segmask);
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TLBRET_MATCH;
+ }
+}
+
+static int get_segctl_physical_address(CPUMIPSState *env, hwaddr *physical,
+ int *prot, target_ulong real_address,
+ MMUAccessType access_type, int mmu_idx,
+ uint16_t segctl, target_ulong segmask)
+{
+ unsigned int am = (segctl & CP0SC_AM_MASK) >> CP0SC_AM;
+ bool eu = (segctl >> CP0SC_EU) & 1;
+ hwaddr pa = ((hwaddr)segctl & CP0SC_PA_MASK) << 20;
+
+ return get_seg_physical_address(env, physical, prot, real_address,
+ access_type, mmu_idx, am, eu, segmask,
+ pa & ~(hwaddr)segmask);
+}
+
+int get_physical_address(CPUMIPSState *env, hwaddr *physical,
+ int *prot, target_ulong real_address,
+ MMUAccessType access_type, int mmu_idx)
+{
+ /* User mode can only access useg/xuseg */
+#if defined(TARGET_MIPS64)
+ int user_mode = mmu_idx == MIPS_HFLAG_UM;
+ int supervisor_mode = mmu_idx == MIPS_HFLAG_SM;
+ int kernel_mode = !user_mode && !supervisor_mode;
+ int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+ int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+ int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+#endif
+ int ret = TLBRET_MATCH;
+ /* effective address (modified for KVM T&E kernel segments) */
+ target_ulong address = real_address;
+
+ if (mips_um_ksegs_enabled()) {
+ /* KVM T&E adds guest kernel segments in useg */
+ if (real_address >= KVM_KSEG0_BASE) {
+ if (real_address < KVM_KSEG2_BASE) {
+ /* kseg0 */
+ address += KSEG0_BASE - KVM_KSEG0_BASE;
+ } else if (real_address <= USEG_LIMIT) {
+ /* kseg2/3 */
+ address += KSEG2_BASE - KVM_KSEG2_BASE;
+ }
+ }
+ }
+
+ if (address <= USEG_LIMIT) {
+ /* useg */
+ uint16_t segctl;
+
+ if (address >= 0x40000000UL) {
+ segctl = env->CP0_SegCtl2;
+ } else {
+ segctl = env->CP0_SegCtl2 >> 16;
+ }
+ ret = get_segctl_physical_address(env, physical, prot,
+ real_address, access_type,
+ mmu_idx, segctl, 0x3FFFFFFF);
+#if defined(TARGET_MIPS64)
+ } else if (address < 0x4000000000000000ULL) {
+ /* xuseg */
+ if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
+ ret = env->tlb->map_address(env, physical, prot,
+ real_address, access_type);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else if (address < 0x8000000000000000ULL) {
+ /* xsseg */
+ if ((supervisor_mode || kernel_mode) &&
+ SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
+ ret = env->tlb->map_address(env, physical, prot,
+ real_address, access_type);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else if (address < 0xC000000000000000ULL) {
+ /* xkphys */
+ if ((address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
+ /* KX/SX/UX bit to check for each xkphys EVA access mode */
+ static const uint8_t am_ksux[8] = {
+ [CP0SC_AM_UK] = (1u << CP0St_KX),
+ [CP0SC_AM_MK] = (1u << CP0St_KX),
+ [CP0SC_AM_MSK] = (1u << CP0St_SX),
+ [CP0SC_AM_MUSK] = (1u << CP0St_UX),
+ [CP0SC_AM_MUSUK] = (1u << CP0St_UX),
+ [CP0SC_AM_USK] = (1u << CP0St_SX),
+ [6] = (1u << CP0St_KX),
+ [CP0SC_AM_UUSK] = (1u << CP0St_UX),
+ };
+ unsigned int am = CP0SC_AM_UK;
+ unsigned int xr = (env->CP0_SegCtl2 & CP0SC2_XR_MASK) >> CP0SC2_XR;
+
+ if (xr & (1 << ((address >> 59) & 0x7))) {
+ am = (env->CP0_SegCtl1 & CP0SC1_XAM_MASK) >> CP0SC1_XAM;
+ }
+ /* Does CP0_Status.KX/SX/UX permit the access mode (am) */
+ if (env->CP0_Status & am_ksux[am]) {
+ ret = get_seg_physical_address(env, physical, prot,
+ real_address, access_type,
+ mmu_idx, am, false, env->PAMask,
+ 0);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else if (address < 0xFFFFFFFF80000000ULL) {
+ /* xkseg */
+ if (kernel_mode && KX &&
+ address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
+ ret = env->tlb->map_address(env, physical, prot,
+ real_address, access_type);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+#endif
+ } else if (address < KSEG1_BASE) {
+ /* kseg0 */
+ ret = get_segctl_physical_address(env, physical, prot, real_address,
+ access_type, mmu_idx,
+ env->CP0_SegCtl1 >> 16, 0x1FFFFFFF);
+ } else if (address < KSEG2_BASE) {
+ /* kseg1 */
+ ret = get_segctl_physical_address(env, physical, prot, real_address,
+ access_type, mmu_idx,
+ env->CP0_SegCtl1, 0x1FFFFFFF);
+ } else if (address < KSEG3_BASE) {
+ /* sseg (kseg2) */
+ ret = get_segctl_physical_address(env, physical, prot, real_address,
+ access_type, mmu_idx,
+ env->CP0_SegCtl0 >> 16, 0x1FFFFFFF);
+ } else {
+ /*
+ * kseg3
+ * XXX: debug segment is not emulated
+ */
+ ret = get_segctl_physical_address(env, physical, prot, real_address,
+ access_type, mmu_idx,
+ env->CP0_SegCtl0, 0x1FFFFFFF);
+ }
+ return ret;
+}
+
+hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+ hwaddr phys_addr;
+ int prot;
+
+ if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
+ cpu_mmu_index(env, false)) != 0) {
+ return -1;
+ }
+ return phys_addr;
+}
diff --git a/target/mips/dsp_helper.c b/target/mips/tcg/dsp_helper.c
similarity index 100%
rename from target/mips/dsp_helper.c
rename to target/mips/tcg/dsp_helper.c
diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c
new file mode 100644
index 0000000..4fb8b00
--- /dev/null
+++ b/target/mips/tcg/exception.c
@@ -0,0 +1,167 @@
+/*
+ * MIPS Exceptions processing helpers for QEMU.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internal.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+
+target_ulong exception_resume_pc(CPUMIPSState *env)
+{
+ target_ulong bad_pc;
+ target_ulong isa_mode;
+
+ isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
+ bad_pc = env->active_tc.PC | isa_mode;
+ if (env->hflags & MIPS_HFLAG_BMASK) {
+ /*
+ * If the exception was raised from a delay slot, come back to
+ * the jump.
+ */
+ bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
+ }
+
+ return bad_pc;
+}
+
+void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
+ int error_code)
+{
+ do_raise_exception_err(env, exception, error_code, 0);
+}
+
+void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
+{
+ do_raise_exception(env, exception, GETPC());
+}
+
+void helper_raise_exception_debug(CPUMIPSState *env)
+{
+ do_raise_exception(env, EXCP_DEBUG, 0);
+}
+
+static void raise_exception(CPUMIPSState *env, uint32_t exception)
+{
+ do_raise_exception(env, exception, 0);
+}
+
+void helper_wait(CPUMIPSState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->halted = 1;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
+ /*
+ * Last instruction in the block, PC was updated before
+ * - no need to recover PC and icount.
+ */
+ raise_exception(env, EXCP_HLT);
+}
+
+void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ env->active_tc.PC = tb->pc;
+ env->hflags &= ~MIPS_HFLAG_BMASK;
+ env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
+}
+
+bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ if (cpu_mips_hw_interrupts_enabled(env) &&
+ cpu_mips_hw_interrupts_pending(env)) {
+ /* Raise it */
+ cs->exception_index = EXCP_EXT_INTERRUPT;
+ env->error_code = 0;
+ mips_cpu_do_interrupt(cs);
+ return true;
+ }
+ }
+ return false;
+}
+
+static const char * const excp_names[EXCP_LAST + 1] = {
+ [EXCP_RESET] = "reset",
+ [EXCP_SRESET] = "soft reset",
+ [EXCP_DSS] = "debug single step",
+ [EXCP_DINT] = "debug interrupt",
+ [EXCP_NMI] = "non-maskable interrupt",
+ [EXCP_MCHECK] = "machine check",
+ [EXCP_EXT_INTERRUPT] = "interrupt",
+ [EXCP_DFWATCH] = "deferred watchpoint",
+ [EXCP_DIB] = "debug instruction breakpoint",
+ [EXCP_IWATCH] = "instruction fetch watchpoint",
+ [EXCP_AdEL] = "address error load",
+ [EXCP_AdES] = "address error store",
+ [EXCP_TLBF] = "TLB refill",
+ [EXCP_IBE] = "instruction bus error",
+ [EXCP_DBp] = "debug breakpoint",
+ [EXCP_SYSCALL] = "syscall",
+ [EXCP_BREAK] = "break",
+ [EXCP_CpU] = "coprocessor unusable",
+ [EXCP_RI] = "reserved instruction",
+ [EXCP_OVERFLOW] = "arithmetic overflow",
+ [EXCP_TRAP] = "trap",
+ [EXCP_FPE] = "floating point",
+ [EXCP_DDBS] = "debug data break store",
+ [EXCP_DWATCH] = "data watchpoint",
+ [EXCP_LTLBL] = "TLB modify",
+ [EXCP_TLBL] = "TLB load",
+ [EXCP_TLBS] = "TLB store",
+ [EXCP_DBE] = "data bus error",
+ [EXCP_DDBL] = "debug data break load",
+ [EXCP_THREAD] = "thread",
+ [EXCP_MDMX] = "MDMX",
+ [EXCP_C2E] = "precise coprocessor 2",
+ [EXCP_CACHE] = "cache error",
+ [EXCP_TLBXI] = "TLB execute-inhibit",
+ [EXCP_TLBRI] = "TLB read-inhibit",
+ [EXCP_MSADIS] = "MSA disabled",
+ [EXCP_MSAFPE] = "MSA floating point",
+};
+
+const char *mips_exception_name(int32_t exception)
+{
+ if (exception < 0 || exception > EXCP_LAST) {
+ return "unknown";
+ }
+ return excp_names[exception];
+}
+
+void do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
+ int error_code, uintptr_t pc)
+{
+ CPUState *cs = env_cpu(env);
+
+ qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n",
+ __func__, exception, mips_exception_name(exception),
+ error_code);
+ cs->exception_index = exception;
+ env->error_code = error_code;
+
+ cpu_loop_exit_restore(cs, pc);
+}
diff --git a/target/mips/fpu_helper.c b/target/mips/tcg/fpu_helper.c
similarity index 99%
rename from target/mips/fpu_helper.c
rename to target/mips/tcg/fpu_helper.c
index 6dd8532..8ce56ed 100644
--- a/target/mips/fpu_helper.c
+++ b/target/mips/tcg/fpu_helper.c
@@ -38,14 +38,6 @@
#define FP_TO_INT32_OVERFLOW 0x7fffffff
#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
-/* convert MIPS rounding mode in FCR31 to IEEE library */
-const FloatRoundMode ieee_rm[4] = {
- float_round_nearest_even,
- float_round_to_zero,
- float_round_up,
- float_round_down
-};
-
target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
{
target_ulong arg1 = 0;
diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c
new file mode 100644
index 0000000..d42812b
--- /dev/null
+++ b/target/mips/tcg/ldst_helper.c
@@ -0,0 +1,288 @@
+/*
+ * MIPS emulation load/store helpers for QEMU.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/memop.h"
+#include "internal.h"
+
+#ifndef CONFIG_USER_ONLY
+
+#define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \
+target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
+{ \
+ if (arg & almask) { \
+ if (!(env->hflags & MIPS_HFLAG_DM)) { \
+ env->CP0_BadVAddr = arg; \
+ } \
+ do_raise_exception(env, EXCP_AdEL, GETPC()); \
+ } \
+ env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD, \
+ GETPC()); \
+ env->lladdr = arg; \
+ env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \
+ return env->llval; \
+}
+HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t))
+#ifdef TARGET_MIPS64
+HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
+#endif
+#undef HELPER_LD_ATOMIC
+
+#endif /* !CONFIG_USER_ONLY */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK(v) ((v) & 3)
+#define GET_OFFSET(addr, offset) (addr + (offset))
+#else
+#define GET_LMASK(v) (((v) & 3) ^ 3)
+#define GET_OFFSET(addr, offset) (addr - (offset))
+#endif
+
+void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
+
+ if (GET_LMASK(arg2) <= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) <= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) == 0) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)arg1,
+ mem_idx, GETPC());
+ }
+}
+
+void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
+
+ if (GET_LMASK(arg2) >= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) >= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) == 3) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
+ mem_idx, GETPC());
+ }
+}
+
+#if defined(TARGET_MIPS64)
+/*
+ * "half" load and stores. We must do the memory access inline,
+ * or fault handling won't work.
+ */
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK64(v) ((v) & 7)
+#else
+#define GET_LMASK64(v) (((v) & 7) ^ 7)
+#endif
+
+void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
+
+ if (GET_LMASK64(arg2) <= 6) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 5) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 4) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 3) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 0) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 7), (uint8_t)arg1,
+ mem_idx, GETPC());
+ }
+}
+
+void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
+
+ if (GET_LMASK64(arg2) >= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 3) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 4) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 5) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 6) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) == 7) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56),
+ mem_idx, GETPC());
+ }
+}
+#endif /* TARGET_MIPS64 */
+
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] =
+ (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] =
+ (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
+ }
+}
+
+void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
+ mem_idx, GETPC());
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
+ }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] =
+ cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] =
+ cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
+ }
+}
+
+void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
+ mem_idx, GETPC());
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
+ }
+}
+
+#endif /* TARGET_MIPS64 */
diff --git a/target/mips/lmmi_helper.c b/target/mips/tcg/lmmi_helper.c
similarity index 100%
rename from target/mips/lmmi_helper.c
rename to target/mips/tcg/lmmi_helper.c
diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build
new file mode 100644
index 0000000..5d8acba
--- /dev/null
+++ b/target/mips/tcg/meson.build
@@ -0,0 +1,35 @@
+gen = [
+ decodetree.process('mips32r6.decode', extra_args: '--static-decode=decode_mips32r6'),
+ decodetree.process('mips64r6.decode', extra_args: '--static-decode=decode_mips64r6'),
+ decodetree.process('msa32.decode', extra_args: '--static-decode=decode_msa32'),
+ decodetree.process('msa64.decode', extra_args: '--static-decode=decode_msa64'),
+ decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'),
+]
+
+mips_ss.add(gen)
+mips_ss.add(files(
+ 'dsp_helper.c',
+ 'exception.c',
+ 'fpu_helper.c',
+ 'ldst_helper.c',
+ 'lmmi_helper.c',
+ 'msa_helper.c',
+ 'msa_translate.c',
+ 'op_helper.c',
+ 'rel6_translate.c',
+ 'translate.c',
+ 'translate_addr_const.c',
+ 'txx9_translate.c',
+))
+mips_ss.add(when: 'TARGET_MIPS64', if_true: files(
+ 'tx79_translate.c',
+), if_false: files(
+ 'mxu_translate.c',
+))
+
+if have_user
+ subdir('user')
+endif
+if have_system
+ subdir('sysemu')
+endif
diff --git a/target/mips/mips32r6.decode b/target/mips/tcg/mips32r6.decode
similarity index 100%
rename from target/mips/mips32r6.decode
rename to target/mips/tcg/mips32r6.decode
diff --git a/target/mips/mips64r6.decode b/target/mips/tcg/mips64r6.decode
similarity index 100%
rename from target/mips/mips64r6.decode
rename to target/mips/tcg/mips64r6.decode
diff --git a/target/mips/msa32.decode b/target/mips/tcg/msa32.decode
similarity index 100%
rename from target/mips/msa32.decode
rename to target/mips/tcg/msa32.decode
diff --git a/target/mips/msa64.decode b/target/mips/tcg/msa64.decode
similarity index 100%
rename from target/mips/msa64.decode
rename to target/mips/tcg/msa64.decode
diff --git a/target/mips/msa_helper.c b/target/mips/tcg/msa_helper.c
similarity index 99%
rename from target/mips/msa_helper.c
rename to target/mips/tcg/msa_helper.c
index 4caefe2..04af54f 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/tcg/msa_helper.c
@@ -8595,39 +8595,3 @@
cpu_stq_data(env, addr + (1 << DF_DOUBLE), pwd->d[1]);
#endif
}
-
-void msa_reset(CPUMIPSState *env)
-{
- if (!ase_msa_available(env)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- /* MSA access enabled */
- env->CP0_Config5 |= 1 << CP0C5_MSAEn;
- env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR);
-#endif
-
- /*
- * MSA CSR:
- * - non-signaling floating point exception mode off (NX bit is 0)
- * - Cause, Enables, and Flags are all 0
- * - round to nearest / ties to even (RM bits are 0)
- */
- env->active_tc.msacsr = 0;
-
- restore_msa_fp_status(env);
-
- /* tininess detected after rounding.*/
- set_float_detect_tininess(float_tininess_after_rounding,
- &env->active_tc.msa_fp_status);
-
- /* clear float_status exception flags */
- set_float_exception_flags(0, &env->active_tc.msa_fp_status);
-
- /* clear float_status nan mode */
- set_default_nan_mode(0, &env->active_tc.msa_fp_status);
-
- /* set proper signanling bit meaning ("1" means "quiet") */
- set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
-}
diff --git a/target/mips/msa_helper.h.inc b/target/mips/tcg/msa_helper.h.inc
similarity index 100%
rename from target/mips/msa_helper.h.inc
rename to target/mips/tcg/msa_helper.h.inc
diff --git a/target/mips/msa_translate.c b/target/mips/tcg/msa_translate.c
similarity index 100%
rename from target/mips/msa_translate.c
rename to target/mips/tcg/msa_translate.c
diff --git a/target/mips/mxu_translate.c b/target/mips/tcg/mxu_translate.c
similarity index 100%
rename from target/mips/mxu_translate.c
rename to target/mips/tcg/mxu_translate.c
diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c
new file mode 100644
index 0000000..ce1549c
--- /dev/null
+++ b/target/mips/tcg/op_helper.c
@@ -0,0 +1,420 @@
+/*
+ * MIPS emulation helpers for qemu.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internal.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/memop.h"
+#include "fpu_helper.h"
+
+/* 64 bits arithmetic for 32 bits hosts */
+static inline uint64_t get_HILO(CPUMIPSState *env)
+{
+ return ((uint64_t)(env->active_tc.HI[0]) << 32) |
+ (uint32_t)env->active_tc.LO[0];
+}
+
+static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
+{
+ env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+ return env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+}
+
+static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
+{
+ target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+ env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ return tmp;
+}
+
+/* Multiplication variants of the vr54xx. */
+target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2));
+}
+
+target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
+}
+
+target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
+}
+
+target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
+}
+
+target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
+ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
+}
+
+target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
+ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
+}
+
+target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
+}
+
+target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
+}
+
+target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
+ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
+}
+
+target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
+ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
+}
+
+target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
+}
+
+target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
+}
+
+target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
+}
+
+target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
+}
+
+static inline target_ulong bitswap(target_ulong v)
+{
+ v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
+ ((v & (target_ulong)0x5555555555555555ULL) << 1);
+ v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
+ ((v & (target_ulong)0x3333333333333333ULL) << 2);
+ v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
+ ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
+ return v;
+}
+
+#ifdef TARGET_MIPS64
+target_ulong helper_dbitswap(target_ulong rt)
+{
+ return bitswap(rt);
+}
+#endif
+
+target_ulong helper_bitswap(target_ulong rt)
+{
+ return (int32_t)bitswap(rt);
+}
+
+target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
+ uint32_t stripe)
+{
+ int i;
+ uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff);
+ uint64_t tmp1 = tmp0;
+ for (i = 0; i <= 46; i++) {
+ int s;
+ if (i & 0x8) {
+ s = shift;
+ } else {
+ s = shiftx;
+ }
+
+ if (stripe != 0 && !(i & 0x4)) {
+ s = ~s;
+ }
+ if (s & 0x10) {
+ if (tmp0 & (1LL << (i + 16))) {
+ tmp1 |= 1LL << i;
+ } else {
+ tmp1 &= ~(1LL << i);
+ }
+ }
+ }
+
+ uint64_t tmp2 = tmp1;
+ for (i = 0; i <= 38; i++) {
+ int s;
+ if (i & 0x4) {
+ s = shift;
+ } else {
+ s = shiftx;
+ }
+
+ if (s & 0x8) {
+ if (tmp1 & (1LL << (i + 8))) {
+ tmp2 |= 1LL << i;
+ } else {
+ tmp2 &= ~(1LL << i);
+ }
+ }
+ }
+
+ uint64_t tmp3 = tmp2;
+ for (i = 0; i <= 34; i++) {
+ int s;
+ if (i & 0x2) {
+ s = shift;
+ } else {
+ s = shiftx;
+ }
+ if (s & 0x4) {
+ if (tmp2 & (1LL << (i + 4))) {
+ tmp3 |= 1LL << i;
+ } else {
+ tmp3 &= ~(1LL << i);
+ }
+ }
+ }
+
+ uint64_t tmp4 = tmp3;
+ for (i = 0; i <= 32; i++) {
+ int s;
+ if (i & 0x1) {
+ s = shift;
+ } else {
+ s = shiftx;
+ }
+ if (s & 0x2) {
+ if (tmp3 & (1LL << (i + 2))) {
+ tmp4 |= 1LL << i;
+ } else {
+ tmp4 &= ~(1LL << i);
+ }
+ }
+ }
+
+ uint64_t tmp5 = tmp4;
+ for (i = 0; i <= 31; i++) {
+ int s;
+ s = shift;
+ if (s & 0x1) {
+ if (tmp4 & (1LL << (i + 1))) {
+ tmp5 |= 1LL << i;
+ } else {
+ tmp5 &= ~(1LL << i);
+ }
+ }
+ }
+
+ return (int64_t)(int32_t)(uint32_t)tmp5;
+}
+
+void helper_fork(target_ulong arg1, target_ulong arg2)
+{
+ /*
+ * arg1 = rt, arg2 = rs
+ * TODO: store to TC register
+ */
+}
+
+target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
+{
+ target_long arg1 = arg;
+
+ if (arg1 < 0) {
+ /* No scheduling policy implemented. */
+ if (arg1 != -2) {
+ if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
+ env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
+ env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+ env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
+ do_raise_exception(env, EXCP_THREAD, GETPC());
+ }
+ }
+ } else if (arg1 == 0) {
+ if (0) {
+ /* TODO: TC underflow */
+ env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+ do_raise_exception(env, EXCP_THREAD, GETPC());
+ } else {
+ /* TODO: Deallocate TC */
+ }
+ } else if (arg1 > 0) {
+ /* Yield qualifier inputs not implemented. */
+ env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+ env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
+ do_raise_exception(env, EXCP_THREAD, GETPC());
+ }
+ return env->CP0_YQMask;
+}
+
+static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
+{
+ if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
+ return;
+ }
+ do_raise_exception(env, EXCP_RI, pc);
+}
+
+target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
+{
+ check_hwrena(env, 0, GETPC());
+ return env->CP0_EBase & 0x3ff;
+}
+
+target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
+{
+ check_hwrena(env, 1, GETPC());
+ return env->SYNCI_Step;
+}
+
+target_ulong helper_rdhwr_cc(CPUMIPSState *env)
+{
+ check_hwrena(env, 2, GETPC());
+#ifdef CONFIG_USER_ONLY
+ return env->CP0_Count;
+#else
+ return (int32_t)cpu_mips_get_count(env);
+#endif
+}
+
+target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
+{
+ check_hwrena(env, 3, GETPC());
+ return env->CCRes;
+}
+
+target_ulong helper_rdhwr_performance(CPUMIPSState *env)
+{
+ check_hwrena(env, 4, GETPC());
+ return env->CP0_Performance0;
+}
+
+target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
+{
+ check_hwrena(env, 5, GETPC());
+ return (env->CP0_Config5 >> CP0C5_XNP) & 1;
+}
+
+void helper_pmon(CPUMIPSState *env, int function)
+{
+ function /= 2;
+ switch (function) {
+ case 2: /* TODO: char inbyte(int waitflag); */
+ if (env->active_tc.gpr[4] == 0) {
+ env->active_tc.gpr[2] = -1;
+ }
+ /* Fall through */
+ case 11: /* TODO: char inbyte (void); */
+ env->active_tc.gpr[2] = -1;
+ break;
+ case 3:
+ case 12:
+ printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
+ break;
+ case 17:
+ break;
+ case 158:
+ {
+ unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
+ printf("%s", fmt);
+ }
+ break;
+ }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+ MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+ int error_code = 0;
+ int excp;
+
+ if (!(env->hflags & MIPS_HFLAG_DM)) {
+ env->CP0_BadVAddr = addr;
+ }
+
+ if (access_type == MMU_DATA_STORE) {
+ excp = EXCP_AdES;
+ } else {
+ excp = EXCP_AdEL;
+ if (access_type == MMU_INST_FETCH) {
+ error_code |= EXCP_INST_NOTAVAIL;
+ }
+ }
+
+ do_raise_exception_err(env, excp, error_code, retaddr);
+}
+
+void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ if (access_type == MMU_INST_FETCH) {
+ do_raise_exception(env, EXCP_IBE, retaddr);
+ } else {
+ do_raise_exception(env, EXCP_DBE, retaddr);
+ }
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/mips/rel6_translate.c b/target/mips/tcg/rel6_translate.c
similarity index 100%
rename from target/mips/rel6_translate.c
rename to target/mips/tcg/rel6_translate.c
diff --git a/target/mips/cp0_helper.c b/target/mips/tcg/sysemu/cp0_helper.c
similarity index 100%
rename from target/mips/cp0_helper.c
rename to target/mips/tcg/sysemu/cp0_helper.c
diff --git a/target/mips/tcg/sysemu/meson.build b/target/mips/tcg/sysemu/meson.build
new file mode 100644
index 0000000..4da2c57
--- /dev/null
+++ b/target/mips/tcg/sysemu/meson.build
@@ -0,0 +1,6 @@
+mips_softmmu_ss.add(files(
+ 'cp0_helper.c',
+ 'mips-semi.c',
+ 'special_helper.c',
+ 'tlb_helper.c',
+))
diff --git a/target/mips/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
similarity index 100%
rename from target/mips/mips-semi.c
rename to target/mips/tcg/sysemu/mips-semi.c
diff --git a/target/mips/tcg/sysemu/special_helper.c b/target/mips/tcg/sysemu/special_helper.c
new file mode 100644
index 0000000..2a2afb4
--- /dev/null
+++ b/target/mips/tcg/sysemu/special_helper.c
@@ -0,0 +1,173 @@
+/*
+ * QEMU MIPS emulation: Special opcode helpers
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "internal.h"
+
+/* Specials */
+target_ulong helper_di(CPUMIPSState *env)
+{
+ target_ulong t0 = env->CP0_Status;
+
+ env->CP0_Status = t0 & ~(1 << CP0St_IE);
+ return t0;
+}
+
+target_ulong helper_ei(CPUMIPSState *env)
+{
+ target_ulong t0 = env->CP0_Status;
+
+ env->CP0_Status = t0 | (1 << CP0St_IE);
+ return t0;
+}
+
+static void debug_pre_eret(CPUMIPSState *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
+ qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+ env->active_tc.PC, env->CP0_EPC);
+ if (env->CP0_Status & (1 << CP0St_ERL)) {
+ qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+ }
+ if (env->hflags & MIPS_HFLAG_DM) {
+ qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+ }
+ qemu_log("\n");
+ }
+}
+
+static void debug_post_eret(CPUMIPSState *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
+ qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+ env->active_tc.PC, env->CP0_EPC);
+ if (env->CP0_Status & (1 << CP0St_ERL)) {
+ qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+ }
+ if (env->hflags & MIPS_HFLAG_DM) {
+ qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+ }
+ switch (cpu_mmu_index(env, false)) {
+ case 3:
+ qemu_log(", ERL\n");
+ break;
+ case MIPS_HFLAG_UM:
+ qemu_log(", UM\n");
+ break;
+ case MIPS_HFLAG_SM:
+ qemu_log(", SM\n");
+ break;
+ case MIPS_HFLAG_KM:
+ qemu_log("\n");
+ break;
+ default:
+ cpu_abort(env_cpu(env), "Invalid MMU mode!\n");
+ break;
+ }
+ }
+}
+
+bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ if ((env->hflags & MIPS_HFLAG_BMASK) != 0
+ && env->active_tc.PC != tb->pc) {
+ env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
+ env->hflags &= ~MIPS_HFLAG_BMASK;
+ return true;
+ }
+ return false;
+}
+
+static inline void exception_return(CPUMIPSState *env)
+{
+ debug_pre_eret(env);
+ if (env->CP0_Status & (1 << CP0St_ERL)) {
+ mips_env_set_pc(env, env->CP0_ErrorEPC);
+ env->CP0_Status &= ~(1 << CP0St_ERL);
+ } else {
+ mips_env_set_pc(env, env->CP0_EPC);
+ env->CP0_Status &= ~(1 << CP0St_EXL);
+ }
+ compute_hflags(env);
+ debug_post_eret(env);
+}
+
+void helper_eret(CPUMIPSState *env)
+{
+ exception_return(env);
+ env->CP0_LLAddr = 1;
+ env->lladdr = 1;
+}
+
+void helper_eretnc(CPUMIPSState *env)
+{
+ exception_return(env);
+}
+
+void helper_deret(CPUMIPSState *env)
+{
+ debug_pre_eret(env);
+
+ env->hflags &= ~MIPS_HFLAG_DM;
+ compute_hflags(env);
+
+ mips_env_set_pc(env, env->CP0_DEPC);
+
+ debug_post_eret(env);
+}
+
+void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
+{
+ static const char *const type_name[] = {
+ "Primary Instruction",
+ "Primary Data or Unified Primary",
+ "Tertiary",
+ "Secondary"
+ };
+ uint32_t cache_type = extract32(op, 0, 2);
+ uint32_t cache_operation = extract32(op, 2, 3);
+ target_ulong index = addr & 0x1fffffff;
+
+ switch (cache_operation) {
+ case 0b010: /* Index Store Tag */
+ memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
+ MO_64, MEMTXATTRS_UNSPECIFIED);
+ break;
+ case 0b001: /* Index Load Tag */
+ memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
+ MO_64, MEMTXATTRS_UNSPECIFIED);
+ break;
+ case 0b000: /* Index Invalidate */
+ case 0b100: /* Hit Invalidate */
+ case 0b110: /* Hit Writeback */
+ /* no-op */
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n",
+ cache_operation, type_name[cache_type]);
+ break;
+ }
+}
diff --git a/target/mips/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c
similarity index 75%
rename from target/mips/tlb_helper.c
rename to target/mips/tcg/sysemu/tlb_helper.c
index 8d3ea49..259f780 100644
--- a/target/mips/tlb_helper.c
+++ b/target/mips/tcg/sysemu/tlb_helper.c
@@ -24,22 +24,341 @@
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "hw/mips/cpudevs.h"
+#include "exec/helper-proto.h"
-enum {
- TLBRET_XI = -6,
- TLBRET_RI = -5,
- TLBRET_DIRTY = -4,
- TLBRET_INVALID = -3,
- TLBRET_NOMATCH = -2,
- TLBRET_BADADDR = -1,
- TLBRET_MATCH = 0
-};
+/* TLB management */
+static void r4k_mips_tlb_flush_extra(CPUMIPSState *env, int first)
+{
+ /* Discard entries from env->tlb[first] onwards. */
+ while (env->tlb->tlb_in_use > first) {
+ r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
+ }
+}
-#if !defined(CONFIG_USER_ONLY)
+static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
+{
+#if defined(TARGET_MIPS64)
+ return extract64(entrylo, 6, 54);
+#else
+ return extract64(entrylo, 6, 24) | /* PFN */
+ (extract64(entrylo, 32, 32) << 24); /* PFNX */
+#endif
+}
+
+static void r4k_fill_tlb(CPUMIPSState *env, int idx)
+{
+ r4k_tlb_t *tlb;
+ uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
+
+ /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+ if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
+ tlb->EHINV = 1;
+ return;
+ }
+ tlb->EHINV = 0;
+ tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
+#if defined(TARGET_MIPS64)
+ tlb->VPN &= env->SEGMask;
+#endif
+ tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+ tlb->MMID = env->CP0_MemoryMapID;
+ tlb->PageMask = env->CP0_PageMask;
+ tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
+ tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
+ tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
+ tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
+ tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
+ tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
+ tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
+ tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
+ tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
+ tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
+ tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
+ tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
+ tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
+}
+
+static void r4k_helper_tlbinv(CPUMIPSState *env)
+{
+ bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
+ uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+ uint32_t MMID = env->CP0_MemoryMapID;
+ uint32_t tlb_mmid;
+ r4k_tlb_t *tlb;
+ int idx;
+
+ MMID = mi ? MMID : (uint32_t) ASID;
+ for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+ tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
+ if (!tlb->G && tlb_mmid == MMID) {
+ tlb->EHINV = 1;
+ }
+ }
+ cpu_mips_tlb_flush(env);
+}
+
+static void r4k_helper_tlbinvf(CPUMIPSState *env)
+{
+ int idx;
+
+ for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
+ env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
+ }
+ cpu_mips_tlb_flush(env);
+}
+
+static void r4k_helper_tlbwi(CPUMIPSState *env)
+{
+ bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
+ target_ulong VPN;
+ uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+ uint32_t MMID = env->CP0_MemoryMapID;
+ uint32_t tlb_mmid;
+ bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
+ r4k_tlb_t *tlb;
+ int idx;
+
+ MMID = mi ? MMID : (uint32_t) ASID;
+
+ idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+ VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
+#if defined(TARGET_MIPS64)
+ VPN &= env->SEGMask;
+#endif
+ EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
+ G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
+ V0 = (env->CP0_EntryLo0 & 2) != 0;
+ D0 = (env->CP0_EntryLo0 & 4) != 0;
+ XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
+ RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
+ V1 = (env->CP0_EntryLo1 & 2) != 0;
+ D1 = (env->CP0_EntryLo1 & 4) != 0;
+ XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
+ RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
+
+ tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
+ /*
+ * Discard cached TLB entries, unless tlbwi is just upgrading access
+ * permissions on the current entry.
+ */
+ if (tlb->VPN != VPN || tlb_mmid != MMID || tlb->G != G ||
+ (!tlb->EHINV && EHINV) ||
+ (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
+ (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
+ (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
+ (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
+ r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
+ }
+
+ r4k_invalidate_tlb(env, idx, 0);
+ r4k_fill_tlb(env, idx);
+}
+
+static void r4k_helper_tlbwr(CPUMIPSState *env)
+{
+ int r = cpu_mips_get_random(env);
+
+ r4k_invalidate_tlb(env, r, 1);
+ r4k_fill_tlb(env, r);
+}
+
+static void r4k_helper_tlbp(CPUMIPSState *env)
+{
+ bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
+ r4k_tlb_t *tlb;
+ target_ulong mask;
+ target_ulong tag;
+ target_ulong VPN;
+ uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+ uint32_t MMID = env->CP0_MemoryMapID;
+ uint32_t tlb_mmid;
+ int i;
+
+ MMID = mi ? MMID : (uint32_t) ASID;
+ for (i = 0; i < env->tlb->nb_tlb; i++) {
+ tlb = &env->tlb->mmu.r4k.tlb[i];
+ /* 1k pages are not supported. */
+ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+ tag = env->CP0_EntryHi & ~mask;
+ VPN = tlb->VPN & ~mask;
+#if defined(TARGET_MIPS64)
+ tag &= env->SEGMask;
+#endif
+ tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
+ /* Check ASID/MMID, virtual page number & size */
+ if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag && !tlb->EHINV) {
+ /* TLB match */
+ env->CP0_Index = i;
+ break;
+ }
+ }
+ if (i == env->tlb->nb_tlb) {
+ /* No match. Discard any shadow entries, if any of them match. */
+ for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
+ tlb = &env->tlb->mmu.r4k.tlb[i];
+ /* 1k pages are not supported. */
+ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+ tag = env->CP0_EntryHi & ~mask;
+ VPN = tlb->VPN & ~mask;
+#if defined(TARGET_MIPS64)
+ tag &= env->SEGMask;
+#endif
+ tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
+ /* Check ASID/MMID, virtual page number & size */
+ if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag) {
+ r4k_mips_tlb_flush_extra(env, i);
+ break;
+ }
+ }
+
+ env->CP0_Index |= 0x80000000;
+ }
+}
+
+static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
+{
+#if defined(TARGET_MIPS64)
+ return tlb_pfn << 6;
+#else
+ return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
+ (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
+#endif
+}
+
+static void r4k_helper_tlbr(CPUMIPSState *env)
+{
+ bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
+ uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+ uint32_t MMID = env->CP0_MemoryMapID;
+ uint32_t tlb_mmid;
+ r4k_tlb_t *tlb;
+ int idx;
+
+ MMID = mi ? MMID : (uint32_t) ASID;
+ idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+
+ tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
+ /* If this will change the current ASID/MMID, flush qemu's TLB. */
+ if (MMID != tlb_mmid) {
+ cpu_mips_tlb_flush(env);
+ }
+
+ r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
+
+ if (tlb->EHINV) {
+ env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
+ env->CP0_PageMask = 0;
+ env->CP0_EntryLo0 = 0;
+ env->CP0_EntryLo1 = 0;
+ } else {
+ env->CP0_EntryHi = mi ? tlb->VPN : tlb->VPN | tlb->ASID;
+ env->CP0_MemoryMapID = tlb->MMID;
+ env->CP0_PageMask = tlb->PageMask;
+ env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
+ ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
+ ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
+ get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
+ env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
+ ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
+ ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
+ get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
+ }
+}
+
+void helper_tlbwi(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbwi(env);
+}
+
+void helper_tlbwr(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbwr(env);
+}
+
+void helper_tlbp(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbp(env);
+}
+
+void helper_tlbr(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbr(env);
+}
+
+void helper_tlbinv(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbinv(env);
+}
+
+void helper_tlbinvf(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbinvf(env);
+}
+
+static void global_invalidate_tlb(CPUMIPSState *env,
+ uint32_t invMsgVPN2,
+ uint8_t invMsgR,
+ uint32_t invMsgMMid,
+ bool invAll,
+ bool invVAMMid,
+ bool invMMid,
+ bool invVA)
+{
+
+ int idx;
+ r4k_tlb_t *tlb;
+ bool VAMatch;
+ bool MMidMatch;
+
+ for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+ VAMatch =
+ (((tlb->VPN & ~tlb->PageMask) == (invMsgVPN2 & ~tlb->PageMask))
+#ifdef TARGET_MIPS64
+ &&
+ (extract64(env->CP0_EntryHi, 62, 2) == invMsgR)
+#endif
+ );
+ MMidMatch = tlb->MMID == invMsgMMid;
+ if ((invAll && (idx > env->CP0_Wired)) ||
+ (VAMatch && invVAMMid && (tlb->G || MMidMatch)) ||
+ (VAMatch && invVA) ||
+ (MMidMatch && !(tlb->G) && invMMid)) {
+ tlb->EHINV = 1;
+ }
+ }
+ cpu_mips_tlb_flush(env);
+}
+
+void helper_ginvt(CPUMIPSState *env, target_ulong arg, uint32_t type)
+{
+ bool invAll = type == 0;
+ bool invVA = type == 1;
+ bool invMMid = type == 2;
+ bool invVAMMid = type == 3;
+ uint32_t invMsgVPN2 = arg & (TARGET_PAGE_MASK << 1);
+ uint8_t invMsgR = 0;
+ uint32_t invMsgMMid = env->CP0_MemoryMapID;
+ CPUState *other_cs = first_cpu;
+
+#ifdef TARGET_MIPS64
+ invMsgR = extract64(arg, 62, 2);
+#endif
+
+ CPU_FOREACH(other_cs) {
+ MIPSCPU *other_cpu = MIPS_CPU(other_cs);
+ global_invalidate_tlb(&other_cpu->env, invMsgVPN2, invMsgR, invMsgMMid,
+ invAll, invVAMMid, invMMid, invVA);
+ }
+}
/* no MMU emulation */
-int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, MMUAccessType access_type)
+static int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
+ target_ulong address, MMUAccessType access_type)
{
*physical = address;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
@@ -47,8 +366,9 @@
}
/* fixed mapping MMU emulation */
-int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, MMUAccessType access_type)
+static int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type)
{
if (address <= (int32_t)0x7FFFFFFFUL) {
if (!(env->CP0_Status & (1 << CP0St_ERL))) {
@@ -67,8 +387,8 @@
}
/* MIPS32/MIPS64 R4000-style MMU emulation */
-int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, MMUAccessType access_type)
+static int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
+ target_ulong address, MMUAccessType access_type)
{
uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
uint32_t MMID = env->CP0_MemoryMapID;
@@ -166,236 +486,6 @@
}
}
-static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx)
-{
- /*
- * Interpret access control mode and mmu_idx.
- * AdE? TLB?
- * AM K S U E K S U E
- * UK 0 0 1 1 0 0 - - 0
- * MK 1 0 1 1 0 1 - - !eu
- * MSK 2 0 0 1 0 1 1 - !eu
- * MUSK 3 0 0 0 0 1 1 1 !eu
- * MUSUK 4 0 0 0 0 0 1 1 0
- * USK 5 0 0 1 0 0 0 - 0
- * - 6 - - - - - - - -
- * UUSK 7 0 0 0 0 0 0 0 0
- */
- int32_t adetlb_mask;
-
- switch (mmu_idx) {
- case 3: /* ERL */
- /* If EU is set, always unmapped */
- if (eu) {
- return 0;
- }
- /* fall through */
- case MIPS_HFLAG_KM:
- /* Never AdE, TLB mapped if AM={1,2,3} */
- adetlb_mask = 0x70000000;
- goto check_tlb;
-
- case MIPS_HFLAG_SM:
- /* AdE if AM={0,1}, TLB mapped if AM={2,3,4} */
- adetlb_mask = 0xc0380000;
- goto check_ade;
-
- case MIPS_HFLAG_UM:
- /* AdE if AM={0,1,2,5}, TLB mapped if AM={3,4} */
- adetlb_mask = 0xe4180000;
- /* fall through */
- check_ade:
- /* does this AM cause AdE in current execution mode */
- if ((adetlb_mask << am) < 0) {
- return TLBRET_BADADDR;
- }
- adetlb_mask <<= 8;
- /* fall through */
- check_tlb:
- /* is this AM mapped in current execution mode */
- return ((adetlb_mask << am) < 0);
- default:
- assert(0);
- return TLBRET_BADADDR;
- };
-}
-
-static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical,
- int *prot, target_ulong real_address,
- MMUAccessType access_type, int mmu_idx,
- unsigned int am, bool eu,
- target_ulong segmask,
- hwaddr physical_base)
-{
- int mapped = is_seg_am_mapped(am, eu, mmu_idx);
-
- if (mapped < 0) {
- /* is_seg_am_mapped can report TLBRET_BADADDR */
- return mapped;
- } else if (mapped) {
- /* The segment is TLB mapped */
- return env->tlb->map_address(env, physical, prot, real_address,
- access_type);
- } else {
- /* The segment is unmapped */
- *physical = physical_base | (real_address & segmask);
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return TLBRET_MATCH;
- }
-}
-
-static int get_segctl_physical_address(CPUMIPSState *env, hwaddr *physical,
- int *prot, target_ulong real_address,
- MMUAccessType access_type, int mmu_idx,
- uint16_t segctl, target_ulong segmask)
-{
- unsigned int am = (segctl & CP0SC_AM_MASK) >> CP0SC_AM;
- bool eu = (segctl >> CP0SC_EU) & 1;
- hwaddr pa = ((hwaddr)segctl & CP0SC_PA_MASK) << 20;
-
- return get_seg_physical_address(env, physical, prot, real_address,
- access_type, mmu_idx, am, eu, segmask,
- pa & ~(hwaddr)segmask);
-}
-
-static int get_physical_address(CPUMIPSState *env, hwaddr *physical,
- int *prot, target_ulong real_address,
- MMUAccessType access_type, int mmu_idx)
-{
- /* User mode can only access useg/xuseg */
-#if defined(TARGET_MIPS64)
- int user_mode = mmu_idx == MIPS_HFLAG_UM;
- int supervisor_mode = mmu_idx == MIPS_HFLAG_SM;
- int kernel_mode = !user_mode && !supervisor_mode;
- int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
- int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
- int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
-#endif
- int ret = TLBRET_MATCH;
- /* effective address (modified for KVM T&E kernel segments) */
- target_ulong address = real_address;
-
-#define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL)
-#define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL)
-#define KSEG1_BASE ((target_ulong)(int32_t)0xA0000000UL)
-#define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL)
-#define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL)
-
-#define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL)
-#define KVM_KSEG2_BASE ((target_ulong)(int32_t)0x60000000UL)
-
- if (mips_um_ksegs_enabled()) {
- /* KVM T&E adds guest kernel segments in useg */
- if (real_address >= KVM_KSEG0_BASE) {
- if (real_address < KVM_KSEG2_BASE) {
- /* kseg0 */
- address += KSEG0_BASE - KVM_KSEG0_BASE;
- } else if (real_address <= USEG_LIMIT) {
- /* kseg2/3 */
- address += KSEG2_BASE - KVM_KSEG2_BASE;
- }
- }
- }
-
- if (address <= USEG_LIMIT) {
- /* useg */
- uint16_t segctl;
-
- if (address >= 0x40000000UL) {
- segctl = env->CP0_SegCtl2;
- } else {
- segctl = env->CP0_SegCtl2 >> 16;
- }
- ret = get_segctl_physical_address(env, physical, prot,
- real_address, access_type,
- mmu_idx, segctl, 0x3FFFFFFF);
-#if defined(TARGET_MIPS64)
- } else if (address < 0x4000000000000000ULL) {
- /* xuseg */
- if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
- ret = env->tlb->map_address(env, physical, prot,
- real_address, access_type);
- } else {
- ret = TLBRET_BADADDR;
- }
- } else if (address < 0x8000000000000000ULL) {
- /* xsseg */
- if ((supervisor_mode || kernel_mode) &&
- SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
- ret = env->tlb->map_address(env, physical, prot,
- real_address, access_type);
- } else {
- ret = TLBRET_BADADDR;
- }
- } else if (address < 0xC000000000000000ULL) {
- /* xkphys */
- if ((address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
- /* KX/SX/UX bit to check for each xkphys EVA access mode */
- static const uint8_t am_ksux[8] = {
- [CP0SC_AM_UK] = (1u << CP0St_KX),
- [CP0SC_AM_MK] = (1u << CP0St_KX),
- [CP0SC_AM_MSK] = (1u << CP0St_SX),
- [CP0SC_AM_MUSK] = (1u << CP0St_UX),
- [CP0SC_AM_MUSUK] = (1u << CP0St_UX),
- [CP0SC_AM_USK] = (1u << CP0St_SX),
- [6] = (1u << CP0St_KX),
- [CP0SC_AM_UUSK] = (1u << CP0St_UX),
- };
- unsigned int am = CP0SC_AM_UK;
- unsigned int xr = (env->CP0_SegCtl2 & CP0SC2_XR_MASK) >> CP0SC2_XR;
-
- if (xr & (1 << ((address >> 59) & 0x7))) {
- am = (env->CP0_SegCtl1 & CP0SC1_XAM_MASK) >> CP0SC1_XAM;
- }
- /* Does CP0_Status.KX/SX/UX permit the access mode (am) */
- if (env->CP0_Status & am_ksux[am]) {
- ret = get_seg_physical_address(env, physical, prot,
- real_address, access_type,
- mmu_idx, am, false, env->PAMask,
- 0);
- } else {
- ret = TLBRET_BADADDR;
- }
- } else {
- ret = TLBRET_BADADDR;
- }
- } else if (address < 0xFFFFFFFF80000000ULL) {
- /* xkseg */
- if (kernel_mode && KX &&
- address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
- ret = env->tlb->map_address(env, physical, prot,
- real_address, access_type);
- } else {
- ret = TLBRET_BADADDR;
- }
-#endif
- } else if (address < KSEG1_BASE) {
- /* kseg0 */
- ret = get_segctl_physical_address(env, physical, prot, real_address,
- access_type, mmu_idx,
- env->CP0_SegCtl1 >> 16, 0x1FFFFFFF);
- } else if (address < KSEG2_BASE) {
- /* kseg1 */
- ret = get_segctl_physical_address(env, physical, prot, real_address,
- access_type, mmu_idx,
- env->CP0_SegCtl1, 0x1FFFFFFF);
- } else if (address < KSEG3_BASE) {
- /* sseg (kseg2) */
- ret = get_segctl_physical_address(env, physical, prot, real_address,
- access_type, mmu_idx,
- env->CP0_SegCtl0 >> 16, 0x1FFFFFFF);
- } else {
- /*
- * kseg3
- * XXX: debug segment is not emulated
- */
- ret = get_segctl_physical_address(env, physical, prot, real_address,
- access_type, mmu_idx,
- env->CP0_SegCtl0, 0x1FFFFFFF);
- }
- return ret;
-}
-
void cpu_mips_tlb_flush(CPUMIPSState *env)
{
/* Flush qemu's TLB and discard all shadowed entries. */
@@ -403,8 +493,6 @@
env->tlb->tlb_in_use = env->tlb->nb_tlb;
}
-#endif /* !CONFIG_USER_ONLY */
-
static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
MMUAccessType access_type, int tlb_error)
{
@@ -484,22 +572,6 @@
env->error_code = error_code;
}
-#if !defined(CONFIG_USER_ONLY)
-
-hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
- hwaddr phys_addr;
- int prot;
-
- if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
- cpu_mmu_index(env, false)) != 0) {
- return -1;
- }
- return phys_addr;
-}
-
#if !defined(TARGET_MIPS64)
/*
@@ -833,7 +905,6 @@
return true;
}
#endif
-#endif /* !CONFIG_USER_ONLY */
bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
@@ -841,14 +912,11 @@
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
-#if !defined(CONFIG_USER_ONLY)
hwaddr physical;
int prot;
-#endif
int ret = TLBRET_BADADDR;
/* data access */
-#if !defined(CONFIG_USER_ONLY)
/* XXX: put correct access by using cpu_restore_state() correctly */
ret = get_physical_address(env, &physical, &prot, address,
access_type, mmu_idx);
@@ -896,29 +964,28 @@
if (probe) {
return false;
}
-#endif
raise_mmu_exception(env, address, access_type, ret);
do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
}
-#ifndef CONFIG_USER_ONLY
hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
- MMUAccessType access_type)
+ MMUAccessType access_type, uintptr_t retaddr)
{
hwaddr physical;
int prot;
int ret = 0;
+ CPUState *cs = env_cpu(env);
/* data access */
ret = get_physical_address(env, &physical, &prot, address, access_type,
cpu_mmu_index(env, false));
- if (ret != TLBRET_MATCH) {
- raise_mmu_exception(env, address, access_type, ret);
- return -1LL;
- } else {
+ if (ret == TLBRET_MATCH) {
return physical;
}
+
+ raise_mmu_exception(env, address, access_type, ret);
+ cpu_loop_exit_restore(cs, retaddr);
}
static void set_hflags_for_handler(CPUMIPSState *env)
@@ -964,11 +1031,8 @@
}
}
-#endif /* !CONFIG_USER_ONLY */
-
void mips_cpu_do_interrupt(CPUState *cs)
{
-#if !defined(CONFIG_USER_ONLY)
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
bool update_badinstr = 0;
@@ -1271,11 +1335,9 @@
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
}
-#endif
cs->exception_index = EXCP_NONE;
}
-#if !defined(CONFIG_USER_ONLY)
void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra)
{
CPUState *cs = env_cpu(env);
@@ -1340,4 +1402,3 @@
}
}
}
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target/mips/tcg/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc
new file mode 100644
index 0000000..4353a96
--- /dev/null
+++ b/target/mips/tcg/sysemu_helper.h.inc
@@ -0,0 +1,185 @@
+/*
+ * QEMU MIPS sysemu helpers
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ * Copyright (c) 2006 Marius Groeger (FPU operations)
+ * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+DEF_HELPER_1(do_semihosting, void, env)
+
+/* CP0 helpers */
+DEF_HELPER_1(mfc0_mvpcontrol, tl, env)
+DEF_HELPER_1(mfc0_mvpconf0, tl, env)
+DEF_HELPER_1(mfc0_mvpconf1, tl, env)
+DEF_HELPER_1(mftc0_vpecontrol, tl, env)
+DEF_HELPER_1(mftc0_vpeconf0, tl, env)
+DEF_HELPER_1(mfc0_random, tl, env)
+DEF_HELPER_1(mfc0_tcstatus, tl, env)
+DEF_HELPER_1(mftc0_tcstatus, tl, env)
+DEF_HELPER_1(mfc0_tcbind, tl, env)
+DEF_HELPER_1(mftc0_tcbind, tl, env)
+DEF_HELPER_1(mfc0_tcrestart, tl, env)
+DEF_HELPER_1(mftc0_tcrestart, tl, env)
+DEF_HELPER_1(mfc0_tchalt, tl, env)
+DEF_HELPER_1(mftc0_tchalt, tl, env)
+DEF_HELPER_1(mfc0_tccontext, tl, env)
+DEF_HELPER_1(mftc0_tccontext, tl, env)
+DEF_HELPER_1(mfc0_tcschedule, tl, env)
+DEF_HELPER_1(mftc0_tcschedule, tl, env)
+DEF_HELPER_1(mfc0_tcschefback, tl, env)
+DEF_HELPER_1(mftc0_tcschefback, tl, env)
+DEF_HELPER_1(mfc0_count, tl, env)
+DEF_HELPER_1(mfc0_saar, tl, env)
+DEF_HELPER_1(mfhc0_saar, tl, env)
+DEF_HELPER_1(mftc0_entryhi, tl, env)
+DEF_HELPER_1(mftc0_status, tl, env)
+DEF_HELPER_1(mftc0_cause, tl, env)
+DEF_HELPER_1(mftc0_epc, tl, env)
+DEF_HELPER_1(mftc0_ebase, tl, env)
+DEF_HELPER_2(mftc0_configx, tl, env, tl)
+DEF_HELPER_1(mfc0_lladdr, tl, env)
+DEF_HELPER_1(mfc0_maar, tl, env)
+DEF_HELPER_1(mfhc0_maar, tl, env)
+DEF_HELPER_2(mfc0_watchlo, tl, env, i32)
+DEF_HELPER_2(mfc0_watchhi, tl, env, i32)
+DEF_HELPER_2(mfhc0_watchhi, tl, env, i32)
+DEF_HELPER_1(mfc0_debug, tl, env)
+DEF_HELPER_1(mftc0_debug, tl, env)
+#ifdef TARGET_MIPS64
+DEF_HELPER_1(dmfc0_tcrestart, tl, env)
+DEF_HELPER_1(dmfc0_tchalt, tl, env)
+DEF_HELPER_1(dmfc0_tccontext, tl, env)
+DEF_HELPER_1(dmfc0_tcschedule, tl, env)
+DEF_HELPER_1(dmfc0_tcschefback, tl, env)
+DEF_HELPER_1(dmfc0_lladdr, tl, env)
+DEF_HELPER_1(dmfc0_maar, tl, env)
+DEF_HELPER_2(dmfc0_watchlo, tl, env, i32)
+DEF_HELPER_2(dmfc0_watchhi, tl, env, i32)
+DEF_HELPER_1(dmfc0_saar, tl, env)
+#endif /* TARGET_MIPS64 */
+
+DEF_HELPER_2(mtc0_index, void, env, tl)
+DEF_HELPER_2(mtc0_mvpcontrol, void, env, tl)
+DEF_HELPER_2(mtc0_vpecontrol, void, env, tl)
+DEF_HELPER_2(mttc0_vpecontrol, void, env, tl)
+DEF_HELPER_2(mtc0_vpeconf0, void, env, tl)
+DEF_HELPER_2(mttc0_vpeconf0, void, env, tl)
+DEF_HELPER_2(mtc0_vpeconf1, void, env, tl)
+DEF_HELPER_2(mtc0_yqmask, void, env, tl)
+DEF_HELPER_2(mtc0_vpeopt, void, env, tl)
+DEF_HELPER_2(mtc0_entrylo0, void, env, tl)
+DEF_HELPER_2(mtc0_tcstatus, void, env, tl)
+DEF_HELPER_2(mttc0_tcstatus, void, env, tl)
+DEF_HELPER_2(mtc0_tcbind, void, env, tl)
+DEF_HELPER_2(mttc0_tcbind, void, env, tl)
+DEF_HELPER_2(mtc0_tcrestart, void, env, tl)
+DEF_HELPER_2(mttc0_tcrestart, void, env, tl)
+DEF_HELPER_2(mtc0_tchalt, void, env, tl)
+DEF_HELPER_2(mttc0_tchalt, void, env, tl)
+DEF_HELPER_2(mtc0_tccontext, void, env, tl)
+DEF_HELPER_2(mttc0_tccontext, void, env, tl)
+DEF_HELPER_2(mtc0_tcschedule, void, env, tl)
+DEF_HELPER_2(mttc0_tcschedule, void, env, tl)
+DEF_HELPER_2(mtc0_tcschefback, void, env, tl)
+DEF_HELPER_2(mttc0_tcschefback, void, env, tl)
+DEF_HELPER_2(mtc0_entrylo1, void, env, tl)
+DEF_HELPER_2(mtc0_context, void, env, tl)
+DEF_HELPER_2(mtc0_memorymapid, void, env, tl)
+DEF_HELPER_2(mtc0_pagemask, void, env, tl)
+DEF_HELPER_2(mtc0_pagegrain, void, env, tl)
+DEF_HELPER_2(mtc0_segctl0, void, env, tl)
+DEF_HELPER_2(mtc0_segctl1, void, env, tl)
+DEF_HELPER_2(mtc0_segctl2, void, env, tl)
+DEF_HELPER_2(mtc0_pwfield, void, env, tl)
+DEF_HELPER_2(mtc0_pwsize, void, env, tl)
+DEF_HELPER_2(mtc0_wired, void, env, tl)
+DEF_HELPER_2(mtc0_srsconf0, void, env, tl)
+DEF_HELPER_2(mtc0_srsconf1, void, env, tl)
+DEF_HELPER_2(mtc0_srsconf2, void, env, tl)
+DEF_HELPER_2(mtc0_srsconf3, void, env, tl)
+DEF_HELPER_2(mtc0_srsconf4, void, env, tl)
+DEF_HELPER_2(mtc0_hwrena, void, env, tl)
+DEF_HELPER_2(mtc0_pwctl, void, env, tl)
+DEF_HELPER_2(mtc0_count, void, env, tl)
+DEF_HELPER_2(mtc0_saari, void, env, tl)
+DEF_HELPER_2(mtc0_saar, void, env, tl)
+DEF_HELPER_2(mthc0_saar, void, env, tl)
+DEF_HELPER_2(mtc0_entryhi, void, env, tl)
+DEF_HELPER_2(mttc0_entryhi, void, env, tl)
+DEF_HELPER_2(mtc0_compare, void, env, tl)
+DEF_HELPER_2(mtc0_status, void, env, tl)
+DEF_HELPER_2(mttc0_status, void, env, tl)
+DEF_HELPER_2(mtc0_intctl, void, env, tl)
+DEF_HELPER_2(mtc0_srsctl, void, env, tl)
+DEF_HELPER_2(mtc0_cause, void, env, tl)
+DEF_HELPER_2(mttc0_cause, void, env, tl)
+DEF_HELPER_2(mtc0_ebase, void, env, tl)
+DEF_HELPER_2(mttc0_ebase, void, env, tl)
+DEF_HELPER_2(mtc0_config0, void, env, tl)
+DEF_HELPER_2(mtc0_config2, void, env, tl)
+DEF_HELPER_2(mtc0_config3, void, env, tl)
+DEF_HELPER_2(mtc0_config4, void, env, tl)
+DEF_HELPER_2(mtc0_config5, void, env, tl)
+DEF_HELPER_2(mtc0_lladdr, void, env, tl)
+DEF_HELPER_2(mtc0_maar, void, env, tl)
+DEF_HELPER_2(mthc0_maar, void, env, tl)
+DEF_HELPER_2(mtc0_maari, void, env, tl)
+DEF_HELPER_3(mtc0_watchlo, void, env, tl, i32)
+DEF_HELPER_3(mtc0_watchhi, void, env, tl, i32)
+DEF_HELPER_3(mthc0_watchhi, void, env, tl, i32)
+DEF_HELPER_2(mtc0_xcontext, void, env, tl)
+DEF_HELPER_2(mtc0_framemask, void, env, tl)
+DEF_HELPER_2(mtc0_debug, void, env, tl)
+DEF_HELPER_2(mttc0_debug, void, env, tl)
+DEF_HELPER_2(mtc0_performance0, void, env, tl)
+DEF_HELPER_2(mtc0_errctl, void, env, tl)
+DEF_HELPER_2(mtc0_taglo, void, env, tl)
+DEF_HELPER_2(mtc0_datalo, void, env, tl)
+DEF_HELPER_2(mtc0_taghi, void, env, tl)
+DEF_HELPER_2(mtc0_datahi, void, env, tl)
+
+#if defined(TARGET_MIPS64)
+DEF_HELPER_2(dmtc0_entrylo0, void, env, i64)
+DEF_HELPER_2(dmtc0_entrylo1, void, env, i64)
+#endif
+
+/* MIPS MT functions */
+DEF_HELPER_2(mftgpr, tl, env, i32)
+DEF_HELPER_2(mftlo, tl, env, i32)
+DEF_HELPER_2(mfthi, tl, env, i32)
+DEF_HELPER_2(mftacx, tl, env, i32)
+DEF_HELPER_1(mftdsp, tl, env)
+DEF_HELPER_3(mttgpr, void, env, tl, i32)
+DEF_HELPER_3(mttlo, void, env, tl, i32)
+DEF_HELPER_3(mtthi, void, env, tl, i32)
+DEF_HELPER_3(mttacx, void, env, tl, i32)
+DEF_HELPER_2(mttdsp, void, env, tl)
+DEF_HELPER_0(dmt, tl)
+DEF_HELPER_0(emt, tl)
+DEF_HELPER_1(dvpe, tl, env)
+DEF_HELPER_1(evpe, tl, env)
+
+/* R6 Multi-threading */
+DEF_HELPER_1(dvp, tl, env)
+DEF_HELPER_1(evp, tl, env)
+
+/* TLB */
+DEF_HELPER_1(tlbwi, void, env)
+DEF_HELPER_1(tlbwr, void, env)
+DEF_HELPER_1(tlbp, void, env)
+DEF_HELPER_1(tlbr, void, env)
+DEF_HELPER_1(tlbinv, void, env)
+DEF_HELPER_1(tlbinvf, void, env)
+DEF_HELPER_3(ginvt, void, env, tl, i32)
+
+/* Special */
+DEF_HELPER_1(di, tl, env)
+DEF_HELPER_1(ei, tl, env)
+DEF_HELPER_1(eret, void, env)
+DEF_HELPER_1(eretnc, void, env)
+DEF_HELPER_1(deret, void, env)
+DEF_HELPER_3(cache, void, env, tl, i32)
diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h
new file mode 100644
index 0000000..81b14eb
--- /dev/null
+++ b/target/mips/tcg/tcg-internal.h
@@ -0,0 +1,64 @@
+/*
+ * MIPS internal definitions and helpers (TCG accelerator)
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef MIPS_TCG_INTERNAL_H
+#define MIPS_TCG_INTERNAL_H
+
+#include "tcg/tcg.h"
+#include "exec/memattrs.h"
+#include "hw/core/cpu.h"
+#include "cpu.h"
+
+void mips_tcg_init(void);
+
+void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb);
+void mips_cpu_do_interrupt(CPUState *cpu);
+bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
+bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
+ MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr);
+
+const char *mips_exception_name(int32_t exception);
+
+void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
+ int error_code, uintptr_t pc);
+
+static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
+ uint32_t exception,
+ uintptr_t pc)
+{
+ do_raise_exception_err(env, exception, 0, pc);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+void mmu_init(CPUMIPSState *env, const mips_def_t *def);
+
+void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
+
+void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
+uint32_t cpu_mips_get_random(CPUMIPSState *env);
+
+bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb);
+
+hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
+ MMUAccessType access_type, uintptr_t retaddr);
+void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
+void cpu_mips_tlb_flush(CPUMIPSState *env);
+
+#endif /* !CONFIG_USER_ONLY */
+
+#endif
diff --git a/target/mips/translate.c b/target/mips/tcg/translate.c
similarity index 99%
rename from target/mips/translate.c
rename to target/mips/tcg/translate.c
index 71fa5ec..c03a8ae 100644
--- a/target/mips/translate.c
+++ b/target/mips/tcg/translate.c
@@ -39,6 +39,19 @@
#include "fpu_helper.h"
#include "translate.h"
+/*
+ * Many sysemu-only helpers are not reachable for user-only.
+ * Define stub generators here, so that we need not either sprinkle
+ * ifdefs through the translator, nor provide the helper function.
+ */
+#define STUB_HELPER(NAME, ...) \
+ static inline void gen_helper_##NAME(__VA_ARGS__) \
+ { g_assert_not_reached(); }
+
+#ifdef CONFIG_USER_ONLY
+STUB_HELPER(cache, TCGv_env env, TCGv val, TCGv_i32 reg)
+#endif
+
enum {
/* indirect opcode tables */
OPC_SPECIAL = (0x00 << 26),
@@ -1267,13 +1280,6 @@
#define DISAS_STOP DISAS_TARGET_0
#define DISAS_EXIT DISAS_TARGET_1
-static const char * const regnames[] = {
- "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
-};
-
static const char * const regnames_HI[] = {
"HI0", "HI1", "HI2", "HI3",
};
@@ -1282,13 +1288,6 @@
"LO0", "LO1", "LO2", "LO3",
};
-static const char * const fregnames[] = {
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
-};
-
/* General purpose registers moves. */
void gen_load_gpr(TCGv t, int reg)
{
@@ -1572,11 +1571,13 @@
#endif
}
-void check_cp0_enabled(DisasContext *ctx)
+bool check_cp0_enabled(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) {
generate_exception_end(ctx, EXCP_CpU);
+ return false;
}
+ return true;
}
void check_cp1_enabled(DisasContext *ctx)
@@ -5945,6 +5946,7 @@
goto cp0_unimplemented;
}
trace_mips_translate_c0("mthc0", register_name, reg, sel);
+ return;
cp0_unimplemented:
qemu_log_mask(LOG_UNIMP, "mthc0 %s (reg %d sel %d)\n",
@@ -18969,9 +18971,11 @@
}
break;
case NM_RDPGPR:
+ check_cp0_enabled(ctx);
gen_load_srsgpr(rs, rt);
break;
case NM_WRPGPR:
+ check_cp0_enabled(ctx);
gen_store_srsgpr(rs, rt);
break;
case NM_WAIT:
@@ -20957,6 +20961,8 @@
gen_ld(ctx, OPC_LHUE, rt, rs, s);
break;
case NM_CACHEE:
+ check_eva(ctx);
+ check_cp0_enabled(ctx);
check_nms_dl_il_sl_tl_l2c(ctx);
gen_cache_operation(ctx, rt, rs, s);
break;
@@ -24530,11 +24536,11 @@
gen_st_cond(ctx, rt, rs, imm, MO_TESL, true);
return;
case OPC_CACHEE:
+ check_eva(ctx);
check_cp0_enabled(ctx);
if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) {
gen_cache_operation(ctx, rt, rs, imm);
}
- /* Treat as NOP. */
return;
case OPC_PREFE:
check_cp0_enabled(ctx);
@@ -25593,83 +25599,6 @@
translator_loop(&mips_tr_ops, &ctx.base, cs, tb, max_insns);
}
-static void fpu_dump_state(CPUMIPSState *env, FILE * f, int flags)
-{
- int i;
- int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
-
-#define printfpr(fp) \
- do { \
- if (is_fpu64) \
- qemu_fprintf(f, "w:%08x d:%016" PRIx64 \
- " fd:%13g fs:%13g psu: %13g\n", \
- (fp)->w[FP_ENDIAN_IDX], (fp)->d, \
- (double)(fp)->fd, \
- (double)(fp)->fs[FP_ENDIAN_IDX], \
- (double)(fp)->fs[!FP_ENDIAN_IDX]); \
- else { \
- fpr_t tmp; \
- tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \
- tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \
- qemu_fprintf(f, "w:%08x d:%016" PRIx64 \
- " fd:%13g fs:%13g psu:%13g\n", \
- tmp.w[FP_ENDIAN_IDX], tmp.d, \
- (double)tmp.fd, \
- (double)tmp.fs[FP_ENDIAN_IDX], \
- (double)tmp.fs[!FP_ENDIAN_IDX]); \
- } \
- } while (0)
-
-
- qemu_fprintf(f,
- "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n",
- env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
- get_float_exception_flags(&env->active_fpu.fp_status));
- for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
- qemu_fprintf(f, "%3s: ", fregnames[i]);
- printfpr(&env->active_fpu.fpr[i]);
- }
-
-#undef printfpr
-}
-
-void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- MIPSCPU *cpu = MIPS_CPU(cs);
- CPUMIPSState *env = &cpu->env;
- int i;
-
- qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
- " LO=0x" TARGET_FMT_lx " ds %04x "
- TARGET_FMT_lx " " TARGET_FMT_ld "\n",
- env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0],
- env->hflags, env->btarget, env->bcond);
- for (i = 0; i < 32; i++) {
- if ((i & 3) == 0) {
- qemu_fprintf(f, "GPR%02d:", i);
- }
- qemu_fprintf(f, " %s " TARGET_FMT_lx,
- regnames[i], env->active_tc.gpr[i]);
- if ((i & 3) == 3) {
- qemu_fprintf(f, "\n");
- }
- }
-
- qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x"
- TARGET_FMT_lx "\n",
- env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
- qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016"
- PRIx64 "\n",
- env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
- qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n",
- env->CP0_Config2, env->CP0_Config3);
- qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n",
- env->CP0_Config4, env->CP0_Config5);
- if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) {
- fpu_dump_state(env, f, flags);
- }
-}
-
void mips_tcg_init(void)
{
int i;
diff --git a/target/mips/translate_addr_const.c b/target/mips/tcg/translate_addr_const.c
similarity index 100%
rename from target/mips/translate_addr_const.c
rename to target/mips/tcg/translate_addr_const.c
diff --git a/target/mips/tx79.decode b/target/mips/tcg/tx79.decode
similarity index 100%
rename from target/mips/tx79.decode
rename to target/mips/tcg/tx79.decode
diff --git a/target/mips/tx79_translate.c b/target/mips/tcg/tx79_translate.c
similarity index 100%
rename from target/mips/tx79_translate.c
rename to target/mips/tcg/tx79_translate.c
diff --git a/target/mips/txx9_translate.c b/target/mips/tcg/txx9_translate.c
similarity index 100%
rename from target/mips/txx9_translate.c
rename to target/mips/tcg/txx9_translate.c
diff --git a/target/mips/tcg/user/meson.build b/target/mips/tcg/user/meson.build
new file mode 100644
index 0000000..79badcd
--- /dev/null
+++ b/target/mips/tcg/user/meson.build
@@ -0,0 +1,3 @@
+mips_user_ss.add(files(
+ 'tlb_helper.c',
+))
diff --git a/target/mips/tcg/user/tlb_helper.c b/target/mips/tcg/user/tlb_helper.c
new file mode 100644
index 0000000..b835144
--- /dev/null
+++ b/target/mips/tcg/user/tlb_helper.c
@@ -0,0 +1,64 @@
+/*
+ * MIPS TLB (Translation lookaside buffer) helpers.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "internal.h"
+
+static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
+ MMUAccessType access_type)
+{
+ CPUState *cs = env_cpu(env);
+
+ env->error_code = 0;
+ if (access_type == MMU_INST_FETCH) {
+ env->error_code |= EXCP_INST_NOTAVAIL;
+ }
+
+ /* Reference to kernel address from user mode or supervisor mode */
+ /* Reference to supervisor address from user mode */
+ if (access_type == MMU_DATA_STORE) {
+ cs->exception_index = EXCP_AdES;
+ } else {
+ cs->exception_index = EXCP_AdEL;
+ }
+
+ /* Raise exception */
+ if (!(env->hflags & MIPS_HFLAG_DM)) {
+ env->CP0_BadVAddr = address;
+ }
+}
+
+bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ /* data access */
+ raise_mmu_exception(env, address, access_type);
+ do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
+}
+
+void mips_cpu_do_interrupt(CPUState *cs)
+{
+ cs->exception_index = EXCP_NONE;
+}
diff --git a/target/mips/translate.h b/target/mips/translate.h
index 2b3c7a6..6144259 100644
--- a/target/mips/translate.h
+++ b/target/mips/translate.h
@@ -120,7 +120,12 @@
void check_insn(DisasContext *ctx, uint64_t flags);
void check_mips_64(DisasContext *ctx);
-void check_cp0_enabled(DisasContext *ctx);
+/**
+ * check_cp0_enabled:
+ * Return %true if CP0 is enabled, otherwise return %false
+ * and emit a 'coprocessor unusable' exception.
+ */
+bool check_cp0_enabled(DisasContext *ctx);
void check_cp1_enabled(DisasContext *ctx);
void check_cp1_64bitmode(DisasContext *ctx);
void check_cp1_registers(DisasContext *ctx, int regs);
diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py
index 1ca32ec..276a53f 100644
--- a/tests/acceptance/boot_linux_console.py
+++ b/tests/acceptance/boot_linux_console.py
@@ -1010,6 +1010,74 @@ def test_arm_vexpressa9(self):
self.vm.add_args('-dtb', self.workdir + '/day16/vexpress-v2p-ca9.dtb')
self.do_test_advcal_2018('16', tar_hash, 'winter.zImage')
+ def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
+ """
+ :avocado: tags=arch:arm
+ :avocado: tags=machine:palmetto-bmc
+ """
+
+ image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
+ 'obmc-phosphor-image-palmetto.static.mtd')
+ image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d')
+ image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+ algorithm='sha256')
+
+ self.do_test_arm_aspeed(image_path)
+
+ def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
+ """
+ :avocado: tags=arch:arm
+ :avocado: tags=machine:romulus-bmc
+ """
+
+ image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
+ 'obmc-phosphor-image-romulus.static.mtd')
+ image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
+ image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+ algorithm='sha256')
+
+ self.do_test_arm_aspeed(image_path)
+
+ def do_test_arm_aspeed(self, image):
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic')
+ self.vm.launch()
+
+ self.wait_for_console_pattern("U-Boot 2016.07")
+ self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
+ self.wait_for_console_pattern("Starting kernel ...")
+ self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
+ self.wait_for_console_pattern(
+ "aspeed-smc 1e620000.spi: read control register: 203b0641")
+ self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
+ self.wait_for_console_pattern("systemd[1]: Set hostname to")
+
+ def test_arm_ast2600_debian(self):
+ """
+ :avocado: tags=arch:arm
+ :avocado: tags=machine:tacoma-bmc
+ """
+ deb_url = ('http://snapshot.debian.org/archive/debian/'
+ '20210302T203551Z/'
+ 'pool/main/l/linux/'
+ 'linux-image-5.10.0-3-armmp_5.10.13-1_armhf.deb')
+ deb_hash = 'db40d32fe39255d05482bea48d72467b67d6225bb2a2a4d6f618cb8976f1e09e'
+ deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash,
+ algorithm='sha256')
+ kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.10.0-3-armmp')
+ dtb_path = self.extract_from_deb(deb_path,
+ '/usr/lib/linux-image-5.10.0-3-armmp/aspeed-bmc-opp-tacoma.dtb')
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-net', 'nic')
+ self.vm.launch()
+ self.wait_for_console_pattern("Booting Linux on physical CPU 0xf00")
+ self.wait_for_console_pattern("SMP: Total of 2 processors activated")
+ self.wait_for_console_pattern("No filesystem could mount root")
+
def test_m68k_mcf5208evb(self):
"""
:avocado: tags=arch:m68k
diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c
new file mode 100644
index 0000000..09ee315
--- /dev/null
+++ b/tests/qtest/aspeed_hace-test.c
@@ -0,0 +1,469 @@
+/*
+ * QTest testcase for the ASPEED Hash and Crypto Engine
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 IBM Corp.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqos/libqtest.h"
+#include "qemu-common.h"
+#include "qemu/bitops.h"
+
+#define HACE_CMD 0x10
+#define HACE_SHA_BE_EN BIT(3)
+#define HACE_MD5_LE_EN BIT(2)
+#define HACE_ALGO_MD5 0
+#define HACE_ALGO_SHA1 BIT(5)
+#define HACE_ALGO_SHA224 BIT(6)
+#define HACE_ALGO_SHA256 (BIT(4) | BIT(6))
+#define HACE_ALGO_SHA512 (BIT(5) | BIT(6))
+#define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10))
+#define HACE_SG_EN BIT(18)
+
+#define HACE_STS 0x1c
+#define HACE_RSA_ISR BIT(13)
+#define HACE_CRYPTO_ISR BIT(12)
+#define HACE_HASH_ISR BIT(9)
+#define HACE_RSA_BUSY BIT(2)
+#define HACE_CRYPTO_BUSY BIT(1)
+#define HACE_HASH_BUSY BIT(0)
+#define HACE_HASH_SRC 0x20
+#define HACE_HASH_DIGEST 0x24
+#define HACE_HASH_KEY_BUFF 0x28
+#define HACE_HASH_DATA_LEN 0x2c
+#define HACE_HASH_CMD 0x30
+/* Scatter-Gather Hash */
+#define SG_LIST_LEN_LAST BIT(31)
+struct AspeedSgList {
+ uint32_t len;
+ uint32_t addr;
+} __attribute__ ((__packed__));
+
+/*
+ * Test vector is the ascii "abc"
+ *
+ * Expected results were generated using command line utitiles:
+ *
+ * echo -n -e 'abc' | dd of=/tmp/test
+ * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done
+ *
+ */
+static const uint8_t test_vector[] = {0x61, 0x62, 0x63};
+
+static const uint8_t test_result_sha512[] = {
+ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49,
+ 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
+ 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f,
+ 0xa5, 0x4c, 0xa4, 0x9f};
+
+static const uint8_t test_result_sha256[] = {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
+
+static const uint8_t test_result_md5[] = {
+ 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d,
+ 0x28, 0xe1, 0x7f, 0x72};
+
+/*
+ * The Scatter-Gather Test vector is the ascii "abc" "def" "ghi", broken
+ * into blocks of 3 characters as shown
+ *
+ * Expected results were generated using command line utitiles:
+ *
+ * echo -n -e 'abcdefghijkl' | dd of=/tmp/test
+ * for hash in sha512sum sha256sum; do $hash /tmp/test; done
+ *
+ */
+static const uint8_t test_vector_sg1[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
+static const uint8_t test_vector_sg2[] = {0x67, 0x68, 0x69};
+static const uint8_t test_vector_sg3[] = {0x6a, 0x6b, 0x6c};
+
+static const uint8_t test_result_sg_sha512[] = {
+ 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8,
+ 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3,
+ 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63,
+ 0xd5, 0xb7, 0x3f, 0xc3, 0x96, 0xc1, 0x2b, 0xe3, 0x8b, 0x2b, 0xd5, 0xd8,
+ 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40,
+ 0xf8, 0x6d, 0xda, 0x2e};
+
+static const uint8_t test_result_sg_sha256[] = {
+ 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1,
+ 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3,
+ 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4};
+
+
+static void write_regs(QTestState *s, uint32_t base, uint32_t src,
+ uint32_t length, uint32_t out, uint32_t method)
+{
+ qtest_writel(s, base + HACE_HASH_SRC, src);
+ qtest_writel(s, base + HACE_HASH_DIGEST, out);
+ qtest_writel(s, base + HACE_HASH_DATA_LEN, length);
+ qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method);
+}
+
+static void test_md5(const char *machine, const uint32_t base,
+ const uint32_t src_addr)
+
+{
+ QTestState *s = qtest_init(machine);
+
+ uint32_t digest_addr = src_addr + 0x01000000;
+ uint8_t digest[16] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_MD5);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_md5, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+static void test_sha256(const char *machine, const uint32_t base,
+ const uint32_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint32_t digest_addr = src_addr + 0x1000000;
+ uint8_t digest[32] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA256);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sha256, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+static void test_sha512(const char *machine, const uint32_t base,
+ const uint32_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint32_t digest_addr = src_addr + 0x1000000;
+ uint8_t digest[64] = {0};
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector));
+
+ write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA512);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sha512, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+static void test_sha256_sg(const char *machine, const uint32_t base,
+ const uint32_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint32_t src_addr_1 = src_addr + 0x1000000;
+ const uint32_t src_addr_2 = src_addr + 0x2000000;
+ const uint32_t src_addr_3 = src_addr + 0x3000000;
+ const uint32_t digest_addr = src_addr + 0x4000000;
+ uint8_t digest[32] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_sg1)),
+ cpu_to_le32(src_addr_1) },
+ { cpu_to_le32(sizeof(test_vector_sg2)),
+ cpu_to_le32(src_addr_2) },
+ { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
+ cpu_to_le32(src_addr_3) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
+ qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
+ qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr,
+ (sizeof(test_vector_sg1)
+ + sizeof(test_vector_sg2)
+ + sizeof(test_vector_sg3)),
+ digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sg_sha256, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+static void test_sha512_sg(const char *machine, const uint32_t base,
+ const uint32_t src_addr)
+{
+ QTestState *s = qtest_init(machine);
+
+ const uint32_t src_addr_1 = src_addr + 0x1000000;
+ const uint32_t src_addr_2 = src_addr + 0x2000000;
+ const uint32_t src_addr_3 = src_addr + 0x3000000;
+ const uint32_t digest_addr = src_addr + 0x4000000;
+ uint8_t digest[64] = {0};
+ struct AspeedSgList array[] = {
+ { cpu_to_le32(sizeof(test_vector_sg1)),
+ cpu_to_le32(src_addr_1) },
+ { cpu_to_le32(sizeof(test_vector_sg2)),
+ cpu_to_le32(src_addr_2) },
+ { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST),
+ cpu_to_le32(src_addr_3) },
+ };
+
+ /* Check engine is idle, no busy or irq bits set */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Write test vector into memory */
+ qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1));
+ qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2));
+ qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3));
+ qtest_memwrite(s, src_addr, array, sizeof(array));
+
+ write_regs(s, base, src_addr,
+ (sizeof(test_vector_sg1)
+ + sizeof(test_vector_sg2)
+ + sizeof(test_vector_sg3)),
+ digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN);
+
+ /* Check hash IRQ status is asserted */
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200);
+
+ /* Clear IRQ status and check status is deasserted */
+ qtest_writel(s, base + HACE_STS, 0x00000200);
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0);
+
+ /* Read computed digest from memory */
+ qtest_memread(s, digest_addr, digest, sizeof(digest));
+
+ /* Check result of computation */
+ g_assert_cmpmem(digest, sizeof(digest),
+ test_result_sg_sha512, sizeof(digest));
+
+ qtest_quit(s);
+}
+
+struct masks {
+ uint32_t src;
+ uint32_t dest;
+ uint32_t len;
+};
+
+static const struct masks ast2600_masks = {
+ .src = 0x7fffffff,
+ .dest = 0x7ffffff8,
+ .len = 0x0fffffff,
+};
+
+static const struct masks ast2500_masks = {
+ .src = 0x3fffffff,
+ .dest = 0x3ffffff8,
+ .len = 0x0fffffff,
+};
+
+static const struct masks ast2400_masks = {
+ .src = 0x0fffffff,
+ .dest = 0x0ffffff8,
+ .len = 0x0fffffff,
+};
+
+static void test_addresses(const char *machine, const uint32_t base,
+ const struct masks *expected)
+{
+ QTestState *s = qtest_init(machine);
+
+ /*
+ * Check command mode is zero, meaning engine is in direct access mode,
+ * as this affects the masking behavior of the HASH_SRC register.
+ */
+ g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0);
+
+
+ /* Check that the address masking is correct */
+ qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src);
+
+ qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, expected->dest);
+
+ qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, expected->len);
+
+ /* Reset to zero */
+ qtest_writel(s, base + HACE_HASH_SRC, 0);
+ qtest_writel(s, base + HACE_HASH_DIGEST, 0);
+ qtest_writel(s, base + HACE_HASH_DATA_LEN, 0);
+
+ /* Check that all bits are now zero */
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0);
+ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0);
+
+ qtest_quit(s);
+}
+
+/* ast2600 */
+static void test_md5_ast2600(void)
+{
+ test_md5("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha256_ast2600(void)
+{
+ test_sha256("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha256_sg_ast2600(void)
+{
+ test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha512_ast2600(void)
+{
+ test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_sha512_sg_ast2600(void)
+{
+ test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000);
+}
+
+static void test_addresses_ast2600(void)
+{
+ test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks);
+}
+
+/* ast2500 */
+static void test_md5_ast2500(void)
+{
+ test_md5("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
+}
+
+static void test_sha256_ast2500(void)
+{
+ test_sha256("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
+}
+
+static void test_sha512_ast2500(void)
+{
+ test_sha512("-machine ast2500-evb", 0x1e6e3000, 0x80000000);
+}
+
+static void test_addresses_ast2500(void)
+{
+ test_addresses("-machine ast2500-evb", 0x1e6e3000, &ast2500_masks);
+}
+
+/* ast2400 */
+static void test_md5_ast2400(void)
+{
+ test_md5("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
+}
+
+static void test_sha256_ast2400(void)
+{
+ test_sha256("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
+}
+
+static void test_sha512_ast2400(void)
+{
+ test_sha512("-machine palmetto-bmc", 0x1e6e3000, 0x40000000);
+}
+
+static void test_addresses_ast2400(void)
+{
+ test_addresses("-machine palmetto-bmc", 0x1e6e3000, &ast2400_masks);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("ast2600/hace/addresses", test_addresses_ast2600);
+ qtest_add_func("ast2600/hace/sha512", test_sha512_ast2600);
+ qtest_add_func("ast2600/hace/sha256", test_sha256_ast2600);
+ qtest_add_func("ast2600/hace/md5", test_md5_ast2600);
+
+ qtest_add_func("ast2600/hace/sha512_sg", test_sha512_sg_ast2600);
+ qtest_add_func("ast2600/hace/sha256_sg", test_sha256_sg_ast2600);
+
+ qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500);
+ qtest_add_func("ast2500/hace/sha512", test_sha512_ast2500);
+ qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500);
+ qtest_add_func("ast2500/hace/md5", test_md5_ast2500);
+
+ qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400);
+ qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400);
+ qtest_add_func("ast2400/hace/sha256", test_sha256_ast2400);
+ qtest_add_func("ast2400/hace/md5", test_md5_ast2400);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/m25p80-test.c b/tests/qtest/aspeed_smc-test.c
similarity index 95%
rename from tests/qtest/m25p80-test.c
rename to tests/qtest/aspeed_smc-test.c
index f860cef..87b40a0 100644
--- a/tests/qtest/m25p80-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -367,12 +367,12 @@
"-drive file=%s,format=raw,if=mtd",
tmp_path);
- qtest_add_func("/m25p80/read_jedec", test_read_jedec);
- qtest_add_func("/m25p80/erase_sector", test_erase_sector);
- qtest_add_func("/m25p80/erase_all", test_erase_all);
- qtest_add_func("/m25p80/write_page", test_write_page);
- qtest_add_func("/m25p80/read_page_mem", test_read_page_mem);
- qtest_add_func("/m25p80/write_page_mem", test_write_page_mem);
+ qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
+ qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
+ qtest_add_func("/ast2400/smc/erase_all", test_erase_all);
+ qtest_add_func("/ast2400/smc/write_page", test_write_page);
+ qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
+ qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
ret = g_test_run();
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 0c76738..966bc93 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -161,16 +161,19 @@
'npcm7xx_timer-test',
'npcm7xx_watchdog_timer-test'] + \
(slirp.found() ? ['npcm7xx_emc-test'] : [])
+qtests_aspeed = \
+ ['aspeed_hace-test',
+ 'aspeed_smc-test']
qtests_arm = \
(config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
(config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \
(config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \
(config_all_devices.has_key('CONFIG_CMSDK_APB_WATCHDOG') ? ['cmsdk-apb-watchdog-test'] : []) + \
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
['arm-cpu-features',
'microbit-test',
- 'm25p80-test',
'test-arm-mptimer',
'boot-serial-test',
'hexloader-test']
diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 616af69..0992787 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -28,6 +28,7 @@
CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal
+CFLAGS += -fno-unroll-loops
HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
VPATH += $(HEX_SRC)
@@ -39,7 +40,12 @@
HEX_TESTS += misc
HEX_TESTS += preg_alias
HEX_TESTS += dual_stores
+HEX_TESTS += multi_result
HEX_TESTS += mem_noshuf
+HEX_TESTS += circ
+HEX_TESTS += brev
+HEX_TESTS += load_unpack
+HEX_TESTS += load_align
HEX_TESTS += atomics
HEX_TESTS += fpstuff
diff --git a/tests/tcg/hexagon/brev.c b/tests/tcg/hexagon/brev.c
new file mode 100644
index 0000000..9736a24
--- /dev/null
+++ b/tests/tcg/hexagon/brev.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int err;
+
+#define NBITS 8
+#define SIZE (1 << NBITS)
+
+long long dbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
+int wbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
+short hbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
+unsigned char bbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
+
+/*
+ * We use the C preporcessor to deal with the combinations of types
+ */
+
+#define BREV_LOAD(SZ, RES, ADDR, INC) \
+ __asm__( \
+ "m0 = %2\n\t" \
+ "%0 = mem" #SZ "(%1++m0:brev)\n\t" \
+ : "=r"(RES), "+r"(ADDR) \
+ : "r"(INC) \
+ : "m0")
+
+#define BREV_LOAD_b(RES, ADDR, INC) \
+ BREV_LOAD(b, RES, ADDR, INC)
+#define BREV_LOAD_ub(RES, ADDR, INC) \
+ BREV_LOAD(ub, RES, ADDR, INC)
+#define BREV_LOAD_h(RES, ADDR, INC) \
+ BREV_LOAD(h, RES, ADDR, INC)
+#define BREV_LOAD_uh(RES, ADDR, INC) \
+ BREV_LOAD(uh, RES, ADDR, INC)
+#define BREV_LOAD_w(RES, ADDR, INC) \
+ BREV_LOAD(w, RES, ADDR, INC)
+#define BREV_LOAD_d(RES, ADDR, INC) \
+ BREV_LOAD(d, RES, ADDR, INC)
+
+#define BREV_STORE(SZ, PART, ADDR, VAL, INC) \
+ __asm__( \
+ "m0 = %2\n\t" \
+ "mem" #SZ "(%0++m0:brev) = %1" PART "\n\t" \
+ : "+r"(ADDR) \
+ : "r"(VAL), "r"(INC) \
+ : "m0", "memory")
+
+#define BREV_STORE_b(ADDR, VAL, INC) \
+ BREV_STORE(b, "", ADDR, VAL, INC)
+#define BREV_STORE_h(ADDR, VAL, INC) \
+ BREV_STORE(h, "", ADDR, VAL, INC)
+#define BREV_STORE_f(ADDR, VAL, INC) \
+ BREV_STORE(h, ".H", ADDR, VAL, INC)
+#define BREV_STORE_w(ADDR, VAL, INC) \
+ BREV_STORE(w, "", ADDR, VAL, INC)
+#define BREV_STORE_d(ADDR, VAL, INC) \
+ BREV_STORE(d, "", ADDR, VAL, INC)
+
+#define BREV_STORE_NEW(SZ, ADDR, VAL, INC) \
+ __asm__( \
+ "m0 = %2\n\t" \
+ "{\n\t" \
+ " r5 = %1\n\t" \
+ " mem" #SZ "(%0++m0:brev) = r5.new\n\t" \
+ "}\n\t" \
+ : "+r"(ADDR) \
+ : "r"(VAL), "r"(INC) \
+ : "r5", "m0", "memory")
+
+#define BREV_STORE_bnew(ADDR, VAL, INC) \
+ BREV_STORE_NEW(b, ADDR, VAL, INC)
+#define BREV_STORE_hnew(ADDR, VAL, INC) \
+ BREV_STORE_NEW(h, ADDR, VAL, INC)
+#define BREV_STORE_wnew(ADDR, VAL, INC) \
+ BREV_STORE_NEW(w, ADDR, VAL, INC)
+
+int bitreverse(int x)
+{
+ int result = 0;
+ int i;
+ for (i = 0; i < NBITS; i++) {
+ result <<= 1;
+ result |= x & 1;
+ x >>= 1;
+ }
+ return result;
+}
+
+int sext8(int x)
+{
+ return (x << 24) >> 24;
+}
+
+void check(int i, long long result, long long expect)
+{
+ if (result != expect) {
+ printf("ERROR(%d): 0x%04llx != 0x%04llx\n", i, result, expect);
+ err++;
+ }
+}
+
+#define TEST_BREV_LOAD(SZ, TYPE, BUF, SHIFT, EXP) \
+ do { \
+ p = BUF; \
+ for (i = 0; i < SIZE; i++) { \
+ TYPE result; \
+ BREV_LOAD_##SZ(result, p, 1 << (SHIFT - NBITS)); \
+ check(i, result, EXP); \
+ } \
+ } while (0)
+
+#define TEST_BREV_STORE(SZ, TYPE, BUF, VAL, SHIFT) \
+ do { \
+ p = BUF; \
+ memset(BUF, 0xff, sizeof(BUF)); \
+ for (i = 0; i < SIZE; i++) { \
+ BREV_STORE_##SZ(p, (TYPE)(VAL), 1 << (SHIFT - NBITS)); \
+ } \
+ for (i = 0; i < SIZE; i++) { \
+ check(i, BUF[i], bitreverse(i)); \
+ } \
+ } while (0)
+
+#define TEST_BREV_STORE_NEW(SZ, BUF, SHIFT) \
+ do { \
+ p = BUF; \
+ memset(BUF, 0xff, sizeof(BUF)); \
+ for (i = 0; i < SIZE; i++) { \
+ BREV_STORE_##SZ(p, i, 1 << (SHIFT - NBITS)); \
+ } \
+ for (i = 0; i < SIZE; i++) { \
+ check(i, BUF[i], bitreverse(i)); \
+ } \
+ } while (0)
+
+/*
+ * We'll set high_half[i] = i << 16 for use in the .H form of store
+ * which stores from the high half of the word.
+ */
+int high_half[SIZE];
+
+int main()
+{
+ void *p;
+ int i;
+
+ for (i = 0; i < SIZE; i++) {
+ bbuf[i] = bitreverse(i);
+ hbuf[i] = bitreverse(i);
+ wbuf[i] = bitreverse(i);
+ dbuf[i] = bitreverse(i);
+ high_half[i] = i << 16;
+ }
+
+ TEST_BREV_LOAD(b, int, bbuf, 16, sext8(i));
+ TEST_BREV_LOAD(ub, int, bbuf, 16, i);
+ TEST_BREV_LOAD(h, int, hbuf, 15, i);
+ TEST_BREV_LOAD(uh, int, hbuf, 15, i);
+ TEST_BREV_LOAD(w, int, wbuf, 14, i);
+ TEST_BREV_LOAD(d, long long, dbuf, 13, i);
+
+ TEST_BREV_STORE(b, int, bbuf, i, 16);
+ TEST_BREV_STORE(h, int, hbuf, i, 15);
+ TEST_BREV_STORE(f, int, hbuf, high_half[i], 15);
+ TEST_BREV_STORE(w, int, wbuf, i, 14);
+ TEST_BREV_STORE(d, long long, dbuf, i, 13);
+
+ TEST_BREV_STORE_NEW(bnew, bbuf, 16);
+ TEST_BREV_STORE_NEW(hnew, hbuf, 15);
+ TEST_BREV_STORE_NEW(wnew, wbuf, 14);
+
+ puts(err ? "FAIL" : "PASS");
+ return err ? 1 : 0;
+}
diff --git a/tests/tcg/hexagon/circ.c b/tests/tcg/hexagon/circ.c
new file mode 100644
index 0000000..67a1aa3
--- /dev/null
+++ b/tests/tcg/hexagon/circ.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/>.
+ */
+
+#include <stdio.h>
+
+#define DEBUG 0
+#define DEBUG_PRINTF(...) \
+ do { \
+ if (DEBUG) { \
+ printf(__VA_ARGS__); \
+ } \
+ } while (0)
+
+
+#define NBYTES (1 << 8)
+#define NHALFS (NBYTES / sizeof(short))
+#define NWORDS (NBYTES / sizeof(int))
+#define NDOBLS (NBYTES / sizeof(long long))
+
+long long dbuf[NDOBLS] __attribute__((aligned(1 << 12))) = {0};
+int wbuf[NWORDS] __attribute__((aligned(1 << 12))) = {0};
+short hbuf[NHALFS] __attribute__((aligned(1 << 12))) = {0};
+unsigned char bbuf[NBYTES] __attribute__((aligned(1 << 12))) = {0};
+
+/*
+ * We use the C preporcessor to deal with the combinations of types
+ */
+
+#define INIT(BUF, N) \
+ void init_##BUF(void) \
+ { \
+ int i; \
+ for (i = 0; i < N; i++) { \
+ BUF[i] = i; \
+ } \
+ } \
+
+INIT(bbuf, NBYTES)
+INIT(hbuf, NHALFS)
+INIT(wbuf, NWORDS)
+INIT(dbuf, NDOBLS)
+
+/*
+ * Macros for performing circular load
+ * RES result
+ * ADDR address
+ * START start address of buffer
+ * LEN length of buffer (in bytes)
+ * INC address increment (in bytes for IMM, elements for REG)
+ */
+#define CIRC_LOAD_IMM(SIZE, RES, ADDR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %3\n\t" \
+ "m0 = r4\n\t" \
+ "cs0 = %2\n\t" \
+ "%0 = mem" #SIZE "(%1++#" #INC ":circ(M0))\n\t" \
+ : "=r"(RES), "+r"(ADDR) \
+ : "r"(START), "r"(LEN) \
+ : "r4", "m0", "cs0")
+#define CIRC_LOAD_IMM_b(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_IMM(b, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_IMM_ub(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_IMM(ub, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_IMM_h(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_IMM(h, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_IMM_uh(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_IMM(uh, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_IMM_w(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_IMM(w, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_IMM_d(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_IMM(d, RES, ADDR, START, LEN, INC)
+
+/*
+ * The mreg has the following pieces
+ * mreg[31:28] increment[10:7]
+ * mreg[27:24] K value (used Hexagon v3 and earlier)
+ * mreg[23:17] increment[6:0]
+ * mreg[16:0] circular buffer length
+ */
+static int build_mreg(int inc, int K, int len)
+{
+ return ((inc & 0x780) << 21) |
+ ((K & 0xf) << 24) |
+ ((inc & 0x7f) << 17) |
+ (len & 0x1ffff);
+}
+
+#define CIRC_LOAD_REG(SIZE, RES, ADDR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %2\n\t" \
+ "m1 = r4\n\t" \
+ "cs1 = %3\n\t" \
+ "%0 = mem" #SIZE "(%1++I:circ(M1))\n\t" \
+ : "=r"(RES), "+r"(ADDR) \
+ : "r"(build_mreg((INC), 0, (LEN))), \
+ "r"(START) \
+ : "r4", "m1", "cs1")
+#define CIRC_LOAD_REG_b(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_REG(b, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_REG_ub(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_REG(ub, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_REG_h(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_REG(h, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_REG_uh(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_REG(uh, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_REG_w(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_REG(w, RES, ADDR, START, LEN, INC)
+#define CIRC_LOAD_REG_d(RES, ADDR, START, LEN, INC) \
+ CIRC_LOAD_REG(d, RES, ADDR, START, LEN, INC)
+
+/*
+ * Macros for performing circular store
+ * VAL value to store
+ * ADDR address
+ * START start address of buffer
+ * LEN length of buffer (in bytes)
+ * INC address increment (in bytes for IMM, elements for REG)
+ */
+#define CIRC_STORE_IMM(SIZE, PART, VAL, ADDR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %3\n\t" \
+ "m0 = r4\n\t" \
+ "cs0 = %1\n\t" \
+ "mem" #SIZE "(%0++#" #INC ":circ(M0)) = %2" PART "\n\t" \
+ : "+r"(ADDR) \
+ : "r"(START), "r"(VAL), "r"(LEN) \
+ : "r4", "m0", "cs0", "memory")
+#define CIRC_STORE_IMM_b(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_IMM(b, "", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_IMM_h(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_IMM(h, "", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_IMM_f(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_IMM(h, ".H", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_IMM_w(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_IMM(w, "", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_IMM_d(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_IMM(d, "", VAL, ADDR, START, LEN, INC)
+
+#define CIRC_STORE_NEW_IMM(SIZE, VAL, ADDR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %3\n\t" \
+ "m0 = r4\n\t" \
+ "cs0 = %1\n\t" \
+ "{\n\t" \
+ " r5 = %2\n\t" \
+ " mem" #SIZE "(%0++#" #INC ":circ(M0)) = r5.new\n\t" \
+ "}\n\t" \
+ : "+r"(ADDR) \
+ : "r"(START), "r"(VAL), "r"(LEN) \
+ : "r4", "r5", "m0", "cs0", "memory")
+#define CIRC_STORE_IMM_bnew(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_NEW_IMM(b, VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_IMM_hnew(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_NEW_IMM(h, VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_IMM_wnew(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_NEW_IMM(w, VAL, ADDR, START, LEN, INC)
+
+#define CIRC_STORE_REG(SIZE, PART, VAL, ADDR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %1\n\t" \
+ "m1 = r4\n\t" \
+ "cs1 = %2\n\t" \
+ "mem" #SIZE "(%0++I:circ(M1)) = %3" PART "\n\t" \
+ : "+r"(ADDR) \
+ : "r"(build_mreg((INC), 0, (LEN))), \
+ "r"(START), \
+ "r"(VAL) \
+ : "r4", "m1", "cs1", "memory")
+#define CIRC_STORE_REG_b(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_REG(b, "", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_REG_h(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_REG(h, "", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_REG_f(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_REG(h, ".H", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_REG_w(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_REG(w, "", VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_REG_d(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_REG(d, "", VAL, ADDR, START, LEN, INC)
+
+#define CIRC_STORE_NEW_REG(SIZE, VAL, ADDR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %1\n\t" \
+ "m1 = r4\n\t" \
+ "cs1 = %2\n\t" \
+ "{\n\t" \
+ " r5 = %3\n\t" \
+ " mem" #SIZE "(%0++I:circ(M1)) = r5.new\n\t" \
+ "}\n\t" \
+ : "+r"(ADDR) \
+ : "r"(build_mreg((INC), 0, (LEN))), \
+ "r"(START), \
+ "r"(VAL) \
+ : "r4", "r5", "m1", "cs1", "memory")
+#define CIRC_STORE_REG_bnew(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_NEW_REG(b, VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_REG_hnew(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_NEW_REG(h, VAL, ADDR, START, LEN, INC)
+#define CIRC_STORE_REG_wnew(VAL, ADDR, START, LEN, INC) \
+ CIRC_STORE_NEW_REG(w, VAL, ADDR, START, LEN, INC)
+
+
+int err;
+
+/* We'll test increments +1 and -1 */
+void check_load(int i, long long result, int inc, int size)
+{
+ int expect = (i * inc);
+ while (expect >= size) {
+ expect -= size;
+ }
+ while (expect < 0) {
+ expect += size;
+ }
+ if (result != expect) {
+ printf("ERROR(%d): %lld != %d\n", i, result, expect);
+ err++;
+ }
+}
+
+#define TEST_LOAD_IMM(SZ, TYPE, BUF, BUFSIZE, INC, FMT) \
+void circ_test_load_imm_##SZ(void) \
+{ \
+ TYPE *p = (TYPE *)BUF; \
+ int size = 10; \
+ int i; \
+ for (i = 0; i < BUFSIZE; i++) { \
+ TYPE element; \
+ CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), (INC)); \
+ DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
+ i, p, element); \
+ check_load(i, element, ((INC) / (int)sizeof(TYPE)), size); \
+ } \
+ p = (TYPE *)BUF; \
+ for (i = 0; i < BUFSIZE; i++) { \
+ TYPE element; \
+ CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), -(INC)); \
+ DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
+ i, p, element); \
+ check_load(i, element, (-(INC) / (int)sizeof(TYPE)), size); \
+ } \
+}
+
+TEST_LOAD_IMM(b, char, bbuf, NBYTES, 1, d)
+TEST_LOAD_IMM(ub, unsigned char, bbuf, NBYTES, 1, d)
+TEST_LOAD_IMM(h, short, hbuf, NHALFS, 2, d)
+TEST_LOAD_IMM(uh, unsigned short, hbuf, NHALFS, 2, d)
+TEST_LOAD_IMM(w, int, wbuf, NWORDS, 4, d)
+TEST_LOAD_IMM(d, long long, dbuf, NDOBLS, 8, lld)
+
+#define TEST_LOAD_REG(SZ, TYPE, BUF, BUFSIZE, FMT) \
+void circ_test_load_reg_##SZ(void) \
+{ \
+ TYPE *p = (TYPE *)BUF; \
+ int size = 13; \
+ int i; \
+ for (i = 0; i < BUFSIZE; i++) { \
+ TYPE element; \
+ CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), 1); \
+ DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
+ i, p, element); \
+ check_load(i, element, 1, size); \
+ } \
+ p = (TYPE *)BUF; \
+ for (i = 0; i < BUFSIZE; i++) { \
+ TYPE element; \
+ CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), -1); \
+ DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
+ i, p, element); \
+ check_load(i, element, -1, size); \
+ } \
+}
+
+TEST_LOAD_REG(b, char, bbuf, NBYTES, d)
+TEST_LOAD_REG(ub, unsigned char, bbuf, NBYTES, d)
+TEST_LOAD_REG(h, short, hbuf, NHALFS, d)
+TEST_LOAD_REG(uh, unsigned short, hbuf, NHALFS, d)
+TEST_LOAD_REG(w, int, wbuf, NWORDS, d)
+TEST_LOAD_REG(d, long long, dbuf, NDOBLS, lld)
+
+/* The circular stores will wrap around somewhere inside the buffer */
+#define CIRC_VAL(SZ, TYPE, BUFSIZE) \
+TYPE circ_val_##SZ(int i, int inc, int size) \
+{ \
+ int mod = BUFSIZE % size; \
+ int elem = i * inc; \
+ if (elem < 0) { \
+ if (-elem <= size - mod) { \
+ return (elem + BUFSIZE - mod); \
+ } else { \
+ return (elem + BUFSIZE + size - mod); \
+ } \
+ } else if (elem < mod) {\
+ return (elem + BUFSIZE - mod); \
+ } else { \
+ return (elem + BUFSIZE - size - mod); \
+ } \
+}
+
+CIRC_VAL(b, unsigned char, NBYTES)
+CIRC_VAL(h, short, NHALFS)
+CIRC_VAL(w, int, NWORDS)
+CIRC_VAL(d, long long, NDOBLS)
+
+/*
+ * Circular stores should only write to the first "size" elements of the buffer
+ * the remainder of the elements should have BUF[i] == i
+ */
+#define CHECK_STORE(SZ, BUF, BUFSIZE, FMT) \
+void check_store_##SZ(int inc, int size) \
+{ \
+ int i; \
+ for (i = 0; i < size; i++) { \
+ DEBUG_PRINTF(#BUF "[%3d] = 0x%02" #FMT ", guess = 0x%02" #FMT "\n", \
+ i, BUF[i], circ_val_##SZ(i, inc, size)); \
+ if (BUF[i] != circ_val_##SZ(i, inc, size)) { \
+ printf("ERROR(%3d): 0x%02" #FMT " != 0x%02" #FMT "\n", \
+ i, BUF[i], circ_val_##SZ(i, inc, size)); \
+ err++; \
+ } \
+ } \
+ for (i = size; i < BUFSIZE; i++) { \
+ if (BUF[i] != i) { \
+ printf("ERROR(%3d): 0x%02" #FMT " != 0x%02x\n", i, BUF[i], i); \
+ err++; \
+ } \
+ } \
+}
+
+CHECK_STORE(b, bbuf, NBYTES, x)
+CHECK_STORE(h, hbuf, NHALFS, x)
+CHECK_STORE(w, wbuf, NWORDS, x)
+CHECK_STORE(d, dbuf, NDOBLS, llx)
+
+#define CIRC_TEST_STORE_IMM(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT, INC) \
+void circ_test_store_imm_##SZ(void) \
+{ \
+ unsigned int size = 27; \
+ TYPE *p = BUF; \
+ TYPE val = 0; \
+ int i; \
+ init_##BUF(); \
+ for (i = 0; i < BUFSIZE; i++) { \
+ CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), INC); \
+ val++; \
+ } \
+ check_store_##CHK(((INC) / (int)sizeof(TYPE)), size); \
+ p = BUF; \
+ val = 0; \
+ init_##BUF(); \
+ for (i = 0; i < BUFSIZE; i++) { \
+ CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), \
+ -(INC)); \
+ val++; \
+ } \
+ check_store_##CHK((-(INC) / (int)sizeof(TYPE)), size); \
+}
+
+CIRC_TEST_STORE_IMM(b, b, unsigned char, bbuf, NBYTES, 0, 1)
+CIRC_TEST_STORE_IMM(h, h, short, hbuf, NHALFS, 0, 2)
+CIRC_TEST_STORE_IMM(f, h, short, hbuf, NHALFS, 16, 2)
+CIRC_TEST_STORE_IMM(w, w, int, wbuf, NWORDS, 0, 4)
+CIRC_TEST_STORE_IMM(d, d, long long, dbuf, NDOBLS, 0, 8)
+CIRC_TEST_STORE_IMM(bnew, b, unsigned char, bbuf, NBYTES, 0, 1)
+CIRC_TEST_STORE_IMM(hnew, h, short, hbuf, NHALFS, 0, 2)
+CIRC_TEST_STORE_IMM(wnew, w, int, wbuf, NWORDS, 0, 4)
+
+#define CIRC_TEST_STORE_REG(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT) \
+void circ_test_store_reg_##SZ(void) \
+{ \
+ TYPE *p = BUF; \
+ unsigned int size = 19; \
+ TYPE val = 0; \
+ int i; \
+ init_##BUF(); \
+ for (i = 0; i < BUFSIZE; i++) { \
+ CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), 1); \
+ val++; \
+ } \
+ check_store_##CHK(1, size); \
+ p = BUF; \
+ val = 0; \
+ init_##BUF(); \
+ for (i = 0; i < BUFSIZE; i++) { \
+ CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), -1); \
+ val++; \
+ } \
+ check_store_##CHK(-1, size); \
+}
+
+CIRC_TEST_STORE_REG(b, b, unsigned char, bbuf, NBYTES, 0)
+CIRC_TEST_STORE_REG(h, h, short, hbuf, NHALFS, 0)
+CIRC_TEST_STORE_REG(f, h, short, hbuf, NHALFS, 16)
+CIRC_TEST_STORE_REG(w, w, int, wbuf, NWORDS, 0)
+CIRC_TEST_STORE_REG(d, d, long long, dbuf, NDOBLS, 0)
+CIRC_TEST_STORE_REG(bnew, b, unsigned char, bbuf, NBYTES, 0)
+CIRC_TEST_STORE_REG(hnew, h, short, hbuf, NHALFS, 0)
+CIRC_TEST_STORE_REG(wnew, w, int, wbuf, NWORDS, 0)
+
+/* Test the old scheme used in Hexagon V3 */
+static void circ_test_v3(void)
+{
+ int *p = wbuf;
+ int size = 15;
+ int K = 4; /* 64 bytes */
+ int element;
+ int i;
+
+ init_wbuf();
+
+ for (i = 0; i < NWORDS; i++) {
+ __asm__(
+ "r4 = %2\n\t"
+ "m1 = r4\n\t"
+ "%0 = memw(%1++I:circ(M1))\n\t"
+ : "=r"(element), "+r"(p)
+ : "r"(build_mreg(1, K, size * sizeof(int)))
+ : "r4", "m1");
+ DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2d\n", i, p, element);
+ check_load(i, element, 1, size);
+ }
+}
+
+int main()
+{
+ init_bbuf();
+ init_hbuf();
+ init_wbuf();
+ init_dbuf();
+
+ DEBUG_PRINTF("NBYTES = %d\n", NBYTES);
+ DEBUG_PRINTF("Address of dbuf = 0x%p\n", dbuf);
+ DEBUG_PRINTF("Address of wbuf = 0x%p\n", wbuf);
+ DEBUG_PRINTF("Address of hbuf = 0x%p\n", hbuf);
+ DEBUG_PRINTF("Address of bbuf = 0x%p\n", bbuf);
+
+ circ_test_load_imm_b();
+ circ_test_load_imm_ub();
+ circ_test_load_imm_h();
+ circ_test_load_imm_uh();
+ circ_test_load_imm_w();
+ circ_test_load_imm_d();
+
+ circ_test_load_reg_b();
+ circ_test_load_reg_ub();
+ circ_test_load_reg_h();
+ circ_test_load_reg_uh();
+ circ_test_load_reg_w();
+ circ_test_load_reg_d();
+
+ circ_test_store_imm_b();
+ circ_test_store_imm_h();
+ circ_test_store_imm_f();
+ circ_test_store_imm_w();
+ circ_test_store_imm_d();
+ circ_test_store_imm_bnew();
+ circ_test_store_imm_hnew();
+ circ_test_store_imm_wnew();
+
+ circ_test_store_reg_b();
+ circ_test_store_reg_h();
+ circ_test_store_reg_f();
+ circ_test_store_reg_w();
+ circ_test_store_reg_d();
+ circ_test_store_reg_bnew();
+ circ_test_store_reg_hnew();
+ circ_test_store_reg_wnew();
+
+ circ_test_v3();
+
+ puts(err ? "FAIL" : "PASS");
+ return err ? 1 : 0;
+}
diff --git a/tests/tcg/hexagon/fpstuff.c b/tests/tcg/hexagon/fpstuff.c
index e4f1a0e..0dff429 100644
--- a/tests/tcg/hexagon/fpstuff.c
+++ b/tests/tcg/hexagon/fpstuff.c
@@ -37,10 +37,12 @@
const int SF_NaN_special = 0x7f800001;
const int SF_ANY = 0x3f800000;
const int SF_HEX_NAN = 0xffffffff;
+const int SF_small_neg = 0xab98fba8;
const long long DF_NaN = 0x7ff8000000000000ULL;
const long long DF_ANY = 0x3f80000000000000ULL;
const long long DF_HEX_NAN = 0xffffffffffffffffULL;
+const long long DF_small_neg = 0xbd731f7500000000ULL;
int err;
@@ -248,6 +250,87 @@
check_fpstatus(usr, FPINVF);
}
+static void check_recip_exception(void)
+{
+ int result;
+ int usr;
+
+ /*
+ * Check that sfrecipa doesn't set status bits when
+ * a NaN with bit 22 non-zero is passed
+ */
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
+ : "r2", "p0", "usr");
+ check32(result, SF_HEX_NAN);
+ check_fpstatus(usr, 0);
+
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN)
+ : "r2", "p0", "usr");
+ check32(result, SF_HEX_NAN);
+ check_fpstatus(usr, 0);
+
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(SF_NaN)
+ : "r2", "p0", "usr");
+ check32(result, SF_HEX_NAN);
+ check_fpstatus(usr, 0);
+
+ /*
+ * Check that sfrecipa doesn't set status bits when
+ * a NaN with bit 22 zero is passed
+ */
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(SF_NaN_special), "r"(SF_ANY)
+ : "r2", "p0", "usr");
+ check32(result, SF_HEX_NAN);
+ check_fpstatus(usr, FPINVF);
+
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN_special)
+ : "r2", "p0", "usr");
+ check32(result, SF_HEX_NAN);
+ check_fpstatus(usr, FPINVF);
+
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(SF_NaN_special)
+ : "r2", "p0", "usr");
+ check32(result, SF_HEX_NAN);
+ check_fpstatus(usr, FPINVF);
+
+ /*
+ * Check that sfrecipa properly sets divid-by-zero
+ */
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(0x885dc960), "r"(0x80000000)
+ : "r2", "p0", "usr");
+ check32(result, 0x3f800000);
+ check_fpstatus(usr, FPDBZF);
+
+ asm (CLEAR_FPSTATUS
+ "%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(result), "=r"(usr) : "r"(0x7f800000), "r"(SF_ZERO)
+ : "r2", "p0", "usr");
+ check32(result, 0x3f800000);
+ check_fpstatus(usr, 0);
+}
+
static void check_canonical_NaN(void)
{
int sf_result;
@@ -358,12 +441,171 @@
check_fpstatus(usr, 0);
}
+static void check_invsqrta(void)
+{
+ int result;
+ int predval;
+
+ asm volatile("%0,p0 = sfinvsqrta(%2)\n\t"
+ "%1 = p0\n\t"
+ : "+r"(result), "=r"(predval)
+ : "r"(0x7f800000)
+ : "p0");
+ check32(result, 0xff800000);
+ check32(predval, 0x0);
+}
+
+static void check_float2int_convs()
+{
+ int res32;
+ long long res64;
+ int usr;
+
+ /*
+ * Check that the various forms of float-to-unsigned
+ * check sign before rounding
+ */
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2uw(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(SF_small_neg)
+ : "r2", "usr");
+ check32(res32, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2uw(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(SF_small_neg)
+ : "r2", "usr");
+ check32(res32, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2ud(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(SF_small_neg)
+ : "r2", "usr");
+ check64(res64, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2ud(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(SF_small_neg)
+ : "r2", "usr");
+ check64(res64, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2uw(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(DF_small_neg)
+ : "r2", "usr");
+ check32(res32, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2uw(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(DF_small_neg)
+ : "r2", "usr");
+ check32(res32, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2ud(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(DF_small_neg)
+ : "r2", "usr");
+ check64(res64, 0);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2ud(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(DF_small_neg)
+ : "r2", "usr");
+ check64(res64, 0);
+ check_fpstatus(usr, FPINVF);
+
+ /*
+ * Check that the various forms of float-to-signed return -1 for NaN
+ */
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2w(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(SF_NaN)
+ : "r2", "usr");
+ check32(res32, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2w(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(SF_NaN)
+ : "r2", "usr");
+ check32(res32, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2d(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(SF_NaN)
+ : "r2", "usr");
+ check64(res64, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_sf2d(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(SF_NaN)
+ : "r2", "usr");
+ check64(res64, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2w(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(DF_NaN)
+ : "r2", "usr");
+ check32(res32, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2w(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res32), "=r"(usr) : "r"(DF_NaN)
+ : "r2", "usr");
+ check32(res32, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2d(%2)\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(DF_NaN)
+ : "r2", "usr");
+ check64(res64, -1);
+ check_fpstatus(usr, FPINVF);
+
+ asm(CLEAR_FPSTATUS
+ "%0 = convert_df2d(%2):chop\n\t"
+ "%1 = usr\n\t"
+ : "=r"(res64), "=r"(usr) : "r"(DF_NaN)
+ : "r2", "usr");
+ check64(res64, -1);
+ check_fpstatus(usr, FPINVF);
+}
+
int main()
{
check_compare_exception();
check_sfminmax();
check_dfminmax();
+ check_recip_exception();
check_canonical_NaN();
+ check_invsqrta();
+ check_float2int_convs();
puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
diff --git a/tests/tcg/hexagon/load_align.c b/tests/tcg/hexagon/load_align.c
new file mode 100644
index 0000000..12fc9cb
--- /dev/null
+++ b/tests/tcg/hexagon/load_align.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/>.
+ */
+
+/*
+ * Test load align instructions
+ *
+ * Example
+ * r1:0 = memh_fifo(r1+#0)
+ * loads a half word from memory, shifts the destination register
+ * right by one half word and inserts the loaded value into the high
+ * half word of the destination.
+ *
+ * There are 8 addressing modes and byte and half word variants, for a
+ * total of 16 instructions to test
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int err;
+
+char buf[16] __attribute__((aligned(1 << 16)));
+
+void init_buf(void)
+{
+ int i;
+ for (i = 0; i < 16; i++) {
+ buf[i] = i + 1;
+ }
+}
+
+void __check(int line, long long result, long long expect)
+{
+ if (result != expect) {
+ printf("ERROR at line %d: 0x%016llx != 0x%016llx\n",
+ line, result, expect);
+ err++;
+ }
+}
+
+#define check(RES, EXP) __check(__LINE__, RES, EXP)
+
+void __checkp(int line, void *p, void *expect)
+{
+ if (p != expect) {
+ printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect);
+ err++;
+ }
+}
+
+#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP)
+
+/*
+ ****************************************************************************
+ * _io addressing mode (addr + offset)
+ */
+#define LOAD_io(SZ, RES, ADDR, OFF) \
+ __asm__( \
+ "%0 = mem" #SZ "_fifo(%1+#" #OFF ")\n\t" \
+ : "+r"(RES) \
+ : "r"(ADDR))
+#define LOAD_io_b(RES, ADDR, OFF) \
+ LOAD_io(b, RES, ADDR, OFF)
+#define LOAD_io_h(RES, ADDR, OFF) \
+ LOAD_io(h, RES, ADDR, OFF)
+
+#define TEST_io(NAME, SZ, SIZE, EXP1, EXP2, EXP3, EXP4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ LOAD_io_##SZ(result, buf, 0 * (SIZE)); \
+ check(result, (EXP1)); \
+ LOAD_io_##SZ(result, buf, 1 * (SIZE)); \
+ check(result, (EXP2)); \
+ LOAD_io_##SZ(result, buf, 2 * (SIZE)); \
+ check(result, (EXP3)); \
+ LOAD_io_##SZ(result, buf, 3 * (SIZE)); \
+ check(result, (EXP4)); \
+}
+
+TEST_io(loadalignb_io, b, 1,
+ 0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
+ 0x030201ffffffffffLL, 0x04030201ffffffffLL)
+TEST_io(loadalignh_io, h, 2,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x060504030201ffffLL, 0x0807060504030201LL)
+
+/*
+ ****************************************************************************
+ * _ur addressing mode (index << offset + base)
+ */
+#define LOAD_ur(SZ, RES, SHIFT, IDX) \
+ __asm__( \
+ "%0 = mem" #SZ "_fifo(%1<<#" #SHIFT " + ##buf)\n\t" \
+ : "+r"(RES) \
+ : "r"(IDX))
+#define LOAD_ur_b(RES, SHIFT, IDX) \
+ LOAD_ur(b, RES, SHIFT, IDX)
+#define LOAD_ur_h(RES, SHIFT, IDX) \
+ LOAD_ur(h, RES, SHIFT, IDX)
+
+#define TEST_ur(NAME, SZ, SHIFT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ LOAD_ur_##SZ(result, (SHIFT), 0); \
+ check(result, (RES1)); \
+ LOAD_ur_##SZ(result, (SHIFT), 1); \
+ check(result, (RES2)); \
+ LOAD_ur_##SZ(result, (SHIFT), 2); \
+ check(result, (RES3)); \
+ LOAD_ur_##SZ(result, (SHIFT), 3); \
+ check(result, (RES4)); \
+}
+
+TEST_ur(loadalignb_ur, b, 1,
+ 0x01ffffffffffffffLL, 0x0301ffffffffffffLL,
+ 0x050301ffffffffffLL, 0x07050301ffffffffLL)
+TEST_ur(loadalignh_ur, h, 1,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x060504030201ffffLL, 0x0807060504030201LL)
+
+/*
+ ****************************************************************************
+ * _ap addressing mode (addr = base)
+ */
+#define LOAD_ap(SZ, RES, PTR, ADDR) \
+ __asm__( \
+ "%0 = mem" #SZ "_fifo(%1 = ##" #ADDR ")\n\t" \
+ : "+r"(RES), "=r"(PTR))
+#define LOAD_ap_b(RES, PTR, ADDR) \
+ LOAD_ap(b, RES, PTR, ADDR)
+#define LOAD_ap_h(RES, PTR, ADDR) \
+ LOAD_ap(h, RES, PTR, ADDR)
+
+#define TEST_ap(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ void *ptr; \
+ LOAD_ap_##SZ(result, ptr, (buf + 0 * (SIZE))); \
+ check(result, (RES1)); \
+ checkp(ptr, &buf[0 * (SIZE)]); \
+ LOAD_ap_##SZ(result, ptr, (buf + 1 * (SIZE))); \
+ check(result, (RES2)); \
+ checkp(ptr, &buf[1 * (SIZE)]); \
+ LOAD_ap_##SZ(result, ptr, (buf + 2 * (SIZE))); \
+ check(result, (RES3)); \
+ checkp(ptr, &buf[2 * (SIZE)]); \
+ LOAD_ap_##SZ(result, ptr, (buf + 3 * (SIZE))); \
+ check(result, (RES4)); \
+ checkp(ptr, &buf[3 * (SIZE)]); \
+}
+
+TEST_ap(loadalignb_ap, b, 1,
+ 0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
+ 0x030201ffffffffffLL, 0x04030201ffffffffLL)
+TEST_ap(loadalignh_ap, h, 2,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x060504030201ffffLL, 0x0807060504030201LL)
+
+/*
+ ****************************************************************************
+ * _rp addressing mode (addr ++ modifer-reg)
+ */
+#define LOAD_pr(SZ, RES, PTR, INC) \
+ __asm__( \
+ "m0 = %2\n\t" \
+ "%0 = mem" #SZ "_fifo(%1++m0)\n\t" \
+ : "+r"(RES), "+r"(PTR) \
+ : "r"(INC) \
+ : "m0")
+#define LOAD_pr_b(RES, PTR, INC) \
+ LOAD_pr(b, RES, PTR, INC)
+#define LOAD_pr_h(RES, PTR, INC) \
+ LOAD_pr(h, RES, PTR, INC)
+
+#define TEST_pr(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ void *ptr = buf; \
+ LOAD_pr_##SZ(result, ptr, (SIZE)); \
+ check(result, (RES1)); \
+ checkp(ptr, &buf[1 * (SIZE)]); \
+ LOAD_pr_##SZ(result, ptr, (SIZE)); \
+ check(result, (RES2)); \
+ checkp(ptr, &buf[2 * (SIZE)]); \
+ LOAD_pr_##SZ(result, ptr, (SIZE)); \
+ check(result, (RES3)); \
+ checkp(ptr, &buf[3 * (SIZE)]); \
+ LOAD_pr_##SZ(result, ptr, (SIZE)); \
+ check(result, (RES4)); \
+ checkp(ptr, &buf[4 * (SIZE)]); \
+}
+
+TEST_pr(loadalignb_pr, b, 1,
+ 0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
+ 0x030201ffffffffffLL, 0x04030201ffffffffLL)
+TEST_pr(loadalignh_pr, h, 2,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x060504030201ffffLL, 0x0807060504030201LL)
+
+/*
+ ****************************************************************************
+ * _pbr addressing mode (addr ++ modifer-reg:brev)
+ */
+#define LOAD_pbr(SZ, RES, PTR) \
+ __asm__( \
+ "r4 = #(1 << (16 - 3))\n\t" \
+ "m0 = r4\n\t" \
+ "%0 = mem" #SZ "_fifo(%1++m0:brev)\n\t" \
+ : "+r"(RES), "+r"(PTR) \
+ : \
+ : "r4", "m0")
+#define LOAD_pbr_b(RES, PTR) \
+ LOAD_pbr(b, RES, PTR)
+#define LOAD_pbr_h(RES, PTR) \
+ LOAD_pbr(h, RES, PTR)
+
+#define TEST_pbr(NAME, SZ, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ void *ptr = buf; \
+ LOAD_pbr_##SZ(result, ptr); \
+ check(result, (RES1)); \
+ LOAD_pbr_##SZ(result, ptr); \
+ check(result, (RES2)); \
+ LOAD_pbr_##SZ(result, ptr); \
+ check(result, (RES3)); \
+ LOAD_pbr_##SZ(result, ptr); \
+ check(result, (RES4)); \
+}
+
+TEST_pbr(loadalignb_pbr, b,
+ 0x01ffffffffffffffLL, 0x0501ffffffffffffLL,
+ 0x030501ffffffffffLL, 0x07030501ffffffffLL)
+TEST_pbr(loadalignh_pbr, h,
+ 0x0201ffffffffffffLL, 0x06050201ffffffffLL,
+ 0x040306050201ffffLL, 0x0807040306050201LL)
+
+/*
+ ****************************************************************************
+ * _pi addressing mode (addr ++ inc)
+ */
+#define LOAD_pi(SZ, RES, PTR, INC) \
+ __asm__( \
+ "%0 = mem" #SZ "_fifo(%1++#" #INC ")\n\t" \
+ : "+r"(RES), "+r"(PTR))
+#define LOAD_pi_b(RES, PTR, INC) \
+ LOAD_pi(b, RES, PTR, INC)
+#define LOAD_pi_h(RES, PTR, INC) \
+ LOAD_pi(h, RES, PTR, INC)
+
+#define TEST_pi(NAME, SZ, INC, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ void *ptr = buf; \
+ LOAD_pi_##SZ(result, ptr, (INC)); \
+ check(result, (RES1)); \
+ checkp(ptr, &buf[1 * (INC)]); \
+ LOAD_pi_##SZ(result, ptr, (INC)); \
+ check(result, (RES2)); \
+ checkp(ptr, &buf[2 * (INC)]); \
+ LOAD_pi_##SZ(result, ptr, (INC)); \
+ check(result, (RES3)); \
+ checkp(ptr, &buf[3 * (INC)]); \
+ LOAD_pi_##SZ(result, ptr, (INC)); \
+ check(result, (RES4)); \
+ checkp(ptr, &buf[4 * (INC)]); \
+}
+
+TEST_pi(loadalignb_pi, b, 1,
+ 0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
+ 0x030201ffffffffffLL, 0x04030201ffffffffLL)
+TEST_pi(loadalignh_pi, h, 2,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x060504030201ffffLL, 0x0807060504030201LL)
+
+/*
+ ****************************************************************************
+ * _pci addressing mode (addr ++ inc:circ)
+ */
+#define LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %3\n\t" \
+ "m0 = r4\n\t" \
+ "cs0 = %2\n\t" \
+ "%0 = mem" #SZ "_fifo(%1++#" #INC ":circ(m0))\n\t" \
+ : "+r"(RES), "+r"(PTR) \
+ : "r"(START), "r"(LEN) \
+ : "r4", "m0", "cs0")
+#define LOAD_pci_b(RES, PTR, START, LEN, INC) \
+ LOAD_pci(b, RES, PTR, START, LEN, INC)
+#define LOAD_pci_h(RES, PTR, START, LEN, INC) \
+ LOAD_pci(h, RES, PTR, START, LEN, INC)
+
+#define TEST_pci(NAME, SZ, LEN, INC, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ void *ptr = buf; \
+ LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES1)); \
+ checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
+ LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES2)); \
+ checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
+ LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES3)); \
+ checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
+ LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES4)); \
+ checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
+}
+
+TEST_pci(loadalignb_pci, b, 2, 1,
+ 0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
+ 0x010201ffffffffffLL, 0x02010201ffffffffLL)
+TEST_pci(loadalignh_pci, h, 4, 2,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x020104030201ffffLL, 0x0403020104030201LL)
+
+/*
+ ****************************************************************************
+ * _pcr addressing mode (addr ++ I:circ(modifier-reg))
+ */
+#define LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %2\n\t" \
+ "m1 = r4\n\t" \
+ "cs1 = %3\n\t" \
+ "%0 = mem" #SZ "_fifo(%1++I:circ(m1))\n\t" \
+ : "+r"(RES), "+r"(PTR) \
+ : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
+ "r"(START) \
+ : "r4", "m1", "cs1")
+#define LOAD_pcr_b(RES, PTR, START, LEN, INC) \
+ LOAD_pcr(b, RES, PTR, START, LEN, INC)
+#define LOAD_pcr_h(RES, PTR, START, LEN, INC) \
+ LOAD_pcr(h, RES, PTR, START, LEN, INC)
+
+#define TEST_pcr(NAME, SZ, SIZE, LEN, INC, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ long long result = ~0LL; \
+ void *ptr = buf; \
+ LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES1)); \
+ checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
+ LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES2)); \
+ checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
+ LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES3)); \
+ checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
+ LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES4)); \
+ checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
+}
+
+TEST_pcr(loadalignb_pcr, b, 1, 2, 1,
+ 0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
+ 0x010201ffffffffffLL, 0x02010201ffffffffLL)
+TEST_pcr(loadalignh_pcr, h, 2, 4, 1,
+ 0x0201ffffffffffffLL, 0x04030201ffffffffLL,
+ 0x020104030201ffffLL, 0x0403020104030201LL)
+
+int main()
+{
+ init_buf();
+
+ test_loadalignb_io();
+ test_loadalignh_io();
+
+ test_loadalignb_ur();
+ test_loadalignh_ur();
+
+ test_loadalignb_ap();
+ test_loadalignh_ap();
+
+ test_loadalignb_pr();
+ test_loadalignh_pr();
+
+ test_loadalignb_pbr();
+ test_loadalignh_pbr();
+
+ test_loadalignb_pi();
+ test_loadalignh_pi();
+
+ test_loadalignb_pci();
+ test_loadalignh_pci();
+
+ test_loadalignb_pcr();
+ test_loadalignh_pcr();
+
+ puts(err ? "FAIL" : "PASS");
+ return err ? 1 : 0;
+}
diff --git a/tests/tcg/hexagon/load_unpack.c b/tests/tcg/hexagon/load_unpack.c
new file mode 100644
index 0000000..3575a37
--- /dev/null
+++ b/tests/tcg/hexagon/load_unpack.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/>.
+ */
+
+/*
+ * Test load unpack instructions
+ *
+ * Example
+ * r0 = memubh(r1+#0)
+ * loads a half word from memory and zero-extends the 2 bytes to form a word
+ *
+ * For each addressing mode, there are 4 tests
+ * bzw2 unsigned 2 elements
+ * bsw2 signed 2 elements
+ * bzw4 unsigned 4 elements
+ * bsw4 signed 4 elements
+ * There are 8 addressing modes, for a total of 32 instructions to test
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int err;
+
+char buf[16] __attribute__((aligned(1 << 16)));
+
+void init_buf(void)
+{
+ int i;
+ for (i = 0; i < 16; i++) {
+ int sign = i % 2 == 0 ? 0x80 : 0;
+ buf[i] = sign | (i + 1);
+ }
+}
+
+void __check(int line, long long result, long long expect)
+{
+ if (result != expect) {
+ printf("ERROR at line %d: 0x%08llx != 0x%08llx\n",
+ line, result, expect);
+ err++;
+ }
+}
+
+#define check(RES, EXP) __check(__LINE__, RES, EXP)
+
+void __checkp(int line, void *p, void *expect)
+{
+ if (p != expect) {
+ printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect);
+ err++;
+ }
+}
+
+#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP)
+
+/*
+ ****************************************************************************
+ * _io addressing mode (addr + offset)
+ */
+#define BxW_LOAD_io(SZ, RES, ADDR, OFF) \
+ __asm__( \
+ "%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \
+ : "=r"(RES) \
+ : "r"(ADDR))
+#define BxW_LOAD_io_Z(RES, ADDR, OFF) \
+ BxW_LOAD_io(ubh, RES, ADDR, OFF)
+#define BxW_LOAD_io_S(RES, ADDR, OFF) \
+ BxW_LOAD_io(bh, RES, ADDR, OFF)
+
+#define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ init_buf(); \
+ BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \
+ check(result, (EXP1) | (EXT)); \
+ BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \
+ check(result, (EXP2) | (EXT)); \
+ BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \
+ check(result, (EXP3) | (EXT)); \
+ BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \
+ check(result, (EXP4) | (EXT)); \
+}
+
+
+TEST_io(loadbzw2_io, int, Z, 2, 0x00000000,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_io(loadbsw2_io, int, S, 2, 0x0000ff00,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_io(loadbzw4_io, long long, Z, 4, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+TEST_io(loadbsw4_io, long long, S, 4, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+
+/*
+ ****************************************************************************
+ * _ur addressing mode (index << offset + base)
+ */
+#define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \
+ __asm__( \
+ "%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \
+ : "=r"(RES) \
+ : "r"(IDX))
+#define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \
+ BxW_LOAD_ur(ubh, RES, SHIFT, IDX)
+#define BxW_LOAD_ur_S(RES, SHIFT, IDX) \
+ BxW_LOAD_ur(bh, RES, SHIFT, IDX)
+
+#define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ init_buf(); \
+ BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \
+ check(result, (RES1) | (EXT)); \
+ BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \
+ check(result, (RES2) | (EXT)); \
+ BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \
+ check(result, (RES3) | (EXT)); \
+ BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \
+ check(result, (RES4) | (EXT)); \
+} \
+
+TEST_ur(loadbzw2_ur, int, Z, 1, 0x00000000,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_ur(loadbsw2_ur, int, S, 1, 0x0000ff00,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_ur(loadbzw4_ur, long long, Z, 2, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+TEST_ur(loadbsw4_ur, long long, S, 2, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+
+/*
+ ****************************************************************************
+ * _ap addressing mode (addr = base)
+ */
+#define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \
+ __asm__( \
+ "%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \
+ : "=r"(RES), "=r"(PTR))
+#define BxW_LOAD_ap_Z(RES, PTR, ADDR) \
+ BxW_LOAD_ap(ubh, RES, PTR, ADDR)
+#define BxW_LOAD_ap_S(RES, PTR, ADDR) \
+ BxW_LOAD_ap(bh, RES, PTR, ADDR)
+
+#define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ void *ptr; \
+ init_buf(); \
+ BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \
+ check(result, (RES1) | (EXT)); \
+ checkp(ptr, &buf[0 * (SIZE)]); \
+ BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \
+ check(result, (RES2) | (EXT)); \
+ checkp(ptr, &buf[1 * (SIZE)]); \
+ BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \
+ check(result, (RES3) | (EXT)); \
+ checkp(ptr, &buf[2 * (SIZE)]); \
+ BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \
+ check(result, (RES4) | (EXT)); \
+ checkp(ptr, &buf[3 * (SIZE)]); \
+}
+
+TEST_ap(loadbzw2_ap, int, Z, 2, 0x00000000,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_ap(loadbsw2_ap, int, S, 2, 0x0000ff00,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_ap(loadbzw4_ap, long long, Z, 4, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+TEST_ap(loadbsw4_ap, long long, S, 4, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+
+/*
+ ****************************************************************************
+ * _rp addressing mode (addr ++ modifer-reg)
+ */
+#define BxW_LOAD_pr(SZ, RES, PTR, INC) \
+ __asm__( \
+ "m0 = %2\n\t" \
+ "%0 = mem" #SZ "(%1++m0)\n\t" \
+ : "=r"(RES), "+r"(PTR) \
+ : "r"(INC) \
+ : "m0")
+#define BxW_LOAD_pr_Z(RES, PTR, INC) \
+ BxW_LOAD_pr(ubh, RES, PTR, INC)
+#define BxW_LOAD_pr_S(RES, PTR, INC) \
+ BxW_LOAD_pr(bh, RES, PTR, INC)
+
+#define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ void *ptr = buf; \
+ init_buf(); \
+ BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
+ check(result, (RES1) | (EXT)); \
+ checkp(ptr, &buf[1 * (SIZE)]); \
+ BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
+ check(result, (RES2) | (EXT)); \
+ checkp(ptr, &buf[2 * (SIZE)]); \
+ BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
+ check(result, (RES3) | (EXT)); \
+ checkp(ptr, &buf[3 * (SIZE)]); \
+ BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
+ check(result, (RES4) | (EXT)); \
+ checkp(ptr, &buf[4 * (SIZE)]); \
+}
+
+TEST_pr(loadbzw2_pr, int, Z, 2, 0x00000000,
+ 0x00020081, 0x0040083, 0x00060085, 0x00080087)
+TEST_pr(loadbsw2_pr, int, S, 2, 0x0000ff00,
+ 0x00020081, 0x0040083, 0x00060085, 0x00080087)
+TEST_pr(loadbzw4_pr, long long, Z, 4, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+
+/*
+ ****************************************************************************
+ * _pbr addressing mode (addr ++ modifer-reg:brev)
+ */
+#define BxW_LOAD_pbr(SZ, RES, PTR) \
+ __asm__( \
+ "r4 = #(1 << (16 - 3))\n\t" \
+ "m0 = r4\n\t" \
+ "%0 = mem" #SZ "(%1++m0:brev)\n\t" \
+ : "=r"(RES), "+r"(PTR) \
+ : \
+ : "r4", "m0")
+#define BxW_LOAD_pbr_Z(RES, PTR) \
+ BxW_LOAD_pbr(ubh, RES, PTR)
+#define BxW_LOAD_pbr_S(RES, PTR) \
+ BxW_LOAD_pbr(bh, RES, PTR)
+
+#define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ void *ptr = buf; \
+ init_buf(); \
+ BxW_LOAD_pbr_##SIGN(result, ptr); \
+ check(result, (RES1) | (EXT)); \
+ BxW_LOAD_pbr_##SIGN(result, ptr); \
+ check(result, (RES2) | (EXT)); \
+ BxW_LOAD_pbr_##SIGN(result, ptr); \
+ check(result, (RES3) | (EXT)); \
+ BxW_LOAD_pbr_##SIGN(result, ptr); \
+ check(result, (RES4) | (EXT)); \
+}
+
+TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000,
+ 0x00020081, 0x00060085, 0x00040083, 0x00080087)
+TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00,
+ 0x00020081, 0x00060085, 0x00040083, 0x00080087)
+TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x0006008500040083LL, 0x000a008900080087LL)
+TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x0006008500040083LL, 0x000a008900080087LL)
+
+/*
+ ****************************************************************************
+ * _pi addressing mode (addr ++ inc)
+ */
+#define BxW_LOAD_pi(SZ, RES, PTR, INC) \
+ __asm__( \
+ "%0 = mem" #SZ "(%1++#" #INC ")\n\t" \
+ : "=r"(RES), "+r"(PTR))
+#define BxW_LOAD_pi_Z(RES, PTR, INC) \
+ BxW_LOAD_pi(ubh, RES, PTR, INC)
+#define BxW_LOAD_pi_S(RES, PTR, INC) \
+ BxW_LOAD_pi(bh, RES, PTR, INC)
+
+#define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ void *ptr = buf; \
+ init_buf(); \
+ BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
+ check(result, (RES1) | (EXT)); \
+ checkp(ptr, &buf[1 * (INC)]); \
+ BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
+ check(result, (RES2) | (EXT)); \
+ checkp(ptr, &buf[2 * (INC)]); \
+ BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
+ check(result, (RES3) | (EXT)); \
+ checkp(ptr, &buf[3 * (INC)]); \
+ BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
+ check(result, (RES4) | (EXT)); \
+ checkp(ptr, &buf[4 * (INC)]); \
+}
+
+TEST_pi(loadbzw2_pi, int, Z, 2, 0x00000000,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_pi(loadbsw2_pi, int, S, 2, 0x0000ff00,
+ 0x00020081, 0x00040083, 0x00060085, 0x00080087)
+TEST_pi(loadbzw4_pi, long long, Z, 4, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+TEST_pi(loadbsw4_pi, long long, S, 4, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x000c008b000a0089LL, 0x0010008f000e008dLL)
+
+/*
+ ****************************************************************************
+ * _pci addressing mode (addr ++ inc:circ)
+ */
+#define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %3\n\t" \
+ "m0 = r4\n\t" \
+ "cs0 = %2\n\t" \
+ "%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \
+ : "=r"(RES), "+r"(PTR) \
+ : "r"(START), "r"(LEN) \
+ : "r4", "m0", "cs0")
+#define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \
+ BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC)
+#define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \
+ BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC)
+
+#define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ void *ptr = buf; \
+ init_buf(); \
+ BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES1) | (EXT)); \
+ checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
+ BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES2) | (EXT)); \
+ checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
+ BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES3) | (EXT)); \
+ checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
+ BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES4) | (EXT)); \
+ checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
+}
+
+TEST_pci(loadbzw2_pci, int, Z, 6, 2, 0x00000000,
+ 0x00020081, 0x00040083, 0x00060085, 0x00020081)
+TEST_pci(loadbsw2_pci, int, S, 6, 2, 0x0000ff00,
+ 0x00020081, 0x00040083, 0x00060085, 0x00020081)
+TEST_pci(loadbzw4_pci, long long, Z, 8, 4, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x0004008300020081LL, 0x0008008700060085LL)
+TEST_pci(loadbsw4_pci, long long, S, 8, 4, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x0004008300020081LL, 0x0008008700060085LL)
+
+/*
+ ****************************************************************************
+ * _pcr addressing mode (addr ++ I:circ(modifier-reg))
+ */
+#define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
+ __asm__( \
+ "r4 = %2\n\t" \
+ "m1 = r4\n\t" \
+ "cs1 = %3\n\t" \
+ "%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \
+ : "=r"(RES), "+r"(PTR) \
+ : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
+ "r"(START) \
+ : "r4", "m1", "cs1")
+#define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \
+ BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC)
+#define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \
+ BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC)
+
+#define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \
+ EXT, RES1, RES2, RES3, RES4) \
+void test_##NAME(void) \
+{ \
+ TYPE result; \
+ void *ptr = buf; \
+ init_buf(); \
+ BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES1) | (EXT)); \
+ checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
+ BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES2) | (EXT)); \
+ checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
+ BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES3) | (EXT)); \
+ checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
+ BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
+ check(result, (RES4) | (EXT)); \
+ checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
+}
+
+TEST_pcr(loadbzw2_pcr, int, Z, 2, 8, 2, 0x00000000,
+ 0x00020081, 0x00060085, 0x00020081, 0x00060085)
+TEST_pcr(loadbsw2_pcr, int, S, 2, 8, 2, 0x0000ff00,
+ 0x00020081, 0x00060085, 0x00020081, 0x00060085)
+TEST_pcr(loadbzw4_pcr, long long, Z, 4, 8, 1, 0x0000000000000000LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x0004008300020081LL, 0x0008008700060085LL)
+TEST_pcr(loadbsw4_pcr, long long, S, 4, 8, 1, 0x0000ff000000ff00LL,
+ 0x0004008300020081LL, 0x0008008700060085LL,
+ 0x0004008300020081LL, 0x0008008700060085LL)
+
+int main()
+{
+ test_loadbzw2_io();
+ test_loadbsw2_io();
+ test_loadbzw4_io();
+ test_loadbsw4_io();
+
+ test_loadbzw2_ur();
+ test_loadbsw2_ur();
+ test_loadbzw4_ur();
+ test_loadbsw4_ur();
+
+ test_loadbzw2_ap();
+ test_loadbsw2_ap();
+ test_loadbzw4_ap();
+ test_loadbsw4_ap();
+
+ test_loadbzw2_pr();
+ test_loadbsw2_pr();
+ test_loadbzw4_pr();
+ test_loadbsw4_pr();
+
+ test_loadbzw2_pbr();
+ test_loadbsw2_pbr();
+ test_loadbzw4_pbr();
+ test_loadbsw4_pbr();
+
+ test_loadbzw2_pi();
+ test_loadbsw2_pi();
+ test_loadbzw4_pi();
+ test_loadbsw4_pi();
+
+ test_loadbzw2_pci();
+ test_loadbsw2_pci();
+ test_loadbzw4_pci();
+ test_loadbsw4_pci();
+
+ test_loadbzw2_pcr();
+ test_loadbsw2_pcr();
+ test_loadbzw4_pcr();
+ test_loadbsw4_pcr();
+
+ puts(err ? "FAIL" : "PASS");
+ return err ? 1 : 0;
+}
diff --git a/tests/tcg/hexagon/misc.c b/tests/tcg/hexagon/misc.c
index 458759f..17c3919 100644
--- a/tests/tcg/hexagon/misc.c
+++ b/tests/tcg/hexagon/misc.c
@@ -231,6 +231,14 @@
}
}
+static void check64(long long val, long long expect)
+{
+ if (val != expect) {
+ printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect);
+ err++;
+ }
+}
+
uint32_t init[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
uint32_t array[10];
@@ -264,8 +272,36 @@
return retval;
}
+static long long decbin(long long x, long long y, int *pred)
+{
+ long long retval;
+ asm ("%0 = decbin(%2, %3)\n\t"
+ "%1 = p0\n\t"
+ : "=r"(retval), "=r"(*pred)
+ : "r"(x), "r"(y));
+ return retval;
+}
+
+/* Check that predicates are auto-and'ed in a packet */
+static int auto_and(void)
+{
+ int retval;
+ asm ("r5 = #1\n\t"
+ "{\n\t"
+ " p0 = cmp.eq(r1, #1)\n\t"
+ " p0 = cmp.eq(r1, #2)\n\t"
+ "}\n\t"
+ "%0 = p0\n\t"
+ : "=r"(retval)
+ :
+ : "r5", "p0");
+ return retval;
+}
+
int main()
{
+ long long res64;
+ int pred;
memcpy(array, init, sizeof(array));
S4_storerhnew_rr(array, 4, 0xffff);
@@ -375,6 +411,17 @@
res = test_clrtnew(2, 7);
check(res, 7);
+ res64 = decbin(0xf0f1f2f3f4f5f6f7LL, 0x7f6f5f4f3f2f1f0fLL, &pred);
+ check64(res64, 0x357980003700010cLL);
+ check(pred, 0);
+
+ res64 = decbin(0xfLL, 0x1bLL, &pred);
+ check64(res64, 0x78000100LL);
+ check(pred, 1);
+
+ res = auto_and();
+ check(res, 0);
+
puts(err ? "FAIL" : "PASS");
return err;
}
diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c
new file mode 100644
index 0000000..52997b3
--- /dev/null
+++ b/tests/tcg/hexagon/multi_result.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/>.
+ */
+
+#include <stdio.h>
+
+static int sfrecipa(int Rs, int Rt, int *pred_result)
+{
+ int result;
+ int predval;
+
+ asm volatile("%0,p0 = sfrecipa(%2, %3)\n\t"
+ "%1 = p0\n\t"
+ : "+r"(result), "=r"(predval)
+ : "r"(Rs), "r"(Rt)
+ : "p0");
+ *pred_result = predval;
+ return result;
+}
+
+static int sfinvsqrta(int Rs, int *pred_result)
+{
+ int result;
+ int predval;
+
+ asm volatile("%0,p0 = sfinvsqrta(%2)\n\t"
+ "%1 = p0\n\t"
+ : "+r"(result), "=r"(predval)
+ : "r"(Rs)
+ : "p0");
+ *pred_result = predval;
+ return result;
+}
+
+static long long vacsh(long long Rxx, long long Rss, long long Rtt,
+ int *pred_result, int *ovf_result)
+{
+ long long result = Rxx;
+ int predval;
+ int usr;
+
+ /*
+ * This instruction can set bit 0 (OVF/overflow) in usr
+ * Clear the bit first, then return that bit to the caller
+ */
+ asm volatile("r2 = usr\n\t"
+ "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
+ "usr = r2\n\t"
+ "%0,p0 = vacsh(%3, %4)\n\t"
+ "%1 = p0\n\t"
+ "%2 = usr\n\t"
+ : "+r"(result), "=r"(predval), "=r"(usr)
+ : "r"(Rss), "r"(Rtt)
+ : "r2", "p0", "usr");
+ *pred_result = predval;
+ *ovf_result = (usr & 1);
+ return result;
+}
+
+static long long vminub(long long Rtt, long long Rss,
+ int *pred_result)
+{
+ long long result;
+ int predval;
+
+ asm volatile("%0,p0 = vminub(%2, %3)\n\t"
+ "%1 = p0\n\t"
+ : "=r"(result), "=r"(predval)
+ : "r"(Rtt), "r"(Rss)
+ : "p0");
+ *pred_result = predval;
+ return result;
+}
+
+static long long add_carry(long long Rss, long long Rtt,
+ int pred_in, int *pred_result)
+{
+ long long result;
+ int predval = pred_in;
+
+ asm volatile("p0 = %1\n\t"
+ "%0 = add(%2, %3, p0):carry\n\t"
+ "%1 = p0\n\t"
+ : "=r"(result), "+r"(predval)
+ : "r"(Rss), "r"(Rtt)
+ : "p0");
+ *pred_result = predval;
+ return result;
+}
+
+static long long sub_carry(long long Rss, long long Rtt,
+ int pred_in, int *pred_result)
+{
+ long long result;
+ int predval = pred_in;
+
+ asm volatile("p0 = !cmp.eq(%1, #0)\n\t"
+ "%0 = sub(%2, %3, p0):carry\n\t"
+ "%1 = p0\n\t"
+ : "=r"(result), "+r"(predval)
+ : "r"(Rss), "r"(Rtt)
+ : "p0");
+ *pred_result = predval;
+ return result;
+}
+
+int err;
+
+static void check_ll(long long val, long long expect)
+{
+ if (val != expect) {
+ printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect);
+ err++;
+ }
+}
+
+static void check(int val, int expect)
+{
+ if (val != expect) {
+ printf("ERROR: 0x%08x != 0x%08x\n", val, expect);
+ err++;
+ }
+}
+
+static void check_p(int val, int expect)
+{
+ if (val != expect) {
+ printf("ERROR: 0x%02x != 0x%02x\n", val, expect);
+ err++;
+ }
+}
+
+static void test_sfrecipa()
+{
+ int res;
+ int pred_result;
+
+ res = sfrecipa(0x04030201, 0x05060708, &pred_result);
+ check(res, 0x59f38001);
+ check_p(pred_result, 0x00);
+}
+
+static void test_sfinvsqrta()
+{
+ int res;
+ int pred_result;
+
+ res = sfinvsqrta(0x04030201, &pred_result);
+ check(res, 0x4d330000);
+ check_p(pred_result, 0xe0);
+
+ res = sfinvsqrta(0x0, &pred_result);
+ check(res, 0x3f800000);
+ check_p(pred_result, 0x0);
+}
+
+static void test_vacsh()
+{
+ long long res64;
+ int pred_result;
+ int ovf_result;
+
+ res64 = vacsh(0x0004000300020001LL,
+ 0x0001000200030004LL,
+ 0x0000000000000000LL, &pred_result, &ovf_result);
+ check_ll(res64, 0x0004000300030004LL);
+ check_p(pred_result, 0xf0);
+ check(ovf_result, 0);
+
+ res64 = vacsh(0x0004000300020001LL,
+ 0x0001000200030004LL,
+ 0x000affff000d0000LL, &pred_result, &ovf_result);
+ check_ll(res64, 0x000e0003000f0004LL);
+ check_p(pred_result, 0xcc);
+ check(ovf_result, 0);
+
+ res64 = vacsh(0x00047fff00020001LL,
+ 0x00017fff00030004LL,
+ 0x000a0fff000d0000LL, &pred_result, &ovf_result);
+ check_ll(res64, 0x000e7fff000f0004LL);
+ check_p(pred_result, 0xfc);
+ check(ovf_result, 1);
+
+ res64 = vacsh(0x0004000300020001LL,
+ 0x0001000200030009LL,
+ 0x000affff000d0001LL, &pred_result, &ovf_result);
+ check_ll(res64, 0x000e0003000f0008LL);
+ check_p(pred_result, 0xcc);
+ check(ovf_result, 0);
+}
+
+static void test_vminub()
+{
+ long long res64;
+ int pred_result;
+
+ res64 = vminub(0x0807060504030201LL,
+ 0x0102030405060708LL,
+ &pred_result);
+ check_ll(res64, 0x0102030404030201LL);
+ check_p(pred_result, 0xf0);
+
+ res64 = vminub(0x0802060405030701LL,
+ 0x0107030504060208LL,
+ &pred_result);
+ check_ll(res64, 0x0102030404030201LL);
+ check_p(pred_result, 0xaa);
+}
+
+static void test_add_carry()
+{
+ long long res64;
+ int pred_result;
+
+ res64 = add_carry(0x0000000000000000LL,
+ 0xffffffffffffffffLL,
+ 1, &pred_result);
+ check_ll(res64, 0x0000000000000000LL);
+ check_p(pred_result, 0xff);
+
+ res64 = add_carry(0x0000000100000000LL,
+ 0xffffffffffffffffLL,
+ 0, &pred_result);
+ check_ll(res64, 0x00000000ffffffffLL);
+ check_p(pred_result, 0xff);
+
+ res64 = add_carry(0x0000000100000000LL,
+ 0xffffffffffffffffLL,
+ 0, &pred_result);
+ check_ll(res64, 0x00000000ffffffffLL);
+ check_p(pred_result, 0xff);
+}
+
+static void test_sub_carry()
+{
+ long long res64;
+ int pred_result;
+
+ res64 = sub_carry(0x0000000000000000LL,
+ 0x0000000000000000LL,
+ 1, &pred_result);
+ check_ll(res64, 0x0000000000000000LL);
+ check_p(pred_result, 0xff);
+
+ res64 = sub_carry(0x0000000100000000LL,
+ 0x0000000000000000LL,
+ 0, &pred_result);
+ check_ll(res64, 0x00000000ffffffffLL);
+ check_p(pred_result, 0xff);
+
+ res64 = sub_carry(0x0000000100000000LL,
+ 0x0000000000000000LL,
+ 0, &pred_result);
+ check_ll(res64, 0x00000000ffffffffLL);
+ check_p(pred_result, 0xff);
+}
+
+int main()
+{
+ test_sfrecipa();
+ test_sfinvsqrta();
+ test_vacsh();
+ test_vminub();
+ test_add_carry();
+ test_sub_carry();
+
+ puts(err ? "FAIL" : "PASS");
+ return err;
+}