mirror of https://github.com/xemu-project/xemu.git
First RISC-V PR for 8.2
* Remove 'host' CPU from TCG * riscv_htif Fixup printing on big endian hosts * Add zmmul isa string * Add smepmp isa string * Fix page_check_range use in fault-only-first * Use existing lookup tables for MixColumns * Add RISC-V vector cryptographic instruction set support * Implement WARL behaviour for mcountinhibit/mcounteren * Add Zihintntl extension ISA string to DTS * Fix zfa fleq.d and fltq.d * Fix upper/lower mtime write calculation * Make rtc variable names consistent * Use abi type for linux-user target_ucontext * Add RISC-V KVM AIA Support * Fix riscv,pmu DT node path in the virt machine * Update CSR bits name for svadu extension * Mark zicond non-experimental * Fix satp_mode_finalize() when satp_mode.supported = 0 * Fix non-KVM --enable-debug build * Add new extensions to hwprobe * Use accelerated helper for AES64KS1I * Allocate itrigger timers only once * Respect mseccfg.RLB for pmpaddrX changes * Align the AIA model to v1.0 ratified spec * Don't read the CSR in riscv_csrrw_do64 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmT+ttMACgkQr3yVEwxT gBN/rg/+KhOvL9xWSNb8pzlIsMQHLvndno0Sq5b9Rb/o5z1ekyYfyg6712N3JJpA TIfZzOIW7oYZV8gHyaBtOt8kIbrjwzGB2rpCh4blhm+yNZv7Ym9Ko6AVVzoUDo7k 2dWkLnC+52/l3SXGeyYMJOlgUUsQMwjD6ykDEr42P6DfVord34fpTH7ftwSasO9K 35qJQqhUCgB3fMzjKTYICN6Rm1UluijTjRNXUZXC0XZlr+UKw2jT/UsybbWVXyNs SmkRtF1MEVGvw+b8XOgA/nG1qVCWglTMcPvKjWMY+cY9WLM6/R9nXAV8OL/JPead v1LvROJNukfjNtDW6AOl5/svOJTRLbIrV5EO7Hlm1E4kftGmE5C+AKZZ/VT4ucUK XgqaHoXh26tFEymVjzbtyFnUHNv0zLuGelTnmc5Ps1byLSe4lT0dBaJy6Zizg0LE DpTR7s3LpyV3qB96Xf9bOMaTPsekUjD3dQI/3X634r36+YovRXapJDEDacN9whbU BSZc20NoM5UxVXFTbELQXolue/X2BRLxpzB+BDG8/cpu/MPgcCNiOZaVrr/pOo33 6rwwrBhLSCfYAXnJ52qTUEBz0Z/FnRPza8AU/uuRYRFk6JhUXIonmO6xkzsoNKuN QNnih/v1J+1XqUyyT2InOoAiTotzHiWgKZKaMfAhomt2j/slz+A= =aqcx -----END PGP SIGNATURE----- Merge tag 'pull-riscv-to-apply-20230911' of https://github.com/alistair23/qemu into staging First RISC-V PR for 8.2 * Remove 'host' CPU from TCG * riscv_htif Fixup printing on big endian hosts * Add zmmul isa string * Add smepmp isa string * Fix page_check_range use in fault-only-first * Use existing lookup tables for MixColumns * Add RISC-V vector cryptographic instruction set support * Implement WARL behaviour for mcountinhibit/mcounteren * Add Zihintntl extension ISA string to DTS * Fix zfa fleq.d and fltq.d * Fix upper/lower mtime write calculation * Make rtc variable names consistent * Use abi type for linux-user target_ucontext * Add RISC-V KVM AIA Support * Fix riscv,pmu DT node path in the virt machine * Update CSR bits name for svadu extension * Mark zicond non-experimental * Fix satp_mode_finalize() when satp_mode.supported = 0 * Fix non-KVM --enable-debug build * Add new extensions to hwprobe * Use accelerated helper for AES64KS1I * Allocate itrigger timers only once * Respect mseccfg.RLB for pmpaddrX changes * Align the AIA model to v1.0 ratified spec * Don't read the CSR in riscv_csrrw_do64 # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmT+ttMACgkQr3yVEwxT # gBN/rg/+KhOvL9xWSNb8pzlIsMQHLvndno0Sq5b9Rb/o5z1ekyYfyg6712N3JJpA # TIfZzOIW7oYZV8gHyaBtOt8kIbrjwzGB2rpCh4blhm+yNZv7Ym9Ko6AVVzoUDo7k # 2dWkLnC+52/l3SXGeyYMJOlgUUsQMwjD6ykDEr42P6DfVord34fpTH7ftwSasO9K # 35qJQqhUCgB3fMzjKTYICN6Rm1UluijTjRNXUZXC0XZlr+UKw2jT/UsybbWVXyNs # SmkRtF1MEVGvw+b8XOgA/nG1qVCWglTMcPvKjWMY+cY9WLM6/R9nXAV8OL/JPead # v1LvROJNukfjNtDW6AOl5/svOJTRLbIrV5EO7Hlm1E4kftGmE5C+AKZZ/VT4ucUK # XgqaHoXh26tFEymVjzbtyFnUHNv0zLuGelTnmc5Ps1byLSe4lT0dBaJy6Zizg0LE # DpTR7s3LpyV3qB96Xf9bOMaTPsekUjD3dQI/3X634r36+YovRXapJDEDacN9whbU # BSZc20NoM5UxVXFTbELQXolue/X2BRLxpzB+BDG8/cpu/MPgcCNiOZaVrr/pOo33 # 6rwwrBhLSCfYAXnJ52qTUEBz0Z/FnRPza8AU/uuRYRFk6JhUXIonmO6xkzsoNKuN # QNnih/v1J+1XqUyyT2InOoAiTotzHiWgKZKaMfAhomt2j/slz+A= # =aqcx # -----END PGP SIGNATURE----- # gpg: Signature made Mon 11 Sep 2023 02:42:27 EDT # gpg: using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6AE9 02B6 A7CA 877D 6D65 9296 AF7C 9513 0C53 8013 * tag 'pull-riscv-to-apply-20230911' of https://github.com/alistair23/qemu: (45 commits) target/riscv: don't read CSR in riscv_csrrw_do64 target/riscv: Align the AIA model to v1.0 ratified spec target/riscv/pmp.c: respect mseccfg.RLB for pmpaddrX changes target/riscv: Allocate itrigger timers only once target/riscv: Use accelerated helper for AES64KS1I linux-user/riscv: Add new extensions to hwprobe hw/intc/riscv_aplic.c fix non-KVM --enable-debug build hw/riscv/virt.c: fix non-KVM --enable-debug build riscv: zicond: make non-experimental target/riscv: fix satp_mode_finalize() when satp_mode.supported = 0 target/riscv: Update CSR bits name for svadu extension hw/riscv: virt: Fix riscv,pmu DT node path target/riscv: select KVM AIA in riscv virt machine target/riscv: update APLIC and IMSIC to support KVM AIA target/riscv: Create an KVM AIA irqchip target/riscv: check the in-kernel irqchip support target/riscv: support the AIA device emulation with KVM enabled linux-user/riscv: Use abi type for target_ucontext hw/intc: Make rtc variable names consistent hw/intc: Fix upper/lower mtime write calculation ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
cb6c406e26
|
@ -272,7 +272,7 @@ AES_Td3[x] = Si[x].[09, 0d, 0b, 0e];
|
|||
AES_Td4[x] = Si[x].[01, 01, 01, 01];
|
||||
*/
|
||||
|
||||
static const uint32_t AES_Te0[256] = {
|
||||
const uint32_t AES_Te0[256] = {
|
||||
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
|
||||
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
|
||||
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
|
||||
|
@ -607,7 +607,7 @@ static const uint32_t AES_Te4[256] = {
|
|||
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Td0[256] = {
|
||||
const uint32_t AES_Td0[256] = {
|
||||
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
|
||||
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
|
||||
0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
|
||||
|
|
10
crypto/sm4.c
10
crypto/sm4.c
|
@ -47,3 +47,13 @@ uint8_t const sm4_sbox[] = {
|
|||
0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
|
||||
};
|
||||
|
||||
uint32_t const sm4_ck[] = {
|
||||
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
|
||||
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
|
||||
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
|
||||
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
|
||||
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
|
||||
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
|
||||
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
|
||||
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "qemu/timer.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/tswap.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#define RISCV_DEBUG_HTIF 0
|
||||
|
@ -209,11 +210,11 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
|
|||
} else {
|
||||
uint64_t syscall[8];
|
||||
cpu_physical_memory_read(payload, syscall, sizeof(syscall));
|
||||
if (syscall[0] == PK_SYS_WRITE &&
|
||||
syscall[1] == HTIF_DEV_CONSOLE &&
|
||||
syscall[3] == HTIF_CONSOLE_CMD_PUTC) {
|
||||
if (tswap64(syscall[0]) == PK_SYS_WRITE &&
|
||||
tswap64(syscall[1]) == HTIF_DEV_CONSOLE &&
|
||||
tswap64(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
|
||||
uint8_t ch;
|
||||
cpu_physical_memory_read(syscall[2], &ch, 1);
|
||||
cpu_physical_memory_read(tswap64(syscall[2]), &ch, 1);
|
||||
qemu_chr_fe_write(&s->chr, &ch, 1);
|
||||
resp = 0x100 | (uint8_t)payload;
|
||||
} else {
|
||||
|
@ -232,7 +233,8 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
|
|||
s->tohost = 0; /* clear to indicate we read */
|
||||
return;
|
||||
} else if (cmd == HTIF_CONSOLE_CMD_PUTC) {
|
||||
qemu_chr_fe_write(&s->chr, (uint8_t *)&payload, 1);
|
||||
uint8_t ch = (uint8_t)payload;
|
||||
qemu_chr_fe_write(&s->chr, &ch, 1);
|
||||
resp = 0x100 | (uint8_t)payload;
|
||||
} else {
|
||||
qemu_log("HTIF device %d: unknown command\n", device);
|
||||
|
|
|
@ -64,13 +64,13 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
|
|||
uint64_t next;
|
||||
uint64_t diff;
|
||||
|
||||
uint64_t rtc_r = cpu_riscv_read_rtc(mtimer);
|
||||
uint64_t rtc = cpu_riscv_read_rtc(mtimer);
|
||||
|
||||
/* Compute the relative hartid w.r.t the socket */
|
||||
hartid = hartid - mtimer->hartid_base;
|
||||
|
||||
mtimer->timecmp[hartid] = value;
|
||||
if (mtimer->timecmp[hartid] <= rtc_r) {
|
||||
if (mtimer->timecmp[hartid] <= rtc) {
|
||||
/*
|
||||
* If we're setting an MTIMECMP value in the "past",
|
||||
* immediately raise the timer interrupt
|
||||
|
@ -81,7 +81,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
|
|||
|
||||
/* otherwise, set up the future timer interrupt */
|
||||
qemu_irq_lower(mtimer->timer_irqs[hartid]);
|
||||
diff = mtimer->timecmp[hartid] - rtc_r;
|
||||
diff = mtimer->timecmp[hartid] - rtc;
|
||||
/* back to ns (note args switched in muldiv64) */
|
||||
uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
|
||||
|
||||
|
@ -208,11 +208,12 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
return;
|
||||
} else if (addr == mtimer->time_base || addr == mtimer->time_base + 4) {
|
||||
uint64_t rtc_r = cpu_riscv_read_rtc_raw(mtimer->timebase_freq);
|
||||
uint64_t rtc = cpu_riscv_read_rtc(mtimer);
|
||||
|
||||
if (addr == mtimer->time_base) {
|
||||
if (size == 4) {
|
||||
/* time_lo for RV32/RV64 */
|
||||
mtimer->time_delta = ((rtc_r & ~0xFFFFFFFFULL) | value) - rtc_r;
|
||||
mtimer->time_delta = ((rtc & ~0xFFFFFFFFULL) | value) - rtc_r;
|
||||
} else {
|
||||
/* time for RV64 */
|
||||
mtimer->time_delta = value - rtc_r;
|
||||
|
@ -220,7 +221,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
} else {
|
||||
if (size == 4) {
|
||||
/* time_hi for RV32/RV64 */
|
||||
mtimer->time_delta = (value << 32 | (rtc_r & 0xFFFFFFFF)) - rtc_r;
|
||||
mtimer->time_delta = (value << 32 | (rtc & 0xFFFFFFFF)) - rtc_r;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"aclint-mtimer: invalid time_hi write: %08x",
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "hw/irq.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_riscv.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define APLIC_MAX_IDC (1UL << 14)
|
||||
|
@ -148,6 +150,15 @@
|
|||
|
||||
#define APLIC_IDC_CLAIMI 0x1c
|
||||
|
||||
/*
|
||||
* KVM AIA only supports APLIC MSI, fallback to QEMU emulation if we want to use
|
||||
* APLIC Wired.
|
||||
*/
|
||||
static bool is_kvm_aia(bool msimode)
|
||||
{
|
||||
return kvm_irqchip_in_kernel() && msimode;
|
||||
}
|
||||
|
||||
static uint32_t riscv_aplic_read_input_word(RISCVAPLICState *aplic,
|
||||
uint32_t word)
|
||||
{
|
||||
|
@ -801,29 +812,35 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
|
|||
uint32_t i;
|
||||
RISCVAPLICState *aplic = RISCV_APLIC(dev);
|
||||
|
||||
aplic->bitfield_words = (aplic->num_irqs + 31) >> 5;
|
||||
aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
|
||||
aplic->state = g_new0(uint32_t, aplic->num_irqs);
|
||||
aplic->target = g_new0(uint32_t, aplic->num_irqs);
|
||||
if (!aplic->msimode) {
|
||||
for (i = 0; i < aplic->num_irqs; i++) {
|
||||
aplic->target[i] = 1;
|
||||
if (!is_kvm_aia(aplic->msimode)) {
|
||||
aplic->bitfield_words = (aplic->num_irqs + 31) >> 5;
|
||||
aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
|
||||
aplic->state = g_new0(uint32_t, aplic->num_irqs);
|
||||
aplic->target = g_new0(uint32_t, aplic->num_irqs);
|
||||
if (!aplic->msimode) {
|
||||
for (i = 0; i < aplic->num_irqs; i++) {
|
||||
aplic->target[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
|
||||
aplic->iforce = g_new0(uint32_t, aplic->num_harts);
|
||||
aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
|
||||
aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
|
||||
aplic->iforce = g_new0(uint32_t, aplic->num_harts);
|
||||
aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
|
||||
|
||||
memory_region_init_io(&aplic->mmio, OBJECT(dev), &riscv_aplic_ops, aplic,
|
||||
TYPE_RISCV_APLIC, aplic->aperture_size);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &aplic->mmio);
|
||||
memory_region_init_io(&aplic->mmio, OBJECT(dev), &riscv_aplic_ops,
|
||||
aplic, TYPE_RISCV_APLIC, aplic->aperture_size);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &aplic->mmio);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only root APLICs have hardware IRQ lines. All non-root APLICs
|
||||
* have IRQ lines delegated by their parent APLIC.
|
||||
*/
|
||||
if (!aplic->parent) {
|
||||
qdev_init_gpio_in(dev, riscv_aplic_request, aplic->num_irqs);
|
||||
if (kvm_enabled() && is_kvm_aia(aplic->msimode)) {
|
||||
qdev_init_gpio_in(dev, riscv_kvm_aplic_request, aplic->num_irqs);
|
||||
} else {
|
||||
qdev_init_gpio_in(dev, riscv_aplic_request, aplic->num_irqs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create output IRQ lines for non-MSI mode */
|
||||
|
@ -958,7 +975,10 @@ DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size,
|
|||
qdev_prop_set_bit(dev, "mmode", mmode);
|
||||
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
|
||||
if (!is_kvm_aia(msimode)) {
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
riscv_aplic_add_child(parent, dev);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "target/riscv/cpu.h"
|
||||
#include "target/riscv/cpu_bits.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define IMSIC_MMIO_PAGE_LE 0x00
|
||||
|
@ -283,6 +284,20 @@ static void riscv_imsic_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
goto err;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_KVM)
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
struct kvm_msi msi;
|
||||
|
||||
msi.address_lo = extract64(imsic->mmio.addr + addr, 0, 32);
|
||||
msi.address_hi = extract64(imsic->mmio.addr + addr, 32, 32);
|
||||
msi.data = le32_to_cpu(value);
|
||||
|
||||
kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Writes only supported for MSI little-endian registers */
|
||||
page = addr >> IMSIC_MMIO_PAGE_SHIFT;
|
||||
if ((addr & (IMSIC_MMIO_PAGE_SZ - 1)) == IMSIC_MMIO_PAGE_LE) {
|
||||
|
@ -320,10 +335,12 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp)
|
|||
CPUState *cpu = cpu_by_arch_id(imsic->hartid);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
|
||||
imsic->num_eistate = imsic->num_pages * imsic->num_irqs;
|
||||
imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
|
||||
imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
|
||||
imsic->eistate = g_new0(uint32_t, imsic->num_eistate);
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
imsic->num_eistate = imsic->num_pages * imsic->num_irqs;
|
||||
imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
|
||||
imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
|
||||
imsic->eistate = g_new0(uint32_t, imsic->num_eistate);
|
||||
}
|
||||
|
||||
memory_region_init_io(&imsic->mmio, OBJECT(dev), &riscv_imsic_ops,
|
||||
imsic, TYPE_RISCV_IMSIC,
|
||||
|
|
386
hw/riscv/virt.c
386
hw/riscv/virt.c
|
@ -35,6 +35,7 @@
|
|||
#include "hw/riscv/virt.h"
|
||||
#include "hw/riscv/boot.h"
|
||||
#include "hw/riscv/numa.h"
|
||||
#include "kvm_riscv.h"
|
||||
#include "hw/intc/riscv_aclint.h"
|
||||
#include "hw/intc/riscv_aplic.h"
|
||||
#include "hw/intc/riscv_imsic.h"
|
||||
|
@ -75,6 +76,12 @@
|
|||
#error "Can't accommodate all IMSIC groups in address space"
|
||||
#endif
|
||||
|
||||
/* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */
|
||||
static bool virt_use_kvm_aia(RISCVVirtState *s)
|
||||
{
|
||||
return kvm_irqchip_in_kernel() && s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
|
||||
}
|
||||
|
||||
static const MemMapEntry virt_memmap[] = {
|
||||
[VIRT_DEBUG] = { 0x0, 0x100 },
|
||||
[VIRT_MROM] = { 0x1000, 0xf000 },
|
||||
|
@ -516,79 +523,28 @@ static uint32_t imsic_num_bits(uint32_t count)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
uint32_t *phandle, uint32_t *intc_phandles,
|
||||
uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
|
||||
static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr,
|
||||
uint32_t *intc_phandles, uint32_t msi_phandle,
|
||||
bool m_mode, uint32_t imsic_guest_bits)
|
||||
{
|
||||
int cpu, socket;
|
||||
char *imsic_name;
|
||||
MachineState *ms = MACHINE(s);
|
||||
int socket_count = riscv_socket_count(ms);
|
||||
uint32_t imsic_max_hart_per_socket, imsic_guest_bits;
|
||||
uint32_t imsic_max_hart_per_socket;
|
||||
uint32_t *imsic_cells, *imsic_regs, imsic_addr, imsic_size;
|
||||
|
||||
*msi_m_phandle = (*phandle)++;
|
||||
*msi_s_phandle = (*phandle)++;
|
||||
imsic_cells = g_new0(uint32_t, ms->smp.cpus * 2);
|
||||
imsic_regs = g_new0(uint32_t, socket_count * 4);
|
||||
|
||||
/* M-level IMSIC node */
|
||||
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
||||
imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT);
|
||||
imsic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
|
||||
}
|
||||
|
||||
imsic_max_hart_per_socket = 0;
|
||||
for (socket = 0; socket < socket_count; socket++) {
|
||||
imsic_addr = memmap[VIRT_IMSIC_M].base +
|
||||
socket * VIRT_IMSIC_GROUP_MAX_SIZE;
|
||||
imsic_size = IMSIC_HART_SIZE(0) * s->soc[socket].num_harts;
|
||||
imsic_regs[socket * 4 + 0] = 0;
|
||||
imsic_regs[socket * 4 + 1] = cpu_to_be32(imsic_addr);
|
||||
imsic_regs[socket * 4 + 2] = 0;
|
||||
imsic_regs[socket * 4 + 3] = cpu_to_be32(imsic_size);
|
||||
if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
|
||||
imsic_max_hart_per_socket = s->soc[socket].num_harts;
|
||||
}
|
||||
}
|
||||
imsic_name = g_strdup_printf("/soc/imsics@%lx",
|
||||
(unsigned long)memmap[VIRT_IMSIC_M].base);
|
||||
qemu_fdt_add_subnode(ms->fdt, imsic_name);
|
||||
qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible",
|
||||
"riscv,imsics");
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells",
|
||||
FDT_IMSIC_INT_CELLS);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller",
|
||||
NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller",
|
||||
NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended",
|
||||
imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs,
|
||||
socket_count * sizeof(uint32_t) * 4);
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids",
|
||||
VIRT_IRQCHIP_NUM_MSIS);
|
||||
if (socket_count > 1) {
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits",
|
||||
imsic_num_bits(imsic_max_hart_per_socket));
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits",
|
||||
imsic_num_bits(socket_count));
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift",
|
||||
IMSIC_MMIO_GROUP_MIN_SHIFT);
|
||||
}
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", *msi_m_phandle);
|
||||
|
||||
g_free(imsic_name);
|
||||
|
||||
/* S-level IMSIC node */
|
||||
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
||||
imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
|
||||
}
|
||||
imsic_guest_bits = imsic_num_bits(s->aia_guests + 1);
|
||||
imsic_max_hart_per_socket = 0;
|
||||
for (socket = 0; socket < socket_count; socket++) {
|
||||
imsic_addr = memmap[VIRT_IMSIC_S].base +
|
||||
socket * VIRT_IMSIC_GROUP_MAX_SIZE;
|
||||
imsic_addr = base_addr + socket * VIRT_IMSIC_GROUP_MAX_SIZE;
|
||||
imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) *
|
||||
s->soc[socket].num_harts;
|
||||
imsic_regs[socket * 4 + 0] = 0;
|
||||
|
@ -599,119 +555,151 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
imsic_max_hart_per_socket = s->soc[socket].num_harts;
|
||||
}
|
||||
}
|
||||
imsic_name = g_strdup_printf("/soc/imsics@%lx",
|
||||
(unsigned long)memmap[VIRT_IMSIC_S].base);
|
||||
|
||||
imsic_name = g_strdup_printf("/soc/imsics@%lx", (unsigned long)base_addr);
|
||||
qemu_fdt_add_subnode(ms->fdt, imsic_name);
|
||||
qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible",
|
||||
"riscv,imsics");
|
||||
qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible", "riscv,imsics");
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells",
|
||||
FDT_IMSIC_INT_CELLS);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller",
|
||||
NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller",
|
||||
NULL, 0);
|
||||
FDT_IMSIC_INT_CELLS);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended",
|
||||
imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2);
|
||||
imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2);
|
||||
qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs,
|
||||
socket_count * sizeof(uint32_t) * 4);
|
||||
socket_count * sizeof(uint32_t) * 4);
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids",
|
||||
VIRT_IRQCHIP_NUM_MSIS);
|
||||
VIRT_IRQCHIP_NUM_MSIS);
|
||||
|
||||
if (imsic_guest_bits) {
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,guest-index-bits",
|
||||
imsic_guest_bits);
|
||||
imsic_guest_bits);
|
||||
}
|
||||
|
||||
if (socket_count > 1) {
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits",
|
||||
imsic_num_bits(imsic_max_hart_per_socket));
|
||||
imsic_num_bits(imsic_max_hart_per_socket));
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits",
|
||||
imsic_num_bits(socket_count));
|
||||
imsic_num_bits(socket_count));
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift",
|
||||
IMSIC_MMIO_GROUP_MIN_SHIFT);
|
||||
IMSIC_MMIO_GROUP_MIN_SHIFT);
|
||||
}
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", *msi_s_phandle);
|
||||
g_free(imsic_name);
|
||||
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle);
|
||||
|
||||
g_free(imsic_name);
|
||||
g_free(imsic_regs);
|
||||
g_free(imsic_cells);
|
||||
}
|
||||
|
||||
static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
uint32_t *phandle, uint32_t *intc_phandles,
|
||||
uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
|
||||
{
|
||||
*msi_m_phandle = (*phandle)++;
|
||||
*msi_s_phandle = (*phandle)++;
|
||||
|
||||
if (!kvm_enabled()) {
|
||||
/* M-level IMSIC node */
|
||||
create_fdt_one_imsic(s, memmap[VIRT_IMSIC_M].base, intc_phandles,
|
||||
*msi_m_phandle, true, 0);
|
||||
}
|
||||
|
||||
/* S-level IMSIC node */
|
||||
create_fdt_one_imsic(s, memmap[VIRT_IMSIC_S].base, intc_phandles,
|
||||
*msi_s_phandle, false,
|
||||
imsic_num_bits(s->aia_guests + 1));
|
||||
|
||||
}
|
||||
|
||||
static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
|
||||
unsigned long aplic_addr, uint32_t aplic_size,
|
||||
uint32_t msi_phandle,
|
||||
uint32_t *intc_phandles,
|
||||
uint32_t aplic_phandle,
|
||||
uint32_t aplic_child_phandle,
|
||||
bool m_mode, int num_harts)
|
||||
{
|
||||
int cpu;
|
||||
char *aplic_name;
|
||||
uint32_t *aplic_cells;
|
||||
MachineState *ms = MACHINE(s);
|
||||
|
||||
aplic_cells = g_new0(uint32_t, num_harts * 2);
|
||||
|
||||
for (cpu = 0; cpu < num_harts; cpu++) {
|
||||
aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
|
||||
}
|
||||
|
||||
aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr);
|
||||
qemu_fdt_add_subnode(ms->fdt, aplic_name);
|
||||
qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic");
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name,
|
||||
"#interrupt-cells", FDT_APLIC_INT_CELLS);
|
||||
qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
|
||||
|
||||
if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
|
||||
qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
|
||||
aplic_cells, num_harts * sizeof(uint32_t) * 2);
|
||||
} else {
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_phandle);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg",
|
||||
0x0, aplic_addr, 0x0, aplic_size);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
|
||||
VIRT_IRQCHIP_NUM_SOURCES);
|
||||
|
||||
if (aplic_child_phandle) {
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
|
||||
aplic_child_phandle);
|
||||
qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate",
|
||||
aplic_child_phandle, 0x1,
|
||||
VIRT_IRQCHIP_NUM_SOURCES);
|
||||
}
|
||||
|
||||
riscv_socket_fdt_write_id(ms, aplic_name, socket);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_phandle);
|
||||
|
||||
g_free(aplic_name);
|
||||
g_free(aplic_cells);
|
||||
}
|
||||
|
||||
static void create_fdt_socket_aplic(RISCVVirtState *s,
|
||||
const MemMapEntry *memmap, int socket,
|
||||
uint32_t msi_m_phandle,
|
||||
uint32_t msi_s_phandle,
|
||||
uint32_t *phandle,
|
||||
uint32_t *intc_phandles,
|
||||
uint32_t *aplic_phandles)
|
||||
uint32_t *aplic_phandles,
|
||||
int num_harts)
|
||||
{
|
||||
int cpu;
|
||||
char *aplic_name;
|
||||
uint32_t *aplic_cells;
|
||||
unsigned long aplic_addr;
|
||||
MachineState *ms = MACHINE(s);
|
||||
uint32_t aplic_m_phandle, aplic_s_phandle;
|
||||
|
||||
aplic_m_phandle = (*phandle)++;
|
||||
aplic_s_phandle = (*phandle)++;
|
||||
aplic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
|
||||
|
||||
/* M-level APLIC node */
|
||||
for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
|
||||
aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
aplic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT);
|
||||
if (!kvm_enabled()) {
|
||||
/* M-level APLIC node */
|
||||
aplic_addr = memmap[VIRT_APLIC_M].base +
|
||||
(memmap[VIRT_APLIC_M].size * socket);
|
||||
create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_M].size,
|
||||
msi_m_phandle, intc_phandles,
|
||||
aplic_m_phandle, aplic_s_phandle,
|
||||
true, num_harts);
|
||||
}
|
||||
aplic_addr = memmap[VIRT_APLIC_M].base +
|
||||
(memmap[VIRT_APLIC_M].size * socket);
|
||||
aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr);
|
||||
qemu_fdt_add_subnode(ms->fdt, aplic_name);
|
||||
qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic");
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name,
|
||||
"#interrupt-cells", FDT_APLIC_INT_CELLS);
|
||||
qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
|
||||
if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
|
||||
qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
|
||||
aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2);
|
||||
} else {
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent",
|
||||
msi_m_phandle);
|
||||
}
|
||||
qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg",
|
||||
0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_M].size);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
|
||||
VIRT_IRQCHIP_NUM_SOURCES);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
|
||||
aplic_s_phandle);
|
||||
qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate",
|
||||
aplic_s_phandle, 0x1, VIRT_IRQCHIP_NUM_SOURCES);
|
||||
riscv_socket_fdt_write_id(ms, aplic_name, socket);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_m_phandle);
|
||||
g_free(aplic_name);
|
||||
|
||||
/* S-level APLIC node */
|
||||
for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
|
||||
aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
aplic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
|
||||
}
|
||||
aplic_addr = memmap[VIRT_APLIC_S].base +
|
||||
(memmap[VIRT_APLIC_S].size * socket);
|
||||
create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_S].size,
|
||||
msi_s_phandle, intc_phandles,
|
||||
aplic_s_phandle, 0,
|
||||
false, num_harts);
|
||||
|
||||
aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr);
|
||||
qemu_fdt_add_subnode(ms->fdt, aplic_name);
|
||||
qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic");
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name,
|
||||
"#interrupt-cells", FDT_APLIC_INT_CELLS);
|
||||
qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
|
||||
if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
|
||||
qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
|
||||
aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2);
|
||||
} else {
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent",
|
||||
msi_s_phandle);
|
||||
}
|
||||
qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg",
|
||||
0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_S].size);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
|
||||
VIRT_IRQCHIP_NUM_SOURCES);
|
||||
riscv_socket_fdt_write_id(ms, aplic_name, socket);
|
||||
qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_s_phandle);
|
||||
|
||||
if (!socket) {
|
||||
platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
|
||||
|
@ -722,7 +710,6 @@ static void create_fdt_socket_aplic(RISCVVirtState *s,
|
|||
|
||||
g_free(aplic_name);
|
||||
|
||||
g_free(aplic_cells);
|
||||
aplic_phandles[socket] = aplic_s_phandle;
|
||||
}
|
||||
|
||||
|
@ -732,7 +719,7 @@ static void create_fdt_pmu(RISCVVirtState *s)
|
|||
MachineState *ms = MACHINE(s);
|
||||
RISCVCPU hart = s->soc[0].harts[0];
|
||||
|
||||
pmu_name = g_strdup_printf("/soc/pmu");
|
||||
pmu_name = g_strdup_printf("/pmu");
|
||||
qemu_fdt_add_subnode(ms->fdt, pmu_name);
|
||||
qemu_fdt_setprop_string(ms->fdt, pmu_name, "compatible", "riscv,pmu");
|
||||
riscv_pmu_generate_fdt_node(ms->fdt, hart.cfg.pmu_num, pmu_name);
|
||||
|
@ -794,34 +781,51 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
*msi_pcie_phandle = msi_s_phandle;
|
||||
}
|
||||
|
||||
phandle_pos = ms->smp.cpus;
|
||||
for (socket = (socket_count - 1); socket >= 0; socket--) {
|
||||
phandle_pos -= s->soc[socket].num_harts;
|
||||
/* KVM AIA only has one APLIC instance */
|
||||
if (kvm_enabled() && virt_use_kvm_aia(s)) {
|
||||
create_fdt_socket_aplic(s, memmap, 0,
|
||||
msi_m_phandle, msi_s_phandle, phandle,
|
||||
&intc_phandles[0], xplic_phandles,
|
||||
ms->smp.cpus);
|
||||
} else {
|
||||
phandle_pos = ms->smp.cpus;
|
||||
for (socket = (socket_count - 1); socket >= 0; socket--) {
|
||||
phandle_pos -= s->soc[socket].num_harts;
|
||||
|
||||
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
|
||||
create_fdt_socket_plic(s, memmap, socket, phandle,
|
||||
&intc_phandles[phandle_pos], xplic_phandles);
|
||||
} else {
|
||||
create_fdt_socket_aplic(s, memmap, socket,
|
||||
msi_m_phandle, msi_s_phandle, phandle,
|
||||
&intc_phandles[phandle_pos], xplic_phandles);
|
||||
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
|
||||
create_fdt_socket_plic(s, memmap, socket, phandle,
|
||||
&intc_phandles[phandle_pos],
|
||||
xplic_phandles);
|
||||
} else {
|
||||
create_fdt_socket_aplic(s, memmap, socket,
|
||||
msi_m_phandle, msi_s_phandle, phandle,
|
||||
&intc_phandles[phandle_pos],
|
||||
xplic_phandles,
|
||||
s->soc[socket].num_harts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free(intc_phandles);
|
||||
|
||||
for (socket = 0; socket < socket_count; socket++) {
|
||||
if (socket == 0) {
|
||||
*irq_mmio_phandle = xplic_phandles[socket];
|
||||
*irq_virtio_phandle = xplic_phandles[socket];
|
||||
*irq_pcie_phandle = xplic_phandles[socket];
|
||||
}
|
||||
if (socket == 1) {
|
||||
*irq_virtio_phandle = xplic_phandles[socket];
|
||||
*irq_pcie_phandle = xplic_phandles[socket];
|
||||
}
|
||||
if (socket == 2) {
|
||||
*irq_pcie_phandle = xplic_phandles[socket];
|
||||
if (kvm_enabled() && virt_use_kvm_aia(s)) {
|
||||
*irq_mmio_phandle = xplic_phandles[0];
|
||||
*irq_virtio_phandle = xplic_phandles[0];
|
||||
*irq_pcie_phandle = xplic_phandles[0];
|
||||
} else {
|
||||
for (socket = 0; socket < socket_count; socket++) {
|
||||
if (socket == 0) {
|
||||
*irq_mmio_phandle = xplic_phandles[socket];
|
||||
*irq_virtio_phandle = xplic_phandles[socket];
|
||||
*irq_pcie_phandle = xplic_phandles[socket];
|
||||
}
|
||||
if (socket == 1) {
|
||||
*irq_virtio_phandle = xplic_phandles[socket];
|
||||
*irq_pcie_phandle = xplic_phandles[socket];
|
||||
}
|
||||
if (socket == 2) {
|
||||
*irq_pcie_phandle = xplic_phandles[socket];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1163,16 +1167,20 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
|
|||
int i;
|
||||
hwaddr addr;
|
||||
uint32_t guest_bits;
|
||||
DeviceState *aplic_m;
|
||||
bool msimode = (aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) ? true : false;
|
||||
DeviceState *aplic_s = NULL;
|
||||
DeviceState *aplic_m = NULL;
|
||||
bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
|
||||
|
||||
if (msimode) {
|
||||
/* Per-socket M-level IMSICs */
|
||||
addr = memmap[VIRT_IMSIC_M].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE;
|
||||
for (i = 0; i < hart_count; i++) {
|
||||
riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
|
||||
base_hartid + i, true, 1,
|
||||
VIRT_IRQCHIP_NUM_MSIS);
|
||||
if (!kvm_enabled()) {
|
||||
/* Per-socket M-level IMSICs */
|
||||
addr = memmap[VIRT_IMSIC_M].base +
|
||||
socket * VIRT_IMSIC_GROUP_MAX_SIZE;
|
||||
for (i = 0; i < hart_count; i++) {
|
||||
riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
|
||||
base_hartid + i, true, 1,
|
||||
VIRT_IRQCHIP_NUM_MSIS);
|
||||
}
|
||||
}
|
||||
|
||||
/* Per-socket S-level IMSICs */
|
||||
|
@ -1185,29 +1193,29 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
|
|||
}
|
||||
}
|
||||
|
||||
/* Per-socket M-level APLIC */
|
||||
aplic_m = riscv_aplic_create(
|
||||
memmap[VIRT_APLIC_M].base + socket * memmap[VIRT_APLIC_M].size,
|
||||
memmap[VIRT_APLIC_M].size,
|
||||
(msimode) ? 0 : base_hartid,
|
||||
(msimode) ? 0 : hart_count,
|
||||
VIRT_IRQCHIP_NUM_SOURCES,
|
||||
VIRT_IRQCHIP_NUM_PRIO_BITS,
|
||||
msimode, true, NULL);
|
||||
|
||||
if (aplic_m) {
|
||||
/* Per-socket S-level APLIC */
|
||||
riscv_aplic_create(
|
||||
memmap[VIRT_APLIC_S].base + socket * memmap[VIRT_APLIC_S].size,
|
||||
memmap[VIRT_APLIC_S].size,
|
||||
(msimode) ? 0 : base_hartid,
|
||||
(msimode) ? 0 : hart_count,
|
||||
VIRT_IRQCHIP_NUM_SOURCES,
|
||||
VIRT_IRQCHIP_NUM_PRIO_BITS,
|
||||
msimode, false, aplic_m);
|
||||
if (!kvm_enabled()) {
|
||||
/* Per-socket M-level APLIC */
|
||||
aplic_m = riscv_aplic_create(memmap[VIRT_APLIC_M].base +
|
||||
socket * memmap[VIRT_APLIC_M].size,
|
||||
memmap[VIRT_APLIC_M].size,
|
||||
(msimode) ? 0 : base_hartid,
|
||||
(msimode) ? 0 : hart_count,
|
||||
VIRT_IRQCHIP_NUM_SOURCES,
|
||||
VIRT_IRQCHIP_NUM_PRIO_BITS,
|
||||
msimode, true, NULL);
|
||||
}
|
||||
|
||||
return aplic_m;
|
||||
/* Per-socket S-level APLIC */
|
||||
aplic_s = riscv_aplic_create(memmap[VIRT_APLIC_S].base +
|
||||
socket * memmap[VIRT_APLIC_S].size,
|
||||
memmap[VIRT_APLIC_S].size,
|
||||
(msimode) ? 0 : base_hartid,
|
||||
(msimode) ? 0 : hart_count,
|
||||
VIRT_IRQCHIP_NUM_SOURCES,
|
||||
VIRT_IRQCHIP_NUM_PRIO_BITS,
|
||||
msimode, false, aplic_m);
|
||||
|
||||
return kvm_enabled() ? aplic_s : aplic_m;
|
||||
}
|
||||
|
||||
static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
|
||||
|
@ -1453,6 +1461,14 @@ static void virt_machine_init(MachineState *machine)
|
|||
}
|
||||
}
|
||||
|
||||
if (kvm_enabled() && virt_use_kvm_aia(s)) {
|
||||
kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT,
|
||||
VIRT_IRQCHIP_NUM_SOURCES, VIRT_IRQCHIP_NUM_MSIS,
|
||||
memmap[VIRT_APLIC_S].base,
|
||||
memmap[VIRT_IMSIC_S].base,
|
||||
s->aia_guests);
|
||||
}
|
||||
|
||||
if (riscv_is_32bit(&s->soc[0])) {
|
||||
#if HOST_LONG_BITS == 64
|
||||
/* limit RAM size in a 32-bit system */
|
||||
|
|
|
@ -30,4 +30,11 @@ void AES_decrypt(const unsigned char *in, unsigned char *out,
|
|||
extern const uint8_t AES_sbox[256];
|
||||
extern const uint8_t AES_isbox[256];
|
||||
|
||||
/*
|
||||
AES_Te0[x] = S [x].[02, 01, 01, 03];
|
||||
AES_Td0[x] = Si[x].[0e, 09, 0d, 0b];
|
||||
*/
|
||||
|
||||
extern const uint32_t AES_Te0[256], AES_Td0[256];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,5 +2,14 @@
|
|||
#define QEMU_SM4_H
|
||||
|
||||
extern const uint8_t sm4_sbox[256];
|
||||
extern const uint32_t sm4_ck[32];
|
||||
|
||||
static inline uint32_t sm4_subword(uint32_t word)
|
||||
{
|
||||
return sm4_sbox[word & 0xff] |
|
||||
sm4_sbox[(word >> 8) & 0xff] << 8 |
|
||||
sm4_sbox[(word >> 16) & 0xff] << 16 |
|
||||
sm4_sbox[(word >> 24) & 0xff] << 24;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,8 +38,8 @@ struct target_sigcontext {
|
|||
}; /* cf. riscv-linux:arch/riscv/include/uapi/asm/ptrace.h */
|
||||
|
||||
struct target_ucontext {
|
||||
unsigned long uc_flags;
|
||||
struct target_ucontext *uc_link;
|
||||
abi_ulong uc_flags;
|
||||
abi_ptr uc_link;
|
||||
target_stack_t uc_stack;
|
||||
target_sigset_t uc_sigmask;
|
||||
uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)];
|
||||
|
|
|
@ -8793,6 +8793,10 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
|
|||
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
|
||||
#define RISCV_HWPROBE_IMA_FD (1 << 0)
|
||||
#define RISCV_HWPROBE_IMA_C (1 << 1)
|
||||
#define RISCV_HWPROBE_IMA_V (1 << 2)
|
||||
#define RISCV_HWPROBE_EXT_ZBA (1 << 3)
|
||||
#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
|
||||
#define RISCV_HWPROBE_EXT_ZBS (1 << 5)
|
||||
|
||||
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
|
||||
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
|
||||
|
@ -8840,7 +8844,15 @@ static void risc_hwprobe_fill_pairs(CPURISCVState *env,
|
|||
riscv_has_ext(env, RVD) ?
|
||||
RISCV_HWPROBE_IMA_FD : 0;
|
||||
value |= riscv_has_ext(env, RVC) ?
|
||||
RISCV_HWPROBE_IMA_C : pair->value;
|
||||
RISCV_HWPROBE_IMA_C : 0;
|
||||
value |= riscv_has_ext(env, RVV) ?
|
||||
RISCV_HWPROBE_IMA_V : 0;
|
||||
value |= cfg->ext_zba ?
|
||||
RISCV_HWPROBE_EXT_ZBA : 0;
|
||||
value |= cfg->ext_zbb ?
|
||||
RISCV_HWPROBE_EXT_ZBB : 0;
|
||||
value |= cfg->ext_zbs ?
|
||||
RISCV_HWPROBE_EXT_ZBS : 0;
|
||||
__put_user(value, &pair->value);
|
||||
break;
|
||||
case RISCV_HWPROBE_KEY_CPUPERF_0:
|
||||
|
|
|
@ -614,10 +614,7 @@ static void do_crypto_sm4e(uint64_t *rd, uint64_t *rn, uint64_t *rm)
|
|||
CR_ST_WORD(d, (i + 3) % 4) ^
|
||||
CR_ST_WORD(n, i);
|
||||
|
||||
t = sm4_sbox[t & 0xff] |
|
||||
sm4_sbox[(t >> 8) & 0xff] << 8 |
|
||||
sm4_sbox[(t >> 16) & 0xff] << 16 |
|
||||
sm4_sbox[(t >> 24) & 0xff] << 24;
|
||||
t = sm4_subword(t);
|
||||
|
||||
CR_ST_WORD(d, i) ^= t ^ rol32(t, 2) ^ rol32(t, 10) ^ rol32(t, 18) ^
|
||||
rol32(t, 24);
|
||||
|
@ -651,10 +648,7 @@ static void do_crypto_sm4ekey(uint64_t *rd, uint64_t *rn, uint64_t *rm)
|
|||
CR_ST_WORD(d, (i + 3) % 4) ^
|
||||
CR_ST_WORD(m, i);
|
||||
|
||||
t = sm4_sbox[t & 0xff] |
|
||||
sm4_sbox[(t >> 8) & 0xff] << 8 |
|
||||
sm4_sbox[(t >> 16) & 0xff] << 16 |
|
||||
sm4_sbox[(t >> 24) & 0xff] << 24;
|
||||
t = sm4_subword(t);
|
||||
|
||||
CR_ST_WORD(d, i) ^= t ^ rol32(t, 13) ^ rol32(t, 23);
|
||||
}
|
||||
|
|
|
@ -87,7 +87,9 @@ static const struct isa_ext_data isa_edata_arr[] = {
|
|||
ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond),
|
||||
ISA_EXT_DATA_ENTRY(zicsr, PRIV_VERSION_1_10_0, ext_icsr),
|
||||
ISA_EXT_DATA_ENTRY(zifencei, PRIV_VERSION_1_10_0, ext_ifencei),
|
||||
ISA_EXT_DATA_ENTRY(zihintntl, PRIV_VERSION_1_10_0, ext_zihintntl),
|
||||
ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause),
|
||||
ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul),
|
||||
ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs),
|
||||
ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa),
|
||||
ISA_EXT_DATA_ENTRY(zfbfmin, PRIV_VERSION_1_12_0, ext_zfbfmin),
|
||||
|
@ -119,6 +121,8 @@ static const struct isa_ext_data isa_edata_arr[] = {
|
|||
ISA_EXT_DATA_ENTRY(zksed, PRIV_VERSION_1_12_0, ext_zksed),
|
||||
ISA_EXT_DATA_ENTRY(zksh, PRIV_VERSION_1_12_0, ext_zksh),
|
||||
ISA_EXT_DATA_ENTRY(zkt, PRIV_VERSION_1_12_0, ext_zkt),
|
||||
ISA_EXT_DATA_ENTRY(zvbb, PRIV_VERSION_1_12_0, ext_zvbb),
|
||||
ISA_EXT_DATA_ENTRY(zvbc, PRIV_VERSION_1_12_0, ext_zvbc),
|
||||
ISA_EXT_DATA_ENTRY(zve32f, PRIV_VERSION_1_10_0, ext_zve32f),
|
||||
ISA_EXT_DATA_ENTRY(zve64f, PRIV_VERSION_1_10_0, ext_zve64f),
|
||||
ISA_EXT_DATA_ENTRY(zve64d, PRIV_VERSION_1_10_0, ext_zve64d),
|
||||
|
@ -126,9 +130,16 @@ static const struct isa_ext_data isa_edata_arr[] = {
|
|||
ISA_EXT_DATA_ENTRY(zvfbfwma, PRIV_VERSION_1_12_0, ext_zvfbfwma),
|
||||
ISA_EXT_DATA_ENTRY(zvfh, PRIV_VERSION_1_12_0, ext_zvfh),
|
||||
ISA_EXT_DATA_ENTRY(zvfhmin, PRIV_VERSION_1_12_0, ext_zvfhmin),
|
||||
ISA_EXT_DATA_ENTRY(zvkg, PRIV_VERSION_1_12_0, ext_zvkg),
|
||||
ISA_EXT_DATA_ENTRY(zvkned, PRIV_VERSION_1_12_0, ext_zvkned),
|
||||
ISA_EXT_DATA_ENTRY(zvknha, PRIV_VERSION_1_12_0, ext_zvknha),
|
||||
ISA_EXT_DATA_ENTRY(zvknhb, PRIV_VERSION_1_12_0, ext_zvknhb),
|
||||
ISA_EXT_DATA_ENTRY(zvksed, PRIV_VERSION_1_12_0, ext_zvksed),
|
||||
ISA_EXT_DATA_ENTRY(zvksh, PRIV_VERSION_1_12_0, ext_zvksh),
|
||||
ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
|
||||
ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
|
||||
ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
|
||||
ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, epmp),
|
||||
ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
|
||||
ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia),
|
||||
ISA_EXT_DATA_ENTRY(sscofpmf, PRIV_VERSION_1_12_0, ext_sscofpmf),
|
||||
|
@ -298,6 +309,17 @@ static uint8_t satp_mode_from_str(const char *satp_mode_str)
|
|||
|
||||
uint8_t satp_mode_max_from_map(uint32_t map)
|
||||
{
|
||||
/*
|
||||
* 'map = 0' will make us return (31 - 32), which C will
|
||||
* happily overflow to UINT_MAX. There's no good result to
|
||||
* return if 'map = 0' (e.g. returning 0 will be ambiguous
|
||||
* with the result for 'map = 1').
|
||||
*
|
||||
* Assert out if map = 0. Callers will have to deal with
|
||||
* it outside of this function.
|
||||
*/
|
||||
g_assert(map > 0);
|
||||
|
||||
/* map here has at least one bit set, so no problem with clz */
|
||||
return 31 - __builtin_clz(map);
|
||||
}
|
||||
|
@ -875,9 +897,9 @@ static void riscv_cpu_reset_hold(Object *obj)
|
|||
env->two_stage_lookup = false;
|
||||
|
||||
env->menvcfg = (cpu->cfg.ext_svpbmt ? MENVCFG_PBMTE : 0) |
|
||||
(cpu->cfg.ext_svadu ? MENVCFG_HADE : 0);
|
||||
(cpu->cfg.ext_svadu ? MENVCFG_ADUE : 0);
|
||||
env->henvcfg = (cpu->cfg.ext_svpbmt ? HENVCFG_PBMTE : 0) |
|
||||
(cpu->cfg.ext_svadu ? HENVCFG_HADE : 0);
|
||||
(cpu->cfg.ext_svadu ? HENVCFG_ADUE : 0);
|
||||
|
||||
/* Initialized default priorities of local interrupts. */
|
||||
for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
|
||||
|
@ -904,7 +926,7 @@ static void riscv_cpu_reset_hold(Object *obj)
|
|||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->cfg.debug) {
|
||||
riscv_trigger_init(env);
|
||||
riscv_trigger_reset_hold(env);
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
|
@ -1269,6 +1291,25 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In principle Zve*x would also suffice here, were they supported
|
||||
* in qemu
|
||||
*/
|
||||
if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned ||
|
||||
cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) &&
|
||||
!cpu->cfg.ext_zve32f) {
|
||||
error_setg(errp,
|
||||
"Vector crypto extensions require V or Zve* extensions");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) {
|
||||
error_setg(
|
||||
errp,
|
||||
"Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_zk) {
|
||||
cpu->cfg.ext_zkn = true;
|
||||
cpu->cfg.ext_zkr = true;
|
||||
|
@ -1303,9 +1344,15 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
|
|||
static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
|
||||
{
|
||||
bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
|
||||
uint8_t satp_mode_map_max;
|
||||
uint8_t satp_mode_supported_max =
|
||||
satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
|
||||
uint8_t satp_mode_map_max, satp_mode_supported_max;
|
||||
|
||||
/* The CPU wants the OS to decide which satp mode to use */
|
||||
if (cpu->cfg.satp_mode.supported == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
satp_mode_supported_max =
|
||||
satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
|
||||
|
||||
if (cpu->cfg.satp_mode.map == 0) {
|
||||
if (cpu->cfg.satp_mode.init == 0) {
|
||||
|
@ -1395,6 +1442,11 @@ static void riscv_cpu_realize_tcg(DeviceState *dev, Error **errp)
|
|||
CPURISCVState *env = &cpu->env;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_CPU_HOST)) {
|
||||
error_setg(errp, "'host' CPU is not compatible with TCG acceleration");
|
||||
return;
|
||||
}
|
||||
|
||||
riscv_cpu_validate_misa_mxl(cpu, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
|
@ -1473,6 +1525,12 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
riscv_cpu_register_gdb_regs_for_features(cs);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->cfg.debug) {
|
||||
riscv_trigger_realize(&cpu->env);
|
||||
}
|
||||
#endif
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
cpu_reset(cs);
|
||||
|
||||
|
@ -1756,6 +1814,7 @@ static Property riscv_cpu_extensions[] = {
|
|||
DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false),
|
||||
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
|
||||
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
|
||||
DEFINE_PROP_BOOL("Zihintntl", RISCVCPU, cfg.ext_zihintntl, true),
|
||||
DEFINE_PROP_BOOL("Zihintpause", RISCVCPU, cfg.ext_zihintpause, true),
|
||||
DEFINE_PROP_BOOL("Zawrs", RISCVCPU, cfg.ext_zawrs, true),
|
||||
DEFINE_PROP_BOOL("Zfa", RISCVCPU, cfg.ext_zfa, true),
|
||||
|
@ -1816,6 +1875,7 @@ static Property riscv_cpu_extensions[] = {
|
|||
DEFINE_PROP_BOOL("zcf", RISCVCPU, cfg.ext_zcf, false),
|
||||
DEFINE_PROP_BOOL("zcmp", RISCVCPU, cfg.ext_zcmp, false),
|
||||
DEFINE_PROP_BOOL("zcmt", RISCVCPU, cfg.ext_zcmt, false),
|
||||
DEFINE_PROP_BOOL("zicond", RISCVCPU, cfg.ext_zicond, false),
|
||||
|
||||
/* Vendor-specific custom extensions */
|
||||
DEFINE_PROP_BOOL("xtheadba", RISCVCPU, cfg.ext_xtheadba, false),
|
||||
|
@ -1832,7 +1892,6 @@ static Property riscv_cpu_extensions[] = {
|
|||
DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false),
|
||||
|
||||
/* These are experimental so mark with 'x-' */
|
||||
DEFINE_PROP_BOOL("x-zicond", RISCVCPU, cfg.ext_zicond, false),
|
||||
|
||||
/* ePMP 0.9.3 */
|
||||
DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
|
||||
|
@ -1846,6 +1905,16 @@ static Property riscv_cpu_extensions[] = {
|
|||
DEFINE_PROP_BOOL("x-zvfbfmin", RISCVCPU, cfg.ext_zvfbfmin, false),
|
||||
DEFINE_PROP_BOOL("x-zvfbfwma", RISCVCPU, cfg.ext_zvfbfwma, false),
|
||||
|
||||
/* Vector cryptography extensions */
|
||||
DEFINE_PROP_BOOL("x-zvbb", RISCVCPU, cfg.ext_zvbb, false),
|
||||
DEFINE_PROP_BOOL("x-zvbc", RISCVCPU, cfg.ext_zvbc, false),
|
||||
DEFINE_PROP_BOOL("x-zvkg", RISCVCPU, cfg.ext_zvkg, false),
|
||||
DEFINE_PROP_BOOL("x-zvkned", RISCVCPU, cfg.ext_zvkned, false),
|
||||
DEFINE_PROP_BOOL("x-zvknha", RISCVCPU, cfg.ext_zvknha, false),
|
||||
DEFINE_PROP_BOOL("x-zvknhb", RISCVCPU, cfg.ext_zvknhb, false),
|
||||
DEFINE_PROP_BOOL("x-zvksed", RISCVCPU, cfg.ext_zvksed, false),
|
||||
DEFINE_PROP_BOOL("x-zvksh", RISCVCPU, cfg.ext_zvksh, false),
|
||||
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -745,12 +745,12 @@ typedef enum RISCVException {
|
|||
#define MENVCFG_CBIE (3UL << 4)
|
||||
#define MENVCFG_CBCFE BIT(6)
|
||||
#define MENVCFG_CBZE BIT(7)
|
||||
#define MENVCFG_HADE (1ULL << 61)
|
||||
#define MENVCFG_ADUE (1ULL << 61)
|
||||
#define MENVCFG_PBMTE (1ULL << 62)
|
||||
#define MENVCFG_STCE (1ULL << 63)
|
||||
|
||||
/* For RV32 */
|
||||
#define MENVCFGH_HADE BIT(29)
|
||||
#define MENVCFGH_ADUE BIT(29)
|
||||
#define MENVCFGH_PBMTE BIT(30)
|
||||
#define MENVCFGH_STCE BIT(31)
|
||||
|
||||
|
@ -763,12 +763,12 @@ typedef enum RISCVException {
|
|||
#define HENVCFG_CBIE MENVCFG_CBIE
|
||||
#define HENVCFG_CBCFE MENVCFG_CBCFE
|
||||
#define HENVCFG_CBZE MENVCFG_CBZE
|
||||
#define HENVCFG_HADE MENVCFG_HADE
|
||||
#define HENVCFG_ADUE MENVCFG_ADUE
|
||||
#define HENVCFG_PBMTE MENVCFG_PBMTE
|
||||
#define HENVCFG_STCE MENVCFG_STCE
|
||||
|
||||
/* For RV32 */
|
||||
#define HENVCFGH_HADE MENVCFGH_HADE
|
||||
#define HENVCFGH_ADUE MENVCFGH_ADUE
|
||||
#define HENVCFGH_PBMTE MENVCFGH_PBMTE
|
||||
#define HENVCFGH_STCE MENVCFGH_STCE
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ struct RISCVCPUConfig {
|
|||
bool ext_icbom;
|
||||
bool ext_icboz;
|
||||
bool ext_zicond;
|
||||
bool ext_zihintntl;
|
||||
bool ext_zihintpause;
|
||||
bool ext_smstateen;
|
||||
bool ext_sstc;
|
||||
|
@ -85,6 +86,14 @@ struct RISCVCPUConfig {
|
|||
bool ext_zve32f;
|
||||
bool ext_zve64f;
|
||||
bool ext_zve64d;
|
||||
bool ext_zvbb;
|
||||
bool ext_zvbc;
|
||||
bool ext_zvkg;
|
||||
bool ext_zvkned;
|
||||
bool ext_zvknha;
|
||||
bool ext_zvknhb;
|
||||
bool ext_zvksed;
|
||||
bool ext_zvksh;
|
||||
bool ext_zmmul;
|
||||
bool ext_zvfbfmin;
|
||||
bool ext_zvfbfwma;
|
||||
|
|
|
@ -861,11 +861,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
|||
}
|
||||
|
||||
bool pbmte = env->menvcfg & MENVCFG_PBMTE;
|
||||
bool hade = env->menvcfg & MENVCFG_HADE;
|
||||
bool adue = env->menvcfg & MENVCFG_ADUE;
|
||||
|
||||
if (first_stage && two_stage && env->virt_enabled) {
|
||||
pbmte = pbmte && (env->henvcfg & HENVCFG_PBMTE);
|
||||
hade = hade && (env->henvcfg & HENVCFG_HADE);
|
||||
adue = adue && (env->henvcfg & HENVCFG_ADUE);
|
||||
}
|
||||
|
||||
int ptshift = (levels - 1) * ptidxbits;
|
||||
|
@ -1026,7 +1026,7 @@ restart:
|
|||
|
||||
/* Page table updates need to be atomic with MTTCG enabled */
|
||||
if (updated_pte != pte && !is_debug) {
|
||||
if (!hade) {
|
||||
if (!adue) {
|
||||
return TRANSLATE_FAIL;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,29 +25,6 @@
|
|||
#include "crypto/aes-round.h"
|
||||
#include "crypto/sm4.h"
|
||||
|
||||
#define AES_XTIME(a) \
|
||||
((a << 1) ^ ((a & 0x80) ? 0x1b : 0))
|
||||
|
||||
#define AES_GFMUL(a, b) (( \
|
||||
(((b) & 0x1) ? (a) : 0) ^ \
|
||||
(((b) & 0x2) ? AES_XTIME(a) : 0) ^ \
|
||||
(((b) & 0x4) ? AES_XTIME(AES_XTIME(a)) : 0) ^ \
|
||||
(((b) & 0x8) ? AES_XTIME(AES_XTIME(AES_XTIME(a))) : 0)) & 0xFF)
|
||||
|
||||
static inline uint32_t aes_mixcolumn_byte(uint8_t x, bool fwd)
|
||||
{
|
||||
uint32_t u;
|
||||
|
||||
if (fwd) {
|
||||
u = (AES_GFMUL(x, 3) << 24) | (x << 16) | (x << 8) |
|
||||
(AES_GFMUL(x, 2) << 0);
|
||||
} else {
|
||||
u = (AES_GFMUL(x, 0xb) << 24) | (AES_GFMUL(x, 0xd) << 16) |
|
||||
(AES_GFMUL(x, 0x9) << 8) | (AES_GFMUL(x, 0xe) << 0);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
#define sext32_xlen(x) (target_ulong)(int32_t)(x)
|
||||
|
||||
static inline target_ulong aes32_operation(target_ulong shamt,
|
||||
|
@ -55,23 +32,20 @@ static inline target_ulong aes32_operation(target_ulong shamt,
|
|||
bool enc, bool mix)
|
||||
{
|
||||
uint8_t si = rs2 >> shamt;
|
||||
uint8_t so;
|
||||
uint32_t mixed;
|
||||
target_ulong res;
|
||||
|
||||
if (enc) {
|
||||
so = AES_sbox[si];
|
||||
if (mix) {
|
||||
mixed = aes_mixcolumn_byte(so, true);
|
||||
mixed = be32_to_cpu(AES_Te0[si]);
|
||||
} else {
|
||||
mixed = so;
|
||||
mixed = AES_sbox[si];
|
||||
}
|
||||
} else {
|
||||
so = AES_isbox[si];
|
||||
if (mix) {
|
||||
mixed = aes_mixcolumn_byte(so, false);
|
||||
mixed = be32_to_cpu(AES_Td0[si]);
|
||||
} else {
|
||||
mixed = so;
|
||||
mixed = AES_isbox[si];
|
||||
}
|
||||
}
|
||||
mixed = rol32(mixed, shamt);
|
||||
|
@ -174,24 +148,17 @@ target_ulong HELPER(aes64ks1i)(target_ulong rs1, target_ulong rnum)
|
|||
|
||||
uint8_t enc_rnum = rnum;
|
||||
uint32_t temp = (RS1 >> 32) & 0xFFFFFFFF;
|
||||
uint8_t rcon_ = 0;
|
||||
target_ulong result;
|
||||
AESState t, rc = {};
|
||||
|
||||
if (enc_rnum != 0xA) {
|
||||
temp = ror32(temp, 8); /* Rotate right by 8 */
|
||||
rcon_ = round_consts[enc_rnum];
|
||||
rc.w[0] = rc.w[1] = round_consts[enc_rnum];
|
||||
}
|
||||
|
||||
temp = ((uint32_t)AES_sbox[(temp >> 24) & 0xFF] << 24) |
|
||||
((uint32_t)AES_sbox[(temp >> 16) & 0xFF] << 16) |
|
||||
((uint32_t)AES_sbox[(temp >> 8) & 0xFF] << 8) |
|
||||
((uint32_t)AES_sbox[(temp >> 0) & 0xFF] << 0);
|
||||
t.w[0] = t.w[1] = t.w[2] = t.w[3] = temp;
|
||||
aesenc_SB_SR_AK(&t, &t, &rc, false);
|
||||
|
||||
temp ^= rcon_;
|
||||
|
||||
result = ((uint64_t)temp << 32) | temp;
|
||||
|
||||
return result;
|
||||
return t.d[0];
|
||||
}
|
||||
|
||||
target_ulong HELPER(aes64im)(target_ulong rs1)
|
||||
|
|
|
@ -1684,7 +1684,7 @@ static int rmw_iprio(target_ulong xlen,
|
|||
static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
|
||||
target_ulong new_val, target_ulong wr_mask)
|
||||
{
|
||||
bool virt;
|
||||
bool virt, isel_reserved;
|
||||
uint8_t *iprio;
|
||||
int ret = -EINVAL;
|
||||
target_ulong priv, isel, vgein;
|
||||
|
@ -1694,6 +1694,7 @@ static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
|
|||
|
||||
/* Decode register details from CSR number */
|
||||
virt = false;
|
||||
isel_reserved = false;
|
||||
switch (csrno) {
|
||||
case CSR_MIREG:
|
||||
iprio = env->miprio;
|
||||
|
@ -1738,11 +1739,13 @@ static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
|
|||
riscv_cpu_mxl_bits(env)),
|
||||
val, new_val, wr_mask);
|
||||
}
|
||||
} else {
|
||||
isel_reserved = true;
|
||||
}
|
||||
|
||||
done:
|
||||
if (ret) {
|
||||
return (env->virt_enabled && virt) ?
|
||||
return (env->virt_enabled && virt && !isel_reserved) ?
|
||||
RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
return RISCV_EXCP_NONE;
|
||||
|
@ -1833,8 +1836,11 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno,
|
|||
{
|
||||
int cidx;
|
||||
PMUCTRState *counter;
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
|
||||
env->mcountinhibit = val;
|
||||
/* WARL register - disable unavailable counters; TM bit is always 0 */
|
||||
env->mcountinhibit =
|
||||
val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR);
|
||||
|
||||
/* Check if any other counter is also monitoring cycles/instructions */
|
||||
for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) {
|
||||
|
@ -1857,7 +1863,11 @@ static RISCVException read_mcounteren(CPURISCVState *env, int csrno,
|
|||
static RISCVException write_mcounteren(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
env->mcounteren = val;
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
|
||||
/* WARL register - disable unavailable counters */
|
||||
env->mcounteren = val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_TM |
|
||||
COUNTEREN_IR);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
|
@ -1950,7 +1960,7 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
|
|||
if (riscv_cpu_mxl(env) == MXL_RV64) {
|
||||
mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
|
||||
(cfg->ext_sstc ? MENVCFG_STCE : 0) |
|
||||
(cfg->ext_svadu ? MENVCFG_HADE : 0);
|
||||
(cfg->ext_svadu ? MENVCFG_ADUE : 0);
|
||||
}
|
||||
env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
|
||||
|
||||
|
@ -1970,7 +1980,7 @@ static RISCVException write_menvcfgh(CPURISCVState *env, int csrno,
|
|||
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
|
||||
uint64_t mask = (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
|
||||
(cfg->ext_sstc ? MENVCFG_STCE : 0) |
|
||||
(cfg->ext_svadu ? MENVCFG_HADE : 0);
|
||||
(cfg->ext_svadu ? MENVCFG_ADUE : 0);
|
||||
uint64_t valh = (uint64_t)val << 32;
|
||||
|
||||
env->menvcfg = (env->menvcfg & ~mask) | (valh & mask);
|
||||
|
@ -2022,7 +2032,7 @@ static RISCVException read_henvcfg(CPURISCVState *env, int csrno,
|
|||
* henvcfg.stce is read_only 0 when menvcfg.stce = 0
|
||||
* henvcfg.hade is read_only 0 when menvcfg.hade = 0
|
||||
*/
|
||||
*val = env->henvcfg & (~(HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_HADE) |
|
||||
*val = env->henvcfg & (~(HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE) |
|
||||
env->menvcfg);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
@ -2039,7 +2049,7 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
|
|||
}
|
||||
|
||||
if (riscv_cpu_mxl(env) == MXL_RV64) {
|
||||
mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_HADE);
|
||||
mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE);
|
||||
}
|
||||
|
||||
env->henvcfg = (env->henvcfg & ~mask) | (val & mask);
|
||||
|
@ -2057,7 +2067,7 @@ static RISCVException read_henvcfgh(CPURISCVState *env, int csrno,
|
|||
return ret;
|
||||
}
|
||||
|
||||
*val = (env->henvcfg & (~(HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_HADE) |
|
||||
*val = (env->henvcfg & (~(HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE) |
|
||||
env->menvcfg)) >> 32;
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
@ -2066,7 +2076,7 @@ static RISCVException write_henvcfgh(CPURISCVState *env, int csrno,
|
|||
target_ulong val)
|
||||
{
|
||||
uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE |
|
||||
HENVCFG_HADE);
|
||||
HENVCFG_ADUE);
|
||||
uint64_t valh = (uint64_t)val << 32;
|
||||
RISCVException ret;
|
||||
|
||||
|
@ -3907,21 +3917,27 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
|
|||
target_ulong write_mask)
|
||||
{
|
||||
RISCVException ret;
|
||||
target_ulong old_value;
|
||||
target_ulong old_value = 0;
|
||||
|
||||
/* execute combined read/write operation if it exists */
|
||||
if (csr_ops[csrno].op) {
|
||||
return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask);
|
||||
}
|
||||
|
||||
/* if no accessor exists then return failure */
|
||||
if (!csr_ops[csrno].read) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
/* read old value */
|
||||
ret = csr_ops[csrno].read(env, csrno, &old_value);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
/*
|
||||
* ret_value == NULL means that rd=x0 and we're coming from helper_csrw()
|
||||
* and we can't throw side effects caused by CSR reads.
|
||||
*/
|
||||
if (ret_value) {
|
||||
/* if no accessor exists then return failure */
|
||||
if (!csr_ops[csrno].read) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
/* read old value */
|
||||
ret = csr_ops[csrno].read(env, csrno, &old_value);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* write value if writable and write mask set, otherwise drop writes */
|
||||
|
|
|
@ -903,7 +903,17 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
|
|||
return false;
|
||||
}
|
||||
|
||||
void riscv_trigger_init(CPURISCVState *env)
|
||||
void riscv_trigger_realize(CPURISCVState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RV_MAX_TRIGGERS; i++) {
|
||||
env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
riscv_itrigger_timer_cb, env);
|
||||
}
|
||||
}
|
||||
|
||||
void riscv_trigger_reset_hold(CPURISCVState *env)
|
||||
{
|
||||
target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0);
|
||||
int i;
|
||||
|
@ -928,7 +938,6 @@ void riscv_trigger_init(CPURISCVState *env)
|
|||
env->tdata3[i] = 0;
|
||||
env->cpu_breakpoint[i] = NULL;
|
||||
env->cpu_watchpoint[i] = NULL;
|
||||
env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
riscv_itrigger_timer_cb, env);
|
||||
timer_del(env->itrigger_timer[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,8 @@ void riscv_cpu_debug_excp_handler(CPUState *cs);
|
|||
bool riscv_cpu_debug_check_breakpoint(CPUState *cs);
|
||||
bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
|
||||
|
||||
void riscv_trigger_init(CPURISCVState *env);
|
||||
void riscv_trigger_realize(CPURISCVState *env);
|
||||
void riscv_trigger_reset_hold(CPURISCVState *env);
|
||||
|
||||
bool riscv_itrigger_enabled(CPURISCVState *env);
|
||||
void riscv_itrigger_update_priv(CPURISCVState *env);
|
||||
|
|
|
@ -1182,3 +1182,101 @@ DEF_HELPER_5(vfwcvtbf16_f_f_v, void, ptr, ptr, ptr, env, i32)
|
|||
|
||||
DEF_HELPER_6(vfwmaccbf16_vv, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vfwmaccbf16_vf, void, ptr, ptr, i64, ptr, env, i32)
|
||||
|
||||
/* Vector crypto functions */
|
||||
DEF_HELPER_6(vclmul_vv, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vclmul_vx, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vclmulh_vv, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vclmulh_vx, void, ptr, ptr, tl, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_6(vror_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vror_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vror_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vror_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_6(vror_vx_b, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vror_vx_h, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vror_vx_w, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vror_vx_d, void, ptr, ptr, tl, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_6(vrol_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vrol_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vrol_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vrol_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_6(vrol_vx_b, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vrol_vx_h, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vrol_vx_w, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vrol_vx_d, void, ptr, ptr, tl, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_5(vrev8_v_b, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vrev8_v_h, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vrev8_v_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vrev8_v_d, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev8_v_b, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev8_v_h, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev8_v_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev8_v_d, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev_v_b, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev_v_h, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev_v_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vbrev_v_d, void, ptr, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_5(vclz_v_b, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vclz_v_h, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vclz_v_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vclz_v_d, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vctz_v_b, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vctz_v_h, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vctz_v_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vctz_v_d, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vcpop_v_b, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vcpop_v_h, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vcpop_v_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vcpop_v_d, void, ptr, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_6(vwsll_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vwsll_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vwsll_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vwsll_vx_b, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vwsll_vx_h, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vwsll_vx_w, void, ptr, ptr, tl, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_6(vandn_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vx_b, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vx_h, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vx_w, void, ptr, ptr, tl, ptr, env, i32)
|
||||
DEF_HELPER_6(vandn_vx_d, void, ptr, ptr, tl, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_2(egs_check, void, i32, env)
|
||||
|
||||
DEF_HELPER_4(vaesef_vv, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesef_vs, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesdf_vv, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesdf_vs, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesem_vv, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesem_vs, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesdm_vv, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesdm_vs, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vaesz_vs, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vaeskf1_vi, void, ptr, ptr, i32, env, i32)
|
||||
DEF_HELPER_5(vaeskf2_vi, void, ptr, ptr, i32, env, i32)
|
||||
|
||||
DEF_HELPER_5(vsha2ms_vv, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsha2ch32_vv, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsha2ch64_vv, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsha2cl32_vv, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsha2cl64_vv, void, ptr, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_5(vsm3me_vv, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsm3c_vi, void, ptr, ptr, i32, env, i32)
|
||||
|
||||
DEF_HELPER_5(vghsh_vv, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vgmul_vv, void, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_5(vsm4k_vi, void, ptr, ptr, i32, env, i32)
|
||||
DEF_HELPER_4(vsm4r_vv, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_4(vsm4r_vs, void, ptr, ptr, env, i32)
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
%imm_u 12:s20 !function=ex_shift_12
|
||||
%imm_bs 30:2 !function=ex_shift_3
|
||||
%imm_rnum 20:4
|
||||
%imm_z6 26:1 15:5
|
||||
|
||||
# Argument sets:
|
||||
&empty
|
||||
|
@ -74,6 +75,7 @@
|
|||
@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
|
||||
@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd
|
||||
@r2 ....... ..... ..... ... ..... ....... &r2 %rs1 %rd
|
||||
@r2_vm_1 ...... . ..... ..... ... ..... ....... &rmr vm=1 %rs2 %rd
|
||||
@r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd
|
||||
@r2_vm ...... vm:1 ..... ..... ... ..... ....... &rmr %rs2 %rd
|
||||
@r1_vm ...... vm:1 ..... ..... ... ..... ....... %rd
|
||||
|
@ -82,6 +84,7 @@
|
|||
@r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd
|
||||
@r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd
|
||||
@r_vm_0 ...... . ..... ..... ... ..... ....... &rmrr vm=0 %rs2 %rs1 %rd
|
||||
@r2_zimm6 ..... . vm:1 ..... ..... ... ..... ....... &rmrr %rs2 rs1=%imm_z6 %rd
|
||||
@r2_zimm11 . zimm:11 ..... ... ..... ....... %rs1 %rd
|
||||
@r2_zimm10 .. zimm:10 ..... ... ..... ....... %rs1 %rd
|
||||
@r2_s ....... ..... ..... ... ..... ....... %rs2 %rs1
|
||||
|
@ -946,3 +949,58 @@ vfwcvtbf16_f_f_v 010010 . ..... 01101 001 ..... 1010111 @r2_vm
|
|||
# *** Zvfbfwma Standard Extension ***
|
||||
vfwmaccbf16_vv 111011 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
vfwmaccbf16_vf 111011 . ..... ..... 101 ..... 1010111 @r_vm
|
||||
|
||||
# *** Zvbc vector crypto extension ***
|
||||
vclmul_vv 001100 . ..... ..... 010 ..... 1010111 @r_vm
|
||||
vclmul_vx 001100 . ..... ..... 110 ..... 1010111 @r_vm
|
||||
vclmulh_vv 001101 . ..... ..... 010 ..... 1010111 @r_vm
|
||||
vclmulh_vx 001101 . ..... ..... 110 ..... 1010111 @r_vm
|
||||
|
||||
# *** Zvbb vector crypto extension ***
|
||||
vrol_vv 010101 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vrol_vx 010101 . ..... ..... 100 ..... 1010111 @r_vm
|
||||
vror_vv 010100 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vror_vx 010100 . ..... ..... 100 ..... 1010111 @r_vm
|
||||
vror_vi 01010. . ..... ..... 011 ..... 1010111 @r2_zimm6
|
||||
vbrev8_v 010010 . ..... 01000 010 ..... 1010111 @r2_vm
|
||||
vrev8_v 010010 . ..... 01001 010 ..... 1010111 @r2_vm
|
||||
vandn_vv 000001 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vandn_vx 000001 . ..... ..... 100 ..... 1010111 @r_vm
|
||||
vbrev_v 010010 . ..... 01010 010 ..... 1010111 @r2_vm
|
||||
vclz_v 010010 . ..... 01100 010 ..... 1010111 @r2_vm
|
||||
vctz_v 010010 . ..... 01101 010 ..... 1010111 @r2_vm
|
||||
vcpop_v 010010 . ..... 01110 010 ..... 1010111 @r2_vm
|
||||
vwsll_vv 110101 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vwsll_vx 110101 . ..... ..... 100 ..... 1010111 @r_vm
|
||||
vwsll_vi 110101 . ..... ..... 011 ..... 1010111 @r_vm
|
||||
|
||||
# *** Zvkned vector crypto extension ***
|
||||
vaesef_vv 101000 1 ..... 00011 010 ..... 1110111 @r2_vm_1
|
||||
vaesef_vs 101001 1 ..... 00011 010 ..... 1110111 @r2_vm_1
|
||||
vaesdf_vv 101000 1 ..... 00001 010 ..... 1110111 @r2_vm_1
|
||||
vaesdf_vs 101001 1 ..... 00001 010 ..... 1110111 @r2_vm_1
|
||||
vaesem_vv 101000 1 ..... 00010 010 ..... 1110111 @r2_vm_1
|
||||
vaesem_vs 101001 1 ..... 00010 010 ..... 1110111 @r2_vm_1
|
||||
vaesdm_vv 101000 1 ..... 00000 010 ..... 1110111 @r2_vm_1
|
||||
vaesdm_vs 101001 1 ..... 00000 010 ..... 1110111 @r2_vm_1
|
||||
vaesz_vs 101001 1 ..... 00111 010 ..... 1110111 @r2_vm_1
|
||||
vaeskf1_vi 100010 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
vaeskf2_vi 101010 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
|
||||
# *** Zvknh vector crypto extension ***
|
||||
vsha2ms_vv 101101 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
vsha2ch_vv 101110 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
vsha2cl_vv 101111 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
|
||||
# *** Zvksh vector crypto extension ***
|
||||
vsm3me_vv 100000 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
vsm3c_vi 101011 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
|
||||
# *** Zvkg vector crypto extension ***
|
||||
vghsh_vv 101100 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
vgmul_vv 101000 1 ..... 10001 010 ..... 1110111 @r2_vm_1
|
||||
|
||||
# *** Zvksed vector crypto extension ***
|
||||
vsm4k_vi 100001 1 ..... ..... 010 ..... 1110111 @r_vm_1
|
||||
vsm4r_vv 101000 1 ..... 10000 010 ..... 1110111 @r2_vm_1
|
||||
vsm4r_vs 101001 1 ..... 10000 010 ..... 1110111 @r2_vm_1
|
||||
|
|
|
@ -617,7 +617,6 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
|||
TCGv_i32 desc;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -786,7 +785,6 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
|
|||
TCGv_i32 desc;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -893,7 +891,6 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
|||
TCGv_i32 desc;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -1034,7 +1031,6 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
|||
TCGv_i32 desc;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -1187,11 +1183,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
|
|||
gen_helper_gvec_4_ptr *fn)
|
||||
{
|
||||
TCGLabel *over = gen_new_label();
|
||||
if (!opivv_check(s, a)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
|
||||
|
@ -1223,6 +1215,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
if (!opivv_check(s, a)) { \
|
||||
return false; \
|
||||
} \
|
||||
return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
|
||||
}
|
||||
|
||||
|
@ -1241,7 +1236,6 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
|
|||
uint32_t data = 0;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -1282,10 +1276,6 @@ static inline bool
|
|||
do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
|
||||
gen_helper_opivx *fn)
|
||||
{
|
||||
if (!opivx_check(s, a)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
|
||||
TCGv_i64 src1 = tcg_temp_new_i64();
|
||||
|
||||
|
@ -1307,6 +1297,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
if (!opivx_check(s, a)) { \
|
||||
return false; \
|
||||
} \
|
||||
return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
|
||||
}
|
||||
|
||||
|
@ -1405,7 +1398,6 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
|
|||
uint32_t data = 0;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -1439,10 +1431,6 @@ static inline bool
|
|||
do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
|
||||
gen_helper_opivx *fn, imm_mode_t imm_mode)
|
||||
{
|
||||
if (!opivx_check(s, a)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
|
||||
gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
|
||||
extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s));
|
||||
|
@ -1460,6 +1448,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
|
||||
gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
|
||||
}; \
|
||||
if (!opivx_check(s, a)) { \
|
||||
return false; \
|
||||
} \
|
||||
return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \
|
||||
fns[s->sew], IMM_MODE); \
|
||||
}
|
||||
|
@ -1492,7 +1483,6 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
|
|||
if (checkfn(s, a)) {
|
||||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
|
@ -1536,30 +1526,24 @@ static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
|
|||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
|
||||
gen_helper_opivx *fn)
|
||||
{
|
||||
if (opivx_widen_check(s, a)) {
|
||||
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
|
||||
}
|
||||
return false;
|
||||
#define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_opivx * const fns[3] = { \
|
||||
gen_helper_##NAME##_b, \
|
||||
gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w \
|
||||
}; \
|
||||
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define GEN_OPIVX_WIDEN_TRANS(NAME) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
static gen_helper_opivx * const fns[3] = { \
|
||||
gen_helper_##NAME##_b, \
|
||||
gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w \
|
||||
}; \
|
||||
return do_opivx_widen(s, a, fns[s->sew]); \
|
||||
}
|
||||
|
||||
GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwaddu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwadd_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwsubu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwsub_vx, opivx_widen_check)
|
||||
|
||||
/* WIDEN OPIVV with WIDEN */
|
||||
static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
|
@ -1575,7 +1559,6 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
|
|||
if (opiwv_widen_check(s, a)) {
|
||||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
|
@ -1643,38 +1626,39 @@ GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
|
|||
GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
|
||||
GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
|
||||
|
||||
static bool opivv_trans(uint32_t vd, uint32_t vs1, uint32_t vs2, uint32_t vm,
|
||||
gen_helper_gvec_4_ptr *fn, DisasContext *s)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, vd), vreg_ofs(s, 0), vreg_ofs(s, vs1),
|
||||
vreg_ofs(s, vs2), cpu_env, s->cfg_ptr->vlen / 8,
|
||||
s->cfg_ptr->vlen / 8, data, fn);
|
||||
mark_vs_dirty(s);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
|
||||
/* OPIVV without GVEC IR */
|
||||
#define GEN_OPIVV_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
uint32_t data = 0; \
|
||||
static gen_helper_gvec_4_ptr * const fns[4] = { \
|
||||
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = \
|
||||
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, \
|
||||
s->cfg_ptr->vlen / 8, data, \
|
||||
fns[s->sew]); \
|
||||
mark_vs_dirty(s); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
return false; \
|
||||
#define GEN_OPIVV_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_gvec_4_ptr * const fns[4] = { \
|
||||
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
return opivv_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1783,10 +1767,6 @@ static inline bool
|
|||
do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
|
||||
gen_helper_opivx *fn)
|
||||
{
|
||||
if (!opivx_check(s, a)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
|
||||
TCGv_i32 src1 = tcg_temp_new_i32();
|
||||
|
||||
|
@ -1808,7 +1788,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
\
|
||||
if (!opivx_check(s, a)) { \
|
||||
return false; \
|
||||
} \
|
||||
return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
|
||||
}
|
||||
|
||||
|
@ -1840,7 +1822,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
gen_helper_##NAME##_w, \
|
||||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2010,9 +1991,9 @@ GEN_OPIVX_TRANS(vrem_vx, opivx_check)
|
|||
GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmul_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmulu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx, opivx_widen_check)
|
||||
|
||||
/* Vector Single-Width Integer Multiply-Add Instructions */
|
||||
GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
|
||||
|
@ -2028,10 +2009,10 @@ GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
|
|||
GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check)
|
||||
|
||||
/* Vector Integer Merge and Move Instructions */
|
||||
static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
|
||||
|
@ -2052,7 +2033,6 @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
|
|||
gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
|
||||
};
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
|
||||
|
@ -2076,7 +2056,6 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
|
|||
vext_check_ss(s, a->rd, 0, 1)) {
|
||||
TCGv s1;
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
s1 = get_gpr(s, a->rs1, EXT_SIGN);
|
||||
|
@ -2138,7 +2117,6 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
|
|||
gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
|
||||
};
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
s1 = tcg_constant_i64(simm);
|
||||
|
@ -2286,7 +2264,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm(s, RISCV_FRM_DYN); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2321,7 +2298,6 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
|||
TCGv_i64 t1;
|
||||
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
|
@ -2406,7 +2382,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm(s, RISCV_FRM_DYN); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);\
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2481,7 +2456,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm(s, RISCV_FRM_DYN); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2599,7 +2573,6 @@ static bool do_opfv(DisasContext *s, arg_rmr *a,
|
|||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
gen_set_rm_chkfrm(s, rm);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
|
@ -2711,7 +2684,6 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
|
|||
gen_helper_vmv_v_x_d,
|
||||
};
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
t1 = tcg_temp_new_i64();
|
||||
|
@ -2790,7 +2762,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm_chkfrm(s, FRM); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2842,7 +2813,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm(s, RISCV_FRM_DYN); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2910,7 +2880,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm_chkfrm(s, FRM); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -2960,7 +2929,6 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
gen_set_rm_chkfrm(s, FRM); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
|
@ -3051,7 +3019,6 @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \
|
|||
uint32_t data = 0; \
|
||||
gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
|
@ -3222,7 +3189,6 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
|
|||
require_vm(a->vm, a->rd)) {
|
||||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
|
@ -3409,7 +3375,6 @@ static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
|
|||
TCGv s1;
|
||||
TCGLabel *over = gen_new_label();
|
||||
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
t1 = tcg_temp_new_i64();
|
||||
|
@ -3466,8 +3431,7 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
|
|||
TCGv_i64 t1;
|
||||
TCGLabel *over = gen_new_label();
|
||||
|
||||
/* if vl == 0 or vstart >= vl, skip vector register write back */
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
/* if vstart >= vl, skip vector register write back */
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
/* NaN-box f[rs1] */
|
||||
|
@ -3718,7 +3682,6 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq)
|
|||
uint32_t data = 0;
|
||||
gen_helper_gvec_3_ptr *fn;
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
|
||||
static gen_helper_gvec_3_ptr * const fns[6][4] = {
|
||||
|
|
|
@ -0,0 +1,606 @@
|
|||
/*
|
||||
* RISC-V translation routines for the vector crypto extension.
|
||||
*
|
||||
* Copyright (C) 2023 SiFive, Inc.
|
||||
* Written by Codethink Ltd and SiFive.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Zvbc
|
||||
*/
|
||||
|
||||
#define GEN_VV_MASKED_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
return opivv_trans(a->rd, a->rs1, a->rs2, a->vm, \
|
||||
gen_helper_##NAME, s); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool vclmul_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return opivv_check(s, a) &&
|
||||
s->cfg_ptr->ext_zvbc == true &&
|
||||
s->sew == MO_64;
|
||||
}
|
||||
|
||||
GEN_VV_MASKED_TRANS(vclmul_vv, vclmul_vv_check)
|
||||
GEN_VV_MASKED_TRANS(vclmulh_vv, vclmul_vv_check)
|
||||
|
||||
#define GEN_VX_MASKED_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, \
|
||||
gen_helper_##NAME, s); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool vclmul_vx_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return opivx_check(s, a) &&
|
||||
s->cfg_ptr->ext_zvbc == true &&
|
||||
s->sew == MO_64;
|
||||
}
|
||||
|
||||
GEN_VX_MASKED_TRANS(vclmul_vx, vclmul_vx_check)
|
||||
GEN_VX_MASKED_TRANS(vclmulh_vx, vclmul_vx_check)
|
||||
|
||||
/*
|
||||
* Zvbb
|
||||
*/
|
||||
|
||||
#define GEN_OPIVI_GVEC_TRANS_CHECK(NAME, IMM_MODE, OPIVX, SUF, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_opivx *const fns[4] = { \
|
||||
gen_helper_##OPIVX##_b, \
|
||||
gen_helper_##OPIVX##_h, \
|
||||
gen_helper_##OPIVX##_w, \
|
||||
gen_helper_##OPIVX##_d, \
|
||||
}; \
|
||||
return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew], \
|
||||
IMM_MODE); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define GEN_OPIVV_GVEC_TRANS_CHECK(NAME, SUF, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_gvec_4_ptr *const fns[4] = { \
|
||||
gen_helper_##NAME##_b, \
|
||||
gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, \
|
||||
gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define GEN_OPIVX_GVEC_SHIFT_TRANS_CHECK(NAME, SUF, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_opivx *const fns[4] = { \
|
||||
gen_helper_##NAME##_b, \
|
||||
gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, \
|
||||
gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, \
|
||||
fns[s->sew]); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool zvbb_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return opivv_check(s, a) && s->cfg_ptr->ext_zvbb == true;
|
||||
}
|
||||
|
||||
static bool zvbb_vx_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return opivx_check(s, a) && s->cfg_ptr->ext_zvbb == true;
|
||||
}
|
||||
|
||||
/* vrol.v[vx] */
|
||||
GEN_OPIVV_GVEC_TRANS_CHECK(vrol_vv, rotlv, zvbb_vv_check)
|
||||
GEN_OPIVX_GVEC_SHIFT_TRANS_CHECK(vrol_vx, rotls, zvbb_vx_check)
|
||||
|
||||
/* vror.v[vxi] */
|
||||
GEN_OPIVV_GVEC_TRANS_CHECK(vror_vv, rotrv, zvbb_vv_check)
|
||||
GEN_OPIVX_GVEC_SHIFT_TRANS_CHECK(vror_vx, rotrs, zvbb_vx_check)
|
||||
GEN_OPIVI_GVEC_TRANS_CHECK(vror_vi, IMM_TRUNC_SEW, vror_vx, rotri, zvbb_vx_check)
|
||||
|
||||
#define GEN_OPIVX_GVEC_TRANS_CHECK(NAME, SUF, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_opivx *const fns[4] = { \
|
||||
gen_helper_##NAME##_b, \
|
||||
gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, \
|
||||
gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
/* vandn.v[vx] */
|
||||
GEN_OPIVV_GVEC_TRANS_CHECK(vandn_vv, andc, zvbb_vv_check)
|
||||
GEN_OPIVX_GVEC_TRANS_CHECK(vandn_vx, andcs, zvbb_vx_check)
|
||||
|
||||
#define GEN_OPIV_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
uint32_t data = 0; \
|
||||
static gen_helper_gvec_3_ptr *const fns[4] = { \
|
||||
gen_helper_##NAME##_b, \
|
||||
gen_helper_##NAME##_h, \
|
||||
gen_helper_##NAME##_w, \
|
||||
gen_helper_##NAME##_d, \
|
||||
}; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, \
|
||||
data, fns[s->sew]); \
|
||||
mark_vs_dirty(s); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool zvbb_opiv_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return s->cfg_ptr->ext_zvbb == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ss(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
GEN_OPIV_TRANS(vbrev8_v, zvbb_opiv_check)
|
||||
GEN_OPIV_TRANS(vrev8_v, zvbb_opiv_check)
|
||||
GEN_OPIV_TRANS(vbrev_v, zvbb_opiv_check)
|
||||
GEN_OPIV_TRANS(vclz_v, zvbb_opiv_check)
|
||||
GEN_OPIV_TRANS(vctz_v, zvbb_opiv_check)
|
||||
GEN_OPIV_TRANS(vcpop_v, zvbb_opiv_check)
|
||||
|
||||
static bool vwsll_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return s->cfg_ptr->ext_zvbb && opivv_widen_check(s, a);
|
||||
}
|
||||
|
||||
static bool vwsll_vx_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return s->cfg_ptr->ext_zvbb && opivx_widen_check(s, a);
|
||||
}
|
||||
|
||||
/* OPIVI without GVEC IR */
|
||||
#define GEN_OPIVI_WIDEN_TRANS(NAME, IMM_MODE, OPIVX, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
static gen_helper_opivx *const fns[3] = { \
|
||||
gen_helper_##OPIVX##_b, \
|
||||
gen_helper_##OPIVX##_h, \
|
||||
gen_helper_##OPIVX##_w, \
|
||||
}; \
|
||||
return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, \
|
||||
IMM_MODE); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
GEN_OPIVV_WIDEN_TRANS(vwsll_vv, vwsll_vv_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwsll_vx, vwsll_vx_check)
|
||||
GEN_OPIVI_WIDEN_TRANS(vwsll_vi, IMM_ZX, vwsll_vx, vwsll_vx_check)
|
||||
|
||||
/*
|
||||
* Zvkned
|
||||
*/
|
||||
|
||||
#define ZVKNED_EGS 4
|
||||
|
||||
#define GEN_V_UNMASKED_TRANS(NAME, CHECK, EGS) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
TCGv_ptr rd_v, rs2_v; \
|
||||
TCGv_i32 desc, egs; \
|
||||
uint32_t data = 0; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
\
|
||||
if (!s->vstart_eq_zero || !s->vl_eq_vlmax) { \
|
||||
/* save opcode for unwinding in case we throw an exception */ \
|
||||
decode_save_opc(s); \
|
||||
egs = tcg_constant_i32(EGS); \
|
||||
gen_helper_egs_check(egs, cpu_env); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
} \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
rd_v = tcg_temp_new_ptr(); \
|
||||
rs2_v = tcg_temp_new_ptr(); \
|
||||
desc = tcg_constant_i32( \
|
||||
simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); \
|
||||
tcg_gen_addi_ptr(rd_v, cpu_env, vreg_ofs(s, a->rd)); \
|
||||
tcg_gen_addi_ptr(rs2_v, cpu_env, vreg_ofs(s, a->rs2)); \
|
||||
gen_helper_##NAME(rd_v, rs2_v, cpu_env, desc); \
|
||||
mark_vs_dirty(s); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool vaes_check_vv(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
int egw_bytes = ZVKNED_EGS << s->sew;
|
||||
return s->cfg_ptr->ext_zvkned == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul) &&
|
||||
s->sew == MO_32;
|
||||
}
|
||||
|
||||
static bool vaes_check_overlap(DisasContext *s, int vd, int vs2)
|
||||
{
|
||||
int8_t op_size = s->lmul <= 0 ? 1 : 1 << s->lmul;
|
||||
return !is_overlapped(vd, op_size, vs2, 1);
|
||||
}
|
||||
|
||||
static bool vaes_check_vs(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
int egw_bytes = ZVKNED_EGS << s->sew;
|
||||
return vaes_check_overlap(s, a->rd, a->rs2) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
s->cfg_ptr->ext_zvkned == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
s->sew == MO_32;
|
||||
}
|
||||
|
||||
GEN_V_UNMASKED_TRANS(vaesef_vv, vaes_check_vv, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesef_vs, vaes_check_vs, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesdf_vv, vaes_check_vv, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesdf_vs, vaes_check_vs, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesdm_vv, vaes_check_vv, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesdm_vs, vaes_check_vs, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesz_vs, vaes_check_vs, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesem_vv, vaes_check_vv, ZVKNED_EGS)
|
||||
GEN_V_UNMASKED_TRANS(vaesem_vs, vaes_check_vs, ZVKNED_EGS)
|
||||
|
||||
#define GEN_VI_UNMASKED_TRANS(NAME, CHECK, EGS) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
TCGv_ptr rd_v, rs2_v; \
|
||||
TCGv_i32 uimm_v, desc, egs; \
|
||||
uint32_t data = 0; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
\
|
||||
if (!s->vstart_eq_zero || !s->vl_eq_vlmax) { \
|
||||
/* save opcode for unwinding in case we throw an exception */ \
|
||||
decode_save_opc(s); \
|
||||
egs = tcg_constant_i32(EGS); \
|
||||
gen_helper_egs_check(egs, cpu_env); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
} \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
\
|
||||
rd_v = tcg_temp_new_ptr(); \
|
||||
rs2_v = tcg_temp_new_ptr(); \
|
||||
uimm_v = tcg_constant_i32(a->rs1); \
|
||||
desc = tcg_constant_i32( \
|
||||
simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); \
|
||||
tcg_gen_addi_ptr(rd_v, cpu_env, vreg_ofs(s, a->rd)); \
|
||||
tcg_gen_addi_ptr(rs2_v, cpu_env, vreg_ofs(s, a->rs2)); \
|
||||
gen_helper_##NAME(rd_v, rs2_v, uimm_v, cpu_env, desc); \
|
||||
mark_vs_dirty(s); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool vaeskf1_check(DisasContext *s, arg_vaeskf1_vi *a)
|
||||
{
|
||||
int egw_bytes = ZVKNED_EGS << s->sew;
|
||||
return s->cfg_ptr->ext_zvkned == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
s->sew == MO_32 &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul);
|
||||
}
|
||||
|
||||
static bool vaeskf2_check(DisasContext *s, arg_vaeskf2_vi *a)
|
||||
{
|
||||
int egw_bytes = ZVKNED_EGS << s->sew;
|
||||
return s->cfg_ptr->ext_zvkned == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
s->sew == MO_32 &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul);
|
||||
}
|
||||
|
||||
GEN_VI_UNMASKED_TRANS(vaeskf1_vi, vaeskf1_check, ZVKNED_EGS)
|
||||
GEN_VI_UNMASKED_TRANS(vaeskf2_vi, vaeskf2_check, ZVKNED_EGS)
|
||||
|
||||
/*
|
||||
* Zvknh
|
||||
*/
|
||||
|
||||
#define ZVKNH_EGS 4
|
||||
|
||||
#define GEN_VV_UNMASKED_TRANS(NAME, CHECK, EGS) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (CHECK(s, a)) { \
|
||||
uint32_t data = 0; \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
TCGv_i32 egs; \
|
||||
\
|
||||
if (!s->vstart_eq_zero || !s->vl_eq_vlmax) { \
|
||||
/* save opcode for unwinding in case we throw an exception */ \
|
||||
decode_save_opc(s); \
|
||||
egs = tcg_constant_i32(EGS); \
|
||||
gen_helper_egs_check(egs, cpu_env); \
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
|
||||
} \
|
||||
\
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
\
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, \
|
||||
data, gen_helper_##NAME); \
|
||||
\
|
||||
mark_vs_dirty(s); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static bool vsha_check_sew(DisasContext *s)
|
||||
{
|
||||
return (s->cfg_ptr->ext_zvknha == true && s->sew == MO_32) ||
|
||||
(s->cfg_ptr->ext_zvknhb == true &&
|
||||
(s->sew == MO_32 || s->sew == MO_64));
|
||||
}
|
||||
|
||||
static bool vsha_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
int egw_bytes = ZVKNH_EGS << s->sew;
|
||||
int mult = 1 << MAX(s->lmul, 0);
|
||||
return opivv_check(s, a) &&
|
||||
vsha_check_sew(s) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
!is_overlapped(a->rd, mult, a->rs1, mult) &&
|
||||
!is_overlapped(a->rd, mult, a->rs2, mult) &&
|
||||
s->lmul >= 0;
|
||||
}
|
||||
|
||||
GEN_VV_UNMASKED_TRANS(vsha2ms_vv, vsha_check, ZVKNH_EGS)
|
||||
|
||||
static bool trans_vsha2cl_vv(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
if (vsha_check(s, a)) {
|
||||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
TCGv_i32 egs;
|
||||
|
||||
if (!s->vstart_eq_zero || !s->vl_eq_vlmax) {
|
||||
/* save opcode for unwinding in case we throw an exception */
|
||||
decode_save_opc(s);
|
||||
egs = tcg_constant_i32(ZVKNH_EGS);
|
||||
gen_helper_egs_check(egs, cpu_env);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
}
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
|
||||
vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8,
|
||||
s->cfg_ptr->vlen / 8, data,
|
||||
s->sew == MO_32 ?
|
||||
gen_helper_vsha2cl32_vv : gen_helper_vsha2cl64_vv);
|
||||
|
||||
mark_vs_dirty(s);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_vsha2ch_vv(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
if (vsha_check(s, a)) {
|
||||
uint32_t data = 0;
|
||||
TCGLabel *over = gen_new_label();
|
||||
TCGv_i32 egs;
|
||||
|
||||
if (!s->vstart_eq_zero || !s->vl_eq_vlmax) {
|
||||
/* save opcode for unwinding in case we throw an exception */
|
||||
decode_save_opc(s);
|
||||
egs = tcg_constant_i32(ZVKNH_EGS);
|
||||
gen_helper_egs_check(egs, cpu_env);
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
|
||||
}
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
|
||||
vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8,
|
||||
s->cfg_ptr->vlen / 8, data,
|
||||
s->sew == MO_32 ?
|
||||
gen_helper_vsha2ch32_vv : gen_helper_vsha2ch64_vv);
|
||||
|
||||
mark_vs_dirty(s);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zvksh
|
||||
*/
|
||||
|
||||
#define ZVKSH_EGS 8
|
||||
|
||||
static inline bool vsm3_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
int egw_bytes = ZVKSH_EGS << s->sew;
|
||||
int mult = 1 << MAX(s->lmul, 0);
|
||||
return s->cfg_ptr->ext_zvksh == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
!is_overlapped(a->rd, mult, a->rs2, mult) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
s->sew == MO_32;
|
||||
}
|
||||
|
||||
static inline bool vsm3me_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return vsm3_check(s, a) && vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
static inline bool vsm3c_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return vsm3_check(s, a) && vext_check_ss(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
GEN_VV_UNMASKED_TRANS(vsm3me_vv, vsm3me_check, ZVKSH_EGS)
|
||||
GEN_VI_UNMASKED_TRANS(vsm3c_vi, vsm3c_check, ZVKSH_EGS)
|
||||
|
||||
/*
|
||||
* Zvkg
|
||||
*/
|
||||
|
||||
#define ZVKG_EGS 4
|
||||
|
||||
static bool vgmul_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
int egw_bytes = ZVKG_EGS << s->sew;
|
||||
return s->cfg_ptr->ext_zvkg == true &&
|
||||
vext_check_isa_ill(s) &&
|
||||
require_rvv(s) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
vext_check_ss(s, a->rd, a->rs2, a->vm) &&
|
||||
s->sew == MO_32;
|
||||
}
|
||||
|
||||
GEN_V_UNMASKED_TRANS(vgmul_vv, vgmul_check, ZVKG_EGS)
|
||||
|
||||
static bool vghsh_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
int egw_bytes = ZVKG_EGS << s->sew;
|
||||
return s->cfg_ptr->ext_zvkg == true &&
|
||||
opivv_check(s, a) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
s->sew == MO_32;
|
||||
}
|
||||
|
||||
GEN_VV_UNMASKED_TRANS(vghsh_vv, vghsh_check, ZVKG_EGS)
|
||||
|
||||
/*
|
||||
* Zvksed
|
||||
*/
|
||||
|
||||
#define ZVKSED_EGS 4
|
||||
|
||||
static bool zvksed_check(DisasContext *s)
|
||||
{
|
||||
int egw_bytes = ZVKSED_EGS << s->sew;
|
||||
return s->cfg_ptr->ext_zvksed == true &&
|
||||
require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
MAXSZ(s) >= egw_bytes &&
|
||||
s->sew == MO_32;
|
||||
}
|
||||
|
||||
static bool vsm4k_vi_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return zvksed_check(s) &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul);
|
||||
}
|
||||
|
||||
GEN_VI_UNMASKED_TRANS(vsm4k_vi, vsm4k_vi_check, ZVKSED_EGS)
|
||||
|
||||
static bool vsm4r_vv_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return zvksed_check(s) &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul);
|
||||
}
|
||||
|
||||
GEN_V_UNMASKED_TRANS(vsm4r_vv, vsm4r_vv_check, ZVKSED_EGS)
|
||||
|
||||
static bool vsm4r_vs_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return zvksed_check(s) &&
|
||||
!is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) &&
|
||||
require_align(a->rd, s->lmul);
|
||||
}
|
||||
|
||||
GEN_V_UNMASKED_TRANS(vsm4r_vs, vsm4r_vs_check, ZVKSED_EGS)
|
|
@ -470,7 +470,7 @@ bool trans_fleq_d(DisasContext *ctx, arg_fleq_d *a)
|
|||
TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1);
|
||||
TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2);
|
||||
|
||||
gen_helper_fltq_s(dest, cpu_env, src1, src2);
|
||||
gen_helper_fleq_d(dest, cpu_env, src1, src2);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
@ -485,7 +485,7 @@ bool trans_fltq_d(DisasContext *ctx, arg_fltq_d *a)
|
|||
TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1);
|
||||
TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2);
|
||||
|
||||
gen_helper_fltq_s(dest, cpu_env, src1, src2);
|
||||
gen_helper_fltq_d(dest, cpu_env, src1, src2);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "exec/address-spaces.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/intc/riscv_imsic.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/loader.h"
|
||||
#include "kvm_riscv.h"
|
||||
|
@ -43,6 +44,12 @@
|
|||
#include "chardev/char-fe.h"
|
||||
#include "migration/migration.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/riscv/numa.h"
|
||||
|
||||
void riscv_kvm_aplic_request(void *opaque, int irq, int level)
|
||||
{
|
||||
kvm_set_irq(kvm_state, irq, !!level);
|
||||
}
|
||||
|
||||
static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
|
||||
uint64_t idx)
|
||||
|
@ -926,7 +933,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
|||
|
||||
int kvm_arch_irqchip_create(KVMState *s)
|
||||
{
|
||||
return 0;
|
||||
if (kvm_kernel_irqchip_split()) {
|
||||
error_report("-machine kernel_irqchip=split is not supported on RISC-V.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can create the VAIA using the newer device control API.
|
||||
*/
|
||||
return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
|
||||
}
|
||||
|
||||
int kvm_arch_process_async_events(CPUState *cs)
|
||||
|
@ -1027,6 +1042,190 @@ bool kvm_arch_cpu_check_are_resettable(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int aia_mode;
|
||||
|
||||
static const char *kvm_aia_mode_str(uint64_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case KVM_DEV_RISCV_AIA_MODE_EMUL:
|
||||
return "emul";
|
||||
case KVM_DEV_RISCV_AIA_MODE_HWACCEL:
|
||||
return "hwaccel";
|
||||
case KVM_DEV_RISCV_AIA_MODE_AUTO:
|
||||
default:
|
||||
return "auto";
|
||||
};
|
||||
}
|
||||
|
||||
static char *riscv_get_kvm_aia(Object *obj, Error **errp)
|
||||
{
|
||||
return g_strdup(kvm_aia_mode_str(aia_mode));
|
||||
}
|
||||
|
||||
static void riscv_set_kvm_aia(Object *obj, const char *val, Error **errp)
|
||||
{
|
||||
if (!strcmp(val, "emul")) {
|
||||
aia_mode = KVM_DEV_RISCV_AIA_MODE_EMUL;
|
||||
} else if (!strcmp(val, "hwaccel")) {
|
||||
aia_mode = KVM_DEV_RISCV_AIA_MODE_HWACCEL;
|
||||
} else if (!strcmp(val, "auto")) {
|
||||
aia_mode = KVM_DEV_RISCV_AIA_MODE_AUTO;
|
||||
} else {
|
||||
error_setg(errp, "Invalid KVM AIA mode");
|
||||
error_append_hint(errp, "Valid values are emul, hwaccel, and auto.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_arch_accel_class_init(ObjectClass *oc)
|
||||
{
|
||||
object_class_property_add_str(oc, "riscv-aia", riscv_get_kvm_aia,
|
||||
riscv_set_kvm_aia);
|
||||
object_class_property_set_description(oc, "riscv-aia",
|
||||
"Set KVM AIA mode. Valid values are "
|
||||
"emul, hwaccel, and auto. Default "
|
||||
"is auto.");
|
||||
object_property_set_default_str(object_class_property_find(oc, "riscv-aia"),
|
||||
"auto");
|
||||
}
|
||||
|
||||
void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
|
||||
uint64_t aia_irq_num, uint64_t aia_msi_num,
|
||||
uint64_t aplic_base, uint64_t imsic_base,
|
||||
uint64_t guest_num)
|
||||
{
|
||||
int ret, i;
|
||||
int aia_fd = -1;
|
||||
uint64_t default_aia_mode;
|
||||
uint64_t socket_count = riscv_socket_count(machine);
|
||||
uint64_t max_hart_per_socket = 0;
|
||||
uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr;
|
||||
uint64_t socket_bits, hart_bits, guest_bits;
|
||||
|
||||
aia_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_RISCV_AIA, false);
|
||||
|
||||
if (aia_fd < 0) {
|
||||
error_report("Unable to create in-kernel irqchip");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_MODE,
|
||||
&default_aia_mode, false, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to get current KVM AIA mode");
|
||||
exit(1);
|
||||
}
|
||||
qemu_log("KVM AIA: default mode is %s\n",
|
||||
kvm_aia_mode_str(default_aia_mode));
|
||||
|
||||
if (default_aia_mode != aia_mode) {
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_MODE,
|
||||
&aia_mode, true, NULL);
|
||||
if (ret < 0)
|
||||
warn_report("KVM AIA: failed to set KVM AIA mode");
|
||||
else
|
||||
qemu_log("KVM AIA: set current mode to %s\n",
|
||||
kvm_aia_mode_str(aia_mode));
|
||||
}
|
||||
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_SRCS,
|
||||
&aia_irq_num, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set number of input irq lines");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_IDS,
|
||||
&aia_msi_num, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set number of msi");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1;
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS,
|
||||
&socket_bits, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set group_bits");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT,
|
||||
&group_shift, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set group_shift");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
guest_bits = guest_num == 0 ? 0 :
|
||||
find_last_bit(&guest_num, BITS_PER_LONG) + 1;
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_GUEST_BITS,
|
||||
&guest_bits, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set guest_bits");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_ADDR,
|
||||
KVM_DEV_RISCV_AIA_ADDR_APLIC,
|
||||
&aplic_base, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set the base address of APLIC");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (socket = 0; socket < socket_count; socket++) {
|
||||
socket_imsic_base = imsic_base + socket * (1U << group_shift);
|
||||
hart_count = riscv_socket_hart_count(machine, socket);
|
||||
base_hart = riscv_socket_first_hartid(machine, socket);
|
||||
|
||||
if (max_hart_per_socket < hart_count) {
|
||||
max_hart_per_socket = hart_count;
|
||||
}
|
||||
|
||||
for (i = 0; i < hart_count; i++) {
|
||||
imsic_addr = socket_imsic_base + i * IMSIC_HART_SIZE(guest_bits);
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_ADDR,
|
||||
KVM_DEV_RISCV_AIA_ADDR_IMSIC(i + base_hart),
|
||||
&imsic_addr, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set the IMSIC address for hart %d", i);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1;
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
|
||||
KVM_DEV_RISCV_AIA_CONFIG_HART_BITS,
|
||||
&hart_bits, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: failed to set hart_bits");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (kvm_has_gsi_routing()) {
|
||||
for (uint64_t idx = 0; idx < aia_irq_num + 1; ++idx) {
|
||||
/* KVM AIA only has one APLIC instance */
|
||||
kvm_irqchip_add_irq_route(kvm_state, idx, 0, idx);
|
||||
}
|
||||
kvm_gsi_routing_allowed = true;
|
||||
kvm_irqchip_commit_routes(kvm_state);
|
||||
}
|
||||
|
||||
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CTRL,
|
||||
KVM_DEV_RISCV_AIA_CTRL_INIT,
|
||||
NULL, true, NULL);
|
||||
if (ret < 0) {
|
||||
error_report("KVM AIA: initialized fail");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
||||
}
|
||||
|
|
|
@ -22,5 +22,10 @@
|
|||
void kvm_riscv_init_user_properties(Object *cpu_obj);
|
||||
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
|
||||
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
|
||||
void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
|
||||
uint64_t aia_irq_num, uint64_t aia_msi_num,
|
||||
uint64_t aplic_base, uint64_t imsic_base,
|
||||
uint64_t guest_num);
|
||||
void riscv_kvm_aplic_request(void *opaque, int irq, int level);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,11 +16,13 @@ riscv_ss.add(files(
|
|||
'gdbstub.c',
|
||||
'op_helper.c',
|
||||
'vector_helper.c',
|
||||
'vector_internals.c',
|
||||
'bitmanip_helper.c',
|
||||
'translate.c',
|
||||
'm128_helper.c',
|
||||
'crypto_helper.c',
|
||||
'zce_helper.c'
|
||||
'zce_helper.c',
|
||||
'vcrypto_helper.c'
|
||||
))
|
||||
riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
|
||||
|
||||
|
|
|
@ -44,6 +44,10 @@ static inline uint8_t pmp_get_a_field(uint8_t cfg)
|
|||
*/
|
||||
static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
/* mseccfg.RLB is set */
|
||||
if (MSECCFG_RLB_ISSET(env)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
|
||||
return 1;
|
||||
|
|
|
@ -1094,6 +1094,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
|
|||
#include "insn_trans/trans_rvzfa.c.inc"
|
||||
#include "insn_trans/trans_rvzfh.c.inc"
|
||||
#include "insn_trans/trans_rvk.c.inc"
|
||||
#include "insn_trans/trans_rvvk.c.inc"
|
||||
#include "insn_trans/trans_privileged.c.inc"
|
||||
#include "insn_trans/trans_svinval.c.inc"
|
||||
#include "insn_trans/trans_rvbf16.c.inc"
|
||||
|
|
|
@ -0,0 +1,970 @@
|
|||
/*
|
||||
* RISC-V Vector Crypto Extension Helpers for QEMU.
|
||||
*
|
||||
* Copyright (C) 2023 SiFive, Inc.
|
||||
* Written by Codethink Ltd and SiFive.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "cpu.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes-round.h"
|
||||
#include "crypto/sm4.h"
|
||||
#include "exec/memop.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "internals.h"
|
||||
#include "vector_internals.h"
|
||||
|
||||
static uint64_t clmul64(uint64_t y, uint64_t x)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (int j = 63; j >= 0; j--) {
|
||||
if ((y >> j) & 1) {
|
||||
result ^= (x << j);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint64_t clmulh64(uint64_t y, uint64_t x)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (int j = 63; j >= 1; j--) {
|
||||
if ((y >> j) & 1) {
|
||||
result ^= (x >> (64 - j));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RVVCALL(OPIVV2, vclmul_vv, OP_UUU_D, H8, H8, H8, clmul64)
|
||||
GEN_VEXT_VV(vclmul_vv, 8)
|
||||
RVVCALL(OPIVX2, vclmul_vx, OP_UUU_D, H8, H8, clmul64)
|
||||
GEN_VEXT_VX(vclmul_vx, 8)
|
||||
RVVCALL(OPIVV2, vclmulh_vv, OP_UUU_D, H8, H8, H8, clmulh64)
|
||||
GEN_VEXT_VV(vclmulh_vv, 8)
|
||||
RVVCALL(OPIVX2, vclmulh_vx, OP_UUU_D, H8, H8, clmulh64)
|
||||
GEN_VEXT_VX(vclmulh_vx, 8)
|
||||
|
||||
RVVCALL(OPIVV2, vror_vv_b, OP_UUU_B, H1, H1, H1, ror8)
|
||||
RVVCALL(OPIVV2, vror_vv_h, OP_UUU_H, H2, H2, H2, ror16)
|
||||
RVVCALL(OPIVV2, vror_vv_w, OP_UUU_W, H4, H4, H4, ror32)
|
||||
RVVCALL(OPIVV2, vror_vv_d, OP_UUU_D, H8, H8, H8, ror64)
|
||||
GEN_VEXT_VV(vror_vv_b, 1)
|
||||
GEN_VEXT_VV(vror_vv_h, 2)
|
||||
GEN_VEXT_VV(vror_vv_w, 4)
|
||||
GEN_VEXT_VV(vror_vv_d, 8)
|
||||
|
||||
RVVCALL(OPIVX2, vror_vx_b, OP_UUU_B, H1, H1, ror8)
|
||||
RVVCALL(OPIVX2, vror_vx_h, OP_UUU_H, H2, H2, ror16)
|
||||
RVVCALL(OPIVX2, vror_vx_w, OP_UUU_W, H4, H4, ror32)
|
||||
RVVCALL(OPIVX2, vror_vx_d, OP_UUU_D, H8, H8, ror64)
|
||||
GEN_VEXT_VX(vror_vx_b, 1)
|
||||
GEN_VEXT_VX(vror_vx_h, 2)
|
||||
GEN_VEXT_VX(vror_vx_w, 4)
|
||||
GEN_VEXT_VX(vror_vx_d, 8)
|
||||
|
||||
RVVCALL(OPIVV2, vrol_vv_b, OP_UUU_B, H1, H1, H1, rol8)
|
||||
RVVCALL(OPIVV2, vrol_vv_h, OP_UUU_H, H2, H2, H2, rol16)
|
||||
RVVCALL(OPIVV2, vrol_vv_w, OP_UUU_W, H4, H4, H4, rol32)
|
||||
RVVCALL(OPIVV2, vrol_vv_d, OP_UUU_D, H8, H8, H8, rol64)
|
||||
GEN_VEXT_VV(vrol_vv_b, 1)
|
||||
GEN_VEXT_VV(vrol_vv_h, 2)
|
||||
GEN_VEXT_VV(vrol_vv_w, 4)
|
||||
GEN_VEXT_VV(vrol_vv_d, 8)
|
||||
|
||||
RVVCALL(OPIVX2, vrol_vx_b, OP_UUU_B, H1, H1, rol8)
|
||||
RVVCALL(OPIVX2, vrol_vx_h, OP_UUU_H, H2, H2, rol16)
|
||||
RVVCALL(OPIVX2, vrol_vx_w, OP_UUU_W, H4, H4, rol32)
|
||||
RVVCALL(OPIVX2, vrol_vx_d, OP_UUU_D, H8, H8, rol64)
|
||||
GEN_VEXT_VX(vrol_vx_b, 1)
|
||||
GEN_VEXT_VX(vrol_vx_h, 2)
|
||||
GEN_VEXT_VX(vrol_vx_w, 4)
|
||||
GEN_VEXT_VX(vrol_vx_d, 8)
|
||||
|
||||
static uint64_t brev8(uint64_t val)
|
||||
{
|
||||
val = ((val & 0x5555555555555555ull) << 1) |
|
||||
((val & 0xAAAAAAAAAAAAAAAAull) >> 1);
|
||||
val = ((val & 0x3333333333333333ull) << 2) |
|
||||
((val & 0xCCCCCCCCCCCCCCCCull) >> 2);
|
||||
val = ((val & 0x0F0F0F0F0F0F0F0Full) << 4) |
|
||||
((val & 0xF0F0F0F0F0F0F0F0ull) >> 4);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
RVVCALL(OPIVV1, vbrev8_v_b, OP_UU_B, H1, H1, brev8)
|
||||
RVVCALL(OPIVV1, vbrev8_v_h, OP_UU_H, H2, H2, brev8)
|
||||
RVVCALL(OPIVV1, vbrev8_v_w, OP_UU_W, H4, H4, brev8)
|
||||
RVVCALL(OPIVV1, vbrev8_v_d, OP_UU_D, H8, H8, brev8)
|
||||
GEN_VEXT_V(vbrev8_v_b, 1)
|
||||
GEN_VEXT_V(vbrev8_v_h, 2)
|
||||
GEN_VEXT_V(vbrev8_v_w, 4)
|
||||
GEN_VEXT_V(vbrev8_v_d, 8)
|
||||
|
||||
#define DO_IDENTITY(a) (a)
|
||||
RVVCALL(OPIVV1, vrev8_v_b, OP_UU_B, H1, H1, DO_IDENTITY)
|
||||
RVVCALL(OPIVV1, vrev8_v_h, OP_UU_H, H2, H2, bswap16)
|
||||
RVVCALL(OPIVV1, vrev8_v_w, OP_UU_W, H4, H4, bswap32)
|
||||
RVVCALL(OPIVV1, vrev8_v_d, OP_UU_D, H8, H8, bswap64)
|
||||
GEN_VEXT_V(vrev8_v_b, 1)
|
||||
GEN_VEXT_V(vrev8_v_h, 2)
|
||||
GEN_VEXT_V(vrev8_v_w, 4)
|
||||
GEN_VEXT_V(vrev8_v_d, 8)
|
||||
|
||||
#define DO_ANDN(a, b) ((a) & ~(b))
|
||||
RVVCALL(OPIVV2, vandn_vv_b, OP_UUU_B, H1, H1, H1, DO_ANDN)
|
||||
RVVCALL(OPIVV2, vandn_vv_h, OP_UUU_H, H2, H2, H2, DO_ANDN)
|
||||
RVVCALL(OPIVV2, vandn_vv_w, OP_UUU_W, H4, H4, H4, DO_ANDN)
|
||||
RVVCALL(OPIVV2, vandn_vv_d, OP_UUU_D, H8, H8, H8, DO_ANDN)
|
||||
GEN_VEXT_VV(vandn_vv_b, 1)
|
||||
GEN_VEXT_VV(vandn_vv_h, 2)
|
||||
GEN_VEXT_VV(vandn_vv_w, 4)
|
||||
GEN_VEXT_VV(vandn_vv_d, 8)
|
||||
|
||||
RVVCALL(OPIVX2, vandn_vx_b, OP_UUU_B, H1, H1, DO_ANDN)
|
||||
RVVCALL(OPIVX2, vandn_vx_h, OP_UUU_H, H2, H2, DO_ANDN)
|
||||
RVVCALL(OPIVX2, vandn_vx_w, OP_UUU_W, H4, H4, DO_ANDN)
|
||||
RVVCALL(OPIVX2, vandn_vx_d, OP_UUU_D, H8, H8, DO_ANDN)
|
||||
GEN_VEXT_VX(vandn_vx_b, 1)
|
||||
GEN_VEXT_VX(vandn_vx_h, 2)
|
||||
GEN_VEXT_VX(vandn_vx_w, 4)
|
||||
GEN_VEXT_VX(vandn_vx_d, 8)
|
||||
|
||||
RVVCALL(OPIVV1, vbrev_v_b, OP_UU_B, H1, H1, revbit8)
|
||||
RVVCALL(OPIVV1, vbrev_v_h, OP_UU_H, H2, H2, revbit16)
|
||||
RVVCALL(OPIVV1, vbrev_v_w, OP_UU_W, H4, H4, revbit32)
|
||||
RVVCALL(OPIVV1, vbrev_v_d, OP_UU_D, H8, H8, revbit64)
|
||||
GEN_VEXT_V(vbrev_v_b, 1)
|
||||
GEN_VEXT_V(vbrev_v_h, 2)
|
||||
GEN_VEXT_V(vbrev_v_w, 4)
|
||||
GEN_VEXT_V(vbrev_v_d, 8)
|
||||
|
||||
RVVCALL(OPIVV1, vclz_v_b, OP_UU_B, H1, H1, clz8)
|
||||
RVVCALL(OPIVV1, vclz_v_h, OP_UU_H, H2, H2, clz16)
|
||||
RVVCALL(OPIVV1, vclz_v_w, OP_UU_W, H4, H4, clz32)
|
||||
RVVCALL(OPIVV1, vclz_v_d, OP_UU_D, H8, H8, clz64)
|
||||
GEN_VEXT_V(vclz_v_b, 1)
|
||||
GEN_VEXT_V(vclz_v_h, 2)
|
||||
GEN_VEXT_V(vclz_v_w, 4)
|
||||
GEN_VEXT_V(vclz_v_d, 8)
|
||||
|
||||
RVVCALL(OPIVV1, vctz_v_b, OP_UU_B, H1, H1, ctz8)
|
||||
RVVCALL(OPIVV1, vctz_v_h, OP_UU_H, H2, H2, ctz16)
|
||||
RVVCALL(OPIVV1, vctz_v_w, OP_UU_W, H4, H4, ctz32)
|
||||
RVVCALL(OPIVV1, vctz_v_d, OP_UU_D, H8, H8, ctz64)
|
||||
GEN_VEXT_V(vctz_v_b, 1)
|
||||
GEN_VEXT_V(vctz_v_h, 2)
|
||||
GEN_VEXT_V(vctz_v_w, 4)
|
||||
GEN_VEXT_V(vctz_v_d, 8)
|
||||
|
||||
RVVCALL(OPIVV1, vcpop_v_b, OP_UU_B, H1, H1, ctpop8)
|
||||
RVVCALL(OPIVV1, vcpop_v_h, OP_UU_H, H2, H2, ctpop16)
|
||||
RVVCALL(OPIVV1, vcpop_v_w, OP_UU_W, H4, H4, ctpop32)
|
||||
RVVCALL(OPIVV1, vcpop_v_d, OP_UU_D, H8, H8, ctpop64)
|
||||
GEN_VEXT_V(vcpop_v_b, 1)
|
||||
GEN_VEXT_V(vcpop_v_h, 2)
|
||||
GEN_VEXT_V(vcpop_v_w, 4)
|
||||
GEN_VEXT_V(vcpop_v_d, 8)
|
||||
|
||||
#define DO_SLL(N, M) (N << (M & (sizeof(N) * 8 - 1)))
|
||||
RVVCALL(OPIVV2, vwsll_vv_b, WOP_UUU_B, H2, H1, H1, DO_SLL)
|
||||
RVVCALL(OPIVV2, vwsll_vv_h, WOP_UUU_H, H4, H2, H2, DO_SLL)
|
||||
RVVCALL(OPIVV2, vwsll_vv_w, WOP_UUU_W, H8, H4, H4, DO_SLL)
|
||||
GEN_VEXT_VV(vwsll_vv_b, 2)
|
||||
GEN_VEXT_VV(vwsll_vv_h, 4)
|
||||
GEN_VEXT_VV(vwsll_vv_w, 8)
|
||||
|
||||
RVVCALL(OPIVX2, vwsll_vx_b, WOP_UUU_B, H2, H1, DO_SLL)
|
||||
RVVCALL(OPIVX2, vwsll_vx_h, WOP_UUU_H, H4, H2, DO_SLL)
|
||||
RVVCALL(OPIVX2, vwsll_vx_w, WOP_UUU_W, H8, H4, DO_SLL)
|
||||
GEN_VEXT_VX(vwsll_vx_b, 2)
|
||||
GEN_VEXT_VX(vwsll_vx_h, 4)
|
||||
GEN_VEXT_VX(vwsll_vx_w, 8)
|
||||
|
||||
void HELPER(egs_check)(uint32_t egs, CPURISCVState *env)
|
||||
{
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t vstart = env->vstart;
|
||||
|
||||
if (vl % egs != 0 || vstart % egs != 0) {
|
||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
||||
}
|
||||
}
|
||||
|
||||
static inline void xor_round_key(AESState *round_state, AESState *round_key)
|
||||
{
|
||||
round_state->v = round_state->v ^ round_key->v;
|
||||
}
|
||||
|
||||
#define GEN_ZVKNED_HELPER_VV(NAME, ...) \
|
||||
void HELPER(NAME)(void *vd, void *vs2, CPURISCVState *env, \
|
||||
uint32_t desc) \
|
||||
{ \
|
||||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
\
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \
|
||||
AESState round_key; \
|
||||
round_key.d[0] = *((uint64_t *)vs2 + H8(i * 2 + 0)); \
|
||||
round_key.d[1] = *((uint64_t *)vs2 + H8(i * 2 + 1)); \
|
||||
AESState round_state; \
|
||||
round_state.d[0] = *((uint64_t *)vd + H8(i * 2 + 0)); \
|
||||
round_state.d[1] = *((uint64_t *)vd + H8(i * 2 + 1)); \
|
||||
__VA_ARGS__; \
|
||||
*((uint64_t *)vd + H8(i * 2 + 0)) = round_state.d[0]; \
|
||||
*((uint64_t *)vd + H8(i * 2 + 1)) = round_state.d[1]; \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, vl * 4, total_elems * 4); \
|
||||
}
|
||||
|
||||
#define GEN_ZVKNED_HELPER_VS(NAME, ...) \
|
||||
void HELPER(NAME)(void *vd, void *vs2, CPURISCVState *env, \
|
||||
uint32_t desc) \
|
||||
{ \
|
||||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
\
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \
|
||||
AESState round_key; \
|
||||
round_key.d[0] = *((uint64_t *)vs2 + H8(0)); \
|
||||
round_key.d[1] = *((uint64_t *)vs2 + H8(1)); \
|
||||
AESState round_state; \
|
||||
round_state.d[0] = *((uint64_t *)vd + H8(i * 2 + 0)); \
|
||||
round_state.d[1] = *((uint64_t *)vd + H8(i * 2 + 1)); \
|
||||
__VA_ARGS__; \
|
||||
*((uint64_t *)vd + H8(i * 2 + 0)) = round_state.d[0]; \
|
||||
*((uint64_t *)vd + H8(i * 2 + 1)) = round_state.d[1]; \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, vl * 4, total_elems * 4); \
|
||||
}
|
||||
|
||||
GEN_ZVKNED_HELPER_VV(vaesef_vv, aesenc_SB_SR_AK(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VS(vaesef_vs, aesenc_SB_SR_AK(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VV(vaesdf_vv, aesdec_ISB_ISR_AK(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VS(vaesdf_vs, aesdec_ISB_ISR_AK(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VV(vaesem_vv, aesenc_SB_SR_MC_AK(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VS(vaesem_vs, aesenc_SB_SR_MC_AK(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VV(vaesdm_vv, aesdec_ISB_ISR_AK_IMC(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VS(vaesdm_vs, aesdec_ISB_ISR_AK_IMC(&round_state,
|
||||
&round_state,
|
||||
&round_key,
|
||||
false);)
|
||||
GEN_ZVKNED_HELPER_VS(vaesz_vs, xor_round_key(&round_state, &round_key);)
|
||||
|
||||
void HELPER(vaeskf1_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
uint32_t *vd = vd_vptr;
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
uimm &= 0b1111;
|
||||
if (uimm > 10 || uimm == 0) {
|
||||
uimm ^= 0b1000;
|
||||
}
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint32_t rk[8], tmp;
|
||||
static const uint32_t rcon[] = {
|
||||
0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
|
||||
0x00000020, 0x00000040, 0x00000080, 0x0000001B, 0x00000036,
|
||||
};
|
||||
|
||||
rk[0] = vs2[i * 4 + H4(0)];
|
||||
rk[1] = vs2[i * 4 + H4(1)];
|
||||
rk[2] = vs2[i * 4 + H4(2)];
|
||||
rk[3] = vs2[i * 4 + H4(3)];
|
||||
tmp = ror32(rk[3], 8);
|
||||
|
||||
rk[4] = rk[0] ^ (((uint32_t)AES_sbox[(tmp >> 24) & 0xff] << 24) |
|
||||
((uint32_t)AES_sbox[(tmp >> 16) & 0xff] << 16) |
|
||||
((uint32_t)AES_sbox[(tmp >> 8) & 0xff] << 8) |
|
||||
((uint32_t)AES_sbox[(tmp >> 0) & 0xff] << 0))
|
||||
^ rcon[uimm - 1];
|
||||
rk[5] = rk[1] ^ rk[4];
|
||||
rk[6] = rk[2] ^ rk[5];
|
||||
rk[7] = rk[3] ^ rk[6];
|
||||
|
||||
vd[i * 4 + H4(0)] = rk[4];
|
||||
vd[i * 4 + H4(1)] = rk[5];
|
||||
vd[i * 4 + H4(2)] = rk[6];
|
||||
vd[i * 4 + H4(3)] = rk[7];
|
||||
}
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, vl * 4, total_elems * 4);
|
||||
}
|
||||
|
||||
void HELPER(vaeskf2_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
uint32_t *vd = vd_vptr;
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
uimm &= 0b1111;
|
||||
if (uimm > 14 || uimm < 2) {
|
||||
uimm ^= 0b1000;
|
||||
}
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint32_t rk[12], tmp;
|
||||
static const uint32_t rcon[] = {
|
||||
0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
|
||||
0x00000020, 0x00000040, 0x00000080, 0x0000001B, 0x00000036,
|
||||
};
|
||||
|
||||
rk[0] = vd[i * 4 + H4(0)];
|
||||
rk[1] = vd[i * 4 + H4(1)];
|
||||
rk[2] = vd[i * 4 + H4(2)];
|
||||
rk[3] = vd[i * 4 + H4(3)];
|
||||
rk[4] = vs2[i * 4 + H4(0)];
|
||||
rk[5] = vs2[i * 4 + H4(1)];
|
||||
rk[6] = vs2[i * 4 + H4(2)];
|
||||
rk[7] = vs2[i * 4 + H4(3)];
|
||||
|
||||
if (uimm % 2 == 0) {
|
||||
tmp = ror32(rk[7], 8);
|
||||
rk[8] = rk[0] ^ (((uint32_t)AES_sbox[(tmp >> 24) & 0xff] << 24) |
|
||||
((uint32_t)AES_sbox[(tmp >> 16) & 0xff] << 16) |
|
||||
((uint32_t)AES_sbox[(tmp >> 8) & 0xff] << 8) |
|
||||
((uint32_t)AES_sbox[(tmp >> 0) & 0xff] << 0))
|
||||
^ rcon[(uimm - 1) / 2];
|
||||
} else {
|
||||
rk[8] = rk[0] ^ (((uint32_t)AES_sbox[(rk[7] >> 24) & 0xff] << 24) |
|
||||
((uint32_t)AES_sbox[(rk[7] >> 16) & 0xff] << 16) |
|
||||
((uint32_t)AES_sbox[(rk[7] >> 8) & 0xff] << 8) |
|
||||
((uint32_t)AES_sbox[(rk[7] >> 0) & 0xff] << 0));
|
||||
}
|
||||
rk[9] = rk[1] ^ rk[8];
|
||||
rk[10] = rk[2] ^ rk[9];
|
||||
rk[11] = rk[3] ^ rk[10];
|
||||
|
||||
vd[i * 4 + H4(0)] = rk[8];
|
||||
vd[i * 4 + H4(1)] = rk[9];
|
||||
vd[i * 4 + H4(2)] = rk[10];
|
||||
vd[i * 4 + H4(3)] = rk[11];
|
||||
}
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, vl * 4, total_elems * 4);
|
||||
}
|
||||
|
||||
static inline uint32_t sig0_sha256(uint32_t x)
|
||||
{
|
||||
return ror32(x, 7) ^ ror32(x, 18) ^ (x >> 3);
|
||||
}
|
||||
|
||||
static inline uint32_t sig1_sha256(uint32_t x)
|
||||
{
|
||||
return ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10);
|
||||
}
|
||||
|
||||
static inline uint64_t sig0_sha512(uint64_t x)
|
||||
{
|
||||
return ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7);
|
||||
}
|
||||
|
||||
static inline uint64_t sig1_sha512(uint64_t x)
|
||||
{
|
||||
return ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6);
|
||||
}
|
||||
|
||||
static inline void vsha2ms_e32(uint32_t *vd, uint32_t *vs1, uint32_t *vs2)
|
||||
{
|
||||
uint32_t res[4];
|
||||
res[0] = sig1_sha256(vs1[H4(2)]) + vs2[H4(1)] + sig0_sha256(vd[H4(1)]) +
|
||||
vd[H4(0)];
|
||||
res[1] = sig1_sha256(vs1[H4(3)]) + vs2[H4(2)] + sig0_sha256(vd[H4(2)]) +
|
||||
vd[H4(1)];
|
||||
res[2] =
|
||||
sig1_sha256(res[0]) + vs2[H4(3)] + sig0_sha256(vd[H4(3)]) + vd[H4(2)];
|
||||
res[3] =
|
||||
sig1_sha256(res[1]) + vs1[H4(0)] + sig0_sha256(vs2[H4(0)]) + vd[H4(3)];
|
||||
vd[H4(3)] = res[3];
|
||||
vd[H4(2)] = res[2];
|
||||
vd[H4(1)] = res[1];
|
||||
vd[H4(0)] = res[0];
|
||||
}
|
||||
|
||||
static inline void vsha2ms_e64(uint64_t *vd, uint64_t *vs1, uint64_t *vs2)
|
||||
{
|
||||
uint64_t res[4];
|
||||
res[0] = sig1_sha512(vs1[2]) + vs2[1] + sig0_sha512(vd[1]) + vd[0];
|
||||
res[1] = sig1_sha512(vs1[3]) + vs2[2] + sig0_sha512(vd[2]) + vd[1];
|
||||
res[2] = sig1_sha512(res[0]) + vs2[3] + sig0_sha512(vd[3]) + vd[2];
|
||||
res[3] = sig1_sha512(res[1]) + vs1[0] + sig0_sha512(vs2[0]) + vd[3];
|
||||
vd[3] = res[3];
|
||||
vd[2] = res[2];
|
||||
vd[1] = res[1];
|
||||
vd[0] = res[0];
|
||||
}
|
||||
|
||||
void HELPER(vsha2ms_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
uint32_t sew = FIELD_EX64(env->vtype, VTYPE, VSEW);
|
||||
uint32_t esz = sew == MO_32 ? 4 : 8;
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
if (sew == MO_32) {
|
||||
vsha2ms_e32(((uint32_t *)vd) + i * 4, ((uint32_t *)vs1) + i * 4,
|
||||
((uint32_t *)vs2) + i * 4);
|
||||
} else {
|
||||
/* If not 32 then SEW should be 64 */
|
||||
vsha2ms_e64(((uint64_t *)vd) + i * 4, ((uint64_t *)vs1) + i * 4,
|
||||
((uint64_t *)vs2) + i * 4);
|
||||
}
|
||||
}
|
||||
/* set tail elements to 1s */
|
||||
total_elems = vext_get_total_elems(env, desc, esz);
|
||||
vext_set_elems_1s(vd, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
static inline uint64_t sum0_64(uint64_t x)
|
||||
{
|
||||
return ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39);
|
||||
}
|
||||
|
||||
static inline uint32_t sum0_32(uint32_t x)
|
||||
{
|
||||
return ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22);
|
||||
}
|
||||
|
||||
static inline uint64_t sum1_64(uint64_t x)
|
||||
{
|
||||
return ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41);
|
||||
}
|
||||
|
||||
static inline uint32_t sum1_32(uint32_t x)
|
||||
{
|
||||
return ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25);
|
||||
}
|
||||
|
||||
#define ch(x, y, z) ((x & y) ^ ((~x) & z))
|
||||
|
||||
#define maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
|
||||
|
||||
static void vsha2c_64(uint64_t *vs2, uint64_t *vd, uint64_t *vs1)
|
||||
{
|
||||
uint64_t a = vs2[3], b = vs2[2], e = vs2[1], f = vs2[0];
|
||||
uint64_t c = vd[3], d = vd[2], g = vd[1], h = vd[0];
|
||||
uint64_t W0 = vs1[0], W1 = vs1[1];
|
||||
uint64_t T1 = h + sum1_64(e) + ch(e, f, g) + W0;
|
||||
uint64_t T2 = sum0_64(a) + maj(a, b, c);
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
|
||||
T1 = h + sum1_64(e) + ch(e, f, g) + W1;
|
||||
T2 = sum0_64(a) + maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
|
||||
vd[0] = f;
|
||||
vd[1] = e;
|
||||
vd[2] = b;
|
||||
vd[3] = a;
|
||||
}
|
||||
|
||||
static void vsha2c_32(uint32_t *vs2, uint32_t *vd, uint32_t *vs1)
|
||||
{
|
||||
uint32_t a = vs2[H4(3)], b = vs2[H4(2)], e = vs2[H4(1)], f = vs2[H4(0)];
|
||||
uint32_t c = vd[H4(3)], d = vd[H4(2)], g = vd[H4(1)], h = vd[H4(0)];
|
||||
uint32_t W0 = vs1[H4(0)], W1 = vs1[H4(1)];
|
||||
uint32_t T1 = h + sum1_32(e) + ch(e, f, g) + W0;
|
||||
uint32_t T2 = sum0_32(a) + maj(a, b, c);
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
|
||||
T1 = h + sum1_32(e) + ch(e, f, g) + W1;
|
||||
T2 = sum0_32(a) + maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
|
||||
vd[H4(0)] = f;
|
||||
vd[H4(1)] = e;
|
||||
vd[H4(2)] = b;
|
||||
vd[H4(3)] = a;
|
||||
}
|
||||
|
||||
void HELPER(vsha2ch32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
const uint32_t esz = 4;
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i,
|
||||
((uint32_t *)vs1) + 4 * i + 2);
|
||||
}
|
||||
|
||||
/* set tail elements to 1s */
|
||||
total_elems = vext_get_total_elems(env, desc, esz);
|
||||
vext_set_elems_1s(vd, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
void HELPER(vsha2ch64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
const uint32_t esz = 8;
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i,
|
||||
((uint64_t *)vs1) + 4 * i + 2);
|
||||
}
|
||||
|
||||
/* set tail elements to 1s */
|
||||
total_elems = vext_get_total_elems(env, desc, esz);
|
||||
vext_set_elems_1s(vd, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
void HELPER(vsha2cl32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
const uint32_t esz = 4;
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i,
|
||||
(((uint32_t *)vs1) + 4 * i));
|
||||
}
|
||||
|
||||
/* set tail elements to 1s */
|
||||
total_elems = vext_get_total_elems(env, desc, esz);
|
||||
vext_set_elems_1s(vd, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
void HELPER(vsha2cl64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
uint32_t esz = 8;
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i,
|
||||
(((uint64_t *)vs1) + 4 * i));
|
||||
}
|
||||
|
||||
/* set tail elements to 1s */
|
||||
total_elems = vext_get_total_elems(env, desc, esz);
|
||||
vext_set_elems_1s(vd, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
static inline uint32_t p1(uint32_t x)
|
||||
{
|
||||
return x ^ rol32(x, 15) ^ rol32(x, 23);
|
||||
}
|
||||
|
||||
static inline uint32_t zvksh_w(uint32_t m16, uint32_t m9, uint32_t m3,
|
||||
uint32_t m13, uint32_t m6)
|
||||
{
|
||||
return p1(m16 ^ m9 ^ rol32(m3, 15)) ^ rol32(m13, 7) ^ m6;
|
||||
}
|
||||
|
||||
void HELPER(vsm3me_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr,
|
||||
CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
uint32_t esz = memop_size(FIELD_EX64(env->vtype, VTYPE, VSEW));
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t *vd = vd_vptr;
|
||||
uint32_t *vs1 = vs1_vptr;
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
|
||||
for (int i = env->vstart / 8; i < env->vl / 8; i++) {
|
||||
uint32_t w[24];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
w[j] = bswap32(vs1[H4((i * 8) + j)]);
|
||||
w[j + 8] = bswap32(vs2[H4((i * 8) + j)]);
|
||||
}
|
||||
for (int j = 0; j < 8; j++) {
|
||||
w[j + 16] =
|
||||
zvksh_w(w[j], w[j + 7], w[j + 13], w[j + 3], w[j + 10]);
|
||||
}
|
||||
for (int j = 0; j < 8; j++) {
|
||||
vd[(i * 8) + j] = bswap32(w[H4(j + 16)]);
|
||||
}
|
||||
}
|
||||
vext_set_elems_1s(vd_vptr, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
static inline uint32_t ff1(uint32_t x, uint32_t y, uint32_t z)
|
||||
{
|
||||
return x ^ y ^ z;
|
||||
}
|
||||
|
||||
static inline uint32_t ff2(uint32_t x, uint32_t y, uint32_t z)
|
||||
{
|
||||
return (x & y) | (x & z) | (y & z);
|
||||
}
|
||||
|
||||
static inline uint32_t ff_j(uint32_t x, uint32_t y, uint32_t z, uint32_t j)
|
||||
{
|
||||
return (j <= 15) ? ff1(x, y, z) : ff2(x, y, z);
|
||||
}
|
||||
|
||||
static inline uint32_t gg1(uint32_t x, uint32_t y, uint32_t z)
|
||||
{
|
||||
return x ^ y ^ z;
|
||||
}
|
||||
|
||||
static inline uint32_t gg2(uint32_t x, uint32_t y, uint32_t z)
|
||||
{
|
||||
return (x & y) | (~x & z);
|
||||
}
|
||||
|
||||
static inline uint32_t gg_j(uint32_t x, uint32_t y, uint32_t z, uint32_t j)
|
||||
{
|
||||
return (j <= 15) ? gg1(x, y, z) : gg2(x, y, z);
|
||||
}
|
||||
|
||||
static inline uint32_t t_j(uint32_t j)
|
||||
{
|
||||
return (j <= 15) ? 0x79cc4519 : 0x7a879d8a;
|
||||
}
|
||||
|
||||
static inline uint32_t p_0(uint32_t x)
|
||||
{
|
||||
return x ^ rol32(x, 9) ^ rol32(x, 17);
|
||||
}
|
||||
|
||||
static void sm3c(uint32_t *vd, uint32_t *vs1, uint32_t *vs2, uint32_t uimm)
|
||||
{
|
||||
uint32_t x0, x1;
|
||||
uint32_t j;
|
||||
uint32_t ss1, ss2, tt1, tt2;
|
||||
x0 = vs2[0] ^ vs2[4];
|
||||
x1 = vs2[1] ^ vs2[5];
|
||||
j = 2 * uimm;
|
||||
ss1 = rol32(rol32(vs1[0], 12) + vs1[4] + rol32(t_j(j), j % 32), 7);
|
||||
ss2 = ss1 ^ rol32(vs1[0], 12);
|
||||
tt1 = ff_j(vs1[0], vs1[1], vs1[2], j) + vs1[3] + ss2 + x0;
|
||||
tt2 = gg_j(vs1[4], vs1[5], vs1[6], j) + vs1[7] + ss1 + vs2[0];
|
||||
vs1[3] = vs1[2];
|
||||
vd[3] = rol32(vs1[1], 9);
|
||||
vs1[1] = vs1[0];
|
||||
vd[1] = tt1;
|
||||
vs1[7] = vs1[6];
|
||||
vd[7] = rol32(vs1[5], 19);
|
||||
vs1[5] = vs1[4];
|
||||
vd[5] = p_0(tt2);
|
||||
j = 2 * uimm + 1;
|
||||
ss1 = rol32(rol32(vd[1], 12) + vd[5] + rol32(t_j(j), j % 32), 7);
|
||||
ss2 = ss1 ^ rol32(vd[1], 12);
|
||||
tt1 = ff_j(vd[1], vs1[1], vd[3], j) + vs1[3] + ss2 + x1;
|
||||
tt2 = gg_j(vd[5], vs1[5], vd[7], j) + vs1[7] + ss1 + vs2[1];
|
||||
vd[2] = rol32(vs1[1], 9);
|
||||
vd[0] = tt1;
|
||||
vd[6] = rol32(vs1[5], 19);
|
||||
vd[4] = p_0(tt2);
|
||||
}
|
||||
|
||||
void HELPER(vsm3c_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
uint32_t esz = memop_size(FIELD_EX64(env->vtype, VTYPE, VSEW));
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t *vd = vd_vptr;
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
uint32_t v1[8], v2[8], v3[8];
|
||||
|
||||
for (int i = env->vstart / 8; i < env->vl / 8; i++) {
|
||||
for (int k = 0; k < 8; k++) {
|
||||
v2[k] = bswap32(vd[H4(i * 8 + k)]);
|
||||
v3[k] = bswap32(vs2[H4(i * 8 + k)]);
|
||||
}
|
||||
sm3c(v1, v2, v3, uimm);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
vd[i * 8 + k] = bswap32(v1[H4(k)]);
|
||||
}
|
||||
}
|
||||
vext_set_elems_1s(vd_vptr, vta, env->vl * esz, total_elems * esz);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
void HELPER(vghsh_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr,
|
||||
CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
uint64_t *vd = vd_vptr;
|
||||
uint64_t *vs1 = vs1_vptr;
|
||||
uint64_t *vs2 = vs2_vptr;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint64_t Y[2] = {vd[i * 2 + 0], vd[i * 2 + 1]};
|
||||
uint64_t H[2] = {brev8(vs2[i * 2 + 0]), brev8(vs2[i * 2 + 1])};
|
||||
uint64_t X[2] = {vs1[i * 2 + 0], vs1[i * 2 + 1]};
|
||||
uint64_t Z[2] = {0, 0};
|
||||
|
||||
uint64_t S[2] = {brev8(Y[0] ^ X[0]), brev8(Y[1] ^ X[1])};
|
||||
|
||||
for (int j = 0; j < 128; j++) {
|
||||
if ((S[j / 64] >> (j % 64)) & 1) {
|
||||
Z[0] ^= H[0];
|
||||
Z[1] ^= H[1];
|
||||
}
|
||||
bool reduce = ((H[1] >> 63) & 1);
|
||||
H[1] = H[1] << 1 | H[0] >> 63;
|
||||
H[0] = H[0] << 1;
|
||||
if (reduce) {
|
||||
H[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
vd[i * 2 + 0] = brev8(Z[0]);
|
||||
vd[i * 2 + 1] = brev8(Z[1]);
|
||||
}
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, env->vl * 4, total_elems * 4);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
void HELPER(vgmul_vv)(void *vd_vptr, void *vs2_vptr, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
uint64_t *vd = vd_vptr;
|
||||
uint64_t *vs2 = vs2_vptr;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint64_t Y[2] = {brev8(vd[i * 2 + 0]), brev8(vd[i * 2 + 1])};
|
||||
uint64_t H[2] = {brev8(vs2[i * 2 + 0]), brev8(vs2[i * 2 + 1])};
|
||||
uint64_t Z[2] = {0, 0};
|
||||
|
||||
for (int j = 0; j < 128; j++) {
|
||||
if ((Y[j / 64] >> (j % 64)) & 1) {
|
||||
Z[0] ^= H[0];
|
||||
Z[1] ^= H[1];
|
||||
}
|
||||
bool reduce = ((H[1] >> 63) & 1);
|
||||
H[1] = H[1] << 1 | H[0] >> 63;
|
||||
H[0] = H[0] << 1;
|
||||
if (reduce) {
|
||||
H[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
vd[i * 2 + 0] = brev8(Z[0]);
|
||||
vd[i * 2 + 1] = brev8(Z[1]);
|
||||
}
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, env->vl * 4, total_elems * 4);
|
||||
env->vstart = 0;
|
||||
}
|
||||
|
||||
void HELPER(vsm4k_vi)(void *vd, void *vs2, uint32_t uimm5, CPURISCVState *env,
|
||||
uint32_t desc)
|
||||
{
|
||||
const uint32_t egs = 4;
|
||||
uint32_t rnd = uimm5 & 0x7;
|
||||
uint32_t group_start = env->vstart / egs;
|
||||
uint32_t group_end = env->vl / egs;
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
uint32_t vend = (i + 1) * egs;
|
||||
uint32_t rk[4] = {0};
|
||||
uint32_t tmp[8] = {0};
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
rk[j - vstart] = *((uint32_t *)vs2 + H4(j));
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < egs; ++j) {
|
||||
tmp[j] = rk[j];
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < egs; ++j) {
|
||||
uint32_t b, s;
|
||||
b = tmp[j + 1] ^ tmp[j + 2] ^ tmp[j + 3] ^ sm4_ck[rnd * 4 + j];
|
||||
|
||||
s = sm4_subword(b);
|
||||
|
||||
tmp[j + 4] = tmp[j] ^ (s ^ rol32(s, 13) ^ rol32(s, 23));
|
||||
}
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
*((uint32_t *)vd + H4(j)) = tmp[egs + (j - vstart)];
|
||||
}
|
||||
}
|
||||
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vext_vta(desc), env->vl * esz, total_elems * esz);
|
||||
}
|
||||
|
||||
static void do_sm4_round(uint32_t *rk, uint32_t *buf)
|
||||
{
|
||||
const uint32_t egs = 4;
|
||||
uint32_t s, b;
|
||||
|
||||
for (uint32_t j = egs; j < egs * 2; ++j) {
|
||||
b = buf[j - 3] ^ buf[j - 2] ^ buf[j - 1] ^ rk[j - 4];
|
||||
|
||||
s = sm4_subword(b);
|
||||
|
||||
buf[j] = buf[j - 4] ^ (s ^ rol32(s, 2) ^ rol32(s, 10) ^ rol32(s, 18) ^
|
||||
rol32(s, 24));
|
||||
}
|
||||
}
|
||||
|
||||
void HELPER(vsm4r_vv)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
const uint32_t egs = 4;
|
||||
uint32_t group_start = env->vstart / egs;
|
||||
uint32_t group_end = env->vl / egs;
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
uint32_t vend = (i + 1) * egs;
|
||||
uint32_t rk[4] = {0};
|
||||
uint32_t tmp[8] = {0};
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
rk[j - vstart] = *((uint32_t *)vs2 + H4(j));
|
||||
}
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
tmp[j - vstart] = *((uint32_t *)vd + H4(j));
|
||||
}
|
||||
|
||||
do_sm4_round(rk, tmp);
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
*((uint32_t *)vd + H4(j)) = tmp[egs + (j - vstart)];
|
||||
}
|
||||
}
|
||||
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vext_vta(desc), env->vl * esz, total_elems * esz);
|
||||
}
|
||||
|
||||
void HELPER(vsm4r_vs)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
{
|
||||
const uint32_t egs = 4;
|
||||
uint32_t group_start = env->vstart / egs;
|
||||
uint32_t group_end = env->vl / egs;
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
uint32_t vend = (i + 1) * egs;
|
||||
uint32_t rk[4] = {0};
|
||||
uint32_t tmp[8] = {0};
|
||||
|
||||
for (uint32_t j = 0; j < egs; ++j) {
|
||||
rk[j] = *((uint32_t *)vs2 + H4(j));
|
||||
}
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
tmp[j - vstart] = *((uint32_t *)vd + H4(j));
|
||||
}
|
||||
|
||||
do_sm4_round(rk, tmp);
|
||||
|
||||
for (uint32_t j = vstart; j < vend; ++j) {
|
||||
*((uint32_t *)vd + H4(j)) = tmp[egs + (j - vstart)];
|
||||
}
|
||||
}
|
||||
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vext_vta(desc), env->vl * esz, total_elems * esz);
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
#include "fpu/softfloat.h"
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "internals.h"
|
||||
#include "vector_internals.h"
|
||||
#include <math.h>
|
||||
|
||||
target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
|
||||
|
@ -73,68 +74,6 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
|
|||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that vector data is stored in host-endian 64-bit chunks,
|
||||
* so addressing units smaller than that needs a host-endian fixup.
|
||||
*/
|
||||
#if HOST_BIG_ENDIAN
|
||||
#define H1(x) ((x) ^ 7)
|
||||
#define H1_2(x) ((x) ^ 6)
|
||||
#define H1_4(x) ((x) ^ 4)
|
||||
#define H2(x) ((x) ^ 3)
|
||||
#define H4(x) ((x) ^ 1)
|
||||
#define H8(x) ((x))
|
||||
#else
|
||||
#define H1(x) (x)
|
||||
#define H1_2(x) (x)
|
||||
#define H1_4(x) (x)
|
||||
#define H2(x) (x)
|
||||
#define H4(x) (x)
|
||||
#define H8(x) (x)
|
||||
#endif
|
||||
|
||||
static inline uint32_t vext_nf(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, NF);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vm(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode LMUL to lmul as following:
|
||||
* LMUL vlmul lmul
|
||||
* 1 000 0
|
||||
* 2 001 1
|
||||
* 4 010 2
|
||||
* 8 011 3
|
||||
* - 100 -
|
||||
* 1/8 101 -3
|
||||
* 1/4 110 -2
|
||||
* 1/2 111 -1
|
||||
*/
|
||||
static inline int32_t vext_lmul(uint32_t desc)
|
||||
{
|
||||
return sextract32(FIELD_EX32(simd_data(desc), VDATA, LMUL), 0, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vta(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VTA);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vma(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VMA);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vta_all_1s(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VTA_ALL_1S);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the maximum number of elements can be operated.
|
||||
*
|
||||
|
@ -153,21 +92,6 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t log2_esz)
|
|||
return scale < 0 ? vlenb >> -scale : vlenb << scale;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get number of total elements, including prestart, body and tail elements.
|
||||
* Note that when LMUL < 1, the tail includes the elements past VLMAX that
|
||||
* are held in the same vector register.
|
||||
*/
|
||||
static inline uint32_t vext_get_total_elems(CPURISCVState *env, uint32_t desc,
|
||||
uint32_t esz)
|
||||
{
|
||||
uint32_t vlenb = simd_maxsz(desc);
|
||||
uint32_t sew = 1 << FIELD_EX64(env->vtype, VTYPE, VSEW);
|
||||
int8_t emul = ctzl(esz) - ctzl(sew) + vext_lmul(desc) < 0 ? 0 :
|
||||
ctzl(esz) - ctzl(sew) + vext_lmul(desc);
|
||||
return (vlenb << emul) / esz;
|
||||
}
|
||||
|
||||
static inline target_ulong adjust_addr(CPURISCVState *env, target_ulong addr)
|
||||
{
|
||||
return (addr & ~env->cur_pmmask) | env->cur_pmbase;
|
||||
|
@ -200,20 +124,6 @@ static void probe_pages(CPURISCVState *env, target_ulong addr,
|
|||
}
|
||||
}
|
||||
|
||||
/* set agnostic elements to 1s */
|
||||
static void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt,
|
||||
uint32_t tot)
|
||||
{
|
||||
if (is_agnostic == 0) {
|
||||
/* policy undisturbed */
|
||||
return;
|
||||
}
|
||||
if (tot - cnt == 0) {
|
||||
return;
|
||||
}
|
||||
memset(base + cnt, -1, tot - cnt);
|
||||
}
|
||||
|
||||
static inline void vext_set_elem_mask(void *v0, int index,
|
||||
uint8_t value)
|
||||
{
|
||||
|
@ -223,18 +133,6 @@ static inline void vext_set_elem_mask(void *v0, int index,
|
|||
((uint64_t *)v0)[idx] = deposit64(old, pos, 1, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Earlier designs (pre-0.9) had a varying number of bits
|
||||
* per mask value (MLEN). In the 0.9 design, MLEN=1.
|
||||
* (Section 4.5)
|
||||
*/
|
||||
static inline int vext_elem_mask(void *v0, int index)
|
||||
{
|
||||
int idx = index / 64;
|
||||
int pos = index % 64;
|
||||
return (((uint64_t *)v0)[idx] >> pos) & 1;
|
||||
}
|
||||
|
||||
/* elements operations for load and store */
|
||||
typedef void vext_ldst_elem_fn(CPURISCVState *env, abi_ptr addr,
|
||||
uint32_t idx, void *vd, uintptr_t retaddr);
|
||||
|
@ -584,7 +482,7 @@ vext_ldff(void *vd, void *v0, target_ulong base,
|
|||
cpu_mmu_index(env, false));
|
||||
if (host) {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (page_check_range(addr, offset, PAGE_READ)) {
|
||||
if (!page_check_range(addr, offset, PAGE_READ)) {
|
||||
vl = i;
|
||||
goto ProbeSuccess;
|
||||
}
|
||||
|
@ -729,25 +627,15 @@ GEN_VEXT_ST_WHOLE(vs8r_v, int8_t, ste_b)
|
|||
* Vector Integer Arithmetic Instructions
|
||||
*/
|
||||
|
||||
/* expand macro args before macro */
|
||||
#define RVVCALL(macro, ...) macro(__VA_ARGS__)
|
||||
|
||||
/* (TD, T1, T2, TX1, TX2) */
|
||||
#define OP_SSS_B int8_t, int8_t, int8_t, int8_t, int8_t
|
||||
#define OP_SSS_H int16_t, int16_t, int16_t, int16_t, int16_t
|
||||
#define OP_SSS_W int32_t, int32_t, int32_t, int32_t, int32_t
|
||||
#define OP_SSS_D int64_t, int64_t, int64_t, int64_t, int64_t
|
||||
#define OP_UUU_B uint8_t, uint8_t, uint8_t, uint8_t, uint8_t
|
||||
#define OP_UUU_H uint16_t, uint16_t, uint16_t, uint16_t, uint16_t
|
||||
#define OP_UUU_W uint32_t, uint32_t, uint32_t, uint32_t, uint32_t
|
||||
#define OP_UUU_D uint64_t, uint64_t, uint64_t, uint64_t, uint64_t
|
||||
#define OP_SUS_B int8_t, uint8_t, int8_t, uint8_t, int8_t
|
||||
#define OP_SUS_H int16_t, uint16_t, int16_t, uint16_t, int16_t
|
||||
#define OP_SUS_W int32_t, uint32_t, int32_t, uint32_t, int32_t
|
||||
#define OP_SUS_D int64_t, uint64_t, int64_t, uint64_t, int64_t
|
||||
#define WOP_UUU_B uint16_t, uint8_t, uint8_t, uint16_t, uint16_t
|
||||
#define WOP_UUU_H uint32_t, uint16_t, uint16_t, uint32_t, uint32_t
|
||||
#define WOP_UUU_W uint64_t, uint32_t, uint32_t, uint64_t, uint64_t
|
||||
#define WOP_SSS_B int16_t, int8_t, int8_t, int16_t, int16_t
|
||||
#define WOP_SSS_H int32_t, int16_t, int16_t, int32_t, int32_t
|
||||
#define WOP_SSS_W int64_t, int32_t, int32_t, int64_t, int64_t
|
||||
|
@ -764,16 +652,6 @@ GEN_VEXT_ST_WHOLE(vs8r_v, int8_t, ste_b)
|
|||
#define NOP_UUU_H uint16_t, uint16_t, uint32_t, uint16_t, uint32_t
|
||||
#define NOP_UUU_W uint32_t, uint32_t, uint64_t, uint32_t, uint64_t
|
||||
|
||||
/* operation of two vector elements */
|
||||
typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i);
|
||||
|
||||
#define OPIVV2(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
|
||||
static void do_##NAME(void *vd, void *vs1, void *vs2, int i) \
|
||||
{ \
|
||||
TX1 s1 = *((T1 *)vs1 + HS1(i)); \
|
||||
TX2 s2 = *((T2 *)vs2 + HS2(i)); \
|
||||
*((TD *)vd + HD(i)) = OP(s2, s1); \
|
||||
}
|
||||
#define DO_SUB(N, M) (N - M)
|
||||
#define DO_RSUB(N, M) (M - N)
|
||||
|
||||
|
@ -786,40 +664,6 @@ RVVCALL(OPIVV2, vsub_vv_h, OP_SSS_H, H2, H2, H2, DO_SUB)
|
|||
RVVCALL(OPIVV2, vsub_vv_w, OP_SSS_W, H4, H4, H4, DO_SUB)
|
||||
RVVCALL(OPIVV2, vsub_vv_d, OP_SSS_D, H8, H8, H8, DO_SUB)
|
||||
|
||||
static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
|
||||
CPURISCVState *env, uint32_t desc,
|
||||
opivv2_fn *fn, uint32_t esz)
|
||||
{
|
||||
uint32_t vm = vext_vm(desc);
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, vs1, vs2, i);
|
||||
}
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz);
|
||||
}
|
||||
|
||||
/* generate the helpers for OPIVV */
|
||||
#define GEN_VEXT_VV(NAME, ESZ) \
|
||||
void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
void *vs2, CPURISCVState *env, \
|
||||
uint32_t desc) \
|
||||
{ \
|
||||
do_vext_vv(vd, v0, vs1, vs2, env, desc, \
|
||||
do_##NAME, ESZ); \
|
||||
}
|
||||
|
||||
GEN_VEXT_VV(vadd_vv_b, 1)
|
||||
GEN_VEXT_VV(vadd_vv_h, 2)
|
||||
GEN_VEXT_VV(vadd_vv_w, 4)
|
||||
|
@ -829,18 +673,6 @@ GEN_VEXT_VV(vsub_vv_h, 2)
|
|||
GEN_VEXT_VV(vsub_vv_w, 4)
|
||||
GEN_VEXT_VV(vsub_vv_d, 8)
|
||||
|
||||
typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i);
|
||||
|
||||
/*
|
||||
* (T1)s1 gives the real operator type.
|
||||
* (TX1)(T1)s1 expands the operator type of widen or narrow operations.
|
||||
*/
|
||||
#define OPIVX2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
|
||||
static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \
|
||||
{ \
|
||||
TX2 s2 = *((T2 *)vs2 + HS2(i)); \
|
||||
*((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1); \
|
||||
}
|
||||
|
||||
RVVCALL(OPIVX2, vadd_vx_b, OP_SSS_B, H1, H1, DO_ADD)
|
||||
RVVCALL(OPIVX2, vadd_vx_h, OP_SSS_H, H2, H2, DO_ADD)
|
||||
|
@ -855,40 +687,6 @@ RVVCALL(OPIVX2, vrsub_vx_h, OP_SSS_H, H2, H2, DO_RSUB)
|
|||
RVVCALL(OPIVX2, vrsub_vx_w, OP_SSS_W, H4, H4, DO_RSUB)
|
||||
RVVCALL(OPIVX2, vrsub_vx_d, OP_SSS_D, H8, H8, DO_RSUB)
|
||||
|
||||
static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
|
||||
CPURISCVState *env, uint32_t desc,
|
||||
opivx2_fn fn, uint32_t esz)
|
||||
{
|
||||
uint32_t vm = vext_vm(desc);
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, s1, vs2, i);
|
||||
}
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz);
|
||||
}
|
||||
|
||||
/* generate the helpers for OPIVX */
|
||||
#define GEN_VEXT_VX(NAME, ESZ) \
|
||||
void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
void *vs2, CPURISCVState *env, \
|
||||
uint32_t desc) \
|
||||
{ \
|
||||
do_vext_vx(vd, v0, s1, vs2, env, desc, \
|
||||
do_##NAME, ESZ); \
|
||||
}
|
||||
|
||||
GEN_VEXT_VX(vadd_vx_b, 1)
|
||||
GEN_VEXT_VX(vadd_vx_h, 2)
|
||||
GEN_VEXT_VX(vadd_vx_w, 4)
|
||||
|
@ -3637,11 +3435,6 @@ GEN_VEXT_VF(vfwnmsac_vf_h, 4)
|
|||
GEN_VEXT_VF(vfwnmsac_vf_w, 8)
|
||||
|
||||
/* Vector Floating-Point Square-Root Instruction */
|
||||
/* (TD, T2, TX2) */
|
||||
#define OP_UU_H uint16_t, uint16_t, uint16_t
|
||||
#define OP_UU_W uint32_t, uint32_t, uint32_t
|
||||
#define OP_UU_D uint64_t, uint64_t, uint64_t
|
||||
|
||||
#define OPFVV1(NAME, TD, T2, TX2, HD, HS2, OP) \
|
||||
static void do_##NAME(void *vd, void *vs2, int i, \
|
||||
CPURISCVState *env) \
|
||||
|
@ -4338,40 +4131,6 @@ GEN_VEXT_CMP_VF(vmfge_vf_w, uint32_t, H4, vmfge32)
|
|||
GEN_VEXT_CMP_VF(vmfge_vf_d, uint64_t, H8, vmfge64)
|
||||
|
||||
/* Vector Floating-Point Classify Instruction */
|
||||
#define OPIVV1(NAME, TD, T2, TX2, HD, HS2, OP) \
|
||||
static void do_##NAME(void *vd, void *vs2, int i) \
|
||||
{ \
|
||||
TX2 s2 = *((T2 *)vs2 + HS2(i)); \
|
||||
*((TD *)vd + HD(i)) = OP(s2); \
|
||||
}
|
||||
|
||||
#define GEN_VEXT_V(NAME, ESZ) \
|
||||
void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
CPURISCVState *env, uint32_t desc) \
|
||||
{ \
|
||||
uint32_t vm = vext_vm(desc); \
|
||||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, ESZ); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * ESZ, \
|
||||
(i + 1) * ESZ); \
|
||||
continue; \
|
||||
} \
|
||||
do_##NAME(vd, vs2, i); \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, vl * ESZ, \
|
||||
total_elems * ESZ); \
|
||||
}
|
||||
|
||||
target_ulong fclass_h(uint64_t frs1)
|
||||
{
|
||||
float16 f = frs1;
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* RISC-V Vector Extension Internals
|
||||
*
|
||||
* Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "vector_internals.h"
|
||||
|
||||
/* set agnostic elements to 1s */
|
||||
void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt,
|
||||
uint32_t tot)
|
||||
{
|
||||
if (is_agnostic == 0) {
|
||||
/* policy undisturbed */
|
||||
return;
|
||||
}
|
||||
if (tot - cnt == 0) {
|
||||
return ;
|
||||
}
|
||||
memset(base + cnt, -1, tot - cnt);
|
||||
}
|
||||
|
||||
void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
|
||||
CPURISCVState *env, uint32_t desc,
|
||||
opivv2_fn *fn, uint32_t esz)
|
||||
{
|
||||
uint32_t vm = vext_vm(desc);
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, vs1, vs2, i);
|
||||
}
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz);
|
||||
}
|
||||
|
||||
void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
|
||||
CPURISCVState *env, uint32_t desc,
|
||||
opivx2_fn fn, uint32_t esz)
|
||||
{
|
||||
uint32_t vm = vext_vm(desc);
|
||||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, s1, vs2, i);
|
||||
}
|
||||
env->vstart = 0;
|
||||
/* set tail elements to 1s */
|
||||
vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz);
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* RISC-V Vector Extension Internals
|
||||
*
|
||||
* Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TARGET_RISCV_VECTOR_INTERNALS_H
|
||||
#define TARGET_RISCV_VECTOR_INTERNALS_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "internals.h"
|
||||
|
||||
static inline uint32_t vext_nf(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, NF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that vector data is stored in host-endian 64-bit chunks,
|
||||
* so addressing units smaller than that needs a host-endian fixup.
|
||||
*/
|
||||
#if HOST_BIG_ENDIAN
|
||||
#define H1(x) ((x) ^ 7)
|
||||
#define H1_2(x) ((x) ^ 6)
|
||||
#define H1_4(x) ((x) ^ 4)
|
||||
#define H2(x) ((x) ^ 3)
|
||||
#define H4(x) ((x) ^ 1)
|
||||
#define H8(x) ((x))
|
||||
#else
|
||||
#define H1(x) (x)
|
||||
#define H1_2(x) (x)
|
||||
#define H1_4(x) (x)
|
||||
#define H2(x) (x)
|
||||
#define H4(x) (x)
|
||||
#define H8(x) (x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encode LMUL to lmul as following:
|
||||
* LMUL vlmul lmul
|
||||
* 1 000 0
|
||||
* 2 001 1
|
||||
* 4 010 2
|
||||
* 8 011 3
|
||||
* - 100 -
|
||||
* 1/8 101 -3
|
||||
* 1/4 110 -2
|
||||
* 1/2 111 -1
|
||||
*/
|
||||
static inline int32_t vext_lmul(uint32_t desc)
|
||||
{
|
||||
return sextract32(FIELD_EX32(simd_data(desc), VDATA, LMUL), 0, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vm(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VM);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vma(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VMA);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vta(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VTA);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vta_all_1s(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VTA_ALL_1S);
|
||||
}
|
||||
|
||||
/*
|
||||
* Earlier designs (pre-0.9) had a varying number of bits
|
||||
* per mask value (MLEN). In the 0.9 design, MLEN=1.
|
||||
* (Section 4.5)
|
||||
*/
|
||||
static inline int vext_elem_mask(void *v0, int index)
|
||||
{
|
||||
int idx = index / 64;
|
||||
int pos = index % 64;
|
||||
return (((uint64_t *)v0)[idx] >> pos) & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get number of total elements, including prestart, body and tail elements.
|
||||
* Note that when LMUL < 1, the tail includes the elements past VLMAX that
|
||||
* are held in the same vector register.
|
||||
*/
|
||||
static inline uint32_t vext_get_total_elems(CPURISCVState *env, uint32_t desc,
|
||||
uint32_t esz)
|
||||
{
|
||||
uint32_t vlenb = simd_maxsz(desc);
|
||||
uint32_t sew = 1 << FIELD_EX64(env->vtype, VTYPE, VSEW);
|
||||
int8_t emul = ctzl(esz) - ctzl(sew) + vext_lmul(desc) < 0 ? 0 :
|
||||
ctzl(esz) - ctzl(sew) + vext_lmul(desc);
|
||||
return (vlenb << emul) / esz;
|
||||
}
|
||||
|
||||
/* set agnostic elements to 1s */
|
||||
void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt,
|
||||
uint32_t tot);
|
||||
|
||||
/* expand macro args before macro */
|
||||
#define RVVCALL(macro, ...) macro(__VA_ARGS__)
|
||||
|
||||
/* (TD, T2, TX2) */
|
||||
#define OP_UU_B uint8_t, uint8_t, uint8_t
|
||||
#define OP_UU_H uint16_t, uint16_t, uint16_t
|
||||
#define OP_UU_W uint32_t, uint32_t, uint32_t
|
||||
#define OP_UU_D uint64_t, uint64_t, uint64_t
|
||||
|
||||
/* (TD, T1, T2, TX1, TX2) */
|
||||
#define OP_UUU_B uint8_t, uint8_t, uint8_t, uint8_t, uint8_t
|
||||
#define OP_UUU_H uint16_t, uint16_t, uint16_t, uint16_t, uint16_t
|
||||
#define OP_UUU_W uint32_t, uint32_t, uint32_t, uint32_t, uint32_t
|
||||
#define OP_UUU_D uint64_t, uint64_t, uint64_t, uint64_t, uint64_t
|
||||
|
||||
#define OPIVV1(NAME, TD, T2, TX2, HD, HS2, OP) \
|
||||
static void do_##NAME(void *vd, void *vs2, int i) \
|
||||
{ \
|
||||
TX2 s2 = *((T2 *)vs2 + HS2(i)); \
|
||||
*((TD *)vd + HD(i)) = OP(s2); \
|
||||
}
|
||||
|
||||
#define GEN_VEXT_V(NAME, ESZ) \
|
||||
void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
CPURISCVState *env, uint32_t desc) \
|
||||
{ \
|
||||
uint32_t vm = vext_vm(desc); \
|
||||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, ESZ); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * ESZ, \
|
||||
(i + 1) * ESZ); \
|
||||
continue; \
|
||||
} \
|
||||
do_##NAME(vd, vs2, i); \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, vl * ESZ, \
|
||||
total_elems * ESZ); \
|
||||
}
|
||||
|
||||
/* operation of two vector elements */
|
||||
typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i);
|
||||
|
||||
#define OPIVV2(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
|
||||
static void do_##NAME(void *vd, void *vs1, void *vs2, int i) \
|
||||
{ \
|
||||
TX1 s1 = *((T1 *)vs1 + HS1(i)); \
|
||||
TX2 s2 = *((T2 *)vs2 + HS2(i)); \
|
||||
*((TD *)vd + HD(i)) = OP(s2, s1); \
|
||||
}
|
||||
|
||||
void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
|
||||
CPURISCVState *env, uint32_t desc,
|
||||
opivv2_fn *fn, uint32_t esz);
|
||||
|
||||
/* generate the helpers for OPIVV */
|
||||
#define GEN_VEXT_VV(NAME, ESZ) \
|
||||
void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
void *vs2, CPURISCVState *env, \
|
||||
uint32_t desc) \
|
||||
{ \
|
||||
do_vext_vv(vd, v0, vs1, vs2, env, desc, \
|
||||
do_##NAME, ESZ); \
|
||||
}
|
||||
|
||||
typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i);
|
||||
|
||||
/*
|
||||
* (T1)s1 gives the real operator type.
|
||||
* (TX1)(T1)s1 expands the operator type of widen or narrow operations.
|
||||
*/
|
||||
#define OPIVX2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
|
||||
static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \
|
||||
{ \
|
||||
TX2 s2 = *((T2 *)vs2 + HS2(i)); \
|
||||
*((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1); \
|
||||
}
|
||||
|
||||
void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
|
||||
CPURISCVState *env, uint32_t desc,
|
||||
opivx2_fn fn, uint32_t esz);
|
||||
|
||||
/* generate the helpers for OPIVX */
|
||||
#define GEN_VEXT_VX(NAME, ESZ) \
|
||||
void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
void *vs2, CPURISCVState *env, \
|
||||
uint32_t desc) \
|
||||
{ \
|
||||
do_vext_vx(vd, v0, s1, vs2, env, desc, \
|
||||
do_##NAME, ESZ); \
|
||||
}
|
||||
|
||||
/* Three of the widening shortening macros: */
|
||||
/* (TD, T1, T2, TX1, TX2) */
|
||||
#define WOP_UUU_B uint16_t, uint8_t, uint8_t, uint16_t, uint16_t
|
||||
#define WOP_UUU_H uint32_t, uint16_t, uint16_t, uint32_t, uint32_t
|
||||
#define WOP_UUU_W uint64_t, uint32_t, uint32_t, uint64_t, uint64_t
|
||||
|
||||
#endif /* TARGET_RISCV_VECTOR_INTERNALS_H */
|
Loading…
Reference in New Issue