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
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmEu4LAACgkQIeENKd+X
 cFQfBQf/Q5T6SGY8HC0ao/znTrvuBkUTgoL+R/pyNzamkgkrNFaRkMScOHq6gEqM
 3W//ri1z4+8KDPnXEScI2GWRA1eE0g9QVco1tv6YzenJTHK8ttk380HuptszMcoP
 LGHfNH45BTDjj9D7rpgPkycGSSzR7OxynxH0SAl6pBqT7n8vkaSUsqsUnIvmThY2
 Orx9hQkhAowsNCajwqzW/qLOi/HFXd455U08vFIZ/GSaV5s4uXdpIWShiiFttSVe
 vL9IgNie2GszKJYoD3a5FUYKobHMc1xvoj2XuZSac2XAyl4lS8FNM+NFRg12MdXv
 g1s4EhRMxjn3/X3acc99O5aokhf0+w==
 =YUsp
 -----END PGP SIGNATURE-----

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:
Peter Maydell 2021-09-01 08:33:02 +01:00
commit ec397e90d2
24 changed files with 1246 additions and 1387 deletions

View file

@ -68,3 +68,6 @@ config SIFIVE_UART
config GOLDFISH_TTY
bool
config SHAKTI_UART
bool

View file

@ -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'))

View file

@ -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));

View file

@ -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);
}

View file

@ -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

View file

@ -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(

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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 },

View file

@ -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)

View file

@ -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

View file

@ -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;
}

View file

