mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20210901-2' into staging
First RISC-V PR for QEMU 6.2 - Add a config for Shakti UART - Fixup virt flash node - Don't override users supplied ISA version - Fixup some CSR accesses - Use g_strjoinv() for virt machine PLIC string config - Fix an overflow in the SiFive CLINT - Add 64-bit register access helpers - Replace tcg_const_* with direct constant usage # gpg: Signature made Wed 01 Sep 2021 03:08:48 BST # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full] # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * remotes/alistair/tags/pull-riscv-to-apply-20210901-2: (33 commits) target/riscv: Use {get,dest}_gpr for RVV target/riscv: Tidy trans_rvh.c.inc target/riscv: Use {get,dest}_gpr for RVD target/riscv: Use {get,dest}_gpr for RVF target/riscv: Use gen_shift_imm_fn for slli_uw target/riscv: Use {get,dest}_gpr for RVA target/riscv: Reorg csr instructions target/riscv: Fix hgeie, hgeip target/riscv: Fix rmw_sip, rmw_vsip, rmw_hsip vs write-only operation target/riscv: Use {get, dest}_gpr for integer load/store target/riscv: Use get_gpr in branches target/riscv: Use extracts for sraiw and srliw target/riscv: Use DisasExtend in shift operations target/riscv: Add DisasExtend to gen_unary target/riscv: Move gen_* helpers for RVB target/riscv: Move gen_* helpers for RVM target/riscv: Use gen_arith for mulh and mulhu target/riscv: Remove gen_arith_div* target/riscv: Add DisasExtend to gen_arith* target/riscv: Introduce DisasExtend and new helpers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -68,3 +68,6 @@ config SIFIVE_UART
|
||||
|
||||
config GOLDFISH_TTY
|
||||
bool
|
||||
|
||||
config SHAKTI_UART
|
||||
bool
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SHAKTI', if_true: files('shakti_uart.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen_console.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
|
||||
|
||||
@@ -300,6 +300,18 @@ RegisterInfoArray *register_init_block32(DeviceState *owner,
|
||||
data, ops, debug_enabled, memory_size, 32);
|
||||
}
|
||||
|
||||
RegisterInfoArray *register_init_block64(DeviceState *owner,
|
||||
const RegisterAccessInfo *rae,
|
||||
int num, RegisterInfo *ri,
|
||||
uint64_t *data,
|
||||
const MemoryRegionOps *ops,
|
||||
bool debug_enabled,
|
||||
uint64_t memory_size)
|
||||
{
|
||||
return register_init_block(owner, rae, num, ri, (void *)
|
||||
data, ops, debug_enabled, memory_size, 64);
|
||||
}
|
||||
|
||||
void register_finalize_block(RegisterInfoArray *r_array)
|
||||
{
|
||||
object_unparent(OBJECT(&r_array->mem));
|
||||
|
||||
+23
-2
@@ -59,8 +59,29 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
|
||||
riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
|
||||
diff = cpu->env.timecmp - rtc_r;
|
||||
/* back to ns (note args switched in muldiv64) */
|
||||
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
|
||||
uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
|
||||
|
||||
/*
|
||||
* check if ns_diff overflowed and check if the addition would potentially
|
||||
* overflow
|
||||
*/
|
||||
if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
|
||||
ns_diff > INT64_MAX) {
|
||||
next = INT64_MAX;
|
||||
} else {
|
||||
/*
|
||||
* as it is very unlikely qemu_clock_get_ns will return a value
|
||||
* greater than INT64_MAX, no additional check is needed for an
|
||||
* unsigned integer overflow.
|
||||
*/
|
||||
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
|
||||
/*
|
||||
* if ns_diff is INT64_MAX next may still be outside the range
|
||||
* of a signed integer.
|
||||
*/
|
||||
next = MIN(next, INT64_MAX);
|
||||
}
|
||||
|
||||
timer_mod(cpu->env.timer, next);
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -22,13 +22,10 @@ config OPENTITAN
|
||||
select IBEX
|
||||
select UNIMP
|
||||
|
||||
config SHAKTI
|
||||
bool
|
||||
|
||||
config SHAKTI_C
|
||||
bool
|
||||
select UNIMP
|
||||
select SHAKTI
|
||||
select SHAKTI_UART
|
||||
select SIFIVE_CLINT
|
||||
select SIFIVE_PLIC
|
||||
|
||||
|
||||
+21
-14
@@ -454,7 +454,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
|
||||
g_free(name);
|
||||
|
||||
name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
|
||||
name = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(mc->fdt, name);
|
||||
qemu_fdt_setprop_string(mc->fdt, name, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(mc->fdt, name, "reg",
|
||||
@@ -540,6 +540,24 @@ static FWCfgState *create_fw_cfg(const MachineState *mc)
|
||||
return fw_cfg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the per-socket PLIC hart topology configuration string
|
||||
* (caller must free with g_free())
|
||||
*/
|
||||
static char *plic_hart_config_string(int hart_count)
|
||||
{
|
||||
g_autofree const char **vals = g_new(const char *, hart_count + 1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hart_count; i++) {
|
||||
vals[i] = VIRT_PLIC_HART_CONFIG;
|
||||
}
|
||||
vals[i] = NULL;
|
||||
|
||||
/* g_strjoinv() obliges us to cast away const here */
|
||||
return g_strjoinv(",", (char **)vals);
|
||||
}
|
||||
|
||||
static void virt_machine_init(MachineState *machine)
|
||||
{
|
||||
const MemMapEntry *memmap = virt_memmap;
|
||||
@@ -548,13 +566,12 @@ static void virt_machine_init(MachineState *machine)
|
||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||
char *plic_hart_config, *soc_name;
|
||||
size_t plic_hart_config_len;
|
||||
target_ulong start_addr = memmap[VIRT_DRAM].base;
|
||||
target_ulong firmware_end_addr, kernel_start_addr;
|
||||
uint32_t fdt_load_addr;
|
||||
uint64_t kernel_entry;
|
||||
DeviceState *mmio_plic, *virtio_plic, *pcie_plic;
|
||||
int i, j, base_hartid, hart_count;
|
||||
int i, base_hartid, hart_count;
|
||||
|
||||
/* Check socket count limit */
|
||||
if (VIRT_SOCKETS_MAX < riscv_socket_count(machine)) {
|
||||
@@ -603,17 +620,7 @@ static void virt_machine_init(MachineState *machine)
|
||||
SIFIVE_CLINT_TIMEBASE_FREQ, true);
|
||||
|
||||
/* Per-socket PLIC hart topology configuration string */
|
||||
plic_hart_config_len =
|
||||
(strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
|
||||
plic_hart_config = g_malloc0(plic_hart_config_len);
|
||||
for (j = 0; j < hart_count; j++) {
|
||||
if (j != 0) {
|
||||
strncat(plic_hart_config, ",", plic_hart_config_len);
|
||||
}
|
||||
strncat(plic_hart_config, VIRT_PLIC_HART_CONFIG,
|
||||
plic_hart_config_len);
|
||||
plic_hart_config_len -= (strlen(VIRT_PLIC_HART_CONFIG) + 1);
|
||||
}
|
||||
plic_hart_config = plic_hart_config_string(hart_count);
|
||||
|
||||
/* Per-socket PLIC */
|
||||
s->plic[i] = sifive_plic_create(
|
||||
|
||||
@@ -204,6 +204,14 @@ RegisterInfoArray *register_init_block32(DeviceState *owner,
|
||||
bool debug_enabled,
|
||||
uint64_t memory_size);
|
||||
|
||||
RegisterInfoArray *register_init_block64(DeviceState *owner,
|
||||
const RegisterAccessInfo *rae,
|
||||
int num, RegisterInfo *ri,
|
||||
uint64_t *data,
|
||||
const MemoryRegionOps *ops,
|
||||
bool debug_enabled,
|
||||
uint64_t memory_size);
|
||||
|
||||
/**
|
||||
* This function should be called to cleanup the registers that were initialized
|
||||
* when calling register_init_block32(). This function should only be called
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
enum { A_ ## reg = (addr) }; \
|
||||
enum { R_ ## reg = (addr) / 2 };
|
||||
|
||||
#define REG64(reg, addr) \
|
||||
enum { A_ ## reg = (addr) }; \
|
||||
enum { R_ ## reg = (addr) / 8 };
|
||||
|
||||
/* Define SHIFT, LENGTH and MASK constants for a field within a register */
|
||||
|
||||
/* This macro will define R_FOO_BAR_MASK, R_FOO_BAR_SHIFT and R_FOO_BAR_LENGTH
|
||||
@@ -58,6 +62,8 @@
|
||||
/* Extract a field from an array of registers */
|
||||
#define ARRAY_FIELD_EX32(regs, reg, field) \
|
||||
FIELD_EX32((regs)[R_ ## reg], reg, field)
|
||||
#define ARRAY_FIELD_EX64(regs, reg, field) \
|
||||
FIELD_EX64((regs)[R_ ## reg], reg, field)
|
||||
|
||||
/* Deposit a register field.
|
||||
* Assigning values larger then the target field will result in
|
||||
@@ -89,7 +95,7 @@
|
||||
_d; })
|
||||
#define FIELD_DP64(storage, reg, field, val) ({ \
|
||||
struct { \
|
||||
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
|
||||
uint64_t v:R_ ## reg ## _ ## field ## _LENGTH; \
|
||||
} _v = { .v = val }; \
|
||||
uint64_t _d; \
|
||||
_d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
|
||||
@@ -99,5 +105,7 @@
|
||||
/* Deposit a field to array of registers. */
|
||||
#define ARRAY_FIELD_DP32(regs, reg, field, val) \
|
||||
(regs)[R_ ## reg] = FIELD_DP32((regs)[R_ ## reg], reg, field, val);
|
||||
#define ARRAY_FIELD_DP64(regs, reg, field, val) \
|
||||
(regs)[R_ ## reg] = FIELD_DP64((regs)[R_ ## reg], reg, field, val);
|
||||
|
||||
#endif
|
||||
|
||||
+8
-6
@@ -392,9 +392,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
RISCVCPU *cpu = RISCV_CPU(dev);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
|
||||
int priv_version = PRIV_VERSION_1_11_0;
|
||||
int bext_version = BEXT_VERSION_0_93_0;
|
||||
int vext_version = VEXT_VERSION_0_07_1;
|
||||
int priv_version = 0;
|
||||
target_ulong target_misa = env->misa;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -417,9 +415,11 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
set_priv_version(env, priv_version);
|
||||
set_bext_version(env, bext_version);
|
||||
set_vext_version(env, vext_version);
|
||||
if (priv_version) {
|
||||
set_priv_version(env, priv_version);
|
||||
} else if (!env->priv_ver) {
|
||||
set_priv_version(env, PRIV_VERSION_1_11_0);
|
||||
}
|
||||
|
||||
if (cpu->cfg.mmu) {
|
||||
set_feature(env, RISCV_FEATURE_MMU);
|
||||
@@ -497,6 +497,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
target_misa |= RVH;
|
||||
}
|
||||
if (cpu->cfg.ext_b) {
|
||||
int bext_version = BEXT_VERSION_0_93_0;
|
||||
target_misa |= RVB;
|
||||
|
||||
if (cpu->cfg.bext_spec) {
|
||||
@@ -515,6 +516,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
set_bext_version(env, bext_version);
|
||||
}
|
||||
if (cpu->cfg.ext_v) {
|
||||
int vext_version = VEXT_VERSION_0_07_1;
|
||||
target_misa |= RVV;
|
||||
if (!is_power_of_2(cpu->cfg.vlen)) {
|
||||
error_setg(errp,
|
||||
|
||||
+29
-30
@@ -937,9 +937,12 @@ static RISCVException rmw_vsip(CPURISCVState *env, int csrno,
|
||||
/* Shift the S bits to their VS bit location in mip */
|
||||
int ret = rmw_mip(env, 0, ret_value, new_value << 1,
|
||||
(write_mask << 1) & vsip_writable_mask & env->hideleg);
|
||||
*ret_value &= VS_MODE_INTERRUPTS;
|
||||
/* Shift the VS bits to their S bit location in vsip */
|
||||
*ret_value >>= 1;
|
||||
|
||||
if (ret_value) {
|
||||
*ret_value &= VS_MODE_INTERRUPTS;
|
||||
/* Shift the VS bits to their S bit location in vsip */
|
||||
*ret_value >>= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -956,7 +959,9 @@ static RISCVException rmw_sip(CPURISCVState *env, int csrno,
|
||||
write_mask & env->mideleg & sip_writable_mask);
|
||||
}
|
||||
|
||||
*ret_value &= env->mideleg;
|
||||
if (ret_value) {
|
||||
*ret_value &= env->mideleg;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1072,8 +1077,9 @@ static RISCVException rmw_hvip(CPURISCVState *env, int csrno,
|
||||
int ret = rmw_mip(env, 0, ret_value, new_value,
|
||||
write_mask & hvip_writable_mask);
|
||||
|
||||
*ret_value &= hvip_writable_mask;
|
||||
|
||||
if (ret_value) {
|
||||
*ret_value &= hvip_writable_mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1084,8 +1090,9 @@ static RISCVException rmw_hip(CPURISCVState *env, int csrno,
|
||||
int ret = rmw_mip(env, 0, ret_value, new_value,
|
||||
write_mask & hip_writable_mask);
|
||||
|
||||
*ret_value &= hip_writable_mask;
|
||||
|
||||
if (ret_value) {
|
||||
*ret_value &= hip_writable_mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1117,17 +1124,12 @@ static RISCVException write_hcounteren(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_hgeie(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException write_hgeie(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||
if (val) {
|
||||
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||
}
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
@@ -1158,17 +1160,12 @@ static RISCVException write_htinst(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_hgeip(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException write_hgeip(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||
if (val) {
|
||||
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||
}
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
@@ -1422,11 +1419,11 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
||||
RISCVException ret;
|
||||
target_ulong old_value;
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
int read_only = get_field(csrno, 0xC00) == 3;
|
||||
|
||||
/* check privileges and return -1 if check fails */
|
||||
/* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int effective_priv = env->priv;
|
||||
int read_only = get_field(csrno, 0xC00) == 3;
|
||||
|
||||
if (riscv_has_ext(env, RVH) &&
|
||||
env->priv == PRV_S &&
|
||||
@@ -1439,11 +1436,13 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
||||
effective_priv++;
|
||||
}
|
||||
|
||||
if ((write_mask && read_only) ||
|
||||
(!env->debugger && (effective_priv < get_field(csrno, 0x300)))) {
|
||||
if (!env->debugger && (effective_priv < get_field(csrno, 0x300))) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
#endif
|
||||
if (write_mask && read_only) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
/* ensure the CSR extension is enabled. */
|
||||
if (!cpu->cfg.ext_icsr) {
|
||||
@@ -1592,10 +1591,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
|
||||
[CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip },
|
||||
[CSR_HIE] = { "hie", hmode, read_hie, write_hie },
|
||||
[CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren },
|
||||
[CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie },
|
||||
[CSR_HGEIE] = { "hgeie", hmode, read_zero, write_hgeie },
|
||||
[CSR_HTVAL] = { "htval", hmode, read_htval, write_htval },
|
||||
[CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst },
|
||||
[CSR_HGEIP] = { "hgeip", hmode, read_hgeip, write_hgeip },
|
||||
[CSR_HGEIP] = { "hgeip", hmode, read_zero, write_hgeip },
|
||||
[CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp },
|
||||
[CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta },
|
||||
[CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah },
|
||||
|
||||
@@ -65,9 +65,9 @@ DEF_HELPER_FLAGS_2(gorc, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(gorcw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
|
||||
/* Special functions */
|
||||
DEF_HELPER_3(csrrw, tl, env, tl, tl)
|
||||
DEF_HELPER_4(csrrs, tl, env, tl, tl, tl)
|
||||
DEF_HELPER_4(csrrc, tl, env, tl, tl, tl)
|
||||
DEF_HELPER_2(csrr, tl, env, int)
|
||||
DEF_HELPER_3(csrw, void, env, int, tl)
|
||||
DEF_HELPER_4(csrrw, tl, env, int, tl, tl)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_2(sret, tl, env, tl)
|
||||
DEF_HELPER_2(mret, tl, env, tl)
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
&j imm rd
|
||||
&r rd rs1 rs2
|
||||
&r2 rd rs1
|
||||
&r2_s rs1 rs2
|
||||
&s imm rs1 rs2
|
||||
&u imm rd
|
||||
&shift shamt rs1 rd
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
{
|
||||
TCGv src1 = tcg_temp_new();
|
||||
/* Put addr in load_res, data in load_val. */
|
||||
gen_get_gpr(src1, a->rs1);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
|
||||
if (a->rl) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||
}
|
||||
@@ -30,33 +29,33 @@ static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
if (a->aq) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||
}
|
||||
tcg_gen_mov_tl(load_res, src1);
|
||||
gen_set_gpr(a->rd, load_val);
|
||||
|
||||
tcg_temp_free(src1);
|
||||
/* Put addr in load_res, data in load_val. */
|
||||
tcg_gen_mov_tl(load_res, src1);
|
||||
gen_set_gpr(ctx, a->rd, load_val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
{
|
||||
TCGv src1 = tcg_temp_new();
|
||||
TCGv src2 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
TCGv dest, src1, src2;
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
|
||||
gen_get_gpr(src1, a->rs1);
|
||||
src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
|
||||
|
||||
gen_get_gpr(src2, a->rs2);
|
||||
/*
|
||||
* Note that the TCG atomic primitives are SC,
|
||||
* so we can ignore AQ/RL along this path.
|
||||
*/
|
||||
tcg_gen_atomic_cmpxchg_tl(src1, load_res, load_val, src2,
|
||||
dest = dest_gpr(ctx, a->rd);
|
||||
src2 = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
tcg_gen_atomic_cmpxchg_tl(dest, load_res, load_val, src2,
|
||||
ctx->mem_idx, mop);
|
||||
tcg_gen_setcond_tl(TCG_COND_NE, dat, src1, load_val);
|
||||
gen_set_gpr(a->rd, dat);
|
||||
tcg_gen_setcond_tl(TCG_COND_NE, dest, dest, load_val);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
tcg_gen_br(l2);
|
||||
|
||||
gen_set_label(l1);
|
||||
@@ -65,8 +64,7 @@ static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
* provide the memory barrier implied by AQ/RL.
|
||||
*/
|
||||
tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL);
|
||||
tcg_gen_movi_tl(dat, 1);
|
||||
gen_set_gpr(a->rd, dat);
|
||||
gen_set_gpr(ctx, a->rd, tcg_constant_tl(1));
|
||||
|
||||
gen_set_label(l2);
|
||||
/*
|
||||
@@ -75,9 +73,6 @@ static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
*/
|
||||
tcg_gen_movi_tl(load_res, -1);
|
||||
|
||||
tcg_temp_free(dat);
|
||||
tcg_temp_free(src1);
|
||||
tcg_temp_free(src2);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -85,17 +80,13 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a,
|
||||
void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
|
||||
MemOp mop)
|
||||
{
|
||||
TCGv src1 = tcg_temp_new();
|
||||
TCGv src2 = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
|
||||
gen_get_gpr(src1, a->rs1);
|
||||
gen_get_gpr(src2, a->rs2);
|
||||
func(dest, src1, src2, ctx->mem_idx, mop);
|
||||
|
||||
(*func)(src2, src1, src2, ctx->mem_idx, mop);
|
||||
|
||||
gen_set_gpr(a->rd, src2);
|
||||
tcg_temp_free(src1);
|
||||
tcg_temp_free(src2);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,30 +20,40 @@
|
||||
|
||||
static bool trans_fld(DisasContext *ctx, arg_fld *a)
|
||||
{
|
||||
TCGv addr;
|
||||
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ);
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEQ);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
|
||||
{
|
||||
TCGv addr;
|
||||
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ);
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEQ);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -252,11 +262,10 @@ static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_feq_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_feq_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -265,11 +274,10 @@ static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_flt_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_flt_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -278,11 +286,10 @@ static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_fle_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_fle_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -291,10 +298,10 @@ static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_fclass_d(t0, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_fclass_d(dest, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -303,12 +310,11 @@ static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_d(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -317,12 +323,11 @@ static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_d(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -331,12 +336,10 @@ static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
@@ -347,12 +350,10 @@ static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
@@ -364,11 +365,11 @@ static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_l_d(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -378,11 +379,11 @@ static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_lu_d(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -393,7 +394,7 @@ static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
gen_set_gpr(a->rd, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]);
|
||||
return true;
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
@@ -406,12 +407,11 @@ static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
@@ -422,12 +422,11 @@ static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
@@ -439,11 +438,7 @@ static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_mov_tl(cpu_fpr[a->rd], t0);
|
||||
tcg_temp_free(t0);
|
||||
tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE));
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
#else
|
||||
|
||||
@@ -25,32 +25,43 @@
|
||||
|
||||
static bool trans_flw(DisasContext *ctx, arg_flw *a)
|
||||
{
|
||||
TCGv_i64 dest;
|
||||
TCGv addr;
|
||||
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL);
|
||||
gen_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rd]);
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
|
||||
dest = cpu_fpr[a->rd];
|
||||
tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL);
|
||||
gen_nanbox_s(dest, dest);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
|
||||
{
|
||||
TCGv addr;
|
||||
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = tcg_temp_new();
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -200,12 +211,11 @@ static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
|
||||
* Replace bit 31 in rs1 with inverse in rs2.
|
||||
* This formulation retains the nanboxing of rs1.
|
||||
*/
|
||||
mask = tcg_const_i64(~MAKE_64BIT_MASK(31, 1));
|
||||
mask = tcg_constant_i64(~MAKE_64BIT_MASK(31, 1));
|
||||
tcg_gen_nor_i64(rs2, rs2, mask);
|
||||
tcg_gen_and_i64(rs1, mask, rs1);
|
||||
tcg_gen_or_i64(cpu_fpr[a->rd], rs1, rs2);
|
||||
|
||||
tcg_temp_free_i64(mask);
|
||||
tcg_temp_free_i64(rs2);
|
||||
}
|
||||
tcg_temp_free_i64(rs1);
|
||||
@@ -272,12 +282,11 @@ static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_s(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -286,12 +295,11 @@ static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_s(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -301,17 +309,15 @@ static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
#if defined(TARGET_RISCV64)
|
||||
tcg_gen_ext32s_tl(t0, cpu_fpr[a->rs1]);
|
||||
tcg_gen_ext32s_tl(dest, cpu_fpr[a->rs1]);
|
||||
#else
|
||||
tcg_gen_extrl_i64_i32(t0, cpu_fpr[a->rs1]);
|
||||
tcg_gen_extrl_i64_i32(dest, cpu_fpr[a->rs1]);
|
||||
#endif
|
||||
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -319,10 +325,11 @@ static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_feq_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_feq_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -330,10 +337,11 @@ static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_flt_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_flt_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -341,10 +349,11 @@ static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_fle_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_fle_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -353,13 +362,10 @@ static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
gen_helper_fclass_s(t0, cpu_fpr[a->rs1]);
|
||||
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_helper_fclass_s(dest, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -368,15 +374,12 @@ static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, t0);
|
||||
gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -385,15 +388,12 @@ static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -403,15 +403,12 @@ static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
|
||||
tcg_gen_extu_tl_i64(cpu_fpr[a->rd], t0);
|
||||
tcg_gen_extu_tl_i64(cpu_fpr[a->rd], src);
|
||||
gen_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rd]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -421,11 +418,11 @@ static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_l_s(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -435,11 +432,11 @@ static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
gen_helper_fcvt_lu_s(dest, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -449,14 +446,12 @@ static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, t0);
|
||||
gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -466,13 +461,11 @@ static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, src);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,281 +17,139 @@
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static void check_access(DisasContext *ctx) {
|
||||
static bool check_access(DisasContext *ctx)
|
||||
{
|
||||
if (!ctx->hlsx) {
|
||||
if (ctx->virt_enabled) {
|
||||
generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT);
|
||||
} else {
|
||||
generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool do_hlv(DisasContext *ctx, arg_r2 *a, MemOp mop)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return false;
|
||||
#else
|
||||
if (check_access(ctx)) {
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
int mem_idx = ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
|
||||
tcg_gen_qemu_ld_tl(dest, addr, mem_idx, mop);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_hlv_b(DisasContext *ctx, arg_hlv_b *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_SB);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hlv(ctx, a, MO_SB);
|
||||
}
|
||||
|
||||
static bool trans_hlv_h(DisasContext *ctx, arg_hlv_h *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESW);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hlv(ctx, a, MO_TESW);
|
||||
}
|
||||
|
||||
static bool trans_hlv_w(DisasContext *ctx, arg_hlv_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESL);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hlv(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
static bool trans_hlv_bu(DisasContext *ctx, arg_hlv_bu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_UB);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hlv(ctx, a, MO_UB);
|
||||
}
|
||||
|
||||
static bool trans_hlv_hu(DisasContext *ctx, arg_hlv_hu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
return do_hlv(ctx, a, MO_TEUW);
|
||||
}
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUW);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
static bool do_hsv(DisasContext *ctx, arg_r2_s *a, MemOp mop)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return false;
|
||||
#else
|
||||
if (check_access(ctx)) {
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
int mem_idx = ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
|
||||
tcg_gen_qemu_st_tl(data, addr, mem_idx, mop);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_hsv_b(DisasContext *ctx, arg_hsv_b *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
gen_get_gpr(dat, a->rs2);
|
||||
|
||||
tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_SB);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(dat);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hsv(ctx, a, MO_SB);
|
||||
}
|
||||
|
||||
static bool trans_hsv_h(DisasContext *ctx, arg_hsv_h *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
gen_get_gpr(dat, a->rs2);
|
||||
|
||||
tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESW);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(dat);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hsv(ctx, a, MO_TESW);
|
||||
}
|
||||
|
||||
static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
gen_get_gpr(dat, a->rs2);
|
||||
|
||||
tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESL);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(dat);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hsv(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUL);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hlv(ctx, a, MO_TEUL);
|
||||
}
|
||||
|
||||
static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return do_hlv(ctx, a, MO_TEQ);
|
||||
}
|
||||
|
||||
static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
return do_hsv(ctx, a, MO_TEQ);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
gen_get_gpr(dat, a->rs2);
|
||||
|
||||
tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(dat);
|
||||
static bool do_hlvx(DisasContext *ctx, arg_r2 *a,
|
||||
void (*func)(TCGv, TCGv_env, TCGv))
|
||||
{
|
||||
if (check_access(ctx)) {
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
func(dest, cpu_env, addr);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_helper_hyp_hlvx_hu(t1, cpu_env, t0);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
return do_hlvx(ctx, a, gen_helper_hyp_hlvx_hu);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -301,19 +159,7 @@ static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
check_access(ctx);
|
||||
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_helper_hyp_hlvx_wu(t1, cpu_env, t0);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
return do_hlvx(ctx, a, gen_helper_hyp_hlvx_wu);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,107 +22,230 @@
|
||||
static bool trans_mul(DisasContext *ctx, arg_mul *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &tcg_gen_mul_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
|
||||
}
|
||||
|
||||
static void gen_mulh(TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
TCGv discard = tcg_temp_new();
|
||||
|
||||
tcg_gen_muls2_tl(discard, ret, s1, s2);
|
||||
tcg_temp_free(discard);
|
||||
}
|
||||
|
||||
static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_mulh);
|
||||
}
|
||||
|
||||
tcg_gen_muls2_tl(source2, source1, source1, source2);
|
||||
static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv rl = tcg_temp_new();
|
||||
TCGv rh = tcg_temp_new();
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
tcg_gen_mulu2_tl(rl, rh, arg1, arg2);
|
||||
/* fix up for one negative */
|
||||
tcg_gen_sari_tl(rl, arg1, TARGET_LONG_BITS - 1);
|
||||
tcg_gen_and_tl(rl, rl, arg2);
|
||||
tcg_gen_sub_tl(ret, rh, rl);
|
||||
|
||||
tcg_temp_free(rl);
|
||||
tcg_temp_free(rh);
|
||||
}
|
||||
|
||||
static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_mulhsu);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_mulhsu);
|
||||
}
|
||||
|
||||
static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
TCGv discard = tcg_temp_new();
|
||||
|
||||
tcg_gen_mulu2_tl(discard, ret, s1, s2);
|
||||
tcg_temp_free(discard);
|
||||
}
|
||||
|
||||
static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_mulhu);
|
||||
}
|
||||
|
||||
tcg_gen_mulu2_tl(source2, source1, source1, source2);
|
||||
static void gen_div(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv temp1, temp2, zero, one, mone, min;
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
temp1 = tcg_temp_new();
|
||||
temp2 = tcg_temp_new();
|
||||
zero = tcg_constant_tl(0);
|
||||
one = tcg_constant_tl(1);
|
||||
mone = tcg_constant_tl(-1);
|
||||
min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
|
||||
|
||||
/*
|
||||
* If overflow, set temp2 to 1, else source2.
|
||||
* This produces the required result of min.
|
||||
*/
|
||||
tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
|
||||
tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
|
||||
tcg_gen_and_tl(temp1, temp1, temp2);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, source2);
|
||||
|
||||
/*
|
||||
* If div by zero, set temp1 to -1 and temp2 to 1 to
|
||||
* produce the required result of -1.
|
||||
*/
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, mone, source1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, temp2);
|
||||
|
||||
tcg_gen_div_tl(ret, temp1, temp2);
|
||||
|
||||
tcg_temp_free(temp1);
|
||||
tcg_temp_free(temp2);
|
||||
}
|
||||
|
||||
static bool trans_div(DisasContext *ctx, arg_div *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_div);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div);
|
||||
}
|
||||
|
||||
static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv temp1, temp2, zero, one, max;
|
||||
|
||||
temp1 = tcg_temp_new();
|
||||
temp2 = tcg_temp_new();
|
||||
zero = tcg_constant_tl(0);
|
||||
one = tcg_constant_tl(1);
|
||||
max = tcg_constant_tl(~0);
|
||||
|
||||
/*
|
||||
* If div by zero, set temp1 to max and temp2 to 1 to
|
||||
* produce the required result of max.
|
||||
*/
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, max, source1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
|
||||
tcg_gen_divu_tl(ret, temp1, temp2);
|
||||
|
||||
tcg_temp_free(temp1);
|
||||
tcg_temp_free(temp2);
|
||||
}
|
||||
|
||||
static bool trans_divu(DisasContext *ctx, arg_divu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_divu);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu);
|
||||
}
|
||||
|
||||
static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv temp1, temp2, zero, one, mone, min;
|
||||
|
||||
temp1 = tcg_temp_new();
|
||||
temp2 = tcg_temp_new();
|
||||
zero = tcg_constant_tl(0);
|
||||
one = tcg_constant_tl(1);
|
||||
mone = tcg_constant_tl(-1);
|
||||
min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
|
||||
|
||||
/*
|
||||
* If overflow, set temp1 to 0, else source1.
|
||||
* This avoids a possible host trap, and produces the required result of 0.
|
||||
*/
|
||||
tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
|
||||
tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
|
||||
tcg_gen_and_tl(temp1, temp1, temp2);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, temp1, temp1, zero, zero, source1);
|
||||
|
||||
/*
|
||||
* If div by zero, set temp2 to 1, else source2.
|
||||
* This avoids a possible host trap, but produces an incorrect result.
|
||||
*/
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
|
||||
|
||||
tcg_gen_rem_tl(temp1, temp1, temp2);
|
||||
|
||||
/* If div by zero, the required result is the original dividend. */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp1);
|
||||
|
||||
tcg_temp_free(temp1);
|
||||
tcg_temp_free(temp2);
|
||||
}
|
||||
|
||||
static bool trans_rem(DisasContext *ctx, arg_rem *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_rem);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem);
|
||||
}
|
||||
|
||||
static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv temp, zero, one;
|
||||
|
||||
temp = tcg_temp_new();
|
||||
zero = tcg_constant_tl(0);
|
||||
one = tcg_constant_tl(1);
|
||||
|
||||
/*
|
||||
* If div by zero, set temp to 1, else source2.
|
||||
* This avoids a possible host trap, but produces an incorrect result.
|
||||
*/
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, temp, source2, zero, one, source2);
|
||||
|
||||
tcg_gen_remu_tl(temp, source1, temp);
|
||||
|
||||
/* If div by zero, the required result is the original dividend. */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp);
|
||||
|
||||
tcg_temp_free(temp);
|
||||
}
|
||||
|
||||
static bool trans_remu(DisasContext *ctx, arg_remu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_remu);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu);
|
||||
}
|
||||
|
||||
static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
|
||||
return gen_arith(ctx, a, &gen_mulw);
|
||||
ctx->w = true;
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
|
||||
}
|
||||
|
||||
static bool trans_divw(DisasContext *ctx, arg_divw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
|
||||
return gen_arith_div_w(ctx, a, &gen_div);
|
||||
ctx->w = true;
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div);
|
||||
}
|
||||
|
||||
static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
|
||||
return gen_arith_div_uw(ctx, a, &gen_divu);
|
||||
ctx->w = true;
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu);
|
||||
}
|
||||
|
||||
static bool trans_remw(DisasContext *ctx, arg_remw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
|
||||
return gen_arith_div_w(ctx, a, &gen_rem);
|
||||
ctx->w = true;
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem);
|
||||
}
|
||||
|
||||
static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
|
||||
return gen_arith_div_uw(ctx, a, &gen_remu);
|
||||
ctx->w = true;
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu);
|
||||
}
|
||||
|
||||
@@ -27,27 +27,22 @@ static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a)
|
||||
return false;
|
||||
}
|
||||
|
||||
s2 = tcg_temp_new();
|
||||
dst = tcg_temp_new();
|
||||
s2 = get_gpr(ctx, a->rs2, EXT_ZERO);
|
||||
dst = dest_gpr(ctx, a->rd);
|
||||
|
||||
/* Using x0 as the rs1 register specifier, encodes an infinite AVL */
|
||||
if (a->rs1 == 0) {
|
||||
/* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
|
||||
s1 = tcg_const_tl(RV_VLEN_MAX);
|
||||
s1 = tcg_constant_tl(RV_VLEN_MAX);
|
||||
} else {
|
||||
s1 = tcg_temp_new();
|
||||
gen_get_gpr(s1, a->rs1);
|
||||
s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
}
|
||||
gen_get_gpr(s2, a->rs2);
|
||||
gen_helper_vsetvl(dst, cpu_env, s1, s2);
|
||||
gen_set_gpr(a->rd, dst);
|
||||
gen_set_gpr(ctx, a->rd, dst);
|
||||
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
|
||||
lookup_and_goto_ptr(ctx);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free(s1);
|
||||
tcg_temp_free(s2);
|
||||
tcg_temp_free(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,25 +54,21 @@ static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a)
|
||||
return false;
|
||||
}
|
||||
|
||||
s2 = tcg_const_tl(a->zimm);
|
||||
dst = tcg_temp_new();
|
||||
s2 = tcg_constant_tl(a->zimm);
|
||||
dst = dest_gpr(ctx, a->rd);
|
||||
|
||||
/* Using x0 as the rs1 register specifier, encodes an infinite AVL */
|
||||
if (a->rs1 == 0) {
|
||||
/* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
|
||||
s1 = tcg_const_tl(RV_VLEN_MAX);
|
||||
s1 = tcg_constant_tl(RV_VLEN_MAX);
|
||||
} else {
|
||||
s1 = tcg_temp_new();
|
||||
gen_get_gpr(s1, a->rs1);
|
||||
s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
}
|
||||
gen_helper_vsetvl(dst, cpu_env, s1, s2);
|
||||
gen_set_gpr(a->rd, dst);
|
||||
gen_set_gpr(ctx, a->rd, dst);
|
||||
|
||||
gen_goto_tb(ctx, 0, ctx->pc_succ_insn);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free(s1);
|
||||
tcg_temp_free(s2);
|
||||
tcg_temp_free(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,7 +165,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
base = get_gpr(s, rs1, EXT_NONE);
|
||||
|
||||
/*
|
||||
* As simd_desc supports at most 256 bytes, and in this implementation,
|
||||
@@ -183,9 +174,8 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
* The first part is vlen in bytes, encoded in maxsz of simd_desc.
|
||||
* The second part is lmul, encoded in data of simd_desc.
|
||||
*/
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
|
||||
@@ -193,8 +183,6 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free(base);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -332,12 +320,10 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
stride = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
base = get_gpr(s, rs1, EXT_NONE);
|
||||
stride = get_gpr(s, rs2, EXT_NONE);
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
gen_get_gpr(stride, rs2);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
|
||||
@@ -345,9 +331,6 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
|
||||
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free(base);
|
||||
tcg_temp_free(stride);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -461,10 +444,9 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
index = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
base = get_gpr(s, rs1, EXT_NONE);
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
@@ -474,8 +456,6 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(index);
|
||||
tcg_temp_free(base);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -593,10 +573,9 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
base = get_gpr(s, rs1, EXT_NONE);
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
|
||||
@@ -604,8 +583,6 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free(base);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -670,10 +647,9 @@ static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
index = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
base = get_gpr(s, rs1, EXT_NONE);
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
@@ -683,8 +659,6 @@ static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(index);
|
||||
tcg_temp_free(base);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -868,13 +842,12 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
src1 = tcg_temp_new();
|
||||
gen_get_gpr(src1, rs1);
|
||||
src1 = get_gpr(s, rs1, EXT_NONE);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
|
||||
data = FIELD_DP32(data, VDATA, VM, vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
|
||||
@@ -885,8 +858,6 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(src2);
|
||||
tcg_temp_free(src1);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -912,15 +883,12 @@ do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
|
||||
|
||||
if (a->vm && s->vl_eq_vlmax) {
|
||||
TCGv_i64 src1 = tcg_temp_new_i64();
|
||||
TCGv tmp = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(tmp, a->rs1);
|
||||
tcg_gen_ext_tl_i64(src1, tmp);
|
||||
tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
|
||||
gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
|
||||
src1, MAXSZ(s), MAXSZ(s));
|
||||
|
||||
tcg_temp_free_i64(src1);
|
||||
tcg_temp_free(tmp);
|
||||
return true;
|
||||
}
|
||||
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
|
||||
@@ -1014,14 +982,14 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
if (zx) {
|
||||
src1 = tcg_const_tl(imm);
|
||||
src1 = tcg_constant_tl(imm);
|
||||
} else {
|
||||
src1 = tcg_const_tl(sextract64(imm, 0, 5));
|
||||
src1 = tcg_constant_tl(sextract64(imm, 0, 5));
|
||||
}
|
||||
data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
|
||||
data = FIELD_DP32(data, VDATA, VM, vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
|
||||
@@ -1032,8 +1000,6 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(src2);
|
||||
tcg_temp_free(src1);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -1080,9 +1046,8 @@ GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi)
|
||||
static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
|
||||
int64_t c, uint32_t oprsz, uint32_t maxsz)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_const_i64(c);
|
||||
TCGv_i64 tmp = tcg_constant_i64(c);
|
||||
tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
|
||||
tcg_temp_free_i64(tmp);
|
||||
}
|
||||
|
||||
GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi)
|
||||
@@ -1408,16 +1373,13 @@ do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
|
||||
|
||||
if (a->vm && s->vl_eq_vlmax) {
|
||||
TCGv_i32 src1 = tcg_temp_new_i32();
|
||||
TCGv tmp = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(tmp, a->rs1);
|
||||
tcg_gen_trunc_tl_i32(src1, tmp);
|
||||
tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
|
||||
tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
|
||||
gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
|
||||
src1, MAXSZ(s), MAXSZ(s));
|
||||
|
||||
tcg_temp_free_i32(src1);
|
||||
tcg_temp_free(tmp);
|
||||
return true;
|
||||
}
|
||||
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
|
||||
@@ -1675,14 +1637,13 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
|
||||
s1 = tcg_temp_new();
|
||||
gen_get_gpr(s1, a->rs1);
|
||||
s1 = get_gpr(s, a->rs1, EXT_SIGN);
|
||||
|
||||
if (s->vl_eq_vlmax) {
|
||||
tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
|
||||
MAXSZ(s), MAXSZ(s), s1);
|
||||
} else {
|
||||
TCGv_i32 desc ;
|
||||
TCGv_i32 desc;
|
||||
TCGv_i64 s1_i64 = tcg_temp_new_i64();
|
||||
TCGv_ptr dest = tcg_temp_new_ptr();
|
||||
uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
|
||||
@@ -1692,16 +1653,14 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
|
||||
};
|
||||
|
||||
tcg_gen_ext_tl_i64(s1_i64, s1);
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
|
||||
fns[s->sew](dest, s1_i64, cpu_env, desc);
|
||||
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_i32(desc);
|
||||
tcg_temp_free_i64(s1_i64);
|
||||
}
|
||||
|
||||
tcg_temp_free(s1);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -1729,15 +1688,13 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
|
||||
s1 = tcg_const_i64(simm);
|
||||
s1 = tcg_constant_i64(simm);
|
||||
dest = tcg_temp_new_ptr();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
|
||||
fns[s->sew](dest, s1, cpu_env, desc);
|
||||
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_i32(desc);
|
||||
tcg_temp_free_i64(s1);
|
||||
gen_set_label(over);
|
||||
}
|
||||
return true;
|
||||
@@ -1866,7 +1823,7 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
|
||||
@@ -1877,7 +1834,6 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(src2);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@@ -2231,12 +2187,11 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
|
||||
fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
|
||||
|
||||
tcg_temp_free_ptr(dest);
|
||||
tcg_temp_free_i32(desc);
|
||||
gen_set_label(over);
|
||||
}
|
||||
return true;
|
||||
@@ -2427,19 +2382,17 @@ static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
|
||||
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
dst = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
dst = dest_gpr(s, a->rd);
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
|
||||
gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
|
||||
gen_set_gpr(a->rd, dst);
|
||||
gen_set_gpr(s, a->rd, dst);
|
||||
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(src2);
|
||||
tcg_temp_free(dst);
|
||||
tcg_temp_free_i32(desc);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2459,19 +2412,17 @@ static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
|
||||
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
dst = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
dst = dest_gpr(s, a->rd);
|
||||
desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
|
||||
gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
|
||||
gen_set_gpr(a->rd, dst);
|
||||
gen_set_gpr(s, a->rd, dst);
|
||||
|
||||
tcg_temp_free_ptr(mask);
|
||||
tcg_temp_free_ptr(src2);
|
||||
tcg_temp_free(dst);
|
||||
tcg_temp_free_i32(desc);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2636,15 +2587,13 @@ static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
|
||||
tcg_temp_free_i32(ofs);
|
||||
|
||||
/* Flush out-of-range indexing to zero. */
|
||||
t_vlmax = tcg_const_i64(vlmax);
|
||||
t_zero = tcg_const_i64(0);
|
||||
t_vlmax = tcg_constant_i64(vlmax);
|
||||
t_zero = tcg_constant_i64(0);
|
||||
tcg_gen_extu_tl_i64(t_idx, idx);
|
||||
|
||||
tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
|
||||
t_vlmax, dest, t_zero);
|
||||
|
||||
tcg_temp_free_i64(t_vlmax);
|
||||
tcg_temp_free_i64(t_zero);
|
||||
tcg_temp_free_i64(t_idx);
|
||||
}
|
||||
|
||||
@@ -2657,7 +2606,7 @@ static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
|
||||
static bool trans_vext_x_v(DisasContext *s, arg_r *a)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_temp_new_i64();
|
||||
TCGv dest = tcg_temp_new();
|
||||
TCGv dest = dest_gpr(s, a->rd);
|
||||
|
||||
if (a->rs1 == 0) {
|
||||
/* Special case vmv.x.s rd, vs2. */
|
||||
@@ -2667,10 +2616,10 @@ static bool trans_vext_x_v(DisasContext *s, arg_r *a)
|
||||
int vlmax = s->vlen >> (3 + s->sew);
|
||||
vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
|
||||
}
|
||||
tcg_gen_trunc_i64_tl(dest, tmp);
|
||||
gen_set_gpr(a->rd, dest);
|
||||
|
||||
tcg_temp_free(dest);
|
||||
tcg_gen_trunc_i64_tl(dest, tmp);
|
||||
gen_set_gpr(s, a->rd, dest);
|
||||
|
||||
tcg_temp_free_i64(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user