@ -17,422 +17,632 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
static void gen_clz(TCGv ret, TCGv arg1)
{
tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS);
}
static bool trans_clz(DisasContext *ctx, arg_clz *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, gen_clz);
return gen_unary(ctx, a, EXT_ZERO, gen_clz);
}
static void gen_ctz(TCGv ret, TCGv arg1)
{
tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS);
}
static bool trans_ctz(DisasContext *ctx, arg_ctz *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, gen_ctz);
return gen_unary(ctx, a, EXT_ZERO, gen_ctz);
}
static bool trans_cpop(DisasContext *ctx, arg_cpop *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, tcg_gen_ctpop_tl);
return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl);
}
static bool trans_andn(DisasContext *ctx, arg_andn *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_andc_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_andc_tl);
}
static bool trans_orn(DisasContext *ctx, arg_orn *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_orc_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_orc_tl);
}
static bool trans_xnor(DisasContext *ctx, arg_xnor *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_eqv_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_eqv_tl);
}
static void gen_pack(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_deposit_tl(ret, arg1, arg2,
TARGET_LONG_BITS / 2,
TARGET_LONG_BITS / 2);
}
static bool trans_pack(DisasContext *ctx, arg_pack *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, gen_pack);
return gen_arith(ctx, a, EXT_NONE, gen_pack);
}
static void gen_packu(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_shri_tl(t, arg1, TARGET_LONG_BITS / 2);
tcg_gen_deposit_tl(ret, arg2, t, 0, TARGET_LONG_BITS / 2);
tcg_temp_free(t);
}
static bool trans_packu(DisasContext *ctx, arg_packu *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, gen_packu);
return gen_arith(ctx, a, EXT_NONE, gen_packu);
}
static void gen_packh(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_ext8u_tl(t, arg2);
tcg_gen_deposit_tl(ret, arg1, t, 8, TARGET_LONG_BITS - 8);
tcg_temp_free(t);
}
static bool trans_packh(DisasContext *ctx, arg_packh *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, gen_packh);
return gen_arith(ctx, a, EXT_NONE, gen_packh);
}
static bool trans_min(DisasContext *ctx, arg_min *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_smin_tl);
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smin_tl);
}
static bool trans_max(DisasContext *ctx, arg_max *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_smax_tl);
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smax_tl);
}
static bool trans_minu(DisasContext *ctx, arg_minu *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_umin_tl);
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umin_tl);
}
static bool trans_maxu(DisasContext *ctx, arg_maxu *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, tcg_gen_umax_tl);
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umax_tl);
}
static bool trans_sext_b(DisasContext *ctx, arg_sext_b *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, tcg_gen_ext8s_tl);
return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl);
}
static bool trans_sext_h(DisasContext *ctx, arg_sext_h *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, tcg_gen_ext16s_tl);
return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl);
}
static void gen_sbop_mask(TCGv ret, TCGv shamt)
{
tcg_gen_movi_tl(ret, 1);
tcg_gen_shl_tl(ret, ret, shamt);
}
static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
{
TCGv t = tcg_temp_new();
gen_sbop_mask(t, shamt);
tcg_gen_or_tl(ret, arg1, t);
tcg_temp_free(t);
}
static bool trans_bset(DisasContext *ctx, arg_bset *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_bset);
return gen_shift(ctx, a, EXT_NONE, gen_bset);
}
static bool trans_bseti(DisasContext *ctx, arg_bseti *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_bset);
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bset);
}
static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
{
TCGv t = tcg_temp_new();
gen_sbop_mask(t, shamt);
tcg_gen_andc_tl(ret, arg1, t);
tcg_temp_free(t);
}
static bool trans_bclr(DisasContext *ctx, arg_bclr *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_bclr);
return gen_shift(ctx, a, EXT_NONE, gen_bclr);
}
static bool trans_bclri(DisasContext *ctx, arg_bclri *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_bclr);
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bclr);
}
static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
{
TCGv t = tcg_temp_new();
gen_sbop_mask(t, shamt);
tcg_gen_xor_tl(ret, arg1, t);
tcg_temp_free(t);
}
static bool trans_binv(DisasContext *ctx, arg_binv *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_binv);
return gen_shift(ctx, a, EXT_NONE, gen_binv);
}
static bool trans_binvi(DisasContext *ctx, arg_binvi *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_binv);
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_binv);
}
static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
{
tcg_gen_shr_tl(ret, arg1, shamt);
tcg_gen_andi_tl(ret, ret, 1);
}
static bool trans_bext(DisasContext *ctx, arg_bext *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_bext);
return gen_shift(ctx, a, EXT_NONE, gen_bext);
}
static bool trans_bexti(DisasContext *ctx, arg_bexti *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_bext);
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext);
}
static void gen_slo(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_not_tl(ret, arg1);
tcg_gen_shl_tl(ret, ret, arg2);
tcg_gen_not_tl(ret, ret);
}
static bool trans_slo(DisasContext *ctx, arg_slo *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_slo);
return gen_shift(ctx, a, EXT_NONE, gen_slo);
}
static bool trans_sloi(DisasContext *ctx, arg_sloi *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_slo);
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_slo);
}
static void gen_sro(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_not_tl(ret, arg1);
tcg_gen_shr_tl(ret, ret, arg2);
tcg_gen_not_tl(ret, ret);
}
static bool trans_sro(DisasContext *ctx, arg_sro *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_sro);
return gen_shift(ctx, a, EXT_ZERO, gen_sro);
}
static bool trans_sroi(DisasContext *ctx, arg_sroi *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_sro);
return gen_shift_imm_tl(ctx, a, EXT_ZERO, gen_sro);
}
static bool trans_ror(DisasContext *ctx, arg_ror *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, tcg_gen_rotr_tl);
return gen_shift(ctx, a, EXT_NONE, tcg_gen_rotr_tl);
}
static bool trans_rori(DisasContext *ctx, arg_rori *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, tcg_gen_rotr_tl);
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_rotri_tl);
}
static bool trans_rol(DisasContext *ctx, arg_rol *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, tcg_gen_rotl_tl);
return gen_shift(ctx, a, EXT_NONE, tcg_gen_rotl_tl);
}
static bool trans_grev(DisasContext *ctx, arg_grev *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_helper_grev);
return gen_shift(ctx, a, EXT_NONE, gen_helper_grev);
}
static void gen_grevi(TCGv dest, TCGv src, target_long shamt)
{
if (shamt == TARGET_LONG_BITS - 8) {
/* rev8, byte swaps */
tcg_gen_bswap_tl(dest, src);
} else {
gen_helper_grev(dest, src, tcg_constant_tl(shamt));
}
}
static bool trans_grevi(DisasContext *ctx, arg_grevi *a)
{
REQUIRE_EXT(ctx, RVB);
if (a->shamt >= TARGET_LONG_BITS) {
return false;
}
return gen_grevi(ctx, a);
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_grevi);
}
static bool trans_gorc(DisasContext *ctx, arg_gorc *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shift(ctx, a, gen_helper_gorc);
return gen_shift(ctx, a, EXT_ZERO, gen_helper_gorc);
}
static bool trans_gorci(DisasContext *ctx, arg_gorci *a)
{
REQUIRE_EXT(ctx, RVB);
return gen_shifti(ctx, a, gen_helper_gorc);
return gen_shift_imm_tl(ctx, a, EXT_ZERO, gen_helper_gorc);
}
#define GEN_SHADD(SHAMT) \
static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \
{ \
TCGv t = tcg_temp_new(); \
\
tcg_gen_shli_tl(t, arg1, SHAMT); \
tcg_gen_add_tl(ret, t, arg2); \
\
tcg_temp_free(t); \
}
GEN_SHADD(1)
GEN_SHADD(2)
GEN_SHADD(3)
#define GEN_TRANS_SHADD(SHAMT) \
static bool trans_sh##SHAMT##add(DisasContext *ctx, arg_sh##SHAMT##add *a) \
{ \
REQUIRE_EXT(ctx, RVB); \
return gen_arith(ctx, a, gen_sh##SHAMT##add); \
return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add); \
}
GEN_TRANS_SHADD(1)
GEN_TRANS_SHADD(2)
GEN_TRANS_SHADD(3)
static void gen_clzw(TCGv ret, TCGv arg1)
{
tcg_gen_clzi_tl(ret, ret, 64);
tcg_gen_subi_tl(ret, ret, 32);
}
static bool trans_clzw(DisasContext *ctx, arg_clzw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, gen_clzw);
return gen_unary(ctx, a, EXT_ZERO, gen_clzw);
}
static void gen_ctzw(TCGv ret, TCGv arg1)
{
tcg_gen_ori_tl(ret, arg1, (target_ulong)MAKE_64BIT_MASK(32, 32));
tcg_gen_ctzi_tl(ret, ret, 64);
}
static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, gen_ctzw);
return gen_unary(ctx, a, EXT_NONE, gen_ctzw);
}
static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_unary(ctx, a, gen_cpopw);
ctx->w = true;
return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl);
}
static void gen_packw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_ext16s_tl(t, arg2);
tcg_gen_deposit_tl(ret, arg1, t, 16, 48);
tcg_temp_free(t);
}
static bool trans_packw(DisasContext *ctx, arg_packw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, gen_packw);
return gen_arith(ctx, a, EXT_NONE, gen_packw);
}
static void gen_packuw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_shri_tl(t, arg1, 16);
tcg_gen_deposit_tl(ret, arg2, t, 0, 16);
tcg_gen_ext32s_tl(ret, ret);
tcg_temp_free(t);
}
static bool trans_packuw(DisasContext *ctx, arg_packuw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, gen_packuw);
return gen_arith(ctx, a, EXT_NONE, gen_packuw);
}
static bool trans_bsetw(DisasContext *ctx, arg_bsetw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_bset);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_bset);
}
static bool trans_bsetiw(DisasContext *ctx, arg_bsetiw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_bset);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bset);
}
static bool trans_bclrw(DisasContext *ctx, arg_bclrw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_bclr);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_bclr);
}
static bool trans_bclriw(DisasContext *ctx, arg_bclriw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_bclr);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bclr);
}
static bool trans_binvw(DisasContext *ctx, arg_binvw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_binv);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_binv);
}
static bool trans_binviw(DisasContext *ctx, arg_binviw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_binv);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_binv);
}
static bool trans_bextw(DisasContext *ctx, arg_bextw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_bext);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_bext);
}
static bool trans_slow(DisasContext *ctx, arg_slow *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_slo);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_slo);
}
static bool trans_sloiw(DisasContext *ctx, arg_sloiw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_slo);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_slo);
}
static bool trans_srow(DisasContext *ctx, arg_srow *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_sro);
ctx->w = true;
return gen_shift(ctx, a, EXT_ZERO, gen_sro);
}
static bool trans_sroiw(DisasContext *ctx, arg_sroiw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_sro);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_ZERO, gen_sro);
}
static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
/* truncate to 32-bits */
tcg_gen_trunc_tl_i32(t1, arg1);
tcg_gen_trunc_tl_i32(t2, arg2);
tcg_gen_rotr_i32(t1, t1, t2);
/* sign-extend 64-bits */
tcg_gen_ext_i32_tl(ret, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
}
static bool trans_rorw(DisasContext *ctx, arg_rorw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_rorw);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_rorw);
}
static bool trans_roriw(DisasContext *ctx, arg_roriw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_rorw);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_rorw);
}
static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
/* truncate to 32-bits */
tcg_gen_trunc_tl_i32(t1, arg1);
tcg_gen_trunc_tl_i32(t2, arg2);
tcg_gen_rotl_i32(t1, t1, t2);
/* sign-extend 64-bits */
tcg_gen_ext_i32_tl(ret, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
}
static bool trans_rolw(DisasContext *ctx, arg_rolw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_rolw);
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, gen_rolw);
}
static bool trans_grevw(DisasContext *ctx, arg_grevw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_grevw);
ctx->w = true;
return gen_shift(ctx, a, EXT_ZERO, gen_helper_grev);
}
static bool trans_greviw(DisasContext *ctx, arg_greviw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_grevw);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_ZERO, gen_helper_grev);
}
static bool trans_gorcw(DisasContext *ctx, arg_gorcw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftw(ctx, a, gen_gorcw);
ctx->w = true;
return gen_shift(ctx, a, EXT_ZERO, gen_helper_gorc);
}
static bool trans_gorciw(DisasContext *ctx, arg_gorciw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_shiftiw(ctx, a, gen_gorcw);
ctx->w = true;
return gen_shift_imm_tl(ctx, a, EXT_ZERO, gen_helper_gorc);
}
#define GEN_SHADD_UW(SHAMT) \
static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \
{ \
TCGv t = tcg_temp_new(); \
\
tcg_gen_ext32u_tl(t, arg1); \
\
tcg_gen_shli_tl(t, t, SHAMT); \
tcg_gen_add_tl(ret, t, arg2); \
\
tcg_temp_free(t); \
}
GEN_SHADD_UW(1)
GEN_SHADD_UW(2)
GEN_SHADD_UW(3)
#define GEN_TRANS_SHADD_UW(SHAMT) \
static bool trans_sh##SHAMT##add_uw(DisasContext *ctx, \
arg_sh##SHAMT##add_uw *a) \
{ \
REQUIRE_64BIT(ctx); \
REQUIRE_EXT(ctx, RVB); \
return gen_arith(ctx, a, gen_sh##SHAMT##add_uw); \
return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add_uw); \
}
GEN_TRANS_SHADD_UW(1)
GEN_TRANS_SHADD_UW(2)
GEN_TRANS_SHADD_UW(3)
static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_ext32u_tl(arg1, arg1);
tcg_gen_add_tl(ret, arg1, arg2);
}
static bool trans_add_uw(DisasContext *ctx, arg_add_uw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
return gen_arith(ctx, a, gen_add_uw);
return gen_arith(ctx, a, EXT_NONE, gen_add_uw);
}
static void gen_slli_uw(TCGv dest, TCGv src, target_long shamt)
{
tcg_gen_deposit_z_tl(dest, src, shamt, MIN(32, TARGET_LONG_BITS - shamt));
}
static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVB);
TCGv source1 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
if (a->shamt < 32) {
tcg_gen_deposit_z_tl(source1, source1, a->shamt, 32);
} else {
tcg_gen_shli_tl(source1, source1, a->shamt);
}
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
return true;
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_slli_uw);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -54,24 +54,25 @@ static bool trans_jal(DisasContext *ctx, arg_jal *a)
static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
{
/* no chaining with JALR */
TCGLabel *misaligned = NULL;
TCGv t0 = tcg_temp_new();
gen_get_gpr(cpu_pc, a->rs1);
tcg_gen_addi_tl(cpu_pc, cpu_pc, a->imm);
tcg_gen_addi_tl(cpu_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
if (!has_ext(ctx, RVC)) {
TCGv t0 = tcg_temp_new();
misaligned = gen_new_label();
tcg_gen_andi_tl(t0, cpu_pc, 0x2);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
tcg_temp_free(t0);
}
if (a->rd != 0) {
tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
}
/* No chaining with JALR. */
lookup_and_goto_ptr(ctx);
if (misaligned) {
@ -80,21 +81,18 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
}
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free(t0);
return true;
}
static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
{
TCGLabel *l = gen_new_label();
TCGv source1, source2;
source1 = tcg_temp_new();
source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
TCGv src1 = get_gpr(ctx, a->rs1, EXT_SIGN);
TCGv src2 = get_gpr(ctx, a->rs2, EXT_SIGN);
tcg_gen_brcond_tl(cond, source1, source2, l);
tcg_gen_brcond_tl(cond, src1, src2, l);
gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
gen_set_label(l); /* branch taken */
if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) {
@ -105,9 +103,6 @@ static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
}
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
}
@ -143,15 +138,17 @@ static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
gen_get_gpr(t0, a->rs1);
tcg_gen_addi_tl(t0, t0, a->imm);
TCGv dest = dest_gpr(ctx, a->rd);
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop);
gen_set_gpr(a->rd, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
if (a->imm) {
TCGv temp = temp_new(ctx);
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
@ -182,19 +179,19 @@ static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
{
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
gen_get_gpr(t0, a->rs1);
tcg_gen_addi_tl(t0, t0, a->imm);
gen_get_gpr(dat, a->rs2);
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, memop);
tcg_temp_free(t0);
tcg_temp_free(dat);
if (a->imm) {
TCGv temp = temp_new(ctx);
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
return true;
}
static bool trans_sb(DisasContext *ctx, arg_sb *a)
{
return gen_store(ctx, a, MO_SB);
@ -230,7 +227,7 @@ static bool trans_sd(DisasContext *ctx, arg_sd *a)
static bool trans_addi(DisasContext *ctx, arg_addi *a)
{
return gen_arith_imm_fn(ctx, a, &tcg_gen_addi_tl);
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
}
static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
@ -243,204 +240,167 @@ static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2);
}
static bool trans_slti(DisasContext *ctx, arg_slti *a)
{
return gen_arith_imm_tl(ctx, a, &gen_slt);
return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_slt);
}
static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
{
return gen_arith_imm_tl(ctx, a, &gen_sltu);
return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_sltu);
}
static bool trans_xori(DisasContext *ctx, arg_xori *a)
{
return gen_arith_imm_fn(ctx, a, &tcg_gen_xori_tl);
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_xori_tl);
}
static bool trans_ori(DisasContext *ctx, arg_ori *a)
{
return gen_arith_imm_fn(ctx, a, &tcg_gen_ori_tl);
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_ori_tl);
}
static bool trans_andi(DisasContext *ctx, arg_andi *a)
{
return gen_arith_imm_fn(ctx, a, &tcg_gen_andi_tl);
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_andi_tl);
}
static bool trans_slli(DisasContext *ctx, arg_slli *a)
{
return gen_shifti(ctx, a, tcg_gen_shl_tl);
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
}
static bool trans_srli(DisasContext *ctx, arg_srli *a)
{
return gen_shifti(ctx, a, tcg_gen_shr_tl);
return gen_shift_imm_fn(ctx, a, EXT_ZERO, tcg_gen_shri_tl);
}
static bool trans_srai(DisasContext *ctx, arg_srai *a)
{
return gen_shifti(ctx, a, tcg_gen_sar_tl);
return gen_shift_imm_fn(ctx, a, EXT_SIGN, tcg_gen_sari_tl);
}
static bool trans_add(DisasContext *ctx, arg_add *a)
{
return gen_arith(ctx, a, &tcg_gen_add_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
}
static bool trans_sub(DisasContext *ctx, arg_sub *a)
{
return gen_arith(ctx, a, &tcg_gen_sub_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
}
static bool trans_sll(DisasContext *ctx, arg_sll *a)
{
return gen_shift(ctx, a, &tcg_gen_shl_tl);
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
}
static bool trans_slt(DisasContext *ctx, arg_slt *a)
{
return gen_arith(ctx, a, &gen_slt);
return gen_arith(ctx, a, EXT_SIGN, gen_slt);
}
static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
{
return gen_arith(ctx, a, &gen_sltu);
return gen_arith(ctx, a, EXT_SIGN, gen_sltu);
}
static bool trans_xor(DisasContext *ctx, arg_xor *a)
{
return gen_arith(ctx, a, &tcg_gen_xor_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_xor_tl);
}
static bool trans_srl(DisasContext *ctx, arg_srl *a)
{
return gen_shift(ctx, a, &tcg_gen_shr_tl);
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
}
static bool trans_sra(DisasContext *ctx, arg_sra *a)
{
return gen_shift(ctx, a, &tcg_gen_sar_tl);
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
}
static bool trans_or(DisasContext *ctx, arg_or *a)
{
return gen_arith(ctx, a, &tcg_gen_or_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_or_tl);
}
static bool trans_and(DisasContext *ctx, arg_and *a)
{
return gen_arith(ctx, a, &tcg_gen_and_tl);
return gen_arith(ctx, a, EXT_NONE, tcg_gen_and_tl);
}
static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
{
REQUIRE_64BIT(ctx);
return gen_arith_imm_tl(ctx, a, &gen_addw);
ctx->w = true;
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
}
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
{
REQUIRE_64BIT(ctx);
return gen_shiftiw(ctx, a, tcg_gen_shl_tl);
ctx->w = true;
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
}
static void gen_srliw(TCGv dst, TCGv src, target_long shamt)
{
tcg_gen_extract_tl(dst, src, shamt, 32 - shamt);
}
static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
{
REQUIRE_64BIT(ctx);
TCGv t = tcg_temp_new();
gen_get_gpr(t, a->rs1);
tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt);
/* sign-extend for W instructions */
tcg_gen_ext32s_tl(t, t);
gen_set_gpr(a->rd, t);
tcg_temp_free(t);
return true;
ctx->w = true;
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_srliw);
}
static void gen_sraiw(TCGv dst, TCGv src, target_long shamt)
{
tcg_gen_sextract_tl(dst, src, shamt, 32 - shamt);
}
static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
{
REQUIRE_64BIT(ctx);
TCGv t = tcg_temp_new();
gen_get_gpr(t, a->rs1);
tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt);
gen_set_gpr(a->rd, t);
tcg_temp_free(t);
return true;
ctx->w = true;
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_sraiw);
}
static bool trans_addw(DisasContext *ctx, arg_addw *a)
{
REQUIRE_64BIT(ctx);
return gen_arith(ctx, a, &gen_addw);
ctx->w = true;
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
}
static bool trans_subw(DisasContext *ctx, arg_subw *a)
{
REQUIRE_64BIT(ctx);
return gen_arith(ctx, a, &gen_subw);
ctx->w = true;
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
}
static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
{
REQUIRE_64BIT(ctx);
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_andi_tl(source2, source2, 0x1F);
tcg_gen_shl_tl(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
ctx->w = true;
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
}
static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
{
REQUIRE_64BIT(ctx);
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
/* clear upper 32 */
tcg_gen_ext32u_tl(source1, source1);
tcg_gen_andi_tl(source2, source2, 0x1F);
tcg_gen_shr_tl(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
ctx->w = true;
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
}
static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
{
REQUIRE_64BIT(ctx);
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
/*
* first, trick to get it to act like working on 32 bits (get rid of
* upper 32, sign extend to fill space)
*/
tcg_gen_ext32s_tl(source1, source1);
tcg_gen_andi_tl(source2, source2, 0x1F);
tcg_gen_sar_tl(source1, source1, source2);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
ctx->w = true;
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
}
static bool trans_fence(DisasContext *ctx, arg_fence *a)
@ -466,80 +426,150 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
return true;
}
#define RISCV_OP_CSR_PRE do {\
source1 = tcg_temp_new(); \
csr_store = tcg_temp_new(); \
dest = tcg_temp_new(); \
rs1_pass = tcg_temp_new(); \
gen_get_gpr(source1, a->rs1); \
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
tcg_gen_movi_tl(rs1_pass, a->rs1); \
tcg_gen_movi_tl(csr_store, a->csr); \
gen_io_start();\
} while (0)
static bool do_csr_post(DisasContext *ctx)
{
/* We may have changed important cpu state -- exit to main loop. */
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
exit_tb(ctx);
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
#define RISCV_OP_CSR_POST do {\
gen_set_gpr(a->rd, dest); \
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
exit_tb(ctx); \
ctx->base.is_jmp = DISAS_NORETURN; \
tcg_temp_free(source1); \
tcg_temp_free(csr_store); \
tcg_temp_free(dest); \
tcg_temp_free(rs1_pass); \
} while (0)
static bool do_csrr(DisasContext *ctx, int rd, int rc)
{
TCGv dest = dest_gpr(ctx, rd);
TCGv_i32 csr = tcg_constant_i32(rc);
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_csrr(dest, cpu_env, csr);
gen_set_gpr(ctx, rd, dest);
return do_csr_post(ctx);
}
static bool do_csrw(DisasContext *ctx, int rc, TCGv src)
{
TCGv_i32 csr = tcg_constant_i32(rc);
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_csrw(cpu_env, csr, src);
return do_csr_post(ctx);
}
static bool do_csrrw(DisasContext *ctx, int rd, int rc, TCGv src, TCGv mask)
{
TCGv dest = dest_gpr(ctx, rd);
TCGv_i32 csr = tcg_constant_i32(rc);
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_csrrw(dest, cpu_env, csr, src, mask);
gen_set_gpr(ctx, rd, dest);
return do_csr_post(ctx);
}
static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
{
TCGv source1, csr_store, dest, rs1_pass;
RISCV_OP_CSR_PRE;
gen_helper_csrrw(dest, cpu_env, source1, csr_store);
RISCV_OP_CSR_POST;
return true;
TCGv src = get_gpr(ctx, a->rs1, EXT_NONE);
/*
* If rd == 0, the insn shall not read the csr, nor cause any of the
* side effects that might occur on a csr read.
*/
if (a->rd == 0) {
return do_csrw(ctx, a->csr, src);
}
TCGv mask = tcg_constant_tl(-1);
return do_csrrw(ctx, a->rd, a->csr, src, mask);
}
static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
{
TCGv source1, csr_store, dest, rs1_pass;
RISCV_OP_CSR_PRE;
gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass);
RISCV_OP_CSR_POST;
return true;
/*
* If rs1 == 0, the insn shall not write to the csr at all, nor
* cause any of the side effects that might occur on a csr write.
* Note that if rs1 specifies a register other than x0, holding
* a zero value, the instruction will still attempt to write the
* unmodified value back to the csr and will cause side effects.
*/
if (a->rs1 == 0) {
return do_csrr(ctx, a->rd, a->csr);
}
TCGv ones = tcg_constant_tl(-1);
TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
return do_csrrw(ctx, a->rd, a->csr, ones, mask);
}
static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
{
TCGv source1, csr_store, dest, rs1_pass;
RISCV_OP_CSR_PRE;
gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass);
RISCV_OP_CSR_POST;
return true;
/*
* If rs1 == 0, the insn shall not write to the csr at all, nor
* cause any of the side effects that might occur on a csr write.
* Note that if rs1 specifies a register other than x0, holding
* a zero value, the instruction will still attempt to write the
* unmodified value back to the csr and will cause side effects.
*/
if (a->rs1 == 0) {
return do_csrr(ctx, a->rd, a->csr);
}
TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
}
static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
{
TCGv source1, csr_store, dest, rs1_pass;
RISCV_OP_CSR_PRE;
gen_helper_csrrw(dest, cpu_env, rs1_pass, csr_store);
RISCV_OP_CSR_POST;
return true;
TCGv src = tcg_constant_tl(a->rs1);
/*
* If rd == 0, the insn shall not read the csr, nor cause any of the
* side effects that might occur on a csr read.
*/
if (a->rd == 0) {
return do_csrw(ctx, a->csr, src);
}
TCGv mask = tcg_constant_tl(-1);
return do_csrrw(ctx, a->rd, a->csr, src, mask);
}
static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
{
TCGv source1, csr_store, dest, rs1_pass;
RISCV_OP_CSR_PRE;
gen_helper_csrrs(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
RISCV_OP_CSR_POST;
return true;
/*
* If rs1 == 0, the insn shall not write to the csr at all, nor
* cause any of the side effects that might occur on a csr write.
* Note that if rs1 specifies a register other than x0, holding
* a zero value, the instruction will still attempt to write the
* unmodified value back to the csr and will cause side effects.
*/
if (a->rs1 == 0) {
return do_csrr(ctx, a->rd, a->csr);
}
TCGv ones = tcg_constant_tl(-1);
TCGv mask = tcg_constant_tl(a->rs1);
return do_csrrw(ctx, a->rd, a->csr, ones, mask);
}
static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
{
TCGv source1, csr_store, dest, rs1_pass;
RISCV_OP_CSR_PRE;
gen_helper_csrrc(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
RISCV_OP_CSR_POST;
return true;
/*
* If rs1 == 0, the insn shall not write to the csr at all, nor
* cause any of the side effects that might occur on a csr write.
* Note that if rs1 specifies a register other than x0, holding
* a zero value, the instruction will still attempt to write the
* unmodified value back to the csr and will cause side effects.
*/
if (a->rs1 == 0) {
return do_csrr(ctx, a->rd, a->csr);
}
TCGv mask = tcg_constant_tl(a->rs1);
return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -37,11 +37,10 @@ void helper_raise_exception(CPURISCVState *env, uint32_t exception)
riscv_raise_exception(env, exception, 0);
}
target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
target_ulong csr)
target_ulong helper_csrr(CPURISCVState *env, int csr)
{
target_ulong val = 0;
RISCVException ret = riscv_csrrw(env, csr, &val, src, -1);
RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0);
if (ret != RISCV_EXCP_NONE) {
riscv_raise_exception(env, ret, GETPC());
@ -49,23 +48,20 @@ target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
return val;
}
target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
target_ulong csr, target_ulong rs1_pass)
void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
{
target_ulong val = 0;
RISCVException ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0);
RISCVException ret = riscv_csrrw(env, csr, NULL, src, -1);
if (ret != RISCV_EXCP_NONE) {
riscv_raise_exception(env, ret, GETPC());
}
return val;
}
target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
target_ulong csr, target_ulong rs1_pass)
target_ulong helper_csrrw(CPURISCVState *env, int csr,
target_ulong src, target_ulong write_mask)
{
target_ulong val = 0;
RISCVException ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0);
RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask);
if (ret != RISCV_EXCP_NONE) {
riscv_raise_exception(env, ret, GETPC());

View file

@ -39,15 +39,25 @@ static TCGv load_val;
#include "exec/gen-icount.h"
/*
* If an operation is being performed on less than TARGET_LONG_BITS,
* it may require the inputs to be sign- or zero-extended; which will
* depend on the exact operation being performed.
*/
typedef enum {
EXT_NONE,
EXT_SIGN,
EXT_ZERO,
} DisasExtend;
typedef struct DisasContext {
DisasContextBase base;
/* pc_succ_insn points to the instruction following base.pc_next */
target_ulong pc_succ_insn;
target_ulong priv_ver;
bool virt_enabled;
target_ulong misa;
uint32_t opcode;
uint32_t mstatus_fs;
target_ulong misa;
uint32_t mem_idx;
/* Remember the rounding mode encoded in the previous fp instruction,
which we have already installed into env->fp_status. Or -1 for
@ -55,6 +65,8 @@ typedef struct DisasContext {
to any system register, which includes CSR_FRM, so we do not have
to reset this known value. */
int frm;
bool w;
bool virt_enabled;
bool ext_ifencei;
bool hlsx;
/* vector extension */
@ -64,7 +76,11 @@ typedef struct DisasContext {
uint16_t vlen;
uint16_t mlen;
bool vl_eq_vlmax;
uint8_t ntemp;
CPUState *cs;
TCGv zero;
/* Space for 3 operands plus 1 extra for address computation. */
TCGv temp[4];
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@ -83,6 +99,13 @@ static inline bool is_32bit(DisasContext *ctx)
}
#endif
/* The word size for this operation. */
static inline int oper_len(DisasContext *ctx)
{
return ctx->w ? 32 : TARGET_LONG_BITS;
}
/*
* RISC-V requires NaN-boxing of narrower width floating point values.
* This applies when a 32-bit value is assigned to a 64-bit FP register.
@ -104,20 +127,16 @@ static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in)
*/
static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
{
TCGv_i64 t_max = tcg_const_i64(0xffffffff00000000ull);
TCGv_i64 t_nan = tcg_const_i64(0xffffffff7fc00000ull);
TCGv_i64 t_max = tcg_constant_i64(0xffffffff00000000ull);
TCGv_i64 t_nan = tcg_constant_i64(0xffffffff7fc00000ull);
tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
tcg_temp_free_i64(t_max);
tcg_temp_free_i64(t_nan);
}
static void generate_exception(DisasContext *ctx, int excp)
{
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
TCGv_i32 helper_tmp = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, helper_tmp);
tcg_temp_free_i32(helper_tmp);
gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
ctx->base.is_jmp = DISAS_NORETURN;
}
@ -125,17 +144,13 @@ static void generate_exception_mtval(DisasContext *ctx, int excp)
{
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
TCGv_i32 helper_tmp = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, helper_tmp);
tcg_temp_free_i32(helper_tmp);
gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
ctx->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_debug(void)
{
TCGv_i32 helper_tmp = tcg_const_i32(EXCP_DEBUG);
gen_helper_raise_exception(cpu_env, helper_tmp);
tcg_temp_free_i32(helper_tmp);
gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG));
}
/* Wrapper around tcg_gen_exit_tb that handles single stepping */
@ -180,151 +195,60 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
}
}
/* Wrapper for getting reg values - need to check of reg is zero since
* cpu_gpr[0] is not actually allocated
/*
* Wrappers for getting reg values.
*
* The $zero register does not have cpu_gpr[0] allocated -- we supply the
* constant zero as a source, and an uninitialized sink as destination.
*
* Further, we may provide an extension for word operations.
*/
static inline void gen_get_gpr(TCGv t, int reg_num)
static TCGv temp_new(DisasContext *ctx)
{
assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));
return ctx->temp[ctx->ntemp++] = tcg_temp_new();
}
static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
{
TCGv t;
if (reg_num == 0) {
tcg_gen_movi_tl(t, 0);
} else {
tcg_gen_mov_tl(t, cpu_gpr[reg_num]);
return ctx->zero;
}
}
/* Wrapper for setting reg values - need to check of reg is zero since
* cpu_gpr[0] is not actually allocated. this is more for safety purposes,
* since we usually avoid calling the OP_TYPE_gen function if we see a write to
* $zero
*/
static inline void gen_set_gpr(int reg_num_dst, TCGv t)
{
if (reg_num_dst != 0) {
tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);
switch (ctx->w ? ext : EXT_NONE) {
case EXT_NONE:
return cpu_gpr[reg_num];
case EXT_SIGN:
t = temp_new(ctx);
tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
return t;
case EXT_ZERO:
t = temp_new(ctx);
tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
return t;
}
g_assert_not_reached();
}
static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
static TCGv dest_gpr(DisasContext *ctx, int reg_num)
{
TCGv rl = tcg_temp_new();
TCGv rh = tcg_temp_new();
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);
if (reg_num == 0 || ctx->w) {
return temp_new(ctx);
}
return cpu_gpr[reg_num];
}
static void gen_div(TCGv ret, TCGv source1, TCGv source2)
static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
{
TCGv cond1, cond2, zeroreg, resultopt1;
/*
* Handle by altering args to tcg_gen_div to produce req'd results:
* For overflow: want source1 in source1 and 1 in source2
* For div by zero: want -1 in source1 and 1 in source2 -> -1 result
*/
cond1 = tcg_temp_new();
cond2 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
((target_ulong)1) << (TARGET_LONG_BITS - 1));
tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
/* if div by zero, set source1 to -1, otherwise don't change */
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
resultopt1);
/* if overflow or div by zero, set source2 to 1, else don't change */
tcg_gen_or_tl(cond1, cond1, cond2);
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
resultopt1);
tcg_gen_div_tl(ret, source1, source2);
tcg_temp_free(cond1);
tcg_temp_free(cond2);
tcg_temp_free(zeroreg);
tcg_temp_free(resultopt1);
}
static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
{
TCGv cond1, zeroreg, resultopt1;
cond1 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
resultopt1);
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
resultopt1);
tcg_gen_divu_tl(ret, source1, source2);
tcg_temp_free(cond1);
tcg_temp_free(zeroreg);
tcg_temp_free(resultopt1);
}
static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
{
TCGv cond1, cond2, zeroreg, resultopt1;
cond1 = tcg_temp_new();
cond2 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, 1L);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
(target_ulong)1 << (TARGET_LONG_BITS - 1));
tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
/* if overflow or div by zero, set source2 to 1, else don't change */
tcg_gen_or_tl(cond2, cond1, cond2);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
resultopt1);
tcg_gen_rem_tl(resultopt1, source1, source2);
/* if div by zero, just return the original dividend */
tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
source1);
tcg_temp_free(cond1);
tcg_temp_free(cond2);
tcg_temp_free(zeroreg);
tcg_temp_free(resultopt1);
}
static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
{
TCGv cond1, zeroreg, resultopt1;
cond1 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
resultopt1);
tcg_gen_remu_tl(resultopt1, source1, source2);
/* if div by zero, just return the original dividend */
tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
source1);
tcg_temp_free(cond1);
tcg_temp_free(zeroreg);
tcg_temp_free(resultopt1);
if (reg_num != 0) {
if (ctx->w) {
tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
} else {
tcg_gen_mov_tl(cpu_gpr[reg_num], t);
}
}
}
static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
@ -384,15 +308,11 @@ static inline void mark_fs_dirty(DisasContext *ctx) { }
static void gen_set_rm(DisasContext *ctx, int rm)
{
TCGv_i32 t0;
if (ctx->frm == rm) {
return;
}
ctx->frm = rm;
t0 = tcg_const_i32(rm);
gen_helper_set_rounding_mode(cpu_env, t0);
tcg_temp_free_i32(t0);
gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm));
}
static int ex_plus_1(DisasContext *ctx, int nf)
@ -437,355 +357,108 @@ static int ex_rvc_shifti(DisasContext *ctx, int imm)
/* Include the auto-generated decoder for 32 bit insn */
#include "decode-insn32.c.inc"
static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a,
static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext,
void (*func)(TCGv, TCGv, target_long))
{
TCGv source1;
source1 = tcg_temp_new();
TCGv dest = dest_gpr(ctx, a->rd);
TCGv src1 = get_gpr(ctx, a->rs1, ext);
gen_get_gpr(source1, a->rs1);
func(dest, src1, a->imm);
(*func)(source1, source1, a->imm);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a,
static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext,
void (*func)(TCGv, TCGv, TCGv))
{
TCGv source1, source2;
source1 = tcg_temp_new();
source2 = tcg_temp_new();
TCGv dest = dest_gpr(ctx, a->rd);
TCGv src1 = get_gpr(ctx, a->rs1, ext);
TCGv src2 = tcg_constant_tl(a->imm);
gen_get_gpr(source1, a->rs1);
tcg_gen_movi_tl(source2, a->imm);
func(dest, src1, src2);
(*func)(source1, source1, source2);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2)
static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext,
void (*func)(TCGv, TCGv, TCGv))
{
tcg_gen_add_tl(ret, arg1, arg2);
tcg_gen_ext32s_tl(ret, ret);
}
TCGv dest = dest_gpr(ctx, a->rd);
TCGv src1 = get_gpr(ctx, a->rs1, ext);
TCGv src2 = get_gpr(ctx, a->rs2, ext);
static void gen_subw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_sub_tl(ret, arg1, arg2);
tcg_gen_ext32s_tl(ret, ret);
}
func(dest, src1, src2);
static void gen_mulw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_mul_tl(ret, arg1, arg2);
tcg_gen_ext32s_tl(ret, ret);
}
static bool gen_arith_div_w(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
{
TCGv source1, source2;
source1 = tcg_temp_new();
source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_ext32s_tl(source1, source1);
tcg_gen_ext32s_tl(source2, source2);
(*func)(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
void (*func)(TCGv, TCGv, target_long))
{
TCGv source1, source2;
source1 = tcg_temp_new();
source2 = tcg_temp_new();
TCGv dest, src1;
int max_len = oper_len(ctx);
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_ext32u_tl(source1, source1);
tcg_gen_ext32u_tl(source2, source2);
(*func)(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
}
static void gen_pack(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_deposit_tl(ret, arg1, arg2,
TARGET_LONG_BITS / 2,
TARGET_LONG_BITS / 2);
}
static void gen_packu(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_shri_tl(t, arg1, TARGET_LONG_BITS / 2);
tcg_gen_deposit_tl(ret, arg2, t, 0, TARGET_LONG_BITS / 2);
tcg_temp_free(t);
}
static void gen_packh(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_ext8u_tl(t, arg2);
tcg_gen_deposit_tl(ret, arg1, t, 8, TARGET_LONG_BITS - 8);
tcg_temp_free(t);
}
static void gen_sbop_mask(TCGv ret, TCGv shamt)
{
tcg_gen_movi_tl(ret, 1);
tcg_gen_shl_tl(ret, ret, shamt);
}
static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
{
TCGv t = tcg_temp_new();
gen_sbop_mask(t, shamt);
tcg_gen_or_tl(ret, arg1, t);
tcg_temp_free(t);
}
static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
{
TCGv t = tcg_temp_new();
gen_sbop_mask(t, shamt);
tcg_gen_andc_tl(ret, arg1, t);
tcg_temp_free(t);
}
static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
{
TCGv t = tcg_temp_new();
gen_sbop_mask(t, shamt);
tcg_gen_xor_tl(ret, arg1, t);
tcg_temp_free(t);
}
static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
{
tcg_gen_shr_tl(ret, arg1, shamt);
tcg_gen_andi_tl(ret, ret, 1);
}
static void gen_slo(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_not_tl(ret, arg1);
tcg_gen_shl_tl(ret, ret, arg2);
tcg_gen_not_tl(ret, ret);
}
static void gen_sro(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_not_tl(ret, arg1);
tcg_gen_shr_tl(ret, ret, arg2);
tcg_gen_not_tl(ret, ret);
}
static bool gen_grevi(DisasContext *ctx, arg_grevi *a)
{
TCGv source1 = tcg_temp_new();
TCGv source2;
gen_get_gpr(source1, a->rs1);
if (a->shamt == (TARGET_LONG_BITS - 8)) {
/* rev8, byte swaps */
tcg_gen_bswap_tl(source1, source1);
} else {
source2 = tcg_temp_new();
tcg_gen_movi_tl(source2, a->shamt);
gen_helper_grev(source1, source1, source2);
tcg_temp_free(source2);
if (a->shamt >= max_len) {
return false;
}
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
dest = dest_gpr(ctx, a->rd);
src1 = get_gpr(ctx, a->rs1, ext);
func(dest, src1, a->shamt);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
#define GEN_SHADD(SHAMT) \
static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \
{ \
TCGv t = tcg_temp_new(); \
\
tcg_gen_shli_tl(t, arg1, SHAMT); \
tcg_gen_add_tl(ret, t, arg2); \
\
tcg_temp_free(t); \
}
GEN_SHADD(1)
GEN_SHADD(2)
GEN_SHADD(3)
static void gen_ctzw(TCGv ret, TCGv arg1)
static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
void (*func)(TCGv, TCGv, TCGv))
{
tcg_gen_ori_tl(ret, arg1, (target_ulong)MAKE_64BIT_MASK(32, 32));
tcg_gen_ctzi_tl(ret, ret, 64);
}
TCGv dest, src1, src2;
int max_len = oper_len(ctx);
static void gen_clzw(TCGv ret, TCGv arg1)
{
tcg_gen_ext32u_tl(ret, arg1);
tcg_gen_clzi_tl(ret, ret, 64);
tcg_gen_subi_tl(ret, ret, 32);
}
if (a->shamt >= max_len) {
return false;
}
static void gen_cpopw(TCGv ret, TCGv arg1)
{
tcg_gen_ext32u_tl(arg1, arg1);
tcg_gen_ctpop_tl(ret, arg1);
}
dest = dest_gpr(ctx, a->rd);
src1 = get_gpr(ctx, a->rs1, ext);
src2 = tcg_constant_tl(a->shamt);
static void gen_packw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_ext16s_tl(t, arg2);
tcg_gen_deposit_tl(ret, arg1, t, 16, 48);
tcg_temp_free(t);
}
func(dest, src1, src2);
static void gen_packuw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv t = tcg_temp_new();
tcg_gen_shri_tl(t, arg1, 16);
tcg_gen_deposit_tl(ret, arg2, t, 0, 16);
tcg_gen_ext32s_tl(ret, ret);
tcg_temp_free(t);
}
static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
/* truncate to 32-bits */
tcg_gen_trunc_tl_i32(t1, arg1);
tcg_gen_trunc_tl_i32(t2, arg2);
tcg_gen_rotr_i32(t1, t1, t2);
/* sign-extend 64-bits */
tcg_gen_ext_i32_tl(ret, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
}
static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
{
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
/* truncate to 32-bits */
tcg_gen_trunc_tl_i32(t1, arg1);
tcg_gen_trunc_tl_i32(t2, arg2);
tcg_gen_rotl_i32(t1, t1, t2);
/* sign-extend 64-bits */
tcg_gen_ext_i32_tl(ret, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
}
static void gen_grevw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_ext32u_tl(arg1, arg1);
gen_helper_grev(ret, arg1, arg2);
}
static void gen_gorcw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_ext32u_tl(arg1, arg1);
gen_helper_gorcw(ret, arg1, arg2);
}
#define GEN_SHADD_UW(SHAMT) \
static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \
{ \
TCGv t = tcg_temp_new(); \
\
tcg_gen_ext32u_tl(t, arg1); \
\
tcg_gen_shli_tl(t, t, SHAMT); \
tcg_gen_add_tl(ret, t, arg2); \
\
tcg_temp_free(t); \
}
GEN_SHADD_UW(1)
GEN_SHADD_UW(2)
GEN_SHADD_UW(3)
static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_ext32u_tl(arg1, arg1);
tcg_gen_add_tl(ret, arg1, arg2);
}
static bool gen_arith(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
{
TCGv source1, source2;
source1 = tcg_temp_new();
source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
(*func)(source1, source1, source2);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
static bool gen_shift(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext,
void (*func)(TCGv, TCGv, TCGv))
{
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
TCGv dest = dest_gpr(ctx, a->rd);
TCGv src1 = get_gpr(ctx, a->rs1, ext);
TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
TCGv ext2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_andi_tl(ext2, src2, oper_len(ctx) - 1);
func(dest, src1, ext2);
tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
(*func)(source1, source1, source2);
gen_set_gpr(ctx, a->rd, dest);
tcg_temp_free(ext2);
return true;
}
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
void (*func)(TCGv, TCGv))
{
TCGv dest = dest_gpr(ctx, a->rd);
TCGv src1 = get_gpr(ctx, a->rs1, ext);
func(dest, src1);
gen_set_gpr(ctx, a->rd, dest);
return true;
}
@ -798,88 +471,6 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
return cpu_ldl_code(env, pc);
}
static bool gen_shifti(DisasContext *ctx, arg_shift *a,
void(*func)(TCGv, TCGv, TCGv))
{
if (a->shamt >= TARGET_LONG_BITS) {
return false;
}
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
tcg_gen_movi_tl(source2, a->shamt);
(*func)(source1, source1, source2);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
}
static bool gen_shiftw(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
{
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_andi_tl(source2, source2, 31);
(*func)(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
}
static bool gen_shiftiw(DisasContext *ctx, arg_shift *a,
void(*func)(TCGv, TCGv, TCGv))
{
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
tcg_gen_movi_tl(source2, a->shamt);
(*func)(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
}
static void gen_ctz(TCGv ret, TCGv arg1)
{
tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS);
}
static void gen_clz(TCGv ret, TCGv arg1)
{
tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS);
}
static bool gen_unary(DisasContext *ctx, arg_r2 *a,
void(*func)(TCGv, TCGv))
{
TCGv source = tcg_temp_new();
gen_get_gpr(source, a->rs1);
(*func)(source, source);
gen_set_gpr(a->rd, source);
tcg_temp_free(source);
return true;
}
/* Include insn module translation function */
#include "insn_trans/trans_rvi.c.inc"
#include "insn_trans/trans_rvm.c.inc"
@ -948,6 +539,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul);
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
ctx->cs = cs;
ctx->w = false;
ctx->ntemp = 0;
memset(ctx->temp, 0, sizeof(ctx->temp));
ctx->zero = tcg_constant_tl(0);
}
static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
@ -969,6 +565,13 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
decode_opc(env, ctx, opcode16);
ctx->base.pc_next = ctx->pc_succ_insn;
ctx->w = false;
for (int i = ctx->ntemp - 1; i >= 0; --i) {
tcg_temp_free(ctx->temp[i]);
ctx->temp[i] = NULL;
}
ctx->ntemp = 0;
if (ctx->base.is_jmp == DISAS_NEXT) {
target_ulong page_start;
@ -1029,9 +632,11 @@ void riscv_translate_init(void)
{
int i;
/* cpu_gpr[0] is a placeholder for the zero register. Do not use it. */
/* Use the gen_set_gpr and gen_get_gpr helper functions when accessing */
/* registers, unless you specifically block reads/writes to reg 0 */
/*
* cpu_gpr[0] is a placeholder for the zero register. Do not use it.
* Use the gen_set_gpr and get_gpr helper functions when accessing regs,
* unless you specifically block reads/writes to reg 0.
*/
cpu_gpr[0] = NULL;
for (i = 1; i < 32; i++) {

View file

@ -0,0 +1,5 @@
# -*- Mode: makefile -*-
# RISC-V specific tweaks
VPATH += $(SRC_PATH)/tests/tcg/riscv64
TESTS += test-div

View file

@ -0,0 +1,58 @@
#include <assert.h>
#include <limits.h>
struct TestS {
long x, y, q, r;
};
static struct TestS test_s[] = {
{ 4, 2, 2, 0 }, /* normal cases */
{ 9, 7, 1, 2 },
{ 0, 0, -1, 0 }, /* div by zero cases */
{ 9, 0, -1, 9 },
{ LONG_MIN, -1, LONG_MIN, 0 }, /* overflow case */
};
struct TestU {
unsigned long x, y, q, r;
};
static struct TestU test_u[] = {
{ 4, 2, 2, 0 }, /* normal cases */
{ 9, 7, 1, 2 },
{ 0, 0, ULONG_MAX, 0 }, /* div by zero cases */
{ 9, 0, ULONG_MAX, 9 },
};
#define ARRAY_SIZE(X) (sizeof(X) / sizeof(*(X)))
int main (void)
{
int i;
for (i = 0; i < ARRAY_SIZE(test_s); i++) {
long q, r;
asm("div %0, %2, %3\n\t"
"rem %1, %2, %3"
: "=&r" (q), "=r" (r)
: "r" (test_s[i].x), "r" (test_s[i].y));
assert(q == test_s[i].q);
assert(r == test_s[i].r);
}
for (i = 0; i < ARRAY_SIZE(test_u); i++) {
unsigned long q, r;
asm("divu %0, %2, %3\n\t"
"remu %1, %2, %3"
: "=&r" (q), "=r" (r)
: "r" (test_u[i].x), "r" (test_u[i].y));
assert(q == test_u[i].q);
assert(r == test_u[i].r);
}
return 0;
}