mirror of https://github.com/xemu-project/xemu.git
Second RISC-V PR for QEMU 7.0
- Fix illegal instruction when PMP is disabled - SiFive PDMA 64-bit support - SiFive PLIC cleanups - Mark Hypervisor extension as non experimental - Enable Hypervisor extension by default - Support 32 cores on the virt machine - Corrections for the Vector extension - Experimental support for 128-bit CPUs - stval and mtval support for illegal instructions -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmHZJhMACgkQIeENKd+X cFSzfgf9FTU3spDGSFMQXFdHfFionDbbyRhXqHG785/9193DKAZysSCv1PWrScX1 i9GwbR963Z03ksGN0yGFleqZAE2wz6jQxzXPbikeL4kNH1CiBTP1HFUM194d4cLA 4bjZ3l29obkzjD53mlQpi/0siqe3deKbuRu+z55LlS21C3SUkxggb5Fda+V0dzix h+Ytd7Qkif16aVDD20Q6O/4g8tZgqYvuDOdY78/V7VSzFd5bV1j8uONsDmp3NTWo l2vgMDxtv1f7uggtApNvTeWRHeLkDB3OMMHZHiXYceyIcqYvZecmMfRloVC7qY7t TOR378HVElPHJs9iJMzx7xlcJ5xHeQ== =ffGh -----END PGP SIGNATURE----- Merge tag 'pull-riscv-to-apply-20220108' of github.com:alistair23/qemu into staging Second RISC-V PR for QEMU 7.0 - Fix illegal instruction when PMP is disabled - SiFive PDMA 64-bit support - SiFive PLIC cleanups - Mark Hypervisor extension as non experimental - Enable Hypervisor extension by default - Support 32 cores on the virt machine - Corrections for the Vector extension - Experimental support for 128-bit CPUs - stval and mtval support for illegal instructions # gpg: Signature made Fri 07 Jan 2022 09:50:11 PM PST # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * tag 'pull-riscv-to-apply-20220108' of github.com:alistair23/qemu: (37 commits) target/riscv: Implement the stval/mtval illegal instruction target/riscv: Fixup setting GVA target/riscv: Set the opcode in DisasContext target/riscv: actual functions to realize crs 128-bit insns target/riscv: modification of the trans_csrxx for 128-bit support target/riscv: helper functions to wrap calls to 128-bit csr insns target/riscv: adding high part of some csrs target/riscv: support for 128-bit M extension target/riscv: support for 128-bit arithmetic instructions target/riscv: support for 128-bit shift instructions target/riscv: support for 128-bit U-type instructions target/riscv: support for 128-bit bitwise instructions target/riscv: accessors to registers upper part and 128-bit load/store target/riscv: moving some insns close to similar insns target/riscv: setup everything for rv64 to support rv128 execution target/riscv: array for the 64 upper bits of 128-bit registers target/riscv: separation of bitwise logic and arithmetic helpers target/riscv: additional macros to check instruction support qemu/int128: addition of div/rem 128-bit operations exec/memop: Adding signed quad and octo defines ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
afe3326258
|
@ -1885,9 +1885,9 @@ load_memop(const void *haddr, MemOp op)
|
|||
return (uint32_t)ldl_be_p(haddr);
|
||||
case MO_LEUL:
|
||||
return (uint32_t)ldl_le_p(haddr);
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
return ldq_be_p(haddr);
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
return ldq_le_p(haddr);
|
||||
default:
|
||||
qemu_build_not_reached();
|
||||
|
@ -2081,16 +2081,16 @@ tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr,
|
|||
uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEQ, false,
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEUQ, false,
|
||||
helper_le_ldq_mmu);
|
||||
}
|
||||
|
||||
uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEQ, false,
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEUQ, false,
|
||||
helper_be_ldq_mmu);
|
||||
}
|
||||
|
||||
|
@ -2166,7 +2166,7 @@ uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr addr,
|
|||
uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, oi, MO_BEQ, helper_be_ldq_mmu);
|
||||
return cpu_load_helper(env, addr, oi, MO_BEUQ, helper_be_ldq_mmu);
|
||||
}
|
||||
|
||||
uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
|
@ -2210,10 +2210,10 @@ store_memop(void *haddr, uint64_t val, MemOp op)
|
|||
case MO_LEUL:
|
||||
stl_le_p(haddr, val);
|
||||
break;
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
stq_be_p(haddr, val);
|
||||
break;
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
stq_le_p(haddr, val);
|
||||
break;
|
||||
default:
|
||||
|
@ -2465,15 +2465,15 @@ void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
|||
void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEQ);
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEUQ);
|
||||
}
|
||||
|
||||
void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEQ);
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEUQ);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2609,11 +2609,11 @@ uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr)
|
|||
static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code);
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEUQ, true, full_ldq_code);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true));
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(env, true));
|
||||
return full_ldq_code(env, addr, oi, 0);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|||
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|||
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|||
void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|||
void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr,
|
|||
void *haddr;
|
||||
uint64_t ret;
|
||||
|
||||
validate_memop(oi, MO_BEQ);
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldq_be_p(haddr);
|
||||
|
@ -339,7 +339,7 @@ uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr,
|
|||
void *haddr;
|
||||
uint64_t ret;
|
||||
|
||||
validate_memop(oi, MO_LEQ);
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldq_le_p(haddr);
|
||||
|
@ -392,7 +392,7 @@ void cpu_stq_be_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
|
|||
{
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_BEQ);
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stq_be_p(haddr, val);
|
||||
|
@ -431,7 +431,7 @@ void cpu_stq_le_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
|
|||
{
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_LEQ);
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stq_le_p(haddr, val);
|
||||
|
|
|
@ -3090,3 +3090,8 @@ int print_insn_riscv64(bfd_vma memaddr, struct disassemble_info *info)
|
|||
{
|
||||
return print_insn_riscv(memaddr, info, rv64);
|
||||
}
|
||||
|
||||
int print_insn_riscv128(bfd_vma memaddr, struct disassemble_info *info)
|
||||
{
|
||||
return print_insn_riscv(memaddr, info, rv128);
|
||||
}
|
||||
|
|
|
@ -177,6 +177,101 @@ static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
|
|||
s->chan[ch].state = DMA_CHAN_STATE_IDLE;
|
||||
}
|
||||
|
||||
static uint64_t sifive_pdma_readq(SiFivePDMAState *s, int ch, hwaddr offset)
|
||||
{
|
||||
uint64_t val = 0;
|
||||
|
||||
offset &= 0xfff;
|
||||
switch (offset) {
|
||||
case DMA_NEXT_BYTES:
|
||||
val = s->chan[ch].next_bytes;
|
||||
break;
|
||||
case DMA_NEXT_DST:
|
||||
val = s->chan[ch].next_dst;
|
||||
break;
|
||||
case DMA_NEXT_SRC:
|
||||
val = s->chan[ch].next_src;
|
||||
break;
|
||||
case DMA_EXEC_BYTES:
|
||||
val = s->chan[ch].exec_bytes;
|
||||
break;
|
||||
case DMA_EXEC_DST:
|
||||
val = s->chan[ch].exec_dst;
|
||||
break;
|
||||
case DMA_EXEC_SRC:
|
||||
val = s->chan[ch].exec_src;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t sifive_pdma_readl(SiFivePDMAState *s, int ch, hwaddr offset)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
offset &= 0xfff;
|
||||
switch (offset) {
|
||||
case DMA_CONTROL:
|
||||
val = s->chan[ch].control;
|
||||
break;
|
||||
case DMA_NEXT_CONFIG:
|
||||
val = s->chan[ch].next_config;
|
||||
break;
|
||||
case DMA_NEXT_BYTES:
|
||||
val = extract64(s->chan[ch].next_bytes, 0, 32);
|
||||
break;
|
||||
case DMA_NEXT_BYTES + 4:
|
||||
val = extract64(s->chan[ch].next_bytes, 32, 32);
|
||||
break;
|
||||
case DMA_NEXT_DST:
|
||||
val = extract64(s->chan[ch].next_dst, 0, 32);
|
||||
break;
|
||||
case DMA_NEXT_DST + 4:
|
||||
val = extract64(s->chan[ch].next_dst, 32, 32);
|
||||
break;
|
||||
case DMA_NEXT_SRC:
|
||||
val = extract64(s->chan[ch].next_src, 0, 32);
|
||||
break;
|
||||
case DMA_NEXT_SRC + 4:
|
||||
val = extract64(s->chan[ch].next_src, 32, 32);
|
||||
break;
|
||||
case DMA_EXEC_CONFIG:
|
||||
val = s->chan[ch].exec_config;
|
||||
break;
|
||||
case DMA_EXEC_BYTES:
|
||||
val = extract64(s->chan[ch].exec_bytes, 0, 32);
|
||||
break;
|
||||
case DMA_EXEC_BYTES + 4:
|
||||
val = extract64(s->chan[ch].exec_bytes, 32, 32);
|
||||
break;
|
||||
case DMA_EXEC_DST:
|
||||
val = extract64(s->chan[ch].exec_dst, 0, 32);
|
||||
break;
|
||||
case DMA_EXEC_DST + 4:
|
||||
val = extract64(s->chan[ch].exec_dst, 32, 32);
|
||||
break;
|
||||
case DMA_EXEC_SRC:
|
||||
val = extract64(s->chan[ch].exec_src, 0, 32);
|
||||
break;
|
||||
case DMA_EXEC_SRC + 4:
|
||||
val = extract64(s->chan[ch].exec_src, 32, 32);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
SiFivePDMAState *s = opaque;
|
||||
|
@ -189,56 +284,53 @@ static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
offset &= 0xfff;
|
||||
switch (offset) {
|
||||
case DMA_CONTROL:
|
||||
val = s->chan[ch].control;
|
||||
switch (size) {
|
||||
case 8:
|
||||
val = sifive_pdma_readq(s, ch, offset);
|
||||
break;
|
||||
case DMA_NEXT_CONFIG:
|
||||
val = s->chan[ch].next_config;
|
||||
break;
|
||||
case DMA_NEXT_BYTES:
|
||||
val = s->chan[ch].next_bytes;
|
||||
break;
|
||||
case DMA_NEXT_DST:
|
||||
val = s->chan[ch].next_dst;
|
||||
break;
|
||||
case DMA_NEXT_SRC:
|
||||
val = s->chan[ch].next_src;
|
||||
break;
|
||||
case DMA_EXEC_CONFIG:
|
||||
val = s->chan[ch].exec_config;
|
||||
break;
|
||||
case DMA_EXEC_BYTES:
|
||||
val = s->chan[ch].exec_bytes;
|
||||
break;
|
||||
case DMA_EXEC_DST:
|
||||
val = s->chan[ch].exec_dst;
|
||||
break;
|
||||
case DMA_EXEC_SRC:
|
||||
val = s->chan[ch].exec_src;
|
||||
case 4:
|
||||
val = sifive_pdma_readl(s, ch, offset);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid read size %u to PDMA\n",
|
||||
__func__, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void sifive_pdma_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
static void sifive_pdma_writeq(SiFivePDMAState *s, int ch,
|
||||
hwaddr offset, uint64_t value)
|
||||
{
|
||||
SiFivePDMAState *s = opaque;
|
||||
int ch = SIFIVE_PDMA_CHAN_NO(offset);
|
||||
bool claimed, run;
|
||||
|
||||
if (ch >= SIFIVE_PDMA_CHANS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
|
||||
__func__, ch);
|
||||
return;
|
||||
offset &= 0xfff;
|
||||
switch (offset) {
|
||||
case DMA_NEXT_BYTES:
|
||||
s->chan[ch].next_bytes = value;
|
||||
break;
|
||||
case DMA_NEXT_DST:
|
||||
s->chan[ch].next_dst = value;
|
||||
break;
|
||||
case DMA_NEXT_SRC:
|
||||
s->chan[ch].next_src = value;
|
||||
break;
|
||||
case DMA_EXEC_BYTES:
|
||||
case DMA_EXEC_DST:
|
||||
case DMA_EXEC_SRC:
|
||||
/* these are read-only registers */
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sifive_pdma_writel(SiFivePDMAState *s, int ch,
|
||||
hwaddr offset, uint32_t value)
|
||||
{
|
||||
bool claimed, run;
|
||||
|
||||
offset &= 0xfff;
|
||||
switch (offset) {
|
||||
|
@ -282,27 +374,68 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
|
|||
s->chan[ch].next_config = value;
|
||||
break;
|
||||
case DMA_NEXT_BYTES:
|
||||
s->chan[ch].next_bytes = value;
|
||||
s->chan[ch].next_bytes =
|
||||
deposit64(s->chan[ch].next_bytes, 0, 32, value);
|
||||
break;
|
||||
case DMA_NEXT_BYTES + 4:
|
||||
s->chan[ch].next_bytes =
|
||||
deposit64(s->chan[ch].next_bytes, 32, 32, value);
|
||||
break;
|
||||
case DMA_NEXT_DST:
|
||||
s->chan[ch].next_dst = value;
|
||||
s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 0, 32, value);
|
||||
break;
|
||||
case DMA_NEXT_DST + 4:
|
||||
s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 32, 32, value);
|
||||
break;
|
||||
case DMA_NEXT_SRC:
|
||||
s->chan[ch].next_src = value;
|
||||
s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 0, 32, value);
|
||||
break;
|
||||
case DMA_NEXT_SRC + 4:
|
||||
s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 32, 32, value);
|
||||
break;
|
||||
case DMA_EXEC_CONFIG:
|
||||
case DMA_EXEC_BYTES:
|
||||
case DMA_EXEC_BYTES + 4:
|
||||
case DMA_EXEC_DST:
|
||||
case DMA_EXEC_DST + 4:
|
||||
case DMA_EXEC_SRC:
|
||||
case DMA_EXEC_SRC + 4:
|
||||
/* these are read-only registers */
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sifive_pdma_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
SiFivePDMAState *s = opaque;
|
||||
int ch = SIFIVE_PDMA_CHAN_NO(offset);
|
||||
|
||||
if (ch >= SIFIVE_PDMA_CHANS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
|
||||
__func__, ch);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 8:
|
||||
sifive_pdma_writeq(s, ch, offset, value);
|
||||
break;
|
||||
case 4:
|
||||
sifive_pdma_writel(s, ch, offset, (uint32_t) value);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid write size %u to PDMA\n",
|
||||
__func__, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_pdma_ops = {
|
||||
.read = sifive_pdma_read,
|
||||
.write = sifive_pdma_write,
|
||||
|
@ -311,6 +444,10 @@ static const MemoryRegionOps sifive_pdma_ops = {
|
|||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 8,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
#include "migration/vmstate.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
#define RISCV_DEBUG_PLIC 0
|
||||
static bool addr_between(uint32_t addr, uint32_t base, uint32_t num)
|
||||
{
|
||||
return addr >= base && addr - base < num;
|
||||
}
|
||||
|
||||
static PLICMode char_to_mode(char c)
|
||||
{
|
||||
|
@ -46,47 +49,6 @@ static PLICMode char_to_mode(char c)
|
|||
}
|
||||
}
|
||||
|
||||
static char mode_to_char(PLICMode m)
|
||||
{
|
||||
switch (m) {
|
||||
case PLICMode_U: return 'U';
|
||||
case PLICMode_S: return 'S';
|
||||
case PLICMode_H: return 'H';
|
||||
case PLICMode_M: return 'M';
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
|
||||
static void sifive_plic_print_state(SiFivePLICState *plic)
|
||||
{
|
||||
int i;
|
||||
int addrid;
|
||||
|
||||
/* pending */
|
||||
qemu_log("pending : ");
|
||||
for (i = plic->bitfield_words - 1; i >= 0; i--) {
|
||||
qemu_log("%08x", plic->pending[i]);
|
||||
}
|
||||
qemu_log("\n");
|
||||
|
||||
/* pending */
|
||||
qemu_log("claimed : ");
|
||||
for (i = plic->bitfield_words - 1; i >= 0; i--) {
|
||||
qemu_log("%08x", plic->claimed[i]);
|
||||
}
|
||||
qemu_log("\n");
|
||||
|
||||
for (addrid = 0; addrid < plic->num_addrs; addrid++) {
|
||||
qemu_log("hart%d-%c enable: ",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode));
|
||||
for (i = plic->bitfield_words - 1; i >= 0; i--) {
|
||||
qemu_log("%08x", plic->enable[addrid * plic->bitfield_words + i]);
|
||||
}
|
||||
qemu_log("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value)
|
||||
{
|
||||
uint32_t old, new, cmp = qatomic_read(a);
|
||||
|
@ -110,26 +72,34 @@ static void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool level)
|
|||
atomic_set_masked(&plic->claimed[irq >> 5], 1 << (irq & 31), -!!level);
|
||||
}
|
||||
|
||||
static int sifive_plic_irqs_pending(SiFivePLICState *plic, uint32_t addrid)
|
||||
static uint32_t sifive_plic_claimed(SiFivePLICState *plic, uint32_t addrid)
|
||||
{
|
||||
uint32_t max_irq = 0;
|
||||
uint32_t max_prio = plic->target_priority[addrid];
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < plic->bitfield_words; i++) {
|
||||
uint32_t pending_enabled_not_claimed =
|
||||
(plic->pending[i] & ~plic->claimed[i]) &
|
||||
plic->enable[addrid * plic->bitfield_words + i];
|
||||
(plic->pending[i] & ~plic->claimed[i]) &
|
||||
plic->enable[addrid * plic->bitfield_words + i];
|
||||
|
||||
if (!pending_enabled_not_claimed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
int irq = (i << 5) + j;
|
||||
uint32_t prio = plic->source_priority[irq];
|
||||
int enabled = pending_enabled_not_claimed & (1 << j);
|
||||
if (enabled && prio > plic->target_priority[addrid]) {
|
||||
return 1;
|
||||
|
||||
if (enabled && prio > max_prio) {
|
||||
max_irq = irq;
|
||||
max_prio = prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
return max_irq;
|
||||
}
|
||||
|
||||
static void sifive_plic_update(SiFivePLICState *plic)
|
||||
|
@ -140,7 +110,7 @@ static void sifive_plic_update(SiFivePLICState *plic)
|
|||
for (addrid = 0; addrid < plic->num_addrs; addrid++) {
|
||||
uint32_t hartid = plic->addr_config[addrid].hartid;
|
||||
PLICMode mode = plic->addr_config[addrid].mode;
|
||||
int level = sifive_plic_irqs_pending(plic, addrid);
|
||||
bool level = !!sifive_plic_claimed(plic, addrid);
|
||||
|
||||
switch (mode) {
|
||||
case PLICMode_M:
|
||||
|
@ -153,111 +123,48 @@ static void sifive_plic_update(SiFivePLICState *plic)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
sifive_plic_print_state(plic);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t max_irq = 0;
|
||||
uint32_t max_prio = plic->target_priority[addrid];
|
||||
|
||||
for (i = 0; i < plic->bitfield_words; i++) {
|
||||
uint32_t pending_enabled_not_claimed =
|
||||
(plic->pending[i] & ~plic->claimed[i]) &
|
||||
plic->enable[addrid * plic->bitfield_words + i];
|
||||
if (!pending_enabled_not_claimed) {
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < 32; j++) {
|
||||
int irq = (i << 5) + j;
|
||||
uint32_t prio = plic->source_priority[irq];
|
||||
int enabled = pending_enabled_not_claimed & (1 << j);
|
||||
if (enabled && prio > max_prio) {
|
||||
max_irq = irq;
|
||||
max_prio = prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max_irq) {
|
||||
sifive_plic_set_pending(plic, max_irq, false);
|
||||
sifive_plic_set_claimed(plic, max_irq, true);
|
||||
}
|
||||
return max_irq;
|
||||
}
|
||||
|
||||
static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
SiFivePLICState *plic = opaque;
|
||||
|
||||
/* writes must be 4 byte words */
|
||||
if ((addr & 0x3) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (addr >= plic->priority_base && /* 4 bytes per source */
|
||||
addr < plic->priority_base + (plic->num_sources << 2))
|
||||
{
|
||||
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
|
||||
uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: read priority: irq=%d priority=%d\n",
|
||||
irq, plic->source_priority[irq]);
|
||||
}
|
||||
|
||||
return plic->source_priority[irq];
|
||||
} else if (addr >= plic->pending_base && /* 1 bit per source */
|
||||
addr < plic->pending_base + (plic->num_sources >> 3))
|
||||
{
|
||||
} else if (addr_between(addr, plic->pending_base, plic->num_sources >> 3)) {
|
||||
uint32_t word = (addr - plic->pending_base) >> 2;
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: read pending: word=%d value=%d\n",
|
||||
word, plic->pending[word]);
|
||||
}
|
||||
|
||||
return plic->pending[word];
|
||||
} else if (addr >= plic->enable_base && /* 1 bit per source */
|
||||
addr < plic->enable_base + plic->num_addrs * plic->enable_stride)
|
||||
{
|
||||
} else if (addr_between(addr, plic->enable_base,
|
||||
plic->num_addrs * plic->enable_stride)) {
|
||||
uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride;
|
||||
uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2;
|
||||
|
||||
if (wordid < plic->bitfield_words) {
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: read enable: hart%d-%c word=%d value=%x\n",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode), wordid,
|
||||
plic->enable[addrid * plic->bitfield_words + wordid]);
|
||||
}
|
||||
return plic->enable[addrid * plic->bitfield_words + wordid];
|
||||
}
|
||||
} else if (addr >= plic->context_base && /* 1 bit per source */
|
||||
addr < plic->context_base + plic->num_addrs * plic->context_stride)
|
||||
{
|
||||
} else if (addr_between(addr, plic->context_base,
|
||||
plic->num_addrs * plic->context_stride)) {
|
||||
uint32_t addrid = (addr - plic->context_base) / plic->context_stride;
|
||||
uint32_t contextid = (addr & (plic->context_stride - 1));
|
||||
|
||||
if (contextid == 0) {
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: read priority: hart%d-%c priority=%x\n",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode),
|
||||
plic->target_priority[addrid]);
|
||||
}
|
||||
return plic->target_priority[addrid];
|
||||
} else if (contextid == 4) {
|
||||
uint32_t value = sifive_plic_claim(plic, addrid);
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: read claim: hart%d-%c irq=%x\n",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode),
|
||||
value);
|
||||
uint32_t max_irq = sifive_plic_claimed(plic, addrid);
|
||||
|
||||
if (max_irq) {
|
||||
sifive_plic_set_pending(plic, max_irq, false);
|
||||
sifive_plic_set_claimed(plic, max_irq, true);
|
||||
}
|
||||
|
||||
sifive_plic_update(plic);
|
||||
return value;
|
||||
return max_irq;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid register read 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
|
@ -269,80 +176,53 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
{
|
||||
SiFivePLICState *plic = opaque;
|
||||
|
||||
/* writes must be 4 byte words */
|
||||
if ((addr & 0x3) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (addr >= plic->priority_base && /* 4 bytes per source */
|
||||
addr < plic->priority_base + (plic->num_sources << 2))
|
||||
{
|
||||
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
|
||||
uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
|
||||
|
||||
plic->source_priority[irq] = value & 7;
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: write priority: irq=%d priority=%d\n",
|
||||
irq, plic->source_priority[irq]);
|
||||
}
|
||||
sifive_plic_update(plic);
|
||||
return;
|
||||
} else if (addr >= plic->pending_base && /* 1 bit per source */
|
||||
addr < plic->pending_base + (plic->num_sources >> 3))
|
||||
{
|
||||
} else if (addr_between(addr, plic->pending_base,
|
||||
plic->num_sources >> 3)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid pending write: 0x%" HWADDR_PRIx "",
|
||||
__func__, addr);
|
||||
return;
|
||||
} else if (addr >= plic->enable_base && /* 1 bit per source */
|
||||
addr < plic->enable_base + plic->num_addrs * plic->enable_stride)
|
||||
{
|
||||
} else if (addr_between(addr, plic->enable_base,
|
||||
plic->num_addrs * plic->enable_stride)) {
|
||||
uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride;
|
||||
uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2;
|
||||
|
||||
if (wordid < plic->bitfield_words) {
|
||||
plic->enable[addrid * plic->bitfield_words + wordid] = value;
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: write enable: hart%d-%c word=%d value=%x\n",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode), wordid,
|
||||
plic->enable[addrid * plic->bitfield_words + wordid]);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid enable write 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
}
|
||||
} else if (addr >= plic->context_base && /* 4 bytes per reg */
|
||||
addr < plic->context_base + plic->num_addrs * plic->context_stride)
|
||||
{
|
||||
} else if (addr_between(addr, plic->context_base,
|
||||
plic->num_addrs * plic->context_stride)) {
|
||||
uint32_t addrid = (addr - plic->context_base) / plic->context_stride;
|
||||
uint32_t contextid = (addr & (plic->context_stride - 1));
|
||||
|
||||
if (contextid == 0) {
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: write priority: hart%d-%c priority=%x\n",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode),
|
||||
plic->target_priority[addrid]);
|
||||
}
|
||||
if (value <= plic->num_priorities) {
|
||||
plic->target_priority[addrid] = value;
|
||||
sifive_plic_update(plic);
|
||||
}
|
||||
return;
|
||||
} else if (contextid == 4) {
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: write claim: hart%d-%c irq=%x\n",
|
||||
plic->addr_config[addrid].hartid,
|
||||
mode_to_char(plic->addr_config[addrid].mode),
|
||||
(uint32_t)value);
|
||||
}
|
||||
if (value < plic->num_sources) {
|
||||
sifive_plic_set_claimed(plic, value, false);
|
||||
sifive_plic_update(plic);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid context write 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid register write 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
}
|
||||
|
||||
err:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid register write 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_plic_ops = {
|
||||
|
@ -355,6 +235,23 @@ static const MemoryRegionOps sifive_plic_ops = {
|
|||
}
|
||||
};
|
||||
|
||||
static void sifive_plic_reset(DeviceState *dev)
|
||||
{
|
||||
SiFivePLICState *s = SIFIVE_PLIC(dev);
|
||||
int i;
|
||||
|
||||
memset(s->source_priority, 0, sizeof(uint32_t) * s->num_sources);
|
||||
memset(s->target_priority, 0, sizeof(uint32_t) * s->num_addrs);
|
||||
memset(s->pending, 0, sizeof(uint32_t) * s->bitfield_words);
|
||||
memset(s->claimed, 0, sizeof(uint32_t) * s->bitfield_words);
|
||||
memset(s->enable, 0, sizeof(uint32_t) * s->num_enables);
|
||||
|
||||
for (i = 0; i < s->num_harts; i++) {
|
||||
qemu_set_irq(s->m_external_irqs[i], 0);
|
||||
qemu_set_irq(s->s_external_irqs[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* parse PLIC hart/mode address offset config
|
||||
*
|
||||
|
@ -501,6 +398,7 @@ static void sifive_plic_class_init(ObjectClass *klass, void *data)
|
|||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = sifive_plic_reset;
|
||||
device_class_set_props(dc, sifive_plic_properties);
|
||||
dc->realize = sifive_plic_realize;
|
||||
dc->vmsd = &vmstate_sifive_plic;
|
||||
|
|
|
@ -471,7 +471,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
|||
/* Initialize SoC */
|
||||
object_initialize_child(OBJECT(machine), "soc", &s->soc,
|
||||
TYPE_MICROCHIP_PFSOC);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
||||
|
||||
/* Split RAM into low and high regions using aliases to machine->ram */
|
||||
mem_low_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size;
|
||||
|
|
|
@ -80,7 +80,7 @@ static void opentitan_board_init(MachineState *machine)
|
|||
/* Initialize SoC */
|
||||
object_initialize_child(OBJECT(machine), "soc", &s->soc,
|
||||
TYPE_RISCV_IBEX_SOC);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
||||
|
||||
memory_region_add_subregion(sys_mem,
|
||||
memmap[IBEX_DEV_RAM].base, machine->ram);
|
||||
|
|
|
@ -88,7 +88,7 @@ static void sifive_e_machine_init(MachineState *machine)
|
|||
|
||||
/* Initialize SoC */
|
||||
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_E_SOC);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
||||
|
||||
/* Data Tightly Integrated Memory */
|
||||
memory_region_add_subregion(sys_mem,
|
||||
|
|
|
@ -547,7 +547,7 @@ static void sifive_u_machine_init(MachineState *machine)
|
|||
&error_abort);
|
||||
object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type,
|
||||
&error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
||||
|
||||
/* register RAM */
|
||||
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_DRAM].base,
|
||||
|
|
|
@ -459,6 +459,7 @@ int print_insn_nios2(bfd_vma, disassemble_info*);
|
|||
int print_insn_xtensa (bfd_vma, disassemble_info*);
|
||||
int print_insn_riscv32 (bfd_vma, disassemble_info*);
|
||||
int print_insn_riscv64 (bfd_vma, disassemble_info*);
|
||||
int print_insn_riscv128 (bfd_vma, disassemble_info*);
|
||||
int print_insn_rx(bfd_vma, disassemble_info *);
|
||||
int print_insn_hexagon(bfd_vma, disassemble_info *);
|
||||
|
||||
|
|
|
@ -85,29 +85,36 @@ typedef enum MemOp {
|
|||
MO_UB = MO_8,
|
||||
MO_UW = MO_16,
|
||||
MO_UL = MO_32,
|
||||
MO_UQ = MO_64,
|
||||
MO_UO = MO_128,
|
||||
MO_SB = MO_SIGN | MO_8,
|
||||
MO_SW = MO_SIGN | MO_16,
|
||||
MO_SL = MO_SIGN | MO_32,
|
||||
MO_Q = MO_64,
|
||||
MO_SQ = MO_SIGN | MO_64,
|
||||
MO_SO = MO_SIGN | MO_128,
|
||||
|
||||
MO_LEUW = MO_LE | MO_UW,
|
||||
MO_LEUL = MO_LE | MO_UL,
|
||||
MO_LEUQ = MO_LE | MO_UQ,
|
||||
MO_LESW = MO_LE | MO_SW,
|
||||
MO_LESL = MO_LE | MO_SL,
|
||||
MO_LEQ = MO_LE | MO_Q,
|
||||
MO_LESQ = MO_LE | MO_SQ,
|
||||
|
||||
MO_BEUW = MO_BE | MO_UW,
|
||||
MO_BEUL = MO_BE | MO_UL,
|
||||
MO_BEUQ = MO_BE | MO_UQ,
|
||||
MO_BESW = MO_BE | MO_SW,
|
||||
MO_BESL = MO_BE | MO_SL,
|
||||
MO_BEQ = MO_BE | MO_Q,
|
||||
MO_BESQ = MO_BE | MO_SQ,
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
MO_TEUW = MO_TE | MO_UW,
|
||||
MO_TEUL = MO_TE | MO_UL,
|
||||
MO_TEUQ = MO_TE | MO_UQ,
|
||||
MO_TEUO = MO_TE | MO_UO,
|
||||
MO_TESW = MO_TE | MO_SW,
|
||||
MO_TESL = MO_TE | MO_SL,
|
||||
MO_TEQ = MO_TE | MO_Q,
|
||||
MO_TESQ = MO_TE | MO_SQ,
|
||||
#endif
|
||||
|
||||
MO_SSIZE = MO_SIZE | MO_SIGN,
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "hw/block/flash.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define VIRT_CPUS_MAX 8
|
||||
#define VIRT_CPUS_MAX 32
|
||||
#define VIRT_SOCKETS_MAX 8
|
||||
|
||||
#define TYPE_RISCV_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
||||
|
|
|
@ -172,6 +172,26 @@ static inline Int128 bswap128(Int128 a)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline Int128 int128_divu(Int128 a, Int128 b)
|
||||
{
|
||||
return (__uint128_t)a / (__uint128_t)b;
|
||||
}
|
||||
|
||||
static inline Int128 int128_remu(Int128 a, Int128 b)
|
||||
{
|
||||
return (__uint128_t)a % (__uint128_t)b;
|
||||
}
|
||||
|
||||
static inline Int128 int128_divs(Int128 a, Int128 b)
|
||||
{
|
||||
return a / b;
|
||||
}
|
||||
|
||||
static inline Int128 int128_rems(Int128 a, Int128 b)
|
||||
{
|
||||
return a % b;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_INT128 */
|
||||
|
||||
typedef struct Int128 Int128;
|
||||
|
@ -379,6 +399,11 @@ static inline Int128 bswap128(Int128 a)
|
|||
return int128_make128(bswap64(a.hi), bswap64(a.lo));
|
||||
}
|
||||
|
||||
Int128 int128_divu(Int128, Int128);
|
||||
Int128 int128_remu(Int128, Int128);
|
||||
Int128 int128_divs(Int128, Int128);
|
||||
Int128 int128_rems(Int128, Int128);
|
||||
|
||||
#endif /* CONFIG_INT128 */
|
||||
|
||||
static inline void bswap128s(Int128 *s)
|
||||
|
@ -386,4 +411,6 @@ static inline void bswap128s(Int128 *s)
|
|||
*s = bswap128(*s);
|
||||
}
|
||||
|
||||
#define UINT128_MAX int128_make128(~0LL, ~0LL)
|
||||
|
||||
#endif /* INT128_H */
|
||||
|
|
|
@ -894,7 +894,7 @@ static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
|
|||
|
||||
static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
|
||||
{
|
||||
tcg_gen_qemu_ld_i64(ret, addr, mem_index, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(ret, addr, mem_index, MO_TEUQ);
|
||||
}
|
||||
|
||||
static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
|
||||
|
@ -914,7 +914,7 @@ static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
|
|||
|
||||
static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
|
||||
{
|
||||
tcg_gen_qemu_st_i64(arg, addr, mem_index, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(arg, addr, mem_index, MO_TEUQ);
|
||||
}
|
||||
|
||||
void tcg_gen_atomic_cmpxchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGv_i32,
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit 234ed8e427f4d92903123199f6590d144e0d9351
|
||||
Subproject commit 48f91ee9c960f048c4a7d1da4447d31e04931e38
|
|
@ -286,7 +286,7 @@ static void gen_ldf(DisasContext *ctx, TCGv dest, TCGv addr)
|
|||
static void gen_ldg(DisasContext *ctx, TCGv dest, TCGv addr)
|
||||
{
|
||||
TCGv tmp = tcg_temp_new();
|
||||
tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx));
|
||||
tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_LEUQ | UNALIGN(ctx));
|
||||
gen_helper_memory_to_g(dest, tmp);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ static void gen_lds(DisasContext *ctx, TCGv dest, TCGv addr)
|
|||
|
||||
static void gen_ldt(DisasContext *ctx, TCGv dest, TCGv addr)
|
||||
{
|
||||
tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx));
|
||||
tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_LEUQ | UNALIGN(ctx));
|
||||
}
|
||||
|
||||
static void gen_load_fp(DisasContext *ctx, int ra, int rb, int32_t disp16,
|
||||
|
@ -358,7 +358,7 @@ static void gen_stg(DisasContext *ctx, TCGv src, TCGv addr)
|
|||
{
|
||||
TCGv tmp = tcg_temp_new();
|
||||
gen_helper_g_to_memory(tmp, src);
|
||||
tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx));
|
||||
tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_LEUQ | UNALIGN(ctx));
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ static void gen_sts(DisasContext *ctx, TCGv src, TCGv addr)
|
|||
|
||||
static void gen_stt(DisasContext *ctx, TCGv src, TCGv addr)
|
||||
{
|
||||
tcg_gen_qemu_st_i64(src, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx));
|
||||
tcg_gen_qemu_st_i64(src, addr, ctx->mem_idx, MO_LEUQ | UNALIGN(ctx));
|
||||
}
|
||||
|
||||
static void gen_store_fp(DisasContext *ctx, int ra, int rb, int32_t disp16,
|
||||
|
@ -1499,7 +1499,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x0B:
|
||||
/* LDQ_U */
|
||||
gen_load_int(ctx, ra, rb, disp16, MO_LEQ, 1, 0);
|
||||
gen_load_int(ctx, ra, rb, disp16, MO_LEUQ, 1, 0);
|
||||
break;
|
||||
case 0x0C:
|
||||
/* LDWU */
|
||||
|
@ -1518,7 +1518,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x0F:
|
||||
/* STQ_U */
|
||||
gen_store_int(ctx, ra, rb, disp16, MO_LEQ, 1);
|
||||
gen_store_int(ctx, ra, rb, disp16, MO_LEUQ, 1);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
|
@ -2469,7 +2469,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x1:
|
||||
/* Quadword physical access (hw_ldq/p) */
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_PHYS_IDX, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_PHYS_IDX, MO_LEUQ);
|
||||
break;
|
||||
case 0x2:
|
||||
/* Longword physical access with lock (hw_ldl_l/p) */
|
||||
|
@ -2479,7 +2479,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x3:
|
||||
/* Quadword physical access with lock (hw_ldq_l/p) */
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_PHYS_IDX, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_PHYS_IDX, MO_LEUQ);
|
||||
tcg_gen_mov_i64(cpu_lock_addr, addr);
|
||||
tcg_gen_mov_i64(cpu_lock_value, va);
|
||||
break;
|
||||
|
@ -2508,7 +2508,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0xB:
|
||||
/* Quadword virtual access with protection check (hw_ldq/w) */
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_KERNEL_IDX, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_KERNEL_IDX, MO_LEUQ);
|
||||
break;
|
||||
case 0xC:
|
||||
/* Longword virtual access with alt access mode (hw_ldl/a)*/
|
||||
|
@ -2524,7 +2524,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
case 0xF:
|
||||
/* Quadword virtual access with alternate access mode and
|
||||
protection checks (hw_ldq/wa) */
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_USER_IDX, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(va, addr, MMU_USER_IDX, MO_LEUQ);
|
||||
break;
|
||||
}
|
||||
tcg_temp_free(addr);
|
||||
|
@ -2737,7 +2737,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
vb = load_gpr(ctx, rb);
|
||||
tmp = tcg_temp_new();
|
||||
tcg_gen_addi_i64(tmp, vb, disp12);
|
||||
tcg_gen_qemu_st_i64(va, tmp, MMU_PHYS_IDX, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(va, tmp, MMU_PHYS_IDX, MO_LEUQ);
|
||||
tcg_temp_free(tmp);
|
||||
break;
|
||||
case 0x2:
|
||||
|
@ -2748,7 +2748,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
case 0x3:
|
||||
/* Quadword physical access with lock */
|
||||
ret = gen_store_conditional(ctx, ra, rb, disp12,
|
||||
MMU_PHYS_IDX, MO_LEQ);
|
||||
MMU_PHYS_IDX, MO_LEUQ);
|
||||
break;
|
||||
case 0x4:
|
||||
/* Longword virtual access */
|
||||
|
@ -2838,7 +2838,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x29:
|
||||
/* LDQ */
|
||||
gen_load_int(ctx, ra, rb, disp16, MO_LEQ, 0, 0);
|
||||
gen_load_int(ctx, ra, rb, disp16, MO_LEUQ, 0, 0);
|
||||
break;
|
||||
case 0x2A:
|
||||
/* LDL_L */
|
||||
|
@ -2846,7 +2846,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x2B:
|
||||
/* LDQ_L */
|
||||
gen_load_int(ctx, ra, rb, disp16, MO_LEQ, 0, 1);
|
||||
gen_load_int(ctx, ra, rb, disp16, MO_LEUQ, 0, 1);
|
||||
break;
|
||||
case 0x2C:
|
||||
/* STL */
|
||||
|
@ -2854,7 +2854,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
break;
|
||||
case 0x2D:
|
||||
/* STQ */
|
||||
gen_store_int(ctx, ra, rb, disp16, MO_LEQ, 0);
|
||||
gen_store_int(ctx, ra, rb, disp16, MO_LEUQ, 0);
|
||||
break;
|
||||
case 0x2E:
|
||||
/* STL_C */
|
||||
|
@ -2864,7 +2864,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
|||
case 0x2F:
|
||||
/* STQ_C */
|
||||
ret = gen_store_conditional(ctx, ra, rb, disp16,
|
||||
ctx->mem_idx, MO_LEQ);
|
||||
ctx->mem_idx, MO_LEUQ);
|
||||
break;
|
||||
case 0x30:
|
||||
/* BR */
|
||||
|
|
|
@ -513,8 +513,8 @@ uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
|
|||
uint64_t o0, o1;
|
||||
bool success;
|
||||
int mem_idx = cpu_mmu_index(env, false);
|
||||
MemOpIdx oi0 = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
||||
MemOpIdx oi1 = make_memop_idx(MO_LEQ, mem_idx);
|
||||
MemOpIdx oi0 = make_memop_idx(MO_LEUQ | MO_ALIGN_16, mem_idx);
|
||||
MemOpIdx oi1 = make_memop_idx(MO_LEUQ, mem_idx);
|
||||
|
||||
o0 = cpu_ldq_le_mmu(env, addr + 0, oi0, ra);
|
||||
o1 = cpu_ldq_le_mmu(env, addr + 8, oi1, ra);
|
||||
|
@ -565,8 +565,8 @@ uint64_t HELPER(paired_cmpxchg64_be)(CPUARMState *env, uint64_t addr,
|
|||
uint64_t o0, o1;
|
||||
bool success;
|
||||
int mem_idx = cpu_mmu_index(env, false);
|
||||
MemOpIdx oi0 = make_memop_idx(MO_BEQ | MO_ALIGN_16, mem_idx);
|
||||
MemOpIdx oi1 = make_memop_idx(MO_BEQ, mem_idx);
|
||||
MemOpIdx oi0 = make_memop_idx(MO_BEUQ | MO_ALIGN_16, mem_idx);
|
||||
MemOpIdx oi1 = make_memop_idx(MO_BEUQ, mem_idx);
|
||||
|
||||
o1 = cpu_ldq_be_mmu(env, addr + 0, oi0, ra);
|
||||
o0 = cpu_ldq_be_mmu(env, addr + 8, oi1, ra);
|
||||
|
|
|
@ -117,13 +117,13 @@ void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
|
|||
static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
|
||||
TCGv_i32 a32, int index)
|
||||
{
|
||||
gen_aa32_ld_i64(s, val, a32, index, MO_Q);
|
||||
gen_aa32_ld_i64(s, val, a32, index, MO_UQ);
|
||||
}
|
||||
|
||||
static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
|
||||
TCGv_i32 a32, int index)
|
||||
{
|
||||
gen_aa32_st_i64(s, val, a32, index, MO_Q);
|
||||
gen_aa32_st_i64(s, val, a32, index, MO_UQ);
|
||||
}
|
||||
|
||||
DO_GEN_LD(8u, MO_UB)
|
||||
|
|
|
@ -973,7 +973,7 @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
|
|||
|
||||
tcg_gen_ld_i64(tmphi, cpu_env, fp_reg_hi_offset(s, srcidx));
|
||||
|
||||
mop = s->be_data | MO_Q;
|
||||
mop = s->be_data | MO_UQ;
|
||||
tcg_gen_qemu_st_i64(be ? tmphi : tmplo, tcg_addr, get_mem_index(s),
|
||||
mop | (s->align_mem ? MO_ALIGN_16 : 0));
|
||||
tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
|
||||
|
@ -1007,7 +1007,7 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
|
|||
tmphi = tcg_temp_new_i64();
|
||||
tcg_hiaddr = tcg_temp_new_i64();
|
||||
|
||||
mop = s->be_data | MO_Q;
|
||||
mop = s->be_data | MO_UQ;
|
||||
tcg_gen_qemu_ld_i64(be ? tmphi : tmplo, tcg_addr, get_mem_index(s),
|
||||
mop | (s->align_mem ? MO_ALIGN_16 : 0));
|
||||
tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
|
||||
|
@ -4099,10 +4099,10 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
|
|||
int i, n = (1 + is_pair) << LOG2_TAG_GRANULE;
|
||||
|
||||
tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index,
|
||||
MO_Q | MO_ALIGN_16);
|
||||
MO_UQ | MO_ALIGN_16);
|
||||
for (i = 8; i < n; i += 8) {
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
|
||||
tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index, MO_Q);
|
||||
tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index, MO_UQ);
|
||||
}
|
||||
tcg_temp_free_i64(tcg_zero);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
|
|||
case MO_UL:
|
||||
tcg_gen_ld32u_i64(var, cpu_env, offset);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
tcg_gen_ld_i64(var, cpu_env, offset);
|
||||
break;
|
||||
default:
|
||||
|
@ -1830,7 +1830,7 @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((a->vd & 1) || (src1_mop == MO_Q && (a->vn & 1))) {
|
||||
if ((a->vd & 1) || (src1_mop == MO_UQ && (a->vn & 1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1910,7 +1910,7 @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
|
|||
}; \
|
||||
int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1; \
|
||||
return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size], \
|
||||
SRC1WIDE ? MO_Q : narrow_mop, \
|
||||
SRC1WIDE ? MO_UQ : narrow_mop, \
|
||||
narrow_mop); \
|
||||
}
|
||||
|
||||
|
|
|
@ -5087,7 +5087,7 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
|
|||
|
||||
t0 = tcg_temp_new_i64();
|
||||
for (i = 0; i < len_align; i += 8) {
|
||||
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ);
|
||||
tcg_gen_st_i64(t0, cpu_env, vofs + i);
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
|
||||
}
|
||||
|
@ -5104,7 +5104,7 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
|
|||
gen_set_label(loop);
|
||||
|
||||
t0 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ);
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
|
||||
|
||||
tp = tcg_temp_new_ptr();
|
||||
|
@ -5177,7 +5177,7 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
|
|||
t0 = tcg_temp_new_i64();
|
||||
for (i = 0; i < len_align; i += 8) {
|
||||
tcg_gen_ld_i64(t0, cpu_env, vofs + i);
|
||||
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ);
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
|
||||
}
|
||||
tcg_temp_free_i64(t0);
|
||||
|
@ -5199,7 +5199,7 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
|
|||
tcg_gen_addi_ptr(i, i, 8);
|
||||
tcg_temp_free_ptr(tp);
|
||||
|
||||
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ);
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
|
||||
tcg_temp_free_i64(t0);
|
||||
|
||||
|
@ -5283,7 +5283,7 @@ static const MemOp dtype_mop[16] = {
|
|||
MO_UB, MO_UB, MO_UB, MO_UB,
|
||||
MO_SL, MO_UW, MO_UW, MO_UW,
|
||||
MO_SW, MO_SW, MO_UL, MO_UL,
|
||||
MO_SB, MO_SB, MO_SB, MO_Q
|
||||
MO_SB, MO_SB, MO_SB, MO_UQ
|
||||
};
|
||||
|
||||
#define dtype_msz(x) (dtype_mop[x] & MO_SIZE)
|
||||
|
|
|
@ -1170,11 +1170,11 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
|
|||
addr = add_reg_for_lit(s, a->rn, offset);
|
||||
tmp = tcg_temp_new_i64();
|
||||
if (a->l) {
|
||||
gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4);
|
||||
gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4);
|
||||
vfp_store_reg64(tmp, a->vd);
|
||||
} else {
|
||||
vfp_load_reg64(tmp, a->vd);
|
||||
gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4);
|
||||
gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4);
|
||||
}
|
||||
tcg_temp_free_i64(tmp);
|
||||
tcg_temp_free_i32(addr);
|
||||
|
@ -1322,12 +1322,12 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
|
|||
for (i = 0; i < n; i++) {
|
||||
if (a->l) {
|
||||
/* load */
|
||||
gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4);
|
||||
gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4);
|
||||
vfp_store_reg64(tmp, a->vd + i);
|
||||
} else {
|
||||
/* store */
|
||||
vfp_load_reg64(tmp, a->vd + i);
|
||||
gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4);
|
||||
gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4);
|
||||
}
|
||||
tcg_gen_addi_i32(addr, addr, offset);
|
||||
}
|
||||
|
|
|
@ -1217,7 +1217,7 @@ void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
|
|||
case MO_UL:
|
||||
tcg_gen_ld32u_i64(dest, cpu_env, off);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
tcg_gen_ld_i64(dest, cpu_env, off);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1047,7 +1047,7 @@ static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
|
|||
cris_store_direct_jmp(dc);
|
||||
}
|
||||
|
||||
tcg_gen_qemu_ld_i64(dst, addr, mem_index, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(dst, addr, mem_index, MO_TEUQ);
|
||||
}
|
||||
|
||||
static void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
|
||||
|
|
|
@ -1609,7 +1609,7 @@ static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
|
|||
nullify_over(ctx);
|
||||
|
||||
tmp = tcg_temp_new_i64();
|
||||
do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ);
|
||||
do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
|
||||
save_frd(rt, tmp);
|
||||
tcg_temp_free_i64(tmp);
|
||||
|
||||
|
@ -1665,7 +1665,7 @@ static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
|
|||
nullify_over(ctx);
|
||||
|
||||
tmp = load_frd(rt);
|
||||
do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ);
|
||||
do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
|
||||
tcg_temp_free_i64(tmp);
|
||||
|
||||
return nullify_end(ctx);
|
||||
|
|
|
@ -67,7 +67,7 @@ void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
|
|||
{
|
||||
uintptr_t ra = GETPC();
|
||||
int mem_idx = cpu_mmu_index(env, false);
|
||||
MemOpIdx oi = make_memop_idx(MO_TEQ, mem_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUQ, mem_idx);
|
||||
oldv = cpu_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra);
|
||||
}
|
||||
|
||||
|
|
|
@ -2719,23 +2719,23 @@ static void gen_jmp(DisasContext *s, target_ulong eip)
|
|||
|
||||
static inline void gen_ldq_env_A0(DisasContext *s, int offset)
|
||||
{
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ);
|
||||
tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset);
|
||||
}
|
||||
|
||||
static inline void gen_stq_env_A0(DisasContext *s, int offset)
|
||||
{
|
||||
tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ);
|
||||
}
|
||||
|
||||
static inline void gen_ldo_env_A0(DisasContext *s, int offset)
|
||||
{
|
||||
int mem_index = s->mem_index;
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ);
|
||||
tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(0)));
|
||||
tcg_gen_addi_tl(s->tmp0, s->A0, 8);
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ);
|
||||
tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(1)));
|
||||
}
|
||||
|
||||
|
@ -2743,10 +2743,10 @@ static inline void gen_sto_env_A0(DisasContext *s, int offset)
|
|||
{
|
||||
int mem_index = s->mem_index;
|
||||
tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(0)));
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ);
|
||||
tcg_gen_addi_tl(s->tmp0, s->A0, 8);
|
||||
tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(1)));
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ);
|
||||
}
|
||||
|
||||
static inline void gen_op_movo(DisasContext *s, int d_offset, int s_offset)
|
||||
|
@ -4255,7 +4255,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||
tcg_gen_mov_i64(cpu_regs[rm], s->tmp1_i64);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
}
|
||||
#else
|
||||
goto illegal_op;
|
||||
|
@ -4328,7 +4328,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||
gen_op_mov_v_reg(s, ot, s->tmp1_i64, rm);
|
||||
} else {
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
}
|
||||
tcg_gen_st_i64(s->tmp1_i64, cpu_env,
|
||||
offsetof(CPUX86State,
|
||||
|
@ -5948,7 +5948,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
break;
|
||||
case 2:
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
gen_helper_fldl_FT0(cpu_env, s->tmp1_i64);
|
||||
break;
|
||||
case 3:
|
||||
|
@ -5987,7 +5987,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
break;
|
||||
case 2:
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
gen_helper_fldl_ST0(cpu_env, s->tmp1_i64);
|
||||
break;
|
||||
case 3:
|
||||
|
@ -6009,7 +6009,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
case 2:
|
||||
gen_helper_fisttll_ST0(s->tmp1_i64, cpu_env);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
|
@ -6035,7 +6035,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
case 2:
|
||||
gen_helper_fstl_ST0(s->tmp1_i64, cpu_env);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
|
@ -6104,13 +6104,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
break;
|
||||
case 0x3d: /* fildll */
|
||||
tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
gen_helper_fildll_ST0(cpu_env, s->tmp1_i64);
|
||||
break;
|
||||
case 0x3f: /* fistpll */
|
||||
gen_helper_fistll_ST0(s->tmp1_i64, cpu_env);
|
||||
tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
gen_helper_fpop(cpu_env);
|
||||
break;
|
||||
default:
|
||||
|
@ -7932,10 +7932,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
gen_lea_modrm(env, s, modrm);
|
||||
if (CODE64(s)) {
|
||||
tcg_gen_qemu_ld_i64(cpu_bndl[reg], s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
tcg_gen_addi_tl(s->A0, s->A0, 8);
|
||||
tcg_gen_qemu_ld_i64(cpu_bndu[reg], s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
} else {
|
||||
tcg_gen_qemu_ld_i64(cpu_bndl[reg], s->A0,
|
||||
s->mem_index, MO_LEUL);
|
||||
|
@ -8039,10 +8039,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
|||
gen_lea_modrm(env, s, modrm);
|
||||
if (CODE64(s)) {
|
||||
tcg_gen_qemu_st_i64(cpu_bndl[reg], s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
tcg_gen_addi_tl(s->A0, s->A0, 8);
|
||||
tcg_gen_qemu_st_i64(cpu_bndu[reg], s->A0,
|
||||
s->mem_index, MO_LEQ);
|
||||
s->mem_index, MO_LEUQ);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i64(cpu_bndl[reg], s->A0,
|
||||
s->mem_index, MO_LEUL);
|
||||
|
|
|
@ -774,7 +774,7 @@ static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2,
|
|||
uintptr_t ra = GETPC();
|
||||
#if defined(CONFIG_ATOMIC64)
|
||||
int mmu_idx = cpu_mmu_index(env, 0);
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ, mmu_idx);
|
||||
#endif
|
||||
|
||||
if (parallel) {
|
||||
|
|
|
@ -1001,20 +1001,20 @@ static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd,
|
|||
gen_reserved_instruction(ctx);
|
||||
return;
|
||||
}
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_gpr(t1, rd);
|
||||
tcg_gen_movi_tl(t1, 8);
|
||||
gen_op_addr_add(ctx, t0, t0, t1);
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_gpr(t1, rd + 1);
|
||||
break;
|
||||
case SDP:
|
||||
gen_load_gpr(t1, rd);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_gen_movi_tl(t1, 8);
|
||||
gen_op_addr_add(ctx, t0, t0, t1);
|
||||
gen_load_gpr(t1, rd + 1);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
@ -2578,7 +2578,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
case SCD:
|
||||
check_insn(ctx, ISA_MIPS3);
|
||||
check_mips_64(ctx);
|
||||
gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false);
|
||||
gen_st_cond(ctx, rt, rs, offset, MO_TEUQ, false);
|
||||
break;
|
||||
#endif
|
||||
case LD_EVA:
|
||||
|
|
|
@ -2031,7 +2031,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
|
|||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case OPC_LD:
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
|
@ -2053,7 +2053,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
|
|||
}
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~7);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUQ);
|
||||
tcg_gen_shl_tl(t0, t0, t1);
|
||||
t2 = tcg_const_tl(-1);
|
||||
tcg_gen_shl_tl(t2, t2, t1);
|
||||
|
@ -2077,7 +2077,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
|
|||
}
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~7);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUQ);
|
||||
tcg_gen_shr_tl(t0, t0, t1);
|
||||
tcg_gen_xori_tl(t1, t1, 63);
|
||||
t2 = tcg_const_tl(0xfffffffffffffffeull);
|
||||
|
@ -2093,7 +2093,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
|
|||
t1 = tcg_const_tl(pc_relative_pc(ctx));
|
||||
gen_op_addr_add(ctx, t0, t0, t1);
|
||||
tcg_temp_free(t1);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUQ);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
#endif
|
||||
|
@ -2224,7 +2224,7 @@ static void gen_st(DisasContext *ctx, uint32_t opc, int rt,
|
|||
switch (opc) {
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_SD:
|
||||
tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
break;
|
||||
case OPC_SDL:
|
||||
|
@ -2334,7 +2334,7 @@ static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft,
|
|||
case OPC_LDC1:
|
||||
{
|
||||
TCGv_i64 fp0 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_store_fpr64(ctx, fp0, ft);
|
||||
tcg_temp_free_i64(fp0);
|
||||
|
@ -2344,7 +2344,7 @@ static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft,
|
|||
{
|
||||
TCGv_i64 fp0 = tcg_temp_new_i64();
|
||||
gen_load_fpr64(ctx, fp0, ft);
|
||||
tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
tcg_temp_free_i64(fp0);
|
||||
}
|
||||
|
@ -3092,7 +3092,7 @@ static inline void gen_pcrel(DisasContext *ctx, int opc, target_ulong pc,
|
|||
check_mips_64(ctx);
|
||||
offset = sextract32(ctx->opcode << 3, 0, 21);
|
||||
addr = addr_add(ctx, (pc & ~0x7), offset);
|
||||
gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEQ);
|
||||
gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUQ);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -4344,10 +4344,10 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
case OPC_GSLQ:
|
||||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_store_gpr(t1, rt);
|
||||
gen_store_gpr(t0, lsq_rt1);
|
||||
|
@ -4357,10 +4357,10 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
check_cp1_enabled(ctx);
|
||||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_store_fpr64(ctx, t1, rt);
|
||||
gen_store_fpr64(ctx, t0, lsq_rt1);
|
||||
|
@ -4370,11 +4370,11 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
|
||||
gen_load_gpr(t1, rt);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
|
||||
gen_load_gpr(t1, lsq_rt1);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
|
@ -4383,11 +4383,11 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
|
||||
gen_load_fpr64(ctx, t1, rt);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
|
||||
gen_load_fpr64(ctx, t1, lsq_rt1);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
|
@ -4467,7 +4467,7 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
}
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~7);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_gen_shl_tl(t0, t0, t1);
|
||||
t2 = tcg_const_tl(-1);
|
||||
tcg_gen_shl_tl(t2, t2, t1);
|
||||
|
@ -4489,7 +4489,7 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
}
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~7);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_gen_shr_tl(t0, t0, t1);
|
||||
tcg_gen_xori_tl(t1, t1, 63);
|
||||
t2 = tcg_const_tl(0xfffffffffffffffeull);
|
||||
|
@ -4642,7 +4642,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
|
|||
if (rd) {
|
||||
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
|
||||
}
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
|
@ -4664,7 +4664,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
|
|||
if (rd) {
|
||||
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
|
||||
}
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
gen_store_fpr64(ctx, t0, rt);
|
||||
break;
|
||||
|
@ -4693,7 +4693,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
|
|||
case OPC_GSSDX:
|
||||
t1 = tcg_temp_new();
|
||||
gen_load_gpr(t1, rt);
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
|
@ -4709,7 +4709,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
|
|||
case OPC_GSSDXC1:
|
||||
t1 = tcg_temp_new();
|
||||
gen_load_fpr64(ctx, t1, rt);
|
||||
tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEQ |
|
||||
tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEUQ |
|
||||
ctx->default_tcg_memop_mask);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
|
@ -11330,7 +11330,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
|
|||
check_cp1_registers(ctx, fd);
|
||||
{
|
||||
TCGv_i64 fp0 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_fpr64(ctx, fp0, fd);
|
||||
tcg_temp_free_i64(fp0);
|
||||
}
|
||||
|
@ -11341,7 +11341,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
|
|||
{
|
||||
TCGv_i64 fp0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_fpr64(ctx, fp0, fd);
|
||||
tcg_temp_free_i64(fp0);
|
||||
}
|
||||
|
@ -11361,7 +11361,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
|
|||
{
|
||||
TCGv_i64 fp0 = tcg_temp_new_i64();
|
||||
gen_load_fpr64(ctx, fp0, fs);
|
||||
tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_temp_free_i64(fp0);
|
||||
}
|
||||
break;
|
||||
|
@ -11371,7 +11371,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
|
|||
{
|
||||
TCGv_i64 fp0 = tcg_temp_new_i64();
|
||||
gen_load_fpr64(ctx, fp0, fs);
|
||||
tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_temp_free_i64(fp0);
|
||||
}
|
||||
break;
|
||||
|
@ -12187,7 +12187,7 @@ static void gen_mipsdsp_ld(DisasContext *ctx, uint32_t opc,
|
|||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_LDX:
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_gpr(t0, rd);
|
||||
break;
|
||||
#endif
|
||||
|
@ -14403,7 +14403,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
|
|||
#endif
|
||||
#if defined(TARGET_MIPS64)
|
||||
case R6_OPC_SCD:
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TEQ, false);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TEUQ, false);
|
||||
break;
|
||||
case R6_OPC_LLD:
|
||||
gen_ld(ctx, op1, rt, rs, imm);
|
||||
|
@ -15843,7 +15843,7 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
|
|||
check_insn_opc_user_only(ctx, INSN_R5900);
|
||||
}
|
||||
check_mips_64(ctx);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TEQ, false);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TEUQ, false);
|
||||
break;
|
||||
case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */
|
||||
if (ctx->insn_flags & ISA_MIPS_R6) {
|
||||
|
|
|
@ -355,12 +355,12 @@ static bool trans_LQ(DisasContext *ctx, arg_i *a)
|
|||
tcg_gen_andi_tl(addr, addr, ~0xf);
|
||||
|
||||
/* Lower half */
|
||||
tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_gpr(t0, a->rt);
|
||||
|
||||
/* Upper half */
|
||||
tcg_gen_addi_i64(addr, addr, 8);
|
||||
tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
|
||||
gen_store_gpr_hi(t0, a->rt);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
|
@ -383,12 +383,12 @@ static bool trans_SQ(DisasContext *ctx, arg_i *a)
|
|||
|
||||
/* Lower half */
|
||||
gen_load_gpr(t0, a->rt);
|
||||
tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
|
||||
|
||||
/* Upper half */
|
||||
tcg_gen_addi_i64(addr, addr, 8);
|
||||
gen_load_gpr_hi(t0, a->rt);
|
||||
tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
|
||||
|
||||
tcg_temp_free(addr);
|
||||
tcg_temp_free(t0);
|
||||
|
|
|
@ -3277,10 +3277,10 @@ GEN_QEMU_LOAD_64(ld8u, DEF_MEMOP(MO_UB))
|
|||
GEN_QEMU_LOAD_64(ld16u, DEF_MEMOP(MO_UW))
|
||||
GEN_QEMU_LOAD_64(ld32u, DEF_MEMOP(MO_UL))
|
||||
GEN_QEMU_LOAD_64(ld32s, DEF_MEMOP(MO_SL))
|
||||
GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_Q))
|
||||
GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_UQ))
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
GEN_QEMU_LOAD_64(ld64ur, BSWAP_MEMOP(MO_Q))
|
||||
GEN_QEMU_LOAD_64(ld64ur, BSWAP_MEMOP(MO_UQ))
|
||||
#endif
|
||||
|
||||
#define GEN_QEMU_STORE_TL(stop, op) \
|
||||
|
@ -3311,10 +3311,10 @@ static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \
|
|||
GEN_QEMU_STORE_64(st8, DEF_MEMOP(MO_UB))
|
||||
GEN_QEMU_STORE_64(st16, DEF_MEMOP(MO_UW))
|
||||
GEN_QEMU_STORE_64(st32, DEF_MEMOP(MO_UL))
|
||||
GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q))
|
||||
GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_UQ))
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_Q))
|
||||
GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_UQ))
|
||||
#endif
|
||||
|
||||
#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \
|
||||
|
@ -3351,7 +3351,7 @@ GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02)
|
|||
GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08)
|
||||
GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00)
|
||||
#if defined(TARGET_PPC64)
|
||||
GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00)
|
||||
GEN_LDEPX(ld, DEF_MEMOP(MO_UQ), 0x1D, 0x00)
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
|
@ -3397,7 +3397,7 @@ GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06)
|
|||
GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C)
|
||||
GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04)
|
||||
#if defined(TARGET_PPC64)
|
||||
GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1d, 0x04)
|
||||
GEN_STEPX(std, DEF_MEMOP(MO_UQ), 0x1d, 0x04)
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
|
@ -3807,7 +3807,7 @@ static void gen_lwat(DisasContext *ctx)
|
|||
#ifdef TARGET_PPC64
|
||||
static void gen_ldat(DisasContext *ctx)
|
||||
{
|
||||
gen_ld_atomic(ctx, DEF_MEMOP(MO_Q));
|
||||
gen_ld_atomic(ctx, DEF_MEMOP(MO_UQ));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3890,7 +3890,7 @@ static void gen_stwat(DisasContext *ctx)
|
|||
#ifdef TARGET_PPC64
|
||||
static void gen_stdat(DisasContext *ctx)
|
||||
{
|
||||
gen_st_atomic(ctx, DEF_MEMOP(MO_Q));
|
||||
gen_st_atomic(ctx, DEF_MEMOP(MO_UQ));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3942,9 +3942,9 @@ STCX(stwcx_, DEF_MEMOP(MO_UL))
|
|||
|
||||
#if defined(TARGET_PPC64)
|
||||
/* ldarx */
|
||||
LARX(ldarx, DEF_MEMOP(MO_Q))
|
||||
LARX(ldarx, DEF_MEMOP(MO_UQ))
|
||||
/* stdcx. */
|
||||
STCX(stdcx_, DEF_MEMOP(MO_Q))
|
||||
STCX(stdcx_, DEF_MEMOP(MO_UQ))
|
||||
|
||||
/* lqarx */
|
||||
static void gen_lqarx(DisasContext *ctx)
|
||||
|
@ -3988,15 +3988,15 @@ static void gen_lqarx(DisasContext *ctx)
|
|||
return;
|
||||
}
|
||||
} else if (ctx->le_mode) {
|
||||
tcg_gen_qemu_ld_i64(lo, EA, ctx->mem_idx, MO_LEQ | MO_ALIGN_16);
|
||||
tcg_gen_qemu_ld_i64(lo, EA, ctx->mem_idx, MO_LEUQ | MO_ALIGN_16);
|
||||
tcg_gen_mov_tl(cpu_reserve, EA);
|
||||
gen_addr_add(ctx, EA, EA, 8);
|
||||
tcg_gen_qemu_ld_i64(hi, EA, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(hi, EA, ctx->mem_idx, MO_LEUQ);
|
||||
} else {
|
||||
tcg_gen_qemu_ld_i64(hi, EA, ctx->mem_idx, MO_BEQ | MO_ALIGN_16);
|
||||
tcg_gen_qemu_ld_i64(hi, EA, ctx->mem_idx, MO_BEUQ | MO_ALIGN_16);
|
||||
tcg_gen_mov_tl(cpu_reserve, EA);
|
||||
gen_addr_add(ctx, EA, EA, 8);
|
||||
tcg_gen_qemu_ld_i64(lo, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(lo, EA, ctx->mem_idx, MO_BEUQ);
|
||||
}
|
||||
tcg_temp_free(EA);
|
||||
|
||||
|
@ -8018,7 +8018,7 @@ GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02)
|
|||
GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08)
|
||||
GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00)
|
||||
#if defined(TARGET_PPC64)
|
||||
GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00)
|
||||
GEN_LDEPX(ld, DEF_MEMOP(MO_UQ), 0x1D, 0x00)
|
||||
#endif
|
||||
|
||||
#undef GEN_STX_E
|
||||
|
@ -8044,7 +8044,7 @@ GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06)
|
|||
GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C)
|
||||
GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04)
|
||||
#if defined(TARGET_PPC64)
|
||||
GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1D, 0x04)
|
||||
GEN_STEPX(std, DEF_MEMOP(MO_UQ), 0x1D, 0x04)
|
||||
#endif
|
||||
|
||||
#undef GEN_CRLOGIC
|
||||
|
|
|
@ -137,7 +137,7 @@ static bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed)
|
|||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
} else {
|
||||
mop = DEF_MEMOP(MO_Q);
|
||||
mop = DEF_MEMOP(MO_UQ);
|
||||
if (store) {
|
||||
tcg_gen_qemu_st_i64(low_addr_gpr, ea, ctx->mem_idx, mop);
|
||||
} else {
|
||||
|
@ -205,11 +205,11 @@ TRANS64(LWAUX, do_ldst_X, true, false, MO_SL)
|
|||
TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL)
|
||||
|
||||
/* Load Doubleword */
|
||||
TRANS64(LD, do_ldst_D, false, false, MO_Q)
|
||||
TRANS64(LDX, do_ldst_X, false, false, MO_Q)
|
||||
TRANS64(LDU, do_ldst_D, true, false, MO_Q)
|
||||
TRANS64(LDUX, do_ldst_X, true, false, MO_Q)
|
||||
TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q)
|
||||
TRANS64(LD, do_ldst_D, false, false, MO_UQ)
|
||||
TRANS64(LDX, do_ldst_X, false, false, MO_UQ)
|
||||
TRANS64(LDU, do_ldst_D, true, false, MO_UQ)
|
||||
TRANS64(LDUX, do_ldst_X, true, false, MO_UQ)
|
||||
TRANS64(PLD, do_ldst_PLS_D, false, false, MO_UQ)
|
||||
|
||||
/* Load Quadword */
|
||||
TRANS64(LQ, do_ldst_quad, false, false);
|
||||
|
@ -237,11 +237,11 @@ TRANS(STWUX, do_ldst_X, true, true, MO_UL)
|
|||
TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL)
|
||||
|
||||
/* Store Doubleword */
|
||||
TRANS64(STD, do_ldst_D, false, true, MO_Q)
|
||||
TRANS64(STDX, do_ldst_X, false, true, MO_Q)
|
||||
TRANS64(STDU, do_ldst_D, true, true, MO_Q)
|
||||
TRANS64(STDUX, do_ldst_X, true, true, MO_Q)
|
||||
TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q)
|
||||
TRANS64(STD, do_ldst_D, false, true, MO_UQ)
|
||||
TRANS64(STDX, do_ldst_X, false, true, MO_UQ)
|
||||
TRANS64(STDU, do_ldst_D, true, true, MO_UQ)
|
||||
TRANS64(STDUX, do_ldst_X, true, true, MO_UQ)
|
||||
TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_UQ)
|
||||
|
||||
/* Store Quadword */
|
||||
TRANS64(STQ, do_ldst_quad, true, false);
|
||||
|
|
|
@ -863,7 +863,7 @@ static void gen_lfdepx(DisasContext *ctx)
|
|||
EA = tcg_temp_new();
|
||||
t0 = tcg_temp_new_i64();
|
||||
gen_addr_reg_index(ctx, EA);
|
||||
tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_Q));
|
||||
tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UQ));
|
||||
set_fpr(rD(ctx->opcode), t0);
|
||||
tcg_temp_free(EA);
|
||||
tcg_temp_free_i64(t0);
|
||||
|
@ -1021,7 +1021,7 @@ static void gen_stfdepx(DisasContext *ctx)
|
|||
t0 = tcg_temp_new_i64();
|
||||
gen_addr_reg_index(ctx, EA);
|
||||
get_fpr(t0, rD(ctx->opcode));
|
||||
tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_Q));
|
||||
tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_UQ));
|
||||
tcg_temp_free(EA);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
|
|
@ -85,19 +85,19 @@ static void gen_lxvw4x(DisasContext *ctx)
|
|||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEUQ);
|
||||
tcg_gen_shri_i64(t1, t0, 32);
|
||||
tcg_gen_deposit_i64(xth, t1, t0, 32, 32);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEUQ);
|
||||
tcg_gen_shri_i64(t1, t0, 32);
|
||||
tcg_gen_deposit_i64(xtl, t1, t0, 32, 32);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
} else {
|
||||
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
}
|
||||
set_cpu_vsr(xT(ctx->opcode), xth, true);
|
||||
set_cpu_vsr(xT(ctx->opcode), xtl, false);
|
||||
|
@ -152,8 +152,8 @@ static void gen_lxvdsx(DisasContext *ctx)
|
|||
gen_addr_reg_index(ctx, EA);
|
||||
|
||||
data = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_Q));
|
||||
tcg_gen_gvec_dup_i64(MO_Q, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
|
||||
tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UQ));
|
||||
tcg_gen_gvec_dup_i64(MO_UQ, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
|
||||
|
||||
tcg_temp_free(EA);
|
||||
tcg_temp_free_i64(data);
|
||||
|
@ -217,9 +217,9 @@ static void gen_lxvh8x(DisasContext *ctx)
|
|||
|
||||
EA = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, EA);
|
||||
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
if (ctx->le_mode) {
|
||||
gen_bswap16x8(xth, xtl, xth, xtl);
|
||||
}
|
||||
|
@ -245,9 +245,9 @@ static void gen_lxvb16x(DisasContext *ctx)
|
|||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
EA = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, EA);
|
||||
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
set_cpu_vsr(xT(ctx->opcode), xth, true);
|
||||
set_cpu_vsr(xT(ctx->opcode), xtl, false);
|
||||
tcg_temp_free(EA);
|
||||
|
@ -382,17 +382,17 @@ static void gen_stxvw4x(DisasContext *ctx)
|
|||
|
||||
tcg_gen_shri_i64(t0, xsh, 32);
|
||||
tcg_gen_deposit_i64(t1, t0, xsh, 32, 32);
|
||||
tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_shri_i64(t0, xsl, 32);
|
||||
tcg_gen_deposit_i64(t1, t0, xsl, 32, 32);
|
||||
tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEUQ);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
}
|
||||
tcg_temp_free(EA);
|
||||
tcg_temp_free_i64(xsh);
|
||||
|
@ -421,15 +421,15 @@ static void gen_stxvh8x(DisasContext *ctx)
|
|||
TCGv_i64 outl = tcg_temp_new_i64();
|
||||
|
||||
gen_bswap16x8(outh, outl, xsh, xsl);
|
||||
tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_temp_free_i64(outh);
|
||||
tcg_temp_free_i64(outl);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
}
|
||||
tcg_temp_free(EA);
|
||||
tcg_temp_free_i64(xsh);
|
||||
|
@ -453,9 +453,9 @@ static void gen_stxvb16x(DisasContext *ctx)
|
|||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
EA = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, EA);
|
||||
tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_gen_addi_tl(EA, EA, 8);
|
||||
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ);
|
||||
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
|
||||
tcg_temp_free(EA);
|
||||
tcg_temp_free_i64(xsh);
|
||||
tcg_temp_free_i64(xsl);
|
||||
|
@ -2020,7 +2020,7 @@ static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ,
|
|||
|
||||
xt = tcg_temp_new_i64();
|
||||
|
||||
mop = DEF_MEMOP(MO_Q);
|
||||
mop = DEF_MEMOP(MO_UQ);
|
||||
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
ea = do_ea_calc(ctx, ra, displ);
|
||||
|
|
|
@ -42,6 +42,15 @@ const char * const riscv_int_regnames[] = {
|
|||
"x28/t3", "x29/t4", "x30/t5", "x31/t6"
|
||||
};
|
||||
|
||||
const char * const riscv_int_regnamesh[] = {
|
||||
"x0h/zeroh", "x1h/rah", "x2h/sph", "x3h/gph", "x4h/tph", "x5h/t0h",
|
||||
"x6h/t1h", "x7h/t2h", "x8h/s0h", "x9h/s1h", "x10h/a0h", "x11h/a1h",
|
||||
"x12h/a2h", "x13h/a3h", "x14h/a4h", "x15h/a5h", "x16h/a6h", "x17h/a7h",
|
||||
"x18h/s2h", "x19h/s3h", "x20h/s4h", "x21h/s5h", "x22h/s6h", "x23h/s7h",
|
||||
"x24h/s8h", "x25h/s9h", "x26h/s10h", "x27h/s11h", "x28h/t3h", "x29h/t4h",
|
||||
"x30h/t5h", "x31h/t6h"
|
||||
};
|
||||
|
||||
const char * const riscv_fpr_regnames[] = {
|
||||
"f0/ft0", "f1/ft1", "f2/ft2", "f3/ft3", "f4/ft4", "f5/ft5",
|
||||
"f6/ft6", "f7/ft7", "f8/fs0", "f9/fs1", "f10/fa0", "f11/fa1",
|
||||
|
@ -169,6 +178,19 @@ static void rv64_sifive_e_cpu_init(Object *obj)
|
|||
set_priv_version(env, PRIV_VERSION_1_10_0);
|
||||
qdev_prop_set_bit(DEVICE(obj), "mmu", false);
|
||||
}
|
||||
|
||||
static void rv128_base_cpu_init(Object *obj)
|
||||
{
|
||||
if (qemu_tcg_mttcg_enabled()) {
|
||||
/* Missing 128-bit aligned atomics */
|
||||
error_report("128-bit RISC-V currently does not work with Multi "
|
||||
"Threaded TCG. Please use: -accel tcg,thread=single");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
CPURISCVState *env = &RISCV_CPU(obj)->env;
|
||||
/* We set this in the realise function */
|
||||
set_misa(env, MXL_RV128, 0);
|
||||
}
|
||||
#else
|
||||
static void rv32_base_cpu_init(Object *obj)
|
||||
{
|
||||
|
@ -393,6 +415,9 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
|
|||
case MXL_RV64:
|
||||
info->print_insn = print_insn_riscv64;
|
||||
break;
|
||||
case MXL_RV128:
|
||||
info->print_insn = print_insn_riscv128;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -455,6 +480,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
#ifdef TARGET_RISCV64
|
||||
case MXL_RV64:
|
||||
break;
|
||||
case MXL_RV128:
|
||||
break;
|
||||
#endif
|
||||
case MXL_RV32:
|
||||
break;
|
||||
|
@ -627,6 +654,7 @@ static Property riscv_cpu_properties[] = {
|
|||
DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true),
|
||||
DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
|
||||
DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false),
|
||||
DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, true),
|
||||
DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
|
||||
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
|
||||
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
|
||||
|
@ -640,12 +668,12 @@ static Property riscv_cpu_properties[] = {
|
|||
DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128),
|
||||
DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
|
||||
|
||||
/* These are experimental so mark with 'x-' */
|
||||
DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true),
|
||||
DEFINE_PROP_BOOL("zbb", RISCVCPU, cfg.ext_zbb, true),
|
||||
DEFINE_PROP_BOOL("zbc", RISCVCPU, cfg.ext_zbc, true),
|
||||
DEFINE_PROP_BOOL("zbs", RISCVCPU, cfg.ext_zbs, true),
|
||||
DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
|
||||
|
||||
/* These are experimental so mark with 'x-' */
|
||||
DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
|
||||
/* ePMP 0.9.3 */
|
||||
DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
|
||||
|
@ -663,6 +691,7 @@ static gchar *riscv_gdb_arch_name(CPUState *cs)
|
|||
case MXL_RV32:
|
||||
return g_strdup("riscv:rv32");
|
||||
case MXL_RV64:
|
||||
case MXL_RV128:
|
||||
return g_strdup("riscv:rv64");
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
|
@ -817,6 +846,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
|
|||
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init),
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init),
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init),
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "exec/cpu-defs.h"
|
||||
#include "fpu/softfloat-types.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/int128.h"
|
||||
#include "cpu_bits.h"
|
||||
|
||||
#define TCG_GUEST_DEFAULT_MO 0
|
||||
|
@ -38,6 +39,7 @@
|
|||
#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
|
||||
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
|
||||
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
|
||||
#define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128")
|
||||
#define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex")
|
||||
#define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c")
|
||||
#define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31")
|
||||
|
@ -112,6 +114,7 @@ FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 1, 1)
|
|||
|
||||
struct CPURISCVState {
|
||||
target_ulong gpr[32];
|
||||
target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */
|
||||
uint64_t fpr[32]; /* assume both F and D extensions */
|
||||
|
||||
/* vector coprocessor state. */
|
||||
|
@ -129,6 +132,8 @@ struct CPURISCVState {
|
|||
target_ulong frm;
|
||||
|
||||
target_ulong badaddr;
|
||||
uint32_t bins;
|
||||
|
||||
target_ulong guest_phys_fault_addr;
|
||||
|
||||
target_ulong priv_ver;
|
||||
|
@ -141,6 +146,9 @@ struct CPURISCVState {
|
|||
uint32_t misa_ext; /* current extensions */
|
||||
uint32_t misa_ext_mask; /* max ext for this cpu */
|
||||
|
||||
/* 128-bit helpers upper part return value */
|
||||
target_ulong retxh;
|
||||
|
||||
uint32_t features;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
@ -190,6 +198,10 @@ struct CPURISCVState {
|
|||
target_ulong hgatp;
|
||||
uint64_t htimedelta;
|
||||
|
||||
/* Upper 64-bits of 128-bit CSRs */
|
||||
uint64_t mscratchh;
|
||||
uint64_t sscratchh;
|
||||
|
||||
/* Virtual CSRs */
|
||||
/*
|
||||
* For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
|
||||
|
@ -344,6 +356,7 @@ static inline bool riscv_feature(CPURISCVState *env, int feature)
|
|||
#include "cpu_user.h"
|
||||
|
||||
extern const char * const riscv_int_regnames[];
|
||||
extern const char * const riscv_int_regnamesh[];
|
||||
extern const char * const riscv_fpr_regnames[];
|
||||
|
||||
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async);
|
||||
|
@ -490,12 +503,23 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
|
|||
target_ulong new_value,
|
||||
target_ulong write_mask);
|
||||
|
||||
RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value,
|
||||
Int128 new_value, Int128 write_mask);
|
||||
|
||||
typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value);
|
||||
typedef RISCVException (*riscv_csr_write128_fn)(CPURISCVState *env, int csrno,
|
||||
Int128 new_value);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
riscv_csr_predicate_fn predicate;
|
||||
riscv_csr_read_fn read;
|
||||
riscv_csr_write_fn write;
|
||||
riscv_csr_op_fn op;
|
||||
riscv_csr_read128_fn read128;
|
||||
riscv_csr_write128_fn write128;
|
||||
} riscv_csr_operations;
|
||||
|
||||
/* CSR function table constants */
|
||||
|
|
|
@ -401,6 +401,7 @@
|
|||
|
||||
#define MSTATUS32_SD 0x80000000
|
||||
#define MSTATUS64_SD 0x8000000000000000ULL
|
||||
#define MSTATUSH128_SD 0x8000000000000000ULL
|
||||
|
||||
#define MISA32_MXL 0xC0000000
|
||||
#define MISA64_MXL 0xC000000000000000ULL
|
||||
|
@ -423,6 +424,8 @@ typedef enum {
|
|||
#define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */
|
||||
#define SSTATUS_MXR 0x00080000
|
||||
|
||||
#define SSTATUS64_UXL 0x0000000300000000ULL
|
||||
|
||||
#define SSTATUS32_SD 0x80000000
|
||||
#define SSTATUS64_SD 0x8000000000000000ULL
|
||||
|
||||
|
|
|
@ -998,6 +998,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
bool write_gva = false;
|
||||
uint64_t s;
|
||||
|
||||
/* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
|
||||
|
@ -1006,7 +1007,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
|
||||
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
|
||||
target_ulong deleg = async ? env->mideleg : env->medeleg;
|
||||
bool write_tval = false;
|
||||
target_ulong tval = 0;
|
||||
target_ulong htval = 0;
|
||||
target_ulong mtval2 = 0;
|
||||
|
@ -1035,9 +1035,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
case RISCV_EXCP_INST_PAGE_FAULT:
|
||||
case RISCV_EXCP_LOAD_PAGE_FAULT:
|
||||
case RISCV_EXCP_STORE_PAGE_FAULT:
|
||||
write_tval = true;
|
||||
write_gva = true;
|
||||
tval = env->badaddr;
|
||||
break;
|
||||
case RISCV_EXCP_ILLEGAL_INST:
|
||||
tval = env->bins;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1072,18 +1075,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
if (riscv_has_ext(env, RVH)) {
|
||||
target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
|
||||
|
||||
if (env->two_stage_lookup && write_tval) {
|
||||
/*
|
||||
* If we are writing a guest virtual address to stval, set
|
||||
* this to 1. If we are trapping to VS we will set this to 0
|
||||
* later.
|
||||
*/
|
||||
env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 1);
|
||||
} else {
|
||||
/* For other HS-mode traps, we set this to 0. */
|
||||
env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 0);
|
||||
}
|
||||
|
||||
if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1)) {
|
||||
/* Trap to VS mode */
|
||||
/*
|
||||
|
@ -1094,7 +1085,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
cause == IRQ_VS_EXT) {
|
||||
cause = cause - 1;
|
||||
}
|
||||
env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 0);
|
||||
write_gva = false;
|
||||
} else if (riscv_cpu_virt_enabled(env)) {
|
||||
/* Trap into HS mode, from virt */
|
||||
riscv_cpu_swap_hypervisor_regs(env);
|
||||
|
@ -1103,6 +1094,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
|
||||
riscv_cpu_virt_enabled(env));
|
||||
|
||||
|
||||
htval = env->guest_phys_fault_addr;
|
||||
|
||||
riscv_cpu_set_virt_enabled(env, 0);
|
||||
|
@ -1110,7 +1102,9 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
/* Trap into HS mode */
|
||||
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
|
||||
htval = env->guest_phys_fault_addr;
|
||||
write_gva = false;
|
||||
}
|
||||
env->hstatus = set_field(env->hstatus, HSTATUS_GVA, write_gva);
|
||||
}
|
||||
|
||||
s = env->mstatus;
|
||||
|
|
|
@ -481,7 +481,7 @@ static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS &
|
|||
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)));
|
||||
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
|
||||
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
|
||||
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS;
|
||||
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS | (target_ulong)SSTATUS64_UXL;
|
||||
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
|
||||
static const target_ulong hip_writable_mask = MIP_VSSIP;
|
||||
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
|
||||
|
@ -527,6 +527,8 @@ static uint64_t add_status_sd(RISCVMXL xl, uint64_t status)
|
|||
return status | MSTATUS32_SD;
|
||||
case MXL_RV64:
|
||||
return status | MSTATUS64_SD;
|
||||
case MXL_RV128:
|
||||
return MSTATUSH128_SD;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -576,10 +578,11 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
|
|||
|
||||
mstatus = (mstatus & ~mask) | (val & mask);
|
||||
|
||||
if (riscv_cpu_mxl(env) == MXL_RV64) {
|
||||
RISCVMXL xl = riscv_cpu_mxl(env);
|
||||
if (xl > MXL_RV32) {
|
||||
/* SXL and UXL fields are for now read only */
|
||||
mstatus = set_field(mstatus, MSTATUS64_SXL, MXL_RV64);
|
||||
mstatus = set_field(mstatus, MSTATUS64_UXL, MXL_RV64);
|
||||
mstatus = set_field(mstatus, MSTATUS64_SXL, xl);
|
||||
mstatus = set_field(mstatus, MSTATUS64_UXL, xl);
|
||||
}
|
||||
env->mstatus = mstatus;
|
||||
|
||||
|
@ -608,6 +611,20 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno,
|
|||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_mstatus_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *val)
|
||||
{
|
||||
*val = int128_make128(env->mstatus, add_status_sd(MXL_RV128, env->mstatus));
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_misa_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *val)
|
||||
{
|
||||
*val = int128_make128(env->misa_ext, (uint64_t)MXL_RV128 << 62);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_misa(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
|
@ -765,6 +782,21 @@ static RISCVException write_mcounteren(CPURISCVState *env, int csrno,
|
|||
}
|
||||
|
||||
/* Machine Trap Handling */
|
||||
static RISCVException read_mscratch_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *val)
|
||||
{
|
||||
*val = int128_make128(env->mscratch, env->mscratchh);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException write_mscratch_i128(CPURISCVState *env, int csrno,
|
||||
Int128 val)
|
||||
{
|
||||
env->mscratch = int128_getlo(val);
|
||||
env->mscratchh = int128_gethi(val);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_mscratch(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
|
@ -844,6 +876,16 @@ static RISCVException rmw_mip(CPURISCVState *env, int csrno,
|
|||
}
|
||||
|
||||
/* Supervisor Trap Setup */
|
||||
static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *val)
|
||||
{
|
||||
uint64_t mask = sstatus_v1_10_mask;
|
||||
uint64_t sstatus = env->mstatus & mask;
|
||||
|
||||
*val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus));
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_sstatus(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
|
@ -937,6 +979,21 @@ static RISCVException write_scounteren(CPURISCVState *env, int csrno,
|
|||
}
|
||||
|
||||
/* Supervisor Trap Handling */
|
||||
static RISCVException read_sscratch_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *val)
|
||||
{
|
||||
*val = int128_make128(env->sscratch, env->sscratchh);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException write_sscratch_i128(CPURISCVState *env, int csrno,
|
||||
Int128 val)
|
||||
{
|
||||
env->sscratch = int128_getlo(val);
|
||||
env->sscratchh = int128_gethi(val);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException read_sscratch(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
|
@ -1737,16 +1794,13 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
|
|||
* csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value);
|
||||
*/
|
||||
|
||||
RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value, target_ulong write_mask)
|
||||
static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
|
||||
int csrno,
|
||||
bool write_mask,
|
||||
RISCVCPU *cpu)
|
||||
{
|
||||
RISCVException ret;
|
||||
target_ulong old_value;
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
int read_only = get_field(csrno, 0xC00) == 3;
|
||||
|
||||
/* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
|
||||
int read_only = get_field(csrno, 0xC00) == 3;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int effective_priv = env->priv;
|
||||
|
||||
|
@ -1778,10 +1832,17 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
|||
if (!csr_ops[csrno].predicate) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
ret = csr_ops[csrno].predicate(env, csrno);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return csr_ops[csrno].predicate(env, csrno);
|
||||
}
|
||||
|
||||
static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value,
|
||||
target_ulong write_mask)
|
||||
{
|
||||
RISCVException ret;
|
||||
target_ulong old_value;
|
||||
|
||||
/* execute combined read/write operation if it exists */
|
||||
if (csr_ops[csrno].op) {
|
||||
|
@ -1817,6 +1878,92 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
|||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value, target_ulong write_mask)
|
||||
{
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
|
||||
RISCVException ret = riscv_csrrw_check(env, csrno, write_mask, cpu);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask);
|
||||
}
|
||||
|
||||
static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value,
|
||||
Int128 new_value,
|
||||
Int128 write_mask)
|
||||
{
|
||||
RISCVException ret;
|
||||
Int128 old_value;
|
||||
|
||||
/* read old value */
|
||||
ret = csr_ops[csrno].read128(env, csrno, &old_value);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* write value if writable and write mask set, otherwise drop writes */
|
||||
if (int128_nz(write_mask)) {
|
||||
new_value = int128_or(int128_and(old_value, int128_not(write_mask)),
|
||||
int128_and(new_value, write_mask));
|
||||
if (csr_ops[csrno].write128) {
|
||||
ret = csr_ops[csrno].write128(env, csrno, new_value);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
} else if (csr_ops[csrno].write) {
|
||||
/* avoids having to write wrappers for all registers */
|
||||
ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value));
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return old value */
|
||||
if (ret_value) {
|
||||
*ret_value = old_value;
|
||||
}
|
||||
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value,
|
||||
Int128 new_value, Int128 write_mask)
|
||||
{
|
||||
RISCVException ret;
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
|
||||
ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask), cpu);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (csr_ops[csrno].read128) {
|
||||
return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fall back to 64-bit version for now, if the 128-bit alternative isn't
|
||||
* at all defined.
|
||||
* Note, some CSRs don't need to extend to MXLEN (64 upper bits non
|
||||
* significant), for those, this fallback is correctly handling the accesses
|
||||
*/
|
||||
target_ulong old_value;
|
||||
ret = riscv_csrrw_do64(env, csrno, &old_value,
|
||||
int128_getlo(new_value),
|
||||
int128_getlo(write_mask));
|
||||
if (ret == RISCV_EXCP_NONE && ret_value) {
|
||||
*ret_value = int128_make64(old_value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugger support. If not in user mode, set env->debugger before the
|
||||
* riscv_csrrw call and clear it after the call.
|
||||
|
@ -1878,8 +2025,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
|
|||
[CSR_MHARTID] = { "mhartid", any, read_mhartid },
|
||||
|
||||
/* Machine Trap Setup */
|
||||
[CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus },
|
||||
[CSR_MISA] = { "misa", any, read_misa, write_misa },
|
||||
[CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus, NULL,
|
||||
read_mstatus_i128 },
|
||||
[CSR_MISA] = { "misa", any, read_misa, write_misa, NULL,
|
||||
read_misa_i128 },
|
||||
[CSR_MIDELEG] = { "mideleg", any, read_mideleg, write_mideleg },
|
||||
[CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg },
|
||||
[CSR_MIE] = { "mie", any, read_mie, write_mie },
|
||||
|
@ -1889,20 +2038,23 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
|
|||
[CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush },
|
||||
|
||||
/* Machine Trap Handling */
|
||||
[CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch },
|
||||
[CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, NULL,
|
||||
read_mscratch_i128, write_mscratch_i128 },
|
||||
[CSR_MEPC] = { "mepc", any, read_mepc, write_mepc },
|
||||
[CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause },
|
||||
[CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval },
|
||||
[CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip },
|
||||
|
||||
/* Supervisor Trap Setup */
|
||||
[CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus },
|
||||
[CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, NULL,
|
||||
read_sstatus_i128 },
|
||||
[CSR_SIE] = { "sie", smode, read_sie, write_sie },
|
||||
[CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
|
||||
[CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, write_scounteren },
|
||||
|
||||
/* Supervisor Trap Handling */
|
||||
[CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch },
|
||||
[CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, NULL,
|
||||
read_sscratch_i128, write_sscratch_i128 },
|
||||
[CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc },
|
||||
[CSR_SCAUSE] = { "scause", smode, read_scause, write_scause },
|
||||
[CSR_STVAL] = { "stval", smode, read_stval, write_stval },
|
||||
|
|
|
@ -280,6 +280,11 @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
|
|||
int bitsize = 16 << env->misa_mxl_max;
|
||||
int i;
|
||||
|
||||
/* Until gdb knows about 128-bit registers */
|
||||
if (bitsize > 64) {
|
||||
bitsize = 64;
|
||||
}
|
||||
|
||||
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
||||
g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">");
|
||||
g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">");
|
||||
|
|
|
@ -96,6 +96,9 @@ DEF_HELPER_FLAGS_1(fclass_h, TCG_CALL_NO_RWG_SE, tl, i64)
|
|||
DEF_HELPER_2(csrr, tl, env, int)
|
||||
DEF_HELPER_3(csrw, void, env, int, tl)
|
||||
DEF_HELPER_4(csrrw, tl, env, int, tl, tl)
|
||||
DEF_HELPER_2(csrr_i128, tl, env, int)
|
||||
DEF_HELPER_4(csrw_i128, void, env, int, tl, tl)
|
||||
DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_2(sret, tl, env, tl)
|
||||
DEF_HELPER_2(mret, tl, env, tl)
|
||||
|
@ -1101,3 +1104,9 @@ DEF_HELPER_5(vsext_vf2_d, void, ptr, ptr, ptr, env, i32)
|
|||
DEF_HELPER_5(vsext_vf4_w, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsext_vf4_d, void, ptr, ptr, ptr, env, i32)
|
||||
DEF_HELPER_5(vsext_vf8_d, void, ptr, ptr, ptr, env, i32)
|
||||
|
||||
/* 128-bit integer multiplication and division */
|
||||
DEF_HELPER_5(divu_i128, tl, env, tl, tl, tl, tl)
|
||||
DEF_HELPER_5(divs_i128, tl, env, tl, tl, tl, tl)
|
||||
DEF_HELPER_5(remu_i128, tl, env, tl, tl, tl, tl)
|
||||
DEF_HELPER_5(rems_i128, tl, env, tl, tl, tl, tl)
|
||||
|
|
|
@ -25,14 +25,17 @@
|
|||
# Immediates:
|
||||
%imm_ci 12:s1 2:5
|
||||
%nzuimm_ciw 7:4 11:2 5:1 6:1 !function=ex_shift_2
|
||||
%uimm_cl_q 10:1 5:2 11:2 !function=ex_shift_4
|
||||
%uimm_cl_d 5:2 10:3 !function=ex_shift_3
|
||||
%uimm_cl_w 5:1 10:3 6:1 !function=ex_shift_2
|
||||
%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1
|
||||
%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1
|
||||
|
||||
%shimm_6bit 12:1 2:5 !function=ex_rvc_shifti
|
||||
%uimm_6bit_lq 2:4 12:1 6:1 !function=ex_shift_4
|
||||
%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3
|
||||
%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2
|
||||
%uimm_6bit_sq 7:4 11:2 !function=ex_shift_4
|
||||
%uimm_6bit_sd 7:3 10:3 !function=ex_shift_3
|
||||
%uimm_6bit_sw 7:2 9:4 !function=ex_shift_2
|
||||
|
||||
|
@ -54,16 +57,20 @@
|
|||
# Formats 16:
|
||||
@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd
|
||||
@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd
|
||||
@cl_q ... . ..... ..... .. &i imm=%uimm_cl_q rs1=%rs1_3 rd=%rs2_3
|
||||
@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
|
||||
@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
|
||||
@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3
|
||||
@cs_q ... ... ... .. ... .. &s imm=%uimm_cl_q rs1=%rs1_3 rs2=%rs2_3
|
||||
@cs_d ... ... ... .. ... .. &s imm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
|
||||
@cs_w ... ... ... .. ... .. &s imm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
|
||||
@cj ... ........... .. &j imm=%imm_cj
|
||||
@cb_z ... ... ... .. ... .. &b imm=%imm_cb rs1=%rs1_3 rs2=0
|
||||
|
||||
@c_lqsp ... . ..... ..... .. &i imm=%uimm_6bit_lq rs1=2 %rd
|
||||
@c_ldsp ... . ..... ..... .. &i imm=%uimm_6bit_ld rs1=2 %rd
|
||||
@c_lwsp ... . ..... ..... .. &i imm=%uimm_6bit_lw rs1=2 %rd
|
||||
@c_sqsp ... . ..... ..... .. &s imm=%uimm_6bit_sq rs1=2 rs2=%rs2_5
|
||||
@c_sdsp ... . ..... ..... .. &s imm=%uimm_6bit_sd rs1=2 rs2=%rs2_5
|
||||
@c_swsp ... . ..... ..... .. &s imm=%uimm_6bit_sw rs1=2 rs2=%rs2_5
|
||||
@c_li ... . ..... ..... .. &i imm=%imm_ci rs1=0 %rd
|
||||
|
@ -87,9 +94,15 @@
|
|||
illegal 000 000 000 00 --- 00
|
||||
addi 000 ... ... .. ... 00 @c_addi4spn
|
||||
}
|
||||
fld 001 ... ... .. ... 00 @cl_d
|
||||
{
|
||||
lq 001 ... ... .. ... 00 @cl_q
|
||||
fld 001 ... ... .. ... 00 @cl_d
|
||||
}
|
||||
lw 010 ... ... .. ... 00 @cl_w
|
||||
fsd 101 ... ... .. ... 00 @cs_d
|
||||
{
|
||||
sq 101 ... ... .. ... 00 @cs_q
|
||||
fsd 101 ... ... .. ... 00 @cs_d
|
||||
}
|
||||
sw 110 ... ... .. ... 00 @cs_w
|
||||
|
||||
# *** RV32C and RV64C specific Standard Extension (Quadrant 0) ***
|
||||
|
@ -132,7 +145,10 @@ addw 100 1 11 ... 01 ... 01 @cs_2
|
|||
|
||||
# *** RV32/64C Standard Extension (Quadrant 2) ***
|
||||
slli 000 . ..... ..... 10 @c_shift2
|
||||
fld 001 . ..... ..... 10 @c_ldsp
|
||||
{
|
||||
lq 001 ... ... .. ... 10 @c_lqsp
|
||||
fld 001 . ..... ..... 10 @c_ldsp
|
||||
}
|
||||
{
|
||||
illegal 010 - 00000 ----- 10 # c.lwsp, RES rd=0
|
||||
lw 010 . ..... ..... 10 @c_lwsp
|
||||
|
@ -147,7 +163,10 @@ fld 001 . ..... ..... 10 @c_ldsp
|
|||
jalr 100 1 ..... 00000 10 @c_jalr rd=1 # C.JALR
|
||||
add 100 1 ..... ..... 10 @cr
|
||||
}
|
||||
fsd 101 ...... ..... 10 @c_sdsp
|
||||
{
|
||||
sq 101 ... ... .. ... 10 @c_sqsp
|
||||
fsd 101 ...... ..... 10 @c_sdsp
|
||||
}
|
||||
sw 110 . ..... ..... 10 @c_swsp
|
||||
|
||||
# *** RV32C and RV64C specific Standard Extension (Quadrant 2) ***
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
%rs1 15:5
|
||||
%rd 7:5
|
||||
%sh5 20:5
|
||||
%sh6 20:6
|
||||
|
||||
%sh7 20:7
|
||||
%csr 20:12
|
||||
|
@ -91,6 +92,9 @@
|
|||
# Formats 64:
|
||||
@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
|
||||
|
||||
# Formats 128:
|
||||
@sh6 ...... ...... ..... ... ..... ....... &shift shamt=%sh6 %rs1 %rd
|
||||
|
||||
# *** Privileged Instructions ***
|
||||
ecall 000000000000 00000 000 00000 1110011
|
||||
ebreak 000000000001 00000 000 00000 1110011
|
||||
|
@ -162,6 +166,20 @@ sllw 0000000 ..... ..... 001 ..... 0111011 @r
|
|||
srlw 0000000 ..... ..... 101 ..... 0111011 @r
|
||||
sraw 0100000 ..... ..... 101 ..... 0111011 @r
|
||||
|
||||
# *** RV128I Base Instruction Set (in addition to RV64I) ***
|
||||
ldu ............ ..... 111 ..... 0000011 @i
|
||||
lq ............ ..... 010 ..... 0001111 @i
|
||||
sq ............ ..... 100 ..... 0100011 @s
|
||||
addid ............ ..... 000 ..... 1011011 @i
|
||||
sllid 000000 ...... ..... 001 ..... 1011011 @sh6
|
||||
srlid 000000 ...... ..... 101 ..... 1011011 @sh6
|
||||
sraid 010000 ...... ..... 101 ..... 1011011 @sh6
|
||||
addd 0000000 ..... ..... 000 ..... 1111011 @r
|
||||
subd 0100000 ..... ..... 000 ..... 1111011 @r
|
||||
slld 0000000 ..... ..... 001 ..... 1111011 @r
|
||||
srld 0000000 ..... ..... 101 ..... 1111011 @r
|
||||
srad 0100000 ..... ..... 101 ..... 1111011 @r
|
||||
|
||||
# *** RV32M Standard Extension ***
|
||||
mul 0000001 ..... ..... 000 ..... 0110011 @r
|
||||
mulh 0000001 ..... ..... 001 ..... 0110011 @r
|
||||
|
@ -179,6 +197,13 @@ divuw 0000001 ..... ..... 101 ..... 0111011 @r
|
|||
remw 0000001 ..... ..... 110 ..... 0111011 @r
|
||||
remuw 0000001 ..... ..... 111 ..... 0111011 @r
|
||||
|
||||
# *** RV128M Standard Extension (in addition to RV64M) ***
|
||||
muld 0000001 ..... ..... 000 ..... 1111011 @r
|
||||
divd 0000001 ..... ..... 100 ..... 1111011 @r
|
||||
divud 0000001 ..... ..... 101 ..... 1111011 @r
|
||||
remd 0000001 ..... ..... 110 ..... 1111011 @r
|
||||
remud 0000001 ..... ..... 111 ..... 1111011 @r
|
||||
|
||||
# *** RV32A Standard Extension ***
|
||||
lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld
|
||||
sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
|
|
|
@ -162,65 +162,65 @@ static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
|
|||
static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
|
||||
return gen_lr(ctx, a, MO_ALIGN | MO_TEUQ);
|
||||
}
|
||||
|
||||
static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
|
||||
return gen_sc(ctx, a, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
||||
static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEUQ));
|
||||
}
|
||||
|
|
|
@ -86,43 +86,43 @@ static bool trans_cpop(DisasContext *ctx, arg_cpop *a)
|
|||
static bool trans_andn(DisasContext *ctx, arg_andn *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_andc_tl);
|
||||
return gen_logic(ctx, a, tcg_gen_andc_tl);
|
||||
}
|
||||
|
||||
static bool trans_orn(DisasContext *ctx, arg_orn *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_orc_tl);
|
||||
return gen_logic(ctx, a, tcg_gen_orc_tl);
|
||||
}
|
||||
|
||||
static bool trans_xnor(DisasContext *ctx, arg_xnor *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_eqv_tl);
|
||||
return gen_logic(ctx, a, tcg_gen_eqv_tl);
|
||||
}
|
||||
|
||||
static bool trans_min(DisasContext *ctx, arg_min *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smin_tl);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smin_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_max(DisasContext *ctx, arg_max *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smax_tl);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smax_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_minu(DisasContext *ctx, arg_minu *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umin_tl);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umin_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_maxu(DisasContext *ctx, arg_maxu *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umax_tl);
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umax_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_sext_b(DisasContext *ctx, arg_sext_b *a)
|
||||
|
@ -156,7 +156,7 @@ static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
|
|||
static bool trans_bset(DisasContext *ctx, arg_bset *a)
|
||||
{
|
||||
REQUIRE_ZBS(ctx);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_bset);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_bset, NULL);
|
||||
}
|
||||
|
||||
static bool trans_bseti(DisasContext *ctx, arg_bseti *a)
|
||||
|
@ -178,7 +178,7 @@ static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
|
|||
static bool trans_bclr(DisasContext *ctx, arg_bclr *a)
|
||||
{
|
||||
REQUIRE_ZBS(ctx);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_bclr);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_bclr, NULL);
|
||||
}
|
||||
|
||||
static bool trans_bclri(DisasContext *ctx, arg_bclri *a)
|
||||
|
@ -200,7 +200,7 @@ static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
|
|||
static bool trans_binv(DisasContext *ctx, arg_binv *a)
|
||||
{
|
||||
REQUIRE_ZBS(ctx);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_binv);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_binv, NULL);
|
||||
}
|
||||
|
||||
static bool trans_binvi(DisasContext *ctx, arg_binvi *a)
|
||||
|
@ -218,7 +218,7 @@ static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
|
|||
static bool trans_bext(DisasContext *ctx, arg_bext *a)
|
||||
{
|
||||
REQUIRE_ZBS(ctx);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_bext);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_bext, NULL);
|
||||
}
|
||||
|
||||
static bool trans_bexti(DisasContext *ctx, arg_bexti *a)
|
||||
|
@ -248,7 +248,7 @@ static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
|
|||
static bool trans_ror(DisasContext *ctx, arg_ror *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotr_tl, gen_rorw);
|
||||
return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotr_tl, gen_rorw, NULL);
|
||||
}
|
||||
|
||||
static void gen_roriw(TCGv ret, TCGv arg1, target_long shamt)
|
||||
|
@ -266,7 +266,7 @@ static bool trans_rori(DisasContext *ctx, arg_rori *a)
|
|||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
|
||||
tcg_gen_rotri_tl, gen_roriw);
|
||||
tcg_gen_rotri_tl, gen_roriw, NULL);
|
||||
}
|
||||
|
||||
static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
|
@ -290,7 +290,7 @@ static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
|
|||
static bool trans_rol(DisasContext *ctx, arg_rol *a)
|
||||
{
|
||||
REQUIRE_ZBB(ctx);
|
||||
return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotl_tl, gen_rolw);
|
||||
return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotl_tl, gen_rolw, NULL);
|
||||
}
|
||||
|
||||
static void gen_rev8_32(TCGv ret, TCGv src1)
|
||||
|
@ -357,7 +357,7 @@ GEN_SHADD(3)
|
|||
static bool trans_sh##SHAMT##add(DisasContext *ctx, arg_sh##SHAMT##add *a) \
|
||||
{ \
|
||||
REQUIRE_ZBA(ctx); \
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add); \
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add, NULL); \
|
||||
}
|
||||
|
||||
GEN_TRANS_SHADD(1)
|
||||
|
@ -405,7 +405,7 @@ static bool trans_rorw(DisasContext *ctx, arg_rorw *a)
|
|||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_ZBB(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_rorw);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_rorw, NULL);
|
||||
}
|
||||
|
||||
static bool trans_roriw(DisasContext *ctx, arg_roriw *a)
|
||||
|
@ -413,7 +413,7 @@ static bool trans_roriw(DisasContext *ctx, arg_roriw *a)
|
|||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_ZBB(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw, NULL);
|
||||
}
|
||||
|
||||
static bool trans_rolw(DisasContext *ctx, arg_rolw *a)
|
||||
|
@ -421,7 +421,7 @@ static bool trans_rolw(DisasContext *ctx, arg_rolw *a)
|
|||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_ZBB(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_rolw);
|
||||
return gen_shift(ctx, a, EXT_NONE, gen_rolw, NULL);
|
||||
}
|
||||
|
||||
#define GEN_SHADD_UW(SHAMT) \
|
||||
|
@ -447,7 +447,7 @@ static bool trans_sh##SHAMT##add_uw(DisasContext *ctx, \
|
|||
{ \
|
||||
REQUIRE_64BIT(ctx); \
|
||||
REQUIRE_ZBA(ctx); \
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add_uw); \
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add_uw, NULL); \
|
||||
}
|
||||
|
||||
GEN_TRANS_SHADD_UW(1)
|
||||
|
@ -466,7 +466,7 @@ static bool trans_add_uw(DisasContext *ctx, arg_add_uw *a)
|
|||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_ZBA(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_add_uw);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_add_uw, NULL);
|
||||
}
|
||||
|
||||
static void gen_slli_uw(TCGv dest, TCGv src, target_long shamt)
|
||||
|
@ -478,13 +478,13 @@ static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a)
|
|||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_ZBA(ctx);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_slli_uw);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_slli_uw, NULL);
|
||||
}
|
||||
|
||||
static bool trans_clmul(DisasContext *ctx, arg_clmul *a)
|
||||
{
|
||||
REQUIRE_ZBC(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_helper_clmul);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_helper_clmul, NULL);
|
||||
}
|
||||
|
||||
static void gen_clmulh(TCGv dst, TCGv src1, TCGv src2)
|
||||
|
@ -496,11 +496,11 @@ static void gen_clmulh(TCGv dst, TCGv src1, TCGv src2)
|
|||
static bool trans_clmulh(DisasContext *ctx, arg_clmulr *a)
|
||||
{
|
||||
REQUIRE_ZBC(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_clmulh);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_clmulh, NULL);
|
||||
}
|
||||
|
||||
static bool trans_clmulr(DisasContext *ctx, arg_clmulh *a)
|
||||
{
|
||||
REQUIRE_ZBC(ctx);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_helper_clmulr);
|
||||
return gen_arith(ctx, a, EXT_NONE, gen_helper_clmulr, NULL);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a)
|
|||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
|
@ -54,7 +54,7 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
|
|||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -121,14 +121,14 @@ static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
|
|||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVH);
|
||||
return do_hlv(ctx, a, MO_TEQ);
|
||||
return do_hlv(ctx, a, MO_TEUQ);
|
||||
}
|
||||
|
||||
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);
|
||||
return do_hsv(ctx, a, MO_TEUQ);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
|
|
@ -26,14 +26,14 @@ static bool trans_illegal(DisasContext *ctx, arg_empty *a)
|
|||
|
||||
static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return trans_illegal(ctx, a);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
return trans_illegal(ctx, a);
|
||||
}
|
||||
|
||||
static bool trans_lui(DisasContext *ctx, arg_lui *a)
|
||||
{
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm);
|
||||
gen_set_gpri(ctx, a->rd, a->imm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ static bool trans_lui(DisasContext *ctx, arg_lui *a)
|
|||
static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
|
||||
{
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next);
|
||||
gen_set_gpri(ctx, a->rd, a->imm + ctx->base.pc_next);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -82,13 +82,103 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
|
|||
return true;
|
||||
}
|
||||
|
||||
static TCGCond gen_compare_i128(bool bz, TCGv rl,
|
||||
TCGv al, TCGv ah, TCGv bl, TCGv bh,
|
||||
TCGCond cond)
|
||||
{
|
||||
TCGv rh = tcg_temp_new();
|
||||
bool invert = false;
|
||||
|
||||
switch (cond) {
|
||||
case TCG_COND_EQ:
|
||||
case TCG_COND_NE:
|
||||
if (bz) {
|
||||
tcg_gen_or_tl(rl, al, ah);
|
||||
} else {
|
||||
tcg_gen_xor_tl(rl, al, bl);
|
||||
tcg_gen_xor_tl(rh, ah, bh);
|
||||
tcg_gen_or_tl(rl, rl, rh);
|
||||
}
|
||||
break;
|
||||
|
||||
case TCG_COND_GE:
|
||||
case TCG_COND_LT:
|
||||
if (bz) {
|
||||
tcg_gen_mov_tl(rl, ah);
|
||||
} else {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
|
||||
tcg_gen_sub2_tl(rl, rh, al, ah, bl, bh);
|
||||
tcg_gen_xor_tl(rl, rh, ah);
|
||||
tcg_gen_xor_tl(tmp, ah, bh);
|
||||
tcg_gen_and_tl(rl, rl, tmp);
|
||||
tcg_gen_xor_tl(rl, rh, rl);
|
||||
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
case TCG_COND_LTU:
|
||||
invert = true;
|
||||
/* fallthrough */
|
||||
case TCG_COND_GEU:
|
||||
{
|
||||
TCGv tmp = tcg_temp_new();
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
TCGv one = tcg_constant_tl(1);
|
||||
|
||||
cond = TCG_COND_NE;
|
||||
/* borrow in to second word */
|
||||
tcg_gen_setcond_tl(TCG_COND_LTU, tmp, al, bl);
|
||||
/* seed third word with 1, which will be result */
|
||||
tcg_gen_sub2_tl(tmp, rh, ah, one, tmp, zero);
|
||||
tcg_gen_sub2_tl(tmp, rl, tmp, rh, bh, zero);
|
||||
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
cond = tcg_invert_cond(cond);
|
||||
}
|
||||
|
||||
tcg_temp_free(rh);
|
||||
return cond;
|
||||
}
|
||||
|
||||
static void gen_setcond_i128(TCGv rl, TCGv rh,
|
||||
TCGv src1l, TCGv src1h,
|
||||
TCGv src2l, TCGv src2h,
|
||||
TCGCond cond)
|
||||
{
|
||||
cond = gen_compare_i128(false, rl, src1l, src1h, src2l, src2h, cond);
|
||||
tcg_gen_setcondi_tl(cond, rl, rl, 0);
|
||||
tcg_gen_movi_tl(rh, 0);
|
||||
}
|
||||
|
||||
static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
|
||||
{
|
||||
TCGLabel *l = gen_new_label();
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_SIGN);
|
||||
TCGv src2 = get_gpr(ctx, a->rs2, EXT_SIGN);
|
||||
|
||||
tcg_gen_brcond_tl(cond, src1, src2, l);
|
||||
if (get_xl(ctx) == MXL_RV128) {
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv src2h = get_gprh(ctx, a->rs2);
|
||||
TCGv tmp = tcg_temp_new();
|
||||
|
||||
cond = gen_compare_i128(a->rs2 == 0,
|
||||
tmp, src1, src1h, src2, src2h, cond);
|
||||
tcg_gen_brcondi_tl(cond, tmp, 0, l);
|
||||
|
||||
tcg_temp_free(tmp);
|
||||
} else {
|
||||
tcg_gen_brcond_tl(cond, src1, src2, l);
|
||||
}
|
||||
gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
|
||||
|
||||
gen_set_label(l); /* branch taken */
|
||||
|
@ -134,7 +224,7 @@ static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
|
|||
return gen_branch(ctx, a, TCG_COND_GEU);
|
||||
}
|
||||
|
||||
static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
static bool gen_load_tl(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
|
@ -151,6 +241,45 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Compute only 64-bit addresses to use the address translation mechanism */
|
||||
static bool gen_load_i128(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
{
|
||||
TCGv src1l = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv destl = dest_gpr(ctx, a->rd);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
TCGv addrl = tcg_temp_new();
|
||||
|
||||
tcg_gen_addi_tl(addrl, src1l, a->imm);
|
||||
|
||||
if ((memop & MO_SIZE) <= MO_64) {
|
||||
tcg_gen_qemu_ld_tl(destl, addrl, ctx->mem_idx, memop);
|
||||
if (memop & MO_SIGN) {
|
||||
tcg_gen_sari_tl(desth, destl, 63);
|
||||
} else {
|
||||
tcg_gen_movi_tl(desth, 0);
|
||||
}
|
||||
} else {
|
||||
/* assume little-endian memory access for now */
|
||||
tcg_gen_qemu_ld_tl(destl, addrl, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_gen_addi_tl(addrl, addrl, 8);
|
||||
tcg_gen_qemu_ld_tl(desth, addrl, ctx->mem_idx, MO_TEUQ);
|
||||
}
|
||||
|
||||
gen_set_gpr128(ctx, a->rd, destl, desth);
|
||||
|
||||
tcg_temp_free(addrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
{
|
||||
if (get_xl(ctx) == MXL_RV128) {
|
||||
return gen_load_i128(ctx, a, memop);
|
||||
} else {
|
||||
return gen_load_tl(ctx, a, memop);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_lb(DisasContext *ctx, arg_lb *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_SB);
|
||||
|
@ -166,6 +295,18 @@ static bool trans_lw(DisasContext *ctx, arg_lw *a)
|
|||
return gen_load(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
static bool trans_ld(DisasContext *ctx, arg_ld *a)
|
||||
{
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
return gen_load(ctx, a, MO_TESQ);
|
||||
}
|
||||
|
||||
static bool trans_lq(DisasContext *ctx, arg_lq *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
return gen_load(ctx, a, MO_TEUO);
|
||||
}
|
||||
|
||||
static bool trans_lbu(DisasContext *ctx, arg_lbu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_UB);
|
||||
|
@ -176,7 +317,19 @@ static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
|
|||
return gen_load(ctx, a, MO_TEUW);
|
||||
}
|
||||
|
||||
static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
|
||||
static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
|
||||
{
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
return gen_load(ctx, a, MO_TEUL);
|
||||
}
|
||||
|
||||
static bool trans_ldu(DisasContext *ctx, arg_ldu *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
return gen_load(ctx, a, MO_TEUQ);
|
||||
}
|
||||
|
||||
static bool gen_store_tl(DisasContext *ctx, arg_sb *a, MemOp memop)
|
||||
{
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
|
@ -192,6 +345,37 @@ static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop)
|
||||
{
|
||||
TCGv src1l = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv src2l = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
TCGv src2h = get_gprh(ctx, a->rs2);
|
||||
TCGv addrl = tcg_temp_new();
|
||||
|
||||
tcg_gen_addi_tl(addrl, src1l, a->imm);
|
||||
|
||||
if ((memop & MO_SIZE) <= MO_64) {
|
||||
tcg_gen_qemu_st_tl(src2l, addrl, ctx->mem_idx, memop);
|
||||
} else {
|
||||
/* little-endian memory access assumed for now */
|
||||
tcg_gen_qemu_st_tl(src2l, addrl, ctx->mem_idx, MO_TEUQ);
|
||||
tcg_gen_addi_tl(addrl, addrl, 8);
|
||||
tcg_gen_qemu_st_tl(src2h, addrl, ctx->mem_idx, MO_TEUQ);
|
||||
}
|
||||
|
||||
tcg_temp_free(addrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
|
||||
{
|
||||
if (get_xl(ctx) == MXL_RV128) {
|
||||
return gen_store_i128(ctx, a, memop);
|
||||
} else {
|
||||
return gen_store_tl(ctx, a, memop);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_sb(DisasContext *ctx, arg_sb *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_SB);
|
||||
|
@ -207,27 +391,50 @@ static bool trans_sw(DisasContext *ctx, arg_sw *a)
|
|||
return gen_store(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_load(ctx, a, MO_TEUL);
|
||||
}
|
||||
|
||||
static bool trans_ld(DisasContext *ctx, arg_ld *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_load(ctx, a, MO_TEQ);
|
||||
}
|
||||
|
||||
static bool trans_sd(DisasContext *ctx, arg_sd *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
return gen_store(ctx, a, MO_TEQ);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
return gen_store(ctx, a, MO_TEUQ);
|
||||
}
|
||||
|
||||
static bool trans_sq(DisasContext *ctx, arg_sq *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
return gen_store(ctx, a, MO_TEUO);
|
||||
}
|
||||
|
||||
static bool trans_addd(DisasContext *ctx, arg_addd *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_addid(DisasContext *ctx, arg_addid *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_subd(DisasContext *ctx, arg_subd *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl, NULL);
|
||||
}
|
||||
|
||||
static void gen_addi2_i128(TCGv retl, TCGv reth,
|
||||
TCGv srcl, TCGv srch, target_long imm)
|
||||
{
|
||||
TCGv imml = tcg_constant_tl(imm);
|
||||
TCGv immh = tcg_constant_tl(-(imm < 0));
|
||||
tcg_gen_add2_tl(retl, reth, srcl, srch, imml, immh);
|
||||
}
|
||||
|
||||
static bool trans_addi(DisasContext *ctx, arg_addi *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl, gen_addi2_i128);
|
||||
}
|
||||
|
||||
static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
|
||||
|
@ -235,39 +442,64 @@ static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
|
|||
tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2);
|
||||
}
|
||||
|
||||
static void gen_slt_i128(TCGv retl, TCGv reth,
|
||||
TCGv s1l, TCGv s1h, TCGv s2l, TCGv s2h)
|
||||
{
|
||||
gen_setcond_i128(retl, reth, s1l, s1h, s2l, s2h, TCG_COND_LT);
|
||||
}
|
||||
|
||||
static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2);
|
||||
}
|
||||
|
||||
static void gen_sltu_i128(TCGv retl, TCGv reth,
|
||||
TCGv s1l, TCGv s1h, TCGv s2l, TCGv s2h)
|
||||
{
|
||||
gen_setcond_i128(retl, reth, s1l, s1h, s2l, s2h, TCG_COND_LTU);
|
||||
}
|
||||
|
||||
static bool trans_slti(DisasContext *ctx, arg_slti *a)
|
||||
{
|
||||
return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_slt);
|
||||
return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_slt, gen_slt_i128);
|
||||
}
|
||||
|
||||
static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
|
||||
{
|
||||
return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_sltu);
|
||||
return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_sltu, gen_sltu_i128);
|
||||
}
|
||||
|
||||
static bool trans_xori(DisasContext *ctx, arg_xori *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_xori_tl);
|
||||
return gen_logic_imm_fn(ctx, a, tcg_gen_xori_tl);
|
||||
}
|
||||
|
||||
static bool trans_ori(DisasContext *ctx, arg_ori *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_ori_tl);
|
||||
return gen_logic_imm_fn(ctx, a, tcg_gen_ori_tl);
|
||||
}
|
||||
|
||||
static bool trans_andi(DisasContext *ctx, arg_andi *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_andi_tl);
|
||||
return gen_logic_imm_fn(ctx, a, tcg_gen_andi_tl);
|
||||
}
|
||||
|
||||
static void gen_slli_i128(TCGv retl, TCGv reth,
|
||||
TCGv src1l, TCGv src1h,
|
||||
target_long shamt)
|
||||
{
|
||||
if (shamt >= 64) {
|
||||
tcg_gen_shli_tl(reth, src1l, shamt - 64);
|
||||
tcg_gen_movi_tl(retl, 0);
|
||||
} else {
|
||||
tcg_gen_extract2_tl(reth, src1l, src1h, 64 - shamt);
|
||||
tcg_gen_shli_tl(retl, src1l, shamt);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_slli(DisasContext *ctx, arg_slli *a)
|
||||
{
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl, gen_slli_i128);
|
||||
}
|
||||
|
||||
static void gen_srliw(TCGv dst, TCGv src, target_long shamt)
|
||||
|
@ -275,10 +507,23 @@ static void gen_srliw(TCGv dst, TCGv src, target_long shamt)
|
|||
tcg_gen_extract_tl(dst, src, shamt, 32 - shamt);
|
||||
}
|
||||
|
||||
static void gen_srli_i128(TCGv retl, TCGv reth,
|
||||
TCGv src1l, TCGv src1h,
|
||||
target_long shamt)
|
||||
{
|
||||
if (shamt >= 64) {
|
||||
tcg_gen_shri_tl(retl, src1h, shamt - 64);
|
||||
tcg_gen_movi_tl(reth, 0);
|
||||
} else {
|
||||
tcg_gen_extract2_tl(retl, src1l, src1h, shamt);
|
||||
tcg_gen_shri_tl(reth, src1h, shamt);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_srli(DisasContext *ctx, arg_srli *a)
|
||||
{
|
||||
return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
|
||||
tcg_gen_shri_tl, gen_srliw);
|
||||
tcg_gen_shri_tl, gen_srliw, gen_srli_i128);
|
||||
}
|
||||
|
||||
static void gen_sraiw(TCGv dst, TCGv src, target_long shamt)
|
||||
|
@ -286,125 +531,287 @@ static void gen_sraiw(TCGv dst, TCGv src, target_long shamt)
|
|||
tcg_gen_sextract_tl(dst, src, shamt, 32 - shamt);
|
||||
}
|
||||
|
||||
static void gen_srai_i128(TCGv retl, TCGv reth,
|
||||
TCGv src1l, TCGv src1h,
|
||||
target_long shamt)
|
||||
{
|
||||
if (shamt >= 64) {
|
||||
tcg_gen_sari_tl(retl, src1h, shamt - 64);
|
||||
tcg_gen_sari_tl(reth, src1h, 63);
|
||||
} else {
|
||||
tcg_gen_extract2_tl(retl, src1l, src1h, shamt);
|
||||
tcg_gen_sari_tl(reth, src1h, shamt);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_srai(DisasContext *ctx, arg_srai *a)
|
||||
{
|
||||
return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
|
||||
tcg_gen_sari_tl, gen_sraiw);
|
||||
tcg_gen_sari_tl, gen_sraiw, gen_srai_i128);
|
||||
}
|
||||
|
||||
static bool trans_add(DisasContext *ctx, arg_add *a)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl, tcg_gen_add2_tl);
|
||||
}
|
||||
|
||||
static bool trans_sub(DisasContext *ctx, arg_sub *a)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl, tcg_gen_sub2_tl);
|
||||
}
|
||||
|
||||
static void gen_sll_i128(TCGv destl, TCGv desth,
|
||||
TCGv src1l, TCGv src1h, TCGv shamt)
|
||||
{
|
||||
TCGv ls = tcg_temp_new();
|
||||
TCGv rs = tcg_temp_new();
|
||||
TCGv hs = tcg_temp_new();
|
||||
TCGv ll = tcg_temp_new();
|
||||
TCGv lr = tcg_temp_new();
|
||||
TCGv h0 = tcg_temp_new();
|
||||
TCGv h1 = tcg_temp_new();
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
|
||||
tcg_gen_andi_tl(hs, shamt, 64);
|
||||
tcg_gen_andi_tl(ls, shamt, 63);
|
||||
tcg_gen_neg_tl(shamt, shamt);
|
||||
tcg_gen_andi_tl(rs, shamt, 63);
|
||||
|
||||
tcg_gen_shl_tl(ll, src1l, ls);
|
||||
tcg_gen_shl_tl(h0, src1h, ls);
|
||||
tcg_gen_shr_tl(lr, src1l, rs);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, lr, shamt, zero, lr, zero);
|
||||
tcg_gen_or_tl(h1, h0, lr);
|
||||
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, destl, hs, zero, zero, ll);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, desth, hs, zero, ll, h1);
|
||||
|
||||
tcg_temp_free(ls);
|
||||
tcg_temp_free(rs);
|
||||
tcg_temp_free(hs);
|
||||
tcg_temp_free(ll);
|
||||
tcg_temp_free(lr);
|
||||
tcg_temp_free(h0);
|
||||
tcg_temp_free(h1);
|
||||
}
|
||||
|
||||
static bool trans_sll(DisasContext *ctx, arg_sll *a)
|
||||
{
|
||||
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
|
||||
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl, gen_sll_i128);
|
||||
}
|
||||
|
||||
static bool trans_slt(DisasContext *ctx, arg_slt *a)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_slt);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_slt, gen_slt_i128);
|
||||
}
|
||||
|
||||
static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_sltu);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_sltu, gen_sltu_i128);
|
||||
}
|
||||
|
||||
static bool trans_xor(DisasContext *ctx, arg_xor *a)
|
||||
static void gen_srl_i128(TCGv destl, TCGv desth,
|
||||
TCGv src1l, TCGv src1h, TCGv shamt)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_xor_tl);
|
||||
TCGv ls = tcg_temp_new();
|
||||
TCGv rs = tcg_temp_new();
|
||||
TCGv hs = tcg_temp_new();
|
||||
TCGv ll = tcg_temp_new();
|
||||
TCGv lr = tcg_temp_new();
|
||||
TCGv h0 = tcg_temp_new();
|
||||
TCGv h1 = tcg_temp_new();
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
|
||||
tcg_gen_andi_tl(hs, shamt, 64);
|
||||
tcg_gen_andi_tl(rs, shamt, 63);
|
||||
tcg_gen_neg_tl(shamt, shamt);
|
||||
tcg_gen_andi_tl(ls, shamt, 63);
|
||||
|
||||
tcg_gen_shr_tl(lr, src1l, rs);
|
||||
tcg_gen_shr_tl(h1, src1h, rs);
|
||||
tcg_gen_shl_tl(ll, src1h, ls);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, ll, shamt, zero, ll, zero);
|
||||
tcg_gen_or_tl(h0, ll, lr);
|
||||
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, destl, hs, zero, h1, h0);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, desth, hs, zero, zero, h1);
|
||||
|
||||
tcg_temp_free(ls);
|
||||
tcg_temp_free(rs);
|
||||
tcg_temp_free(hs);
|
||||
tcg_temp_free(ll);
|
||||
tcg_temp_free(lr);
|
||||
tcg_temp_free(h0);
|
||||
tcg_temp_free(h1);
|
||||
}
|
||||
|
||||
static bool trans_srl(DisasContext *ctx, arg_srl *a)
|
||||
{
|
||||
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
|
||||
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl, gen_srl_i128);
|
||||
}
|
||||
|
||||
static void gen_sra_i128(TCGv destl, TCGv desth,
|
||||
TCGv src1l, TCGv src1h, TCGv shamt)
|
||||
{
|
||||
TCGv ls = tcg_temp_new();
|
||||
TCGv rs = tcg_temp_new();
|
||||
TCGv hs = tcg_temp_new();
|
||||
TCGv ll = tcg_temp_new();
|
||||
TCGv lr = tcg_temp_new();
|
||||
TCGv h0 = tcg_temp_new();
|
||||
TCGv h1 = tcg_temp_new();
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
|
||||
tcg_gen_andi_tl(hs, shamt, 64);
|
||||
tcg_gen_andi_tl(rs, shamt, 63);
|
||||
tcg_gen_neg_tl(shamt, shamt);
|
||||
tcg_gen_andi_tl(ls, shamt, 63);
|
||||
|
||||
tcg_gen_shr_tl(lr, src1l, rs);
|
||||
tcg_gen_sar_tl(h1, src1h, rs);
|
||||
tcg_gen_shl_tl(ll, src1h, ls);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, ll, shamt, zero, ll, zero);
|
||||
tcg_gen_or_tl(h0, ll, lr);
|
||||
tcg_gen_sari_tl(lr, src1h, 63);
|
||||
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, destl, hs, zero, h1, h0);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, desth, hs, zero, lr, h1);
|
||||
|
||||
tcg_temp_free(ls);
|
||||
tcg_temp_free(rs);
|
||||
tcg_temp_free(hs);
|
||||
tcg_temp_free(ll);
|
||||
tcg_temp_free(lr);
|
||||
tcg_temp_free(h0);
|
||||
tcg_temp_free(h1);
|
||||
}
|
||||
|
||||
static bool trans_sra(DisasContext *ctx, arg_sra *a)
|
||||
{
|
||||
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
|
||||
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl, gen_sra_i128);
|
||||
}
|
||||
|
||||
static bool trans_xor(DisasContext *ctx, arg_xor *a)
|
||||
{
|
||||
return gen_logic(ctx, a, tcg_gen_xor_tl);
|
||||
}
|
||||
|
||||
static bool trans_or(DisasContext *ctx, arg_or *a)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_or_tl);
|
||||
return gen_logic(ctx, a, tcg_gen_or_tl);
|
||||
}
|
||||
|
||||
static bool trans_and(DisasContext *ctx, arg_and *a)
|
||||
{
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_and_tl);
|
||||
return gen_logic(ctx, a, tcg_gen_and_tl);
|
||||
}
|
||||
|
||||
static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
|
||||
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_srliw);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_srliw, NULL);
|
||||
}
|
||||
|
||||
static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_sraiw);
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_sraiw, NULL);
|
||||
}
|
||||
|
||||
static bool trans_sllid(DisasContext *ctx, arg_sllid *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_srlid(DisasContext *ctx, arg_srlid *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shri_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_sraid(DisasContext *ctx, arg_sraid *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_sari_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_addw(DisasContext *ctx, arg_addw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_subw(DisasContext *ctx, arg_subw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
|
||||
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
|
||||
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
|
||||
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_slld(DisasContext *ctx, arg_slld *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_srld(DisasContext *ctx, arg_srld *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_srad(DisasContext *ctx, arg_srad *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl, NULL);
|
||||
}
|
||||
|
||||
|
||||
static bool trans_fence(DisasContext *ctx, arg_fence *a)
|
||||
{
|
||||
/* FENCE is a full memory barrier. */
|
||||
|
@ -474,20 +881,78 @@ static bool do_csrrw(DisasContext *ctx, int rd, int rc, TCGv src, TCGv mask)
|
|||
return do_csr_post(ctx);
|
||||
}
|
||||
|
||||
static bool do_csrr_i128(DisasContext *ctx, int rd, int rc)
|
||||
{
|
||||
TCGv destl = dest_gpr(ctx, rd);
|
||||
TCGv desth = dest_gprh(ctx, rd);
|
||||
TCGv_i32 csr = tcg_constant_i32(rc);
|
||||
|
||||
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_csrr_i128(destl, cpu_env, csr);
|
||||
tcg_gen_ld_tl(desth, cpu_env, offsetof(CPURISCVState, retxh));
|
||||
gen_set_gpr128(ctx, rd, destl, desth);
|
||||
return do_csr_post(ctx);
|
||||
}
|
||||
|
||||
static bool do_csrw_i128(DisasContext *ctx, int rc, TCGv srcl, TCGv srch)
|
||||
{
|
||||
TCGv_i32 csr = tcg_constant_i32(rc);
|
||||
|
||||
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_csrw_i128(cpu_env, csr, srcl, srch);
|
||||
return do_csr_post(ctx);
|
||||
}
|
||||
|
||||
static bool do_csrrw_i128(DisasContext *ctx, int rd, int rc,
|
||||
TCGv srcl, TCGv srch, TCGv maskl, TCGv maskh)
|
||||
{
|
||||
TCGv destl = dest_gpr(ctx, rd);
|
||||
TCGv desth = dest_gprh(ctx, rd);
|
||||
TCGv_i32 csr = tcg_constant_i32(rc);
|
||||
|
||||
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_csrrw_i128(destl, cpu_env, csr, srcl, srch, maskl, maskh);
|
||||
tcg_gen_ld_tl(desth, cpu_env, offsetof(CPURISCVState, retxh));
|
||||
gen_set_gpr128(ctx, rd, destl, desth);
|
||||
return do_csr_post(ctx);
|
||||
}
|
||||
|
||||
static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
|
||||
{
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
} else {
|
||||
TCGv srcl = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv srch = get_gprh(ctx, 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_i128(ctx, a->csr, srcl, srch);
|
||||
}
|
||||
|
||||
TCGv mask = tcg_constant_tl(-1);
|
||||
return do_csrrw_i128(ctx, a->rd, a->csr, srcl, srch, mask, mask);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -499,13 +964,24 @@ static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
|
|||
* 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);
|
||||
}
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
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);
|
||||
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);
|
||||
} else {
|
||||
if (a->rs1 == 0) {
|
||||
return do_csrr_i128(ctx, a->rd, a->csr);
|
||||
}
|
||||
|
||||
TCGv ones = tcg_constant_tl(-1);
|
||||
TCGv maskl = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
TCGv maskh = get_gprh(ctx, a->rs1);
|
||||
return do_csrrw_i128(ctx, a->rd, a->csr, ones, ones, maskl, maskh);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
|
||||
|
@ -517,28 +993,54 @@ static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
|
|||
* 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);
|
||||
}
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
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);
|
||||
TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
|
||||
} else {
|
||||
if (a->rs1 == 0) {
|
||||
return do_csrr_i128(ctx, a->rd, a->csr);
|
||||
}
|
||||
|
||||
TCGv maskl = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
TCGv maskh = get_gprh(ctx, a->rs1);
|
||||
return do_csrrw_i128(ctx, a->rd, a->csr,
|
||||
ctx->zero, ctx->zero, maskl, maskh);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
|
||||
{
|
||||
TCGv src = tcg_constant_tl(a->rs1);
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
} else {
|
||||
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_i128(ctx, a->csr, src, ctx->zero);
|
||||
}
|
||||
|
||||
TCGv mask = tcg_constant_tl(-1);
|
||||
return do_csrrw_i128(ctx, a->rd, a->csr, src, ctx->zero, mask, mask);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -550,16 +1052,26 @@ static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
|
|||
* 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);
|
||||
}
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
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);
|
||||
TCGv ones = tcg_constant_tl(-1);
|
||||
TCGv mask = tcg_constant_tl(a->rs1);
|
||||
return do_csrrw(ctx, a->rd, a->csr, ones, mask);
|
||||
} else {
|
||||
if (a->rs1 == 0) {
|
||||
return do_csrr_i128(ctx, a->rd, a->csr);
|
||||
}
|
||||
|
||||
TCGv ones = tcg_constant_tl(-1);
|
||||
TCGv mask = tcg_constant_tl(a->rs1);
|
||||
return do_csrrw_i128(ctx, a->rd, a->csr, ones, ones, mask, ctx->zero);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
|
||||
static bool trans_csrrci(DisasContext *ctx, arg_csrrci * a)
|
||||
{
|
||||
/*
|
||||
* If rs1 == 0, the insn shall not write to the csr at all, nor
|
||||
|
@ -568,10 +1080,20 @@ static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
|
|||
* 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);
|
||||
}
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
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);
|
||||
TCGv mask = tcg_constant_tl(a->rs1);
|
||||
return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
|
||||
} else {
|
||||
if (a->rs1 == 0) {
|
||||
return do_csrr_i128(ctx, a->rd, a->csr);
|
||||
}
|
||||
|
||||
TCGv mask = tcg_constant_tl(a->rs1);
|
||||
return do_csrrw_i128(ctx, a->rd, a->csr,
|
||||
ctx->zero, ctx->zero, mask, ctx->zero);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,79 @@
|
|||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static void gen_mulhu_i128(TCGv r2, TCGv r3, TCGv al, TCGv ah, TCGv bl, TCGv bh)
|
||||
{
|
||||
TCGv tmpl = tcg_temp_new();
|
||||
TCGv tmph = tcg_temp_new();
|
||||
TCGv r0 = tcg_temp_new();
|
||||
TCGv r1 = tcg_temp_new();
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
|
||||
tcg_gen_mulu2_tl(r0, r1, al, bl);
|
||||
|
||||
tcg_gen_mulu2_tl(tmpl, tmph, al, bh);
|
||||
tcg_gen_add2_tl(r1, r2, r1, zero, tmpl, tmph);
|
||||
tcg_gen_mulu2_tl(tmpl, tmph, ah, bl);
|
||||
tcg_gen_add2_tl(r1, tmph, r1, r2, tmpl, tmph);
|
||||
/* Overflow detection into r3 */
|
||||
tcg_gen_setcond_tl(TCG_COND_LTU, r3, tmph, r2);
|
||||
|
||||
tcg_gen_mov_tl(r2, tmph);
|
||||
|
||||
tcg_gen_mulu2_tl(tmpl, tmph, ah, bh);
|
||||
tcg_gen_add2_tl(r2, r3, r2, r3, tmpl, tmph);
|
||||
|
||||
tcg_temp_free(tmpl);
|
||||
tcg_temp_free(tmph);
|
||||
}
|
||||
|
||||
static void gen_mul_i128(TCGv rl, TCGv rh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
TCGv tmpl = tcg_temp_new();
|
||||
TCGv tmph = tcg_temp_new();
|
||||
TCGv tmpx = tcg_temp_new();
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
|
||||
tcg_gen_mulu2_tl(rl, rh, rs1l, rs2l);
|
||||
tcg_gen_mulu2_tl(tmpl, tmph, rs1l, rs2h);
|
||||
tcg_gen_add2_tl(rh, tmpx, rh, zero, tmpl, tmph);
|
||||
tcg_gen_mulu2_tl(tmpl, tmph, rs1h, rs2l);
|
||||
tcg_gen_add2_tl(rh, tmph, rh, tmpx, tmpl, tmph);
|
||||
|
||||
tcg_temp_free(tmpl);
|
||||
tcg_temp_free(tmph);
|
||||
tcg_temp_free(tmpx);
|
||||
}
|
||||
|
||||
static bool trans_mul(DisasContext *ctx, arg_mul *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, gen_mul_i128);
|
||||
}
|
||||
|
||||
static void gen_mulh_i128(TCGv rl, TCGv rh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
TCGv t0l = tcg_temp_new();
|
||||
TCGv t0h = tcg_temp_new();
|
||||
TCGv t1l = tcg_temp_new();
|
||||
TCGv t1h = tcg_temp_new();
|
||||
|
||||
gen_mulhu_i128(rl, rh, rs1l, rs1h, rs2l, rs2h);
|
||||
tcg_gen_sari_tl(t0h, rs1h, 63);
|
||||
tcg_gen_and_tl(t0l, t0h, rs2l);
|
||||
tcg_gen_and_tl(t0h, t0h, rs2h);
|
||||
tcg_gen_sari_tl(t1h, rs2h, 63);
|
||||
tcg_gen_and_tl(t1l, t1h, rs1l);
|
||||
tcg_gen_and_tl(t1h, t1h, rs1h);
|
||||
tcg_gen_sub2_tl(t0l, t0h, rl, rh, t0l, t0h);
|
||||
tcg_gen_sub2_tl(rl, rh, t0l, t0h, t1l, t1h);
|
||||
|
||||
tcg_temp_free(t0l);
|
||||
tcg_temp_free(t0h);
|
||||
tcg_temp_free(t1l);
|
||||
tcg_temp_free(t1h);
|
||||
}
|
||||
|
||||
static void gen_mulh(TCGv ret, TCGv s1, TCGv s2)
|
||||
|
@ -42,7 +110,25 @@ static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2)
|
|||
static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w);
|
||||
return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w,
|
||||
gen_mulh_i128);
|
||||
}
|
||||
|
||||
static void gen_mulhsu_i128(TCGv rl, TCGv rh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
|
||||
TCGv t0l = tcg_temp_new();
|
||||
TCGv t0h = tcg_temp_new();
|
||||
|
||||
gen_mulhu_i128(rl, rh, rs1l, rs1h, rs2l, rs2h);
|
||||
tcg_gen_sari_tl(t0h, rs1h, 63);
|
||||
tcg_gen_and_tl(t0l, t0h, rs2l);
|
||||
tcg_gen_and_tl(t0h, t0h, rs2h);
|
||||
tcg_gen_sub2_tl(rl, rh, rl, rh, t0l, t0h);
|
||||
|
||||
tcg_temp_free(t0l);
|
||||
tcg_temp_free(t0h);
|
||||
}
|
||||
|
||||
static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
|
@ -76,7 +162,8 @@ static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2)
|
|||
static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w);
|
||||
return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w,
|
||||
gen_mulhsu_i128);
|
||||
}
|
||||
|
||||
static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2)
|
||||
|
@ -91,7 +178,15 @@ static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
|
|||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
/* gen_mulh_w works for either sign as input. */
|
||||
return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w);
|
||||
return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w,
|
||||
gen_mulhu_i128);
|
||||
}
|
||||
|
||||
static void gen_div_i128(TCGv rdl, TCGv rdh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
gen_helper_divs_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
|
||||
tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
|
||||
}
|
||||
|
||||
static void gen_div(TCGv ret, TCGv source1, TCGv source2)
|
||||
|
@ -130,7 +225,14 @@ static void gen_div(TCGv ret, TCGv source1, TCGv source2)
|
|||
static bool trans_div(DisasContext *ctx, arg_div *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div, gen_div_i128);
|
||||
}
|
||||
|
||||
static void gen_divu_i128(TCGv rdl, TCGv rdh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
gen_helper_divu_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
|
||||
tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
|
||||
}
|
||||
|
||||
static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
|
||||
|
@ -158,7 +260,14 @@ static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
|
|||
static bool trans_divu(DisasContext *ctx, arg_divu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu, gen_divu_i128);
|
||||
}
|
||||
|
||||
static void gen_rem_i128(TCGv rdl, TCGv rdh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
gen_helper_rems_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
|
||||
tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
|
||||
}
|
||||
|
||||
static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
|
||||
|
@ -199,7 +308,14 @@ static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
|
|||
static bool trans_rem(DisasContext *ctx, arg_rem *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem, gen_rem_i128);
|
||||
}
|
||||
|
||||
static void gen_remu_i128(TCGv rdl, TCGv rdh,
|
||||
TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
|
||||
{
|
||||
gen_helper_remu_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
|
||||
tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
|
||||
}
|
||||
|
||||
static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
|
||||
|
@ -227,45 +343,85 @@ static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
|
|||
static bool trans_remu(DisasContext *ctx, arg_remu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu, gen_remu_i128);
|
||||
}
|
||||
|
||||
static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
|
||||
return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_divw(DisasContext *ctx, arg_divw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div, NULL);
|
||||
}
|
||||
|
||||
static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu, NULL);
|
||||
}
|
||||
|
||||
static bool trans_remw(DisasContext *ctx, arg_remw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem);
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem, NULL);
|
||||
}
|
||||
|
||||
static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_64_OR_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV32;
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu);
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu, NULL);
|
||||
}
|
||||
|
||||
static bool trans_muld(DisasContext *ctx, arg_muld *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_SIGN, tcg_gen_mul_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_divd(DisasContext *ctx, arg_divd *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_div, NULL);
|
||||
}
|
||||
|
||||
static bool trans_divud(DisasContext *ctx, arg_divud *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_divu, NULL);
|
||||
}
|
||||
|
||||
static bool trans_remd(DisasContext *ctx, arg_remd *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_SIGN, gen_rem, NULL);
|
||||
}
|
||||
|
||||
static bool trans_remud(DisasContext *ctx, arg_remud *a)
|
||||
{
|
||||
REQUIRE_128BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
ctx->ol = MXL_RV64;
|
||||
return gen_arith(ctx, a, EXT_ZERO, gen_remu, NULL);
|
||||
}
|
||||
|
|
|
@ -2254,7 +2254,8 @@ GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check)
|
|||
static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
}
|
||||
|
@ -2292,7 +2293,8 @@ GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
|
|||
static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
@ -2321,7 +2323,8 @@ GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
|
|||
static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
}
|
||||
|
@ -2359,7 +2362,8 @@ GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
|
|||
static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dd(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
@ -2609,16 +2613,27 @@ GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ)
|
|||
static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
#define GEN_OPFV_WIDEN_TRANS(NAME, HELPER, FRM) \
|
||||
static bool opxfv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_widen_check(s, a) &&
|
||||
require_rvf(s);
|
||||
}
|
||||
|
||||
static bool opffv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_widen_check(s, a) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8);
|
||||
}
|
||||
|
||||
#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
{ \
|
||||
if (opfv_widen_check(s, a)) { \
|
||||
if (CHECK(s, a)) { \
|
||||
if (FRM != RISCV_FRM_DYN) { \
|
||||
gen_set_rm(s, RISCV_FRM_DYN); \
|
||||
} \
|
||||
|
@ -2645,12 +2660,17 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
return false; \
|
||||
}
|
||||
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, vfwcvt_xu_f_v, RISCV_FRM_DYN)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, vfwcvt_x_f_v, RISCV_FRM_DYN)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, vfwcvt_f_f_v, RISCV_FRM_DYN)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
|
||||
RISCV_FRM_DYN)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
|
||||
RISCV_FRM_DYN)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v,
|
||||
RISCV_FRM_DYN)
|
||||
/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, vfwcvt_xu_f_v, RISCV_FRM_RTZ)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, vfwcvt_x_f_v, RISCV_FRM_RTZ)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
|
||||
RISCV_FRM_RTZ)
|
||||
GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
|
||||
RISCV_FRM_RTZ)
|
||||
|
||||
static bool opfxv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
|
@ -2699,17 +2719,29 @@ GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v)
|
|||
static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
(s->sew != MO_64) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
/* OPFV narrowing instructions ignore vs1 check */
|
||||
vext_check_sd(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
#define GEN_OPFV_NARROW_TRANS(NAME, HELPER, FRM) \
|
||||
static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_narrow_check(s, a) &&
|
||||
require_rvf(s) &&
|
||||
(s->sew != MO_64);
|
||||
}
|
||||
|
||||
static bool opffv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_narrow_check(s, a) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8);
|
||||
}
|
||||
|
||||
#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
{ \
|
||||
if (opfv_narrow_check(s, a)) { \
|
||||
if (CHECK(s, a)) { \
|
||||
if (FRM != RISCV_FRM_DYN) { \
|
||||
gen_set_rm(s, RISCV_FRM_DYN); \
|
||||
} \
|
||||
|
@ -2736,11 +2768,15 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
return false; \
|
||||
}
|
||||
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, vfncvt_f_xu_w, RISCV_FRM_DYN)
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, vfncvt_f_x_w, RISCV_FRM_DYN)
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, vfncvt_f_f_w, RISCV_FRM_DYN)
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w,
|
||||
RISCV_FRM_DYN)
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w,
|
||||
RISCV_FRM_DYN)
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
|
||||
RISCV_FRM_DYN)
|
||||
/* Reuse the helper function from vfncvt.f.f.w */
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, vfncvt_f_f_w, RISCV_FRM_ROD)
|
||||
GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
|
||||
RISCV_FRM_ROD)
|
||||
|
||||
static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* RISC-V Emulation Helpers for QEMU.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2017-2018 SiFive, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
target_ulong HELPER(divu_i128)(CPURISCVState *env,
|
||||
target_ulong ul, target_ulong uh,
|
||||
target_ulong vl, target_ulong vh)
|
||||
{
|
||||
target_ulong ql, qh;
|
||||
Int128 q;
|
||||
|
||||
if (vl == 0 && vh == 0) { /* Handle special behavior on div by zero */
|
||||
ql = ~0x0;
|
||||
qh = ~0x0;
|
||||
} else {
|
||||
q = int128_divu(int128_make128(ul, uh), int128_make128(vl, vh));
|
||||
ql = int128_getlo(q);
|
||||
qh = int128_gethi(q);
|
||||
}
|
||||
|
||||
env->retxh = qh;
|
||||
return ql;
|
||||
}
|
||||
|
||||
target_ulong HELPER(remu_i128)(CPURISCVState *env,
|
||||
target_ulong ul, target_ulong uh,
|
||||
target_ulong vl, target_ulong vh)
|
||||
{
|
||||
target_ulong rl, rh;
|
||||
Int128 r;
|
||||
|
||||
if (vl == 0 && vh == 0) {
|
||||
rl = ul;
|
||||
rh = uh;
|
||||
} else {
|
||||
r = int128_remu(int128_make128(ul, uh), int128_make128(vl, vh));
|
||||
rl = int128_getlo(r);
|
||||
rh = int128_gethi(r);
|
||||
}
|
||||
|
||||
env->retxh = rh;
|
||||
return rl;
|
||||
}
|
||||
|
||||
target_ulong HELPER(divs_i128)(CPURISCVState *env,
|
||||
target_ulong ul, target_ulong uh,
|
||||
target_ulong vl, target_ulong vh)
|
||||
{
|
||||
target_ulong qh, ql;
|
||||
Int128 q;
|
||||
|
||||
if (vl == 0 && vh == 0) { /* Div by zero check */
|
||||
ql = ~0x0;
|
||||
qh = ~0x0;
|
||||
} else if (uh == (1ULL << (TARGET_LONG_BITS - 1)) && ul == 0 &&
|
||||
vh == ~0x0 && vl == ~0x0) {
|
||||
/* Signed div overflow check (-2**127 / -1) */
|
||||
ql = ul;
|
||||
qh = uh;
|
||||
} else {
|
||||
q = int128_divs(int128_make128(ul, uh), int128_make128(vl, vh));
|
||||
ql = int128_getlo(q);
|
||||
qh = int128_gethi(q);
|
||||
}
|
||||
|
||||
env->retxh = qh;
|
||||
return ql;
|
||||
}
|
||||
|
||||
target_ulong HELPER(rems_i128)(CPURISCVState *env,
|
||||
target_ulong ul, target_ulong uh,
|
||||
target_ulong vl, target_ulong vh)
|
||||
{
|
||||
target_ulong rh, rl;
|
||||
Int128 r;
|
||||
|
||||
if (vl == 0 && vh == 0) {
|
||||
rl = ul;
|
||||
rh = uh;
|
||||
} else {
|
||||
r = int128_rems(int128_make128(ul, uh), int128_make128(vl, vh));
|
||||
rl = int128_getlo(r);
|
||||
rh = int128_gethi(r);
|
||||
}
|
||||
|
||||
env->retxh = rh;
|
||||
return rl;
|
||||
}
|
|
@ -164,6 +164,27 @@ static const VMStateDescription vmstate_pointermasking = {
|
|||
}
|
||||
};
|
||||
|
||||
static bool rv128_needed(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
return env->misa_mxl_max == MXL_RV128;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_rv128 = {
|
||||
.name = "cpu/rv128",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = rv128_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL_ARRAY(env.gprh, RISCVCPU, 32),
|
||||
VMSTATE_UINT64(env.mscratchh, RISCVCPU),
|
||||
VMSTATE_UINT64(env.sscratchh, RISCVCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
const VMStateDescription vmstate_riscv_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 3,
|
||||
|
@ -218,6 +239,7 @@ const VMStateDescription vmstate_riscv_cpu = {
|
|||
&vmstate_hyper,
|
||||
&vmstate_vector,
|
||||
&vmstate_pointermasking,
|
||||
&vmstate_rv128,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@ riscv_ss.add(files(
|
|||
'vector_helper.c',
|
||||
'bitmanip_helper.c',
|
||||
'translate.c',
|
||||
'm128_helper.c'
|
||||
))
|
||||
|
||||
riscv_softmmu_ss = ss.source_set()
|
||||
|
|
|
@ -69,6 +69,50 @@ target_ulong helper_csrrw(CPURISCVState *env, int csr,
|
|||
return val;
|
||||
}
|
||||
|
||||
target_ulong helper_csrr_i128(CPURISCVState *env, int csr)
|
||||
{
|
||||
Int128 rv = int128_zero();
|
||||
RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
|
||||
int128_zero(),
|
||||
int128_zero());
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
}
|
||||
|
||||
env->retxh = int128_gethi(rv);
|
||||
return int128_getlo(rv);
|
||||
}
|
||||
|
||||
void helper_csrw_i128(CPURISCVState *env, int csr,
|
||||
target_ulong srcl, target_ulong srch)
|
||||
{
|
||||
RISCVException ret = riscv_csrrw_i128(env, csr, NULL,
|
||||
int128_make128(srcl, srch),
|
||||
UINT128_MAX);
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
|
||||
target_ulong srcl, target_ulong srch,
|
||||
target_ulong maskl, target_ulong maskh)
|
||||
{
|
||||
Int128 rv = int128_zero();
|
||||
RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
|
||||
int128_make128(srcl, srch),
|
||||
int128_make128(maskl, maskh));
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
}
|
||||
|
||||
env->retxh = int128_gethi(rv);
|
||||
return int128_getlo(rv);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
|
@ -146,7 +190,8 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
|||
uint64_t mstatus = env->mstatus;
|
||||
target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
|
||||
|
||||
if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
|
||||
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
|
||||
!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
|
||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "internals.h"
|
||||
|
||||
/* global register indices */
|
||||
static TCGv cpu_gpr[32], cpu_pc, cpu_vl, cpu_vstart;
|
||||
static TCGv cpu_gpr[32], cpu_gprh[32], cpu_pc, cpu_vl, cpu_vstart;
|
||||
static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
|
||||
static TCGv load_res;
|
||||
static TCGv load_val;
|
||||
|
@ -59,6 +59,7 @@ typedef struct DisasContext {
|
|||
/* pc_succ_insn points to the instruction following base.pc_next */
|
||||
target_ulong pc_succ_insn;
|
||||
target_ulong priv_ver;
|
||||
RISCVMXL misa_mxl_max;
|
||||
RISCVMXL xl;
|
||||
uint32_t misa_ext;
|
||||
uint32_t opcode;
|
||||
|
@ -141,6 +142,13 @@ static inline int get_olen(DisasContext *ctx)
|
|||
return 16 << get_ol(ctx);
|
||||
}
|
||||
|
||||
/* The maximum register length */
|
||||
#ifdef TARGET_RISCV32
|
||||
#define get_xl_max(ctx) MXL_RV32
|
||||
#else
|
||||
#define get_xl_max(ctx) ((ctx)->misa_mxl_max)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -200,6 +208,9 @@ static void generate_exception_mtval(DisasContext *ctx, int excp)
|
|||
|
||||
static void gen_exception_illegal(DisasContext *ctx)
|
||||
{
|
||||
tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env,
|
||||
offsetof(CPURISCVState, bins));
|
||||
|
||||
generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
|
||||
}
|
||||
|
||||
|
@ -260,6 +271,7 @@ static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
|
|||
}
|
||||
break;
|
||||
case MXL_RV64:
|
||||
case MXL_RV128:
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
|
@ -267,6 +279,15 @@ static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
|
|||
return cpu_gpr[reg_num];
|
||||
}
|
||||
|
||||
static TCGv get_gprh(DisasContext *ctx, int reg_num)
|
||||
{
|
||||
assert(get_xl(ctx) == MXL_RV128);
|
||||
if (reg_num == 0) {
|
||||
return ctx->zero;
|
||||
}
|
||||
return cpu_gprh[reg_num];
|
||||
}
|
||||
|
||||
static TCGv dest_gpr(DisasContext *ctx, int reg_num)
|
||||
{
|
||||
if (reg_num == 0 || get_olen(ctx) < TARGET_LONG_BITS) {
|
||||
|
@ -275,6 +296,14 @@ static TCGv dest_gpr(DisasContext *ctx, int reg_num)
|
|||
return cpu_gpr[reg_num];
|
||||
}
|
||||
|
||||
static TCGv dest_gprh(DisasContext *ctx, int reg_num)
|
||||
{
|
||||
if (reg_num == 0) {
|
||||
return temp_new(ctx);
|
||||
}
|
||||
return cpu_gprh[reg_num];
|
||||
}
|
||||
|
||||
static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
|
||||
{
|
||||
if (reg_num != 0) {
|
||||
|
@ -283,11 +312,46 @@ static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
|
|||
tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
|
||||
break;
|
||||
case MXL_RV64:
|
||||
case MXL_RV128:
|
||||
tcg_gen_mov_tl(cpu_gpr[reg_num], t);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (get_xl_max(ctx) == MXL_RV128) {
|
||||
tcg_gen_sari_tl(cpu_gprh[reg_num], cpu_gpr[reg_num], 63);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_set_gpri(DisasContext *ctx, int reg_num, target_long imm)
|
||||
{
|
||||
if (reg_num != 0) {
|
||||
switch (get_ol(ctx)) {
|
||||
case MXL_RV32:
|
||||
tcg_gen_movi_tl(cpu_gpr[reg_num], (int32_t)imm);
|
||||
break;
|
||||
case MXL_RV64:
|
||||
case MXL_RV128:
|
||||
tcg_gen_movi_tl(cpu_gpr[reg_num], imm);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (get_xl_max(ctx) == MXL_RV128) {
|
||||
tcg_gen_movi_tl(cpu_gprh[reg_num], -(imm < 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_set_gpr128(DisasContext *ctx, int reg_num, TCGv rl, TCGv rh)
|
||||
{
|
||||
assert(get_ol(ctx) == MXL_RV128);
|
||||
if (reg_num != 0) {
|
||||
tcg_gen_mov_tl(cpu_gpr[reg_num], rl);
|
||||
tcg_gen_mov_tl(cpu_gprh[reg_num], rh);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,10 +507,22 @@ EX_SH(12)
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_64BIT(ctx) do { \
|
||||
if (get_xl(ctx) < MXL_RV64) { \
|
||||
return false; \
|
||||
} \
|
||||
#define REQUIRE_64BIT(ctx) do { \
|
||||
if (get_xl(ctx) != MXL_RV64) { \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_128BIT(ctx) do { \
|
||||
if (get_xl(ctx) != MXL_RV128) { \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_64_OR_128BIT(ctx) do { \
|
||||
if (get_xl(ctx) == MXL_RV32) { \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int ex_rvc_register(DisasContext *ctx, int reg)
|
||||
|
@ -463,62 +539,146 @@ 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, DisasExtend ext,
|
||||
static bool gen_logic_imm_fn(DisasContext *ctx, arg_i *a,
|
||||
void (*func)(TCGv, TCGv, target_long))
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
|
||||
func(dest, src1, a->imm);
|
||||
|
||||
if (get_xl(ctx) == MXL_RV128) {
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
func(desth, src1h, -(a->imm < 0));
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
} else {
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_logic(DisasContext *ctx, arg_r *a,
|
||||
void (*func)(TCGv, TCGv, TCGv))
|
||||
{
|
||||
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);
|
||||
|
||||
func(dest, src1, src2);
|
||||
|
||||
if (get_xl(ctx) == MXL_RV128) {
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv src2h = get_gprh(ctx, a->rs2);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
func(desth, src1h, src2h);
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
} else {
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext,
|
||||
void (*func)(TCGv, TCGv, target_long),
|
||||
void (*f128)(TCGv, TCGv, TCGv, TCGv, target_long))
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, ext);
|
||||
|
||||
func(dest, src1, a->imm);
|
||||
if (get_ol(ctx) < MXL_RV128) {
|
||||
func(dest, src1, a->imm);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
} else {
|
||||
if (f128 == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
f128(dest, desth, src1, src1h, a->imm);
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext,
|
||||
void (*func)(TCGv, TCGv, TCGv))
|
||||
void (*func)(TCGv, TCGv, TCGv),
|
||||
void (*f128)(TCGv, TCGv, TCGv, TCGv, TCGv, TCGv))
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, ext);
|
||||
TCGv src2 = tcg_constant_tl(a->imm);
|
||||
|
||||
func(dest, src1, src2);
|
||||
if (get_ol(ctx) < MXL_RV128) {
|
||||
func(dest, src1, src2);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
} else {
|
||||
if (f128 == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv src2h = tcg_constant_tl(-(a->imm < 0));
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
f128(dest, desth, src1, src1h, src2, src2h);
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext,
|
||||
void (*func)(TCGv, TCGv, TCGv))
|
||||
void (*func)(TCGv, TCGv, TCGv),
|
||||
void (*f128)(TCGv, TCGv, TCGv, TCGv, TCGv, TCGv))
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, ext);
|
||||
TCGv src2 = get_gpr(ctx, a->rs2, ext);
|
||||
|
||||
func(dest, src1, src2);
|
||||
if (get_ol(ctx) < MXL_RV128) {
|
||||
func(dest, src1, src2);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
} else {
|
||||
if (f128 == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv src2h = get_gprh(ctx, a->rs2);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
f128(dest, desth, src1, src1h, src2, src2h);
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_arith_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
|
||||
void (*f_tl)(TCGv, TCGv, TCGv),
|
||||
void (*f_32)(TCGv, TCGv, TCGv))
|
||||
void (*f_32)(TCGv, TCGv, TCGv),
|
||||
void (*f_128)(TCGv, TCGv, TCGv, TCGv, TCGv, TCGv))
|
||||
{
|
||||
int olen = get_olen(ctx);
|
||||
|
||||
if (olen != TARGET_LONG_BITS) {
|
||||
if (olen == 32) {
|
||||
f_tl = f_32;
|
||||
} else {
|
||||
} else if (olen != 128) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
return gen_arith(ctx, a, ext, f_tl);
|
||||
return gen_arith(ctx, a, ext, f_tl, f_128);
|
||||
}
|
||||
|
||||
static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
|
||||
void (*func)(TCGv, TCGv, target_long))
|
||||
void (*func)(TCGv, TCGv, target_long),
|
||||
void (*f128)(TCGv, TCGv, TCGv, TCGv, target_long))
|
||||
{
|
||||
TCGv dest, src1;
|
||||
int max_len = get_olen(ctx);
|
||||
|
@ -530,26 +690,38 @@ static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
|
|||
dest = dest_gpr(ctx, a->rd);
|
||||
src1 = get_gpr(ctx, a->rs1, ext);
|
||||
|
||||
func(dest, src1, a->shamt);
|
||||
if (max_len < 128) {
|
||||
func(dest, src1, a->shamt);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
} else {
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
if (f128 == NULL) {
|
||||
return false;
|
||||
}
|
||||
f128(dest, desth, src1, src1h, a->shamt);
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_shift_imm_fn_per_ol(DisasContext *ctx, arg_shift *a,
|
||||
DisasExtend ext,
|
||||
void (*f_tl)(TCGv, TCGv, target_long),
|
||||
void (*f_32)(TCGv, TCGv, target_long))
|
||||
void (*f_32)(TCGv, TCGv, target_long),
|
||||
void (*f_128)(TCGv, TCGv, TCGv, TCGv,
|
||||
target_long))
|
||||
{
|
||||
int olen = get_olen(ctx);
|
||||
if (olen != TARGET_LONG_BITS) {
|
||||
if (olen == 32) {
|
||||
f_tl = f_32;
|
||||
} else {
|
||||
} else if (olen != 128) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
return gen_shift_imm_fn(ctx, a, ext, f_tl);
|
||||
return gen_shift_imm_fn(ctx, a, ext, f_tl, f_128);
|
||||
}
|
||||
|
||||
static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
|
||||
|
@ -573,34 +745,49 @@ static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
|
|||
}
|
||||
|
||||
static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext,
|
||||
void (*func)(TCGv, TCGv, TCGv))
|
||||
void (*func)(TCGv, TCGv, TCGv),
|
||||
void (*f128)(TCGv, TCGv, TCGv, TCGv, TCGv))
|
||||
{
|
||||
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();
|
||||
int max_len = get_olen(ctx);
|
||||
|
||||
tcg_gen_andi_tl(ext2, src2, get_olen(ctx) - 1);
|
||||
func(dest, src1, ext2);
|
||||
tcg_gen_andi_tl(ext2, src2, max_len - 1);
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, ext);
|
||||
|
||||
if (max_len < 128) {
|
||||
func(dest, src1, ext2);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
} else {
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
TCGv desth = dest_gprh(ctx, a->rd);
|
||||
|
||||
if (f128 == NULL) {
|
||||
return false;
|
||||
}
|
||||
f128(dest, desth, src1, src1h, ext2);
|
||||
gen_set_gpr128(ctx, a->rd, dest, desth);
|
||||
}
|
||||
tcg_temp_free(ext2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_shift_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
|
||||
void (*f_tl)(TCGv, TCGv, TCGv),
|
||||
void (*f_32)(TCGv, TCGv, TCGv))
|
||||
void (*f_32)(TCGv, TCGv, TCGv),
|
||||
void (*f_128)(TCGv, TCGv, TCGv, TCGv, TCGv))
|
||||
{
|
||||
int olen = get_olen(ctx);
|
||||
if (olen != TARGET_LONG_BITS) {
|
||||
if (olen == 32) {
|
||||
f_tl = f_32;
|
||||
} else {
|
||||
} else if (olen != 128) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
return gen_shift(ctx, a, ext, f_tl);
|
||||
return gen_shift(ctx, a, ext, f_tl, f_128);
|
||||
}
|
||||
|
||||
static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
|
||||
|
@ -662,6 +849,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
|
|||
if (!has_ext(ctx, RVC)) {
|
||||
gen_exception_illegal(ctx);
|
||||
} else {
|
||||
ctx->opcode = opcode;
|
||||
ctx->pc_succ_insn = ctx->base.pc_next + 2;
|
||||
if (!decode_insn16(ctx, opcode)) {
|
||||
gen_exception_illegal(ctx);
|
||||
|
@ -672,6 +860,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
|
|||
opcode32 = deposit32(opcode32, 16, 16,
|
||||
translator_lduw(env, &ctx->base,
|
||||
ctx->base.pc_next + 2));
|
||||
ctx->opcode = opcode32;
|
||||
ctx->pc_succ_insn = ctx->base.pc_next + 4;
|
||||
if (!decode_insn32(ctx, opcode32)) {
|
||||
gen_exception_illegal(ctx);
|
||||
|
@ -715,6 +904,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|||
ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3);
|
||||
ctx->vstart = env->vstart;
|
||||
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
|
||||
ctx->misa_mxl_max = env->misa_mxl_max;
|
||||
ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
|
||||
ctx->cs = cs;
|
||||
ctx->ntemp = 0;
|
||||
|
@ -819,10 +1009,13 @@ void riscv_translate_init(void)
|
|||
* unless you specifically block reads/writes to reg 0.
|
||||
*/
|
||||
cpu_gpr[0] = NULL;
|
||||
cpu_gprh[0] = NULL;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
cpu_gpr[i] = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]);
|
||||
cpu_gprh[i] = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPURISCVState, gprh[i]), riscv_int_regnamesh[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
D(0xeb6a, ASI, SIY, GIE, la1, i2, new, 0, asi, adds32, MO_TESL)
|
||||
C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32)
|
||||
C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64)
|
||||
D(0xeb7a, AGSI, SIY, GIE, la1, i2, new, 0, asi, adds64, MO_TEQ)
|
||||
D(0xeb7a, AGSI, SIY, GIE, la1, i2, new, 0, asi, adds64, MO_TEUQ)
|
||||
C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64)
|
||||
/* ADD IMMEDIATE HIGH */
|
||||
C(0xcc08, AIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, adds32)
|
||||
|
@ -76,7 +76,7 @@
|
|||
/* ADD LOGICAL WITH SIGNED IMMEDIATE */
|
||||
D(0xeb6e, ALSI, SIY, GIE, la1, i2_32u, new, 0, asi, addu32, MO_TEUL)
|
||||
C(0xecda, ALHSIK, RIE_d, DO, r3_32u, i2_32u, new, r1_32, add, addu32)
|
||||
D(0xeb7e, ALGSI, SIY, GIE, la1, i2, new, 0, asiu64, addu64, MO_TEQ)
|
||||
D(0xeb7e, ALGSI, SIY, GIE, la1, i2, new, 0, asiu64, addu64, MO_TEUQ)
|
||||
C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, addu64, addu64)
|
||||
/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */
|
||||
C(0xcc0a, ALSIH, RIL_a, HW, r1_sr32, i2_32u, new, r1_32h, add, addu32)
|
||||
|
@ -269,10 +269,10 @@
|
|||
/* COMPARE AND SWAP */
|
||||
D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL)
|
||||
D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL)
|
||||
D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, MO_TEQ)
|
||||
D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, MO_TEUQ)
|
||||
/* COMPARE DOUBLE AND SWAP */
|
||||
D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEQ)
|
||||
D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEQ)
|
||||
D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ)
|
||||
D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ)
|
||||
C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0)
|
||||
/* COMPARE AND SWAP AND STORE */
|
||||
C(0xc802, CSST, SSF, CASS, la1, a2, 0, 0, csst, 0)
|
||||
|
@ -436,19 +436,19 @@
|
|||
C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0)
|
||||
/* LOAD AND ADD */
|
||||
D(0xebf8, LAA, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, laa, adds32, MO_TESL)
|
||||
D(0xebe8, LAAG, RSY_a, ILA, r3, a2, new, in2_r1, laa, adds64, MO_TEQ)
|
||||
D(0xebe8, LAAG, RSY_a, ILA, r3, a2, new, in2_r1, laa, adds64, MO_TEUQ)
|
||||
/* LOAD AND ADD LOGICAL */
|
||||
D(0xebfa, LAAL, RSY_a, ILA, r3_32u, a2, new, in2_r1_32, laa, addu32, MO_TEUL)
|
||||
D(0xebea, LAALG, RSY_a, ILA, r3, a2, new, in2_r1, laa, addu64, MO_TEQ)
|
||||
D(0xebea, LAALG, RSY_a, ILA, r3, a2, new, in2_r1, laa, addu64, MO_TEUQ)
|
||||
/* LOAD AND AND */
|
||||
D(0xebf4, LAN, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lan, nz32, MO_TESL)
|
||||
D(0xebe4, LANG, RSY_a, ILA, r3, a2, new, in2_r1, lan, nz64, MO_TEQ)
|
||||
D(0xebe4, LANG, RSY_a, ILA, r3, a2, new, in2_r1, lan, nz64, MO_TEUQ)
|
||||
/* LOAD AND EXCLUSIVE OR */
|
||||
D(0xebf7, LAX, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lax, nz32, MO_TESL)
|
||||
D(0xebe7, LAXG, RSY_a, ILA, r3, a2, new, in2_r1, lax, nz64, MO_TEQ)
|
||||
D(0xebe7, LAXG, RSY_a, ILA, r3, a2, new, in2_r1, lax, nz64, MO_TEUQ)
|
||||
/* LOAD AND OR */
|
||||
D(0xebf6, LAO, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lao, nz32, MO_TESL)
|
||||
D(0xebe6, LAOG, RSY_a, ILA, r3, a2, new, in2_r1, lao, nz64, MO_TEQ)
|
||||
D(0xebe6, LAOG, RSY_a, ILA, r3, a2, new, in2_r1, lao, nz64, MO_TEUQ)
|
||||
/* LOAD AND TEST */
|
||||
C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32)
|
||||
C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64)
|
||||
|
@ -565,7 +565,7 @@
|
|||
C(0xebe0, LOCFH, RSY_b, LOC2, r1_sr32, m2_32u, new, r1_32h, loc, 0)
|
||||
/* LOAD PAIR DISJOINT */
|
||||
D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL)
|
||||
D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEQ)
|
||||
D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEUQ)
|
||||
/* LOAD PAIR FROM QUADWORD */
|
||||
C(0xe38f, LPQ, RXY_a, Z, 0, a2, r1_P, 0, lpq, 0)
|
||||
/* LOAD POSITIVE */
|
||||
|
@ -1279,7 +1279,7 @@
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
/* COMPARE AND SWAP AND PURGE */
|
||||
E(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL, IF_PRIV)
|
||||
E(0xb98a, CSPG, RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEQ, IF_PRIV)
|
||||
E(0xb98a, CSPG, RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEUQ, IF_PRIV)
|
||||
/* DIAGNOSE (KVM hypercall) */
|
||||
F(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0, IF_PRIV | IF_IO)
|
||||
/* INSERT STORAGE KEY EXTENDED */
|
||||
|
@ -1303,7 +1303,7 @@
|
|||
F(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0, IF_PRIV)
|
||||
/* LOAD USING REAL ADDRESS */
|
||||
E(0xb24b, LURA, RRE, Z, 0, ra2, new, r1_32, lura, 0, MO_TEUL, IF_PRIV)
|
||||
E(0xb905, LURAG, RRE, Z, 0, ra2, r1, 0, lura, 0, MO_TEQ, IF_PRIV)
|
||||
E(0xb905, LURAG, RRE, Z, 0, ra2, r1, 0, lura, 0, MO_TEUQ, IF_PRIV)
|
||||
/* MOVE TO PRIMARY */
|
||||
F(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0, IF_PRIV)
|
||||
/* MOVE TO SECONDARY */
|
||||
|
@ -1357,7 +1357,7 @@
|
|||
F(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0, IF_PRIV)
|
||||
/* STORE USING REAL ADDRESS */
|
||||
E(0xb246, STURA, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEUL, IF_PRIV)
|
||||
E(0xb925, STURG, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEQ, IF_PRIV)
|
||||
E(0xb925, STURG, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEUQ, IF_PRIV)
|
||||
/* TEST BLOCK */
|
||||
F(0xb22c, TB, RRE, Z, 0, r2_o, 0, 0, testblock, 0, IF_PRIV)
|
||||
/* TEST PROTECTION */
|
||||
|
|
|
@ -1895,7 +1895,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
|
|||
|
||||
if (parallel) {
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
MemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUQ | MO_ALIGN, mem_idx);
|
||||
ov = cpu_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
|
||||
#else
|
||||
/* Note that we asserted !parallel above. */
|
||||
|
@ -1970,7 +1970,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
|
|||
cpu_stq_data_ra(env, a2 + 0, svh, ra);
|
||||
cpu_stq_data_ra(env, a2 + 8, svl, ra);
|
||||
} else if (HAVE_ATOMIC128) {
|
||||
MemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUQ | MO_ALIGN_16, mem_idx);
|
||||
Int128 sv = int128_make128(svl, svh);
|
||||
cpu_atomic_sto_be_mmu(env, a2, sv, oi, ra);
|
||||
} else {
|
||||
|
@ -2494,7 +2494,7 @@ uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
|
|||
assert(HAVE_ATOMIC128);
|
||||
|
||||
mem_idx = cpu_mmu_index(env, false);
|
||||
oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
|
||||
oi = make_memop_idx(MO_TEUQ | MO_ALIGN_16, mem_idx);
|
||||
v = cpu_atomic_ldo_be_mmu(env, addr, oi, ra);
|
||||
hi = int128_gethi(v);
|
||||
lo = int128_getlo(v);
|
||||
|
@ -2525,7 +2525,7 @@ void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
|
|||
assert(HAVE_ATOMIC128);
|
||||
|
||||
mem_idx = cpu_mmu_index(env, false);
|
||||
oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
|
||||
oi = make_memop_idx(MO_TEUQ | MO_ALIGN_16, mem_idx);
|
||||
v = int128_make128(low, high);
|
||||
cpu_atomic_sto_be_mmu(env, addr, v, oi, ra);
|
||||
}
|
||||
|
|
|
@ -3063,7 +3063,7 @@ static DisasJumpType op_lpswe(DisasContext *s, DisasOps *o)
|
|||
t1 = tcg_temp_new_i64();
|
||||
t2 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(t1, o->in2, get_mem_index(s),
|
||||
MO_TEQ | MO_ALIGN_8);
|
||||
MO_TEUQ | MO_ALIGN_8);
|
||||
tcg_gen_addi_i64(o->in2, o->in2, 8);
|
||||
tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s));
|
||||
gen_helper_load_psw(cpu_env, t1, t2);
|
||||
|
@ -4295,7 +4295,7 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps *o)
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
static DisasJumpType op_sck(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
|
||||
tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEUQ | MO_ALIGN);
|
||||
gen_helper_sck(cc_op, cpu_env, o->in1);
|
||||
set_cc_static(s);
|
||||
return DISAS_NEXT;
|
||||
|
@ -5521,7 +5521,7 @@ static void wout_m1_64(DisasContext *s, DisasOps *o)
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
static void wout_m1_64a(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
|
||||
tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEUQ | MO_ALIGN);
|
||||
}
|
||||
#define SPEC_wout_m1_64a 0
|
||||
#endif
|
||||
|
@ -5997,7 +5997,7 @@ static void in2_m2_64w(DisasContext *s, DisasOps *o)
|
|||
static void in2_m2_64a(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
in2_a2(s, o);
|
||||
tcg_gen_qemu_ld_i64(o->in2, o->in2, get_mem_index(s), MO_TEQ | MO_ALIGN);
|
||||
tcg_gen_qemu_ld_i64(o->in2, o->in2, get_mem_index(s), MO_TEUQ | MO_ALIGN);
|
||||
}
|
||||
#define SPEC_in2_m2_64a 0
|
||||
#endif
|
||||
|
|
|
@ -424,9 +424,9 @@ static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
|
|||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
|
||||
tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
|
||||
write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
|
||||
tcg_temp_free(t0);
|
||||
|
@ -592,16 +592,16 @@ static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
|
|||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
|
||||
tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEUQ);
|
||||
|
||||
for (;; v1++) {
|
||||
tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
write_vec_element_i64(t1, v1, 0, ES_64);
|
||||
if (v1 == v3) {
|
||||
break;
|
||||
}
|
||||
gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
|
||||
tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
write_vec_element_i64(t1, v1, 1, ES_64);
|
||||
gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
|
||||
}
|
||||
|
@ -950,10 +950,10 @@ static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
|
|||
gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
|
||||
|
||||
read_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
|
||||
read_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
tcg_temp_free_i64(tmp);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
@ -993,10 +993,10 @@ static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
|
|||
|
||||
for (;; v1++) {
|
||||
read_vec_element_i64(tmp, v1, 0, ES_64);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
|
||||
read_vec_element_i64(tmp, v1, 1, ES_64);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
|
||||
if (v1 == v3) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1010,7 +1010,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
if (ctx->tbflags & FPSCR_SZ) {
|
||||
TCGv_i64 fp = tcg_temp_new_i64();
|
||||
gen_load_fpr64(ctx, fp, XHACK(B7_4));
|
||||
tcg_gen_qemu_st_i64(fp, REG(B11_8), ctx->memidx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(fp, REG(B11_8), ctx->memidx, MO_TEUQ);
|
||||
tcg_temp_free_i64(fp);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i32(FREG(B7_4), REG(B11_8), ctx->memidx, MO_TEUL);
|
||||
|
@ -1020,7 +1020,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
CHECK_FPU_ENABLED
|
||||
if (ctx->tbflags & FPSCR_SZ) {
|
||||
TCGv_i64 fp = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx, MO_TEUQ);
|
||||
gen_store_fpr64(ctx, fp, XHACK(B11_8));
|
||||
tcg_temp_free_i64(fp);
|
||||
} else {
|
||||
|
@ -1031,7 +1031,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
CHECK_FPU_ENABLED
|
||||
if (ctx->tbflags & FPSCR_SZ) {
|
||||
TCGv_i64 fp = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx, MO_TEUQ);
|
||||
gen_store_fpr64(ctx, fp, XHACK(B11_8));
|
||||
tcg_temp_free_i64(fp);
|
||||
tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 8);
|
||||
|
@ -1048,7 +1048,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
TCGv_i64 fp = tcg_temp_new_i64();
|
||||
gen_load_fpr64(ctx, fp, XHACK(B7_4));
|
||||
tcg_gen_subi_i32(addr, REG(B11_8), 8);
|
||||
tcg_gen_qemu_st_i64(fp, addr, ctx->memidx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(fp, addr, ctx->memidx, MO_TEUQ);
|
||||
tcg_temp_free_i64(fp);
|
||||
} else {
|
||||
tcg_gen_subi_i32(addr, REG(B11_8), 4);
|
||||
|
@ -1065,7 +1065,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
tcg_gen_add_i32(addr, REG(B7_4), REG(0));
|
||||
if (ctx->tbflags & FPSCR_SZ) {
|
||||
TCGv_i64 fp = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(fp, addr, ctx->memidx, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(fp, addr, ctx->memidx, MO_TEUQ);
|
||||
gen_store_fpr64(ctx, fp, XHACK(B11_8));
|
||||
tcg_temp_free_i64(fp);
|
||||
} else {
|
||||
|
@ -1082,7 +1082,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
if (ctx->tbflags & FPSCR_SZ) {
|
||||
TCGv_i64 fp = tcg_temp_new_i64();
|
||||
gen_load_fpr64(ctx, fp, XHACK(B7_4));
|
||||
tcg_gen_qemu_st_i64(fp, addr, ctx->memidx, MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(fp, addr, ctx->memidx, MO_TEUQ);
|
||||
tcg_temp_free_i64(fp);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i32(FREG(B7_4), addr, ctx->memidx, MO_TEUL);
|
||||
|
|
|
@ -2464,7 +2464,7 @@ static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn)
|
|||
static void gen_ldf_asi(DisasContext *dc, TCGv addr,
|
||||
int insn, int size, int rd)
|
||||
{
|
||||
DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ));
|
||||
DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEUQ));
|
||||
TCGv_i32 d32;
|
||||
TCGv_i64 d64;
|
||||
|
||||
|
@ -2578,7 +2578,7 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr,
|
|||
static void gen_stf_asi(DisasContext *dc, TCGv addr,
|
||||
int insn, int size, int rd)
|
||||
{
|
||||
DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ));
|
||||
DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEUQ));
|
||||
TCGv_i32 d32;
|
||||
|
||||
switch (da.type) {
|
||||
|
@ -2660,7 +2660,7 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr,
|
|||
|
||||
static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
|
||||
{
|
||||
DisasASI da = get_asi(dc, insn, MO_TEQ);
|
||||
DisasASI da = get_asi(dc, insn, MO_TEUQ);
|
||||
TCGv_i64 hi = gen_dest_gpr(dc, rd);
|
||||
TCGv_i64 lo = gen_dest_gpr(dc, rd + 1);
|
||||
|
||||
|
@ -2727,7 +2727,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
|
|||
static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
|
||||
int insn, int rd)
|
||||
{
|
||||
DisasASI da = get_asi(dc, insn, MO_TEQ);
|
||||
DisasASI da = get_asi(dc, insn, MO_TEUQ);
|
||||
TCGv lo = gen_load_gpr(dc, rd + 1);
|
||||
|
||||
switch (da.type) {
|
||||
|
@ -2787,7 +2787,7 @@ static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
|
|||
static void gen_casx_asi(DisasContext *dc, TCGv addr, TCGv cmpv,
|
||||
int insn, int rd)
|
||||
{
|
||||
DisasASI da = get_asi(dc, insn, MO_TEQ);
|
||||
DisasASI da = get_asi(dc, insn, MO_TEUQ);
|
||||
TCGv oldv;
|
||||
|
||||
switch (da.type) {
|
||||
|
@ -2817,7 +2817,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
|
|||
TCGv lo = gen_dest_gpr(dc, rd | 1);
|
||||
TCGv hi = gen_dest_gpr(dc, rd);
|
||||
TCGv_i64 t64 = tcg_temp_new_i64();
|
||||
DisasASI da = get_asi(dc, insn, MO_TEQ);
|
||||
DisasASI da = get_asi(dc, insn, MO_TEUQ);
|
||||
|
||||
switch (da.type) {
|
||||
case GET_ASI_EXCP:
|
||||
|
@ -2830,7 +2830,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
|
|||
default:
|
||||
{
|
||||
TCGv_i32 r_asi = tcg_const_i32(da.asi);
|
||||
TCGv_i32 r_mop = tcg_const_i32(MO_Q);
|
||||
TCGv_i32 r_mop = tcg_const_i32(MO_UQ);
|
||||
|
||||
save_state(dc);
|
||||
gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop);
|
||||
|
@ -2849,7 +2849,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
|
|||
static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
|
||||
int insn, int rd)
|
||||
{
|
||||
DisasASI da = get_asi(dc, insn, MO_TEQ);
|
||||
DisasASI da = get_asi(dc, insn, MO_TEUQ);
|
||||
TCGv lo = gen_load_gpr(dc, rd + 1);
|
||||
TCGv_i64 t64 = tcg_temp_new_i64();
|
||||
|
||||
|
@ -2886,7 +2886,7 @@ static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
|
|||
default:
|
||||
{
|
||||
TCGv_i32 r_asi = tcg_const_i32(da.asi);
|
||||
TCGv_i32 r_mop = tcg_const_i32(MO_Q);
|
||||
TCGv_i32 r_mop = tcg_const_i32(MO_UQ);
|
||||
|
||||
save_state(dc);
|
||||
gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop);
|
||||
|
@ -5479,7 +5479,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TESL);
|
||||
break;
|
||||
case 0x1b: /* V9 ldxa */
|
||||
gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEQ);
|
||||
gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEUQ);
|
||||
break;
|
||||
case 0x2d: /* V9 prefetch, no effect */
|
||||
goto skip_move;
|
||||
|
@ -5533,7 +5533,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
if (rd == 1) {
|
||||
TCGv_i64 t64 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(t64, cpu_addr,
|
||||
dc->mem_idx, MO_TEQ);
|
||||
dc->mem_idx, MO_TEUQ);
|
||||
gen_helper_ldxfsr(cpu_fsr, cpu_env, cpu_fsr, t64);
|
||||
tcg_temp_free_i64(t64);
|
||||
break;
|
||||
|
@ -5549,11 +5549,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
gen_address_mask(dc, cpu_addr);
|
||||
cpu_src1_64 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(cpu_src1_64, cpu_addr, dc->mem_idx,
|
||||
MO_TEQ | MO_ALIGN_4);
|
||||
MO_TEUQ | MO_ALIGN_4);
|
||||
tcg_gen_addi_tl(cpu_addr, cpu_addr, 8);
|
||||
cpu_src2_64 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(cpu_src2_64, cpu_addr, dc->mem_idx,
|
||||
MO_TEQ | MO_ALIGN_4);
|
||||
MO_TEUQ | MO_ALIGN_4);
|
||||
gen_store_fpr_Q(dc, rd, cpu_src1_64, cpu_src2_64);
|
||||
tcg_temp_free_i64(cpu_src1_64);
|
||||
tcg_temp_free_i64(cpu_src2_64);
|
||||
|
@ -5562,7 +5562,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
gen_address_mask(dc, cpu_addr);
|
||||
cpu_dst_64 = gen_dest_fpr_D(dc, rd);
|
||||
tcg_gen_qemu_ld_i64(cpu_dst_64, cpu_addr, dc->mem_idx,
|
||||
MO_TEQ | MO_ALIGN_4);
|
||||
MO_TEUQ | MO_ALIGN_4);
|
||||
gen_store_fpr_D(dc, rd, cpu_dst_64);
|
||||
break;
|
||||
default:
|
||||
|
@ -5623,7 +5623,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx);
|
||||
break;
|
||||
case 0x1e: /* V9 stxa */
|
||||
gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEQ);
|
||||
gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUQ);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -5664,11 +5664,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
before performing the first write. */
|
||||
cpu_src1_64 = gen_load_fpr_Q0(dc, rd);
|
||||
tcg_gen_qemu_st_i64(cpu_src1_64, cpu_addr,
|
||||
dc->mem_idx, MO_TEQ | MO_ALIGN_16);
|
||||
dc->mem_idx, MO_TEUQ | MO_ALIGN_16);
|
||||
tcg_gen_addi_tl(cpu_addr, cpu_addr, 8);
|
||||
cpu_src2_64 = gen_load_fpr_Q1(dc, rd);
|
||||
tcg_gen_qemu_st_i64(cpu_src1_64, cpu_addr,
|
||||
dc->mem_idx, MO_TEQ);
|
||||
dc->mem_idx, MO_TEUQ);
|
||||
break;
|
||||
#else /* !TARGET_SPARC64 */
|
||||
/* stdfq, store floating point queue */
|
||||
|
@ -5687,7 +5687,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
gen_address_mask(dc, cpu_addr);
|
||||
cpu_src1_64 = gen_load_fpr_D(dc, rd);
|
||||
tcg_gen_qemu_st_i64(cpu_src1_64, cpu_addr, dc->mem_idx,
|
||||
MO_TEQ | MO_ALIGN_4);
|
||||
MO_TEUQ | MO_ALIGN_4);
|
||||
break;
|
||||
default:
|
||||
goto illegal_insn;
|
||||
|
|
|
@ -246,7 +246,7 @@ static void gen_st_2regs_64(TCGv rh, TCGv rl, TCGv address, DisasContext *ctx)
|
|||
TCGv_i64 temp = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_concat_i32_i64(temp, rl, rh);
|
||||
tcg_gen_qemu_st_i64(temp, address, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_st_i64(temp, address, ctx->mem_idx, MO_LEUQ);
|
||||
|
||||
tcg_temp_free_i64(temp);
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ static void gen_ld_2regs_64(TCGv rh, TCGv rl, TCGv address, DisasContext *ctx)
|
|||
{
|
||||
TCGv_i64 temp = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(temp, address, ctx->mem_idx, MO_LEQ);
|
||||
tcg_gen_qemu_ld_i64(temp, address, ctx->mem_idx, MO_LEUQ);
|
||||
/* write back to two 32 bit regs */
|
||||
tcg_gen_extr_i64_i32(rl, rh, temp);
|
||||
|
||||
|
|
|
@ -7077,7 +7077,7 @@ static void translate_ldsti_d(DisasContext *dc, const OpcodeArg arg[],
|
|||
} else {
|
||||
addr = arg[1].in;
|
||||
}
|
||||
mop = gen_load_store_alignment(dc, MO_TEQ, addr);
|
||||
mop = gen_load_store_alignment(dc, MO_TEUQ, addr);
|
||||
if (par[0]) {
|
||||
tcg_gen_qemu_st_i64(arg[0].in, addr, dc->cring, mop);
|
||||
} else {
|
||||
|
@ -7142,7 +7142,7 @@ static void translate_ldstx_d(DisasContext *dc, const OpcodeArg arg[],
|
|||
} else {
|
||||
addr = arg[1].in;
|
||||
}
|
||||
mop = gen_load_store_alignment(dc, MO_TEQ, addr);
|
||||
mop = gen_load_store_alignment(dc, MO_TEUQ, addr);
|
||||
if (par[0]) {
|
||||
tcg_gen_qemu_st_i64(arg[0].in, addr, dc->cring, mop);
|
||||
} else {
|
||||
|
|
|
@ -1744,7 +1744,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext,
|
|||
case MO_SL:
|
||||
tcg_out_ldst_r(s, I3312_LDRSWX, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
tcg_out_ldst_r(s, I3312_LDRX, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1443,13 +1443,13 @@ static void * const qemu_ld_helpers[MO_SSIZE + 1] = {
|
|||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
[MO_UW] = helper_be_lduw_mmu,
|
||||
[MO_UL] = helper_be_ldul_mmu,
|
||||
[MO_Q] = helper_be_ldq_mmu,
|
||||
[MO_UQ] = helper_be_ldq_mmu,
|
||||
[MO_SW] = helper_be_ldsw_mmu,
|
||||
[MO_SL] = helper_be_ldul_mmu,
|
||||
#else
|
||||
[MO_UW] = helper_le_lduw_mmu,
|
||||
[MO_UL] = helper_le_ldul_mmu,
|
||||
[MO_Q] = helper_le_ldq_mmu,
|
||||
[MO_UQ] = helper_le_ldq_mmu,
|
||||
[MO_SW] = helper_le_ldsw_mmu,
|
||||
[MO_SL] = helper_le_ldul_mmu,
|
||||
#endif
|
||||
|
@ -1694,7 +1694,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
|
|||
default:
|
||||
tcg_out_mov_reg(s, COND_AL, datalo, TCG_REG_R0);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
if (datalo != TCG_REG_R1) {
|
||||
tcg_out_mov_reg(s, COND_AL, datalo, TCG_REG_R0);
|
||||
tcg_out_mov_reg(s, COND_AL, datahi, TCG_REG_R1);
|
||||
|
@ -1781,7 +1781,7 @@ static void tcg_out_qemu_ld_index(TCGContext *s, MemOp opc,
|
|||
case MO_UL:
|
||||
tcg_out_ld32_r(s, COND_AL, datalo, addrlo, addend);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
/* Avoid ldrd for user-only emulation, to handle unaligned. */
|
||||
if (USING_SOFTMMU && use_armv6_instructions
|
||||
&& (datalo & 1) == 0 && datahi == datalo + 1) {
|
||||
|
@ -1824,7 +1824,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg datalo,
|
|||
case MO_UL:
|
||||
tcg_out_ld32_12(s, COND_AL, datalo, addrlo, 0);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
/* Avoid ldrd for user-only emulation, to handle unaligned. */
|
||||
if (USING_SOFTMMU && use_armv6_instructions
|
||||
&& (datalo & 1) == 0 && datahi == datalo + 1) {
|
||||
|
|
|
@ -1615,10 +1615,10 @@ static void * const qemu_ld_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
|
|||
[MO_UB] = helper_ret_ldub_mmu,
|
||||
[MO_LEUW] = helper_le_lduw_mmu,
|
||||
[MO_LEUL] = helper_le_ldul_mmu,
|
||||
[MO_LEQ] = helper_le_ldq_mmu,
|
||||
[MO_LEUQ] = helper_le_ldq_mmu,
|
||||
[MO_BEUW] = helper_be_lduw_mmu,
|
||||
[MO_BEUL] = helper_be_ldul_mmu,
|
||||
[MO_BEQ] = helper_be_ldq_mmu,
|
||||
[MO_BEUQ] = helper_be_ldq_mmu,
|
||||
};
|
||||
|
||||
/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
|
||||
|
@ -1628,10 +1628,10 @@ static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
|
|||
[MO_UB] = helper_ret_stb_mmu,
|
||||
[MO_LEUW] = helper_le_stw_mmu,
|
||||
[MO_LEUL] = helper_le_stl_mmu,
|
||||
[MO_LEQ] = helper_le_stq_mmu,
|
||||
[MO_LEUQ] = helper_le_stq_mmu,
|
||||
[MO_BEUW] = helper_be_stw_mmu,
|
||||
[MO_BEUL] = helper_be_stl_mmu,
|
||||
[MO_BEQ] = helper_be_stq_mmu,
|
||||
[MO_BEUQ] = helper_be_stq_mmu,
|
||||
};
|
||||
|
||||
/* Perform the TLB load and compare.
|
||||
|
@ -1827,7 +1827,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
|
|||
case MO_UL:
|
||||
tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_RAX);
|
||||
} else if (data_reg == TCG_REG_EDX) {
|
||||
|
@ -2019,7 +2019,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_modrm_sib_offset(s, movop + P_REXW + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
|
|
|
@ -1023,11 +1023,11 @@ static void * const qemu_ld_helpers[(MO_SSIZE | MO_BSWAP) + 1] = {
|
|||
[MO_LEUW] = helper_le_lduw_mmu,
|
||||
[MO_LESW] = helper_le_ldsw_mmu,
|
||||
[MO_LEUL] = helper_le_ldul_mmu,
|
||||
[MO_LEQ] = helper_le_ldq_mmu,
|
||||
[MO_LEUQ] = helper_le_ldq_mmu,
|
||||
[MO_BEUW] = helper_be_lduw_mmu,
|
||||
[MO_BESW] = helper_be_ldsw_mmu,
|
||||
[MO_BEUL] = helper_be_ldul_mmu,
|
||||
[MO_BEQ] = helper_be_ldq_mmu,
|
||||
[MO_BEUQ] = helper_be_ldq_mmu,
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
[MO_LESL] = helper_le_ldsl_mmu,
|
||||
[MO_BESL] = helper_be_ldsl_mmu,
|
||||
|
@ -1038,10 +1038,10 @@ static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
|
|||
[MO_UB] = helper_ret_stb_mmu,
|
||||
[MO_LEUW] = helper_le_stw_mmu,
|
||||
[MO_LEUL] = helper_le_stl_mmu,
|
||||
[MO_LEQ] = helper_le_stq_mmu,
|
||||
[MO_LEUQ] = helper_le_stq_mmu,
|
||||
[MO_BEUW] = helper_be_stw_mmu,
|
||||
[MO_BEUL] = helper_be_stl_mmu,
|
||||
[MO_BEQ] = helper_be_stq_mmu,
|
||||
[MO_BEUQ] = helper_be_stq_mmu,
|
||||
};
|
||||
|
||||
/* Helper routines for marshalling helper function arguments into
|
||||
|
@ -1384,7 +1384,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
|||
case MO_SL:
|
||||
tcg_out_opc_imm(s, OPC_LW, lo, base, 0);
|
||||
break;
|
||||
case MO_Q | MO_BSWAP:
|
||||
case MO_UQ | MO_BSWAP:
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
if (use_mips32r2_instructions) {
|
||||
tcg_out_opc_imm(s, OPC_LD, lo, base, 0);
|
||||
|
@ -1413,7 +1413,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
|||
tcg_out_mov(s, TCG_TYPE_I32, MIPS_BE ? hi : lo, TCG_TMP3);
|
||||
}
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
/* Prefer to load from offset 0 first, but allow for overlap. */
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_LD, lo, base, 0);
|
||||
|
|
|
@ -1935,24 +1935,24 @@ static const uint32_t qemu_ldx_opc[(MO_SSIZE + MO_BSWAP) + 1] = {
|
|||
[MO_UB] = LBZX,
|
||||
[MO_UW] = LHZX,
|
||||
[MO_UL] = LWZX,
|
||||
[MO_Q] = LDX,
|
||||
[MO_UQ] = LDX,
|
||||
[MO_SW] = LHAX,
|
||||
[MO_SL] = LWAX,
|
||||
[MO_BSWAP | MO_UB] = LBZX,
|
||||
[MO_BSWAP | MO_UW] = LHBRX,
|
||||
[MO_BSWAP | MO_UL] = LWBRX,
|
||||
[MO_BSWAP | MO_Q] = LDBRX,
|
||||
[MO_BSWAP | MO_UQ] = LDBRX,
|
||||
};
|
||||
|
||||
static const uint32_t qemu_stx_opc[(MO_SIZE + MO_BSWAP) + 1] = {
|
||||
[MO_UB] = STBX,
|
||||
[MO_UW] = STHX,
|
||||
[MO_UL] = STWX,
|
||||
[MO_Q] = STDX,
|
||||
[MO_UQ] = STDX,
|
||||
[MO_BSWAP | MO_UB] = STBX,
|
||||
[MO_BSWAP | MO_UW] = STHBRX,
|
||||
[MO_BSWAP | MO_UL] = STWBRX,
|
||||
[MO_BSWAP | MO_Q] = STDBRX,
|
||||
[MO_BSWAP | MO_UQ] = STDBRX,
|
||||
};
|
||||
|
||||
static const uint32_t qemu_exts_opc[4] = {
|
||||
|
@ -1969,10 +1969,10 @@ static void * const qemu_ld_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
|
|||
[MO_UB] = helper_ret_ldub_mmu,
|
||||
[MO_LEUW] = helper_le_lduw_mmu,
|
||||
[MO_LEUL] = helper_le_ldul_mmu,
|
||||
[MO_LEQ] = helper_le_ldq_mmu,
|
||||
[MO_LEUQ] = helper_le_ldq_mmu,
|
||||
[MO_BEUW] = helper_be_lduw_mmu,
|
||||
[MO_BEUL] = helper_be_ldul_mmu,
|
||||
[MO_BEQ] = helper_be_ldq_mmu,
|
||||
[MO_BEUQ] = helper_be_ldq_mmu,
|
||||
};
|
||||
|
||||
/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
|
||||
|
@ -1982,10 +1982,10 @@ static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
|
|||
[MO_UB] = helper_ret_stb_mmu,
|
||||
[MO_LEUW] = helper_le_stw_mmu,
|
||||
[MO_LEUL] = helper_le_stl_mmu,
|
||||
[MO_LEQ] = helper_le_stq_mmu,
|
||||
[MO_LEUQ] = helper_le_stq_mmu,
|
||||
[MO_BEUW] = helper_be_stw_mmu,
|
||||
[MO_BEUL] = helper_be_stl_mmu,
|
||||
[MO_BEQ] = helper_be_stq_mmu,
|
||||
[MO_BEUQ] = helper_be_stq_mmu,
|
||||
};
|
||||
|
||||
/* We expect to use a 16-bit negative offset from ENV. */
|
||||
|
|
|
@ -862,7 +862,7 @@ static void * const qemu_ld_helpers[MO_SSIZE + 1] = {
|
|||
#if TCG_TARGET_REG_BITS == 64
|
||||
[MO_SL] = helper_be_ldsl_mmu,
|
||||
#endif
|
||||
[MO_Q] = helper_be_ldq_mmu,
|
||||
[MO_UQ] = helper_be_ldq_mmu,
|
||||
#else
|
||||
[MO_UW] = helper_le_lduw_mmu,
|
||||
[MO_SW] = helper_le_ldsw_mmu,
|
||||
|
@ -870,7 +870,7 @@ static void * const qemu_ld_helpers[MO_SSIZE + 1] = {
|
|||
#if TCG_TARGET_REG_BITS == 64
|
||||
[MO_SL] = helper_le_ldsl_mmu,
|
||||
#endif
|
||||
[MO_Q] = helper_le_ldq_mmu,
|
||||
[MO_UQ] = helper_le_ldq_mmu,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1083,7 +1083,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
|||
case MO_SL:
|
||||
tcg_out_opc_imm(s, OPC_LW, lo, base, 0);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
/* Prefer to load from offset 0 first, but allow for overlap. */
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_LD, lo, base, 0);
|
||||
|
|
|
@ -438,22 +438,22 @@ static void * const qemu_ld_helpers[(MO_SSIZE | MO_BSWAP) + 1] = {
|
|||
[MO_LESW] = helper_le_ldsw_mmu,
|
||||
[MO_LEUL] = helper_le_ldul_mmu,
|
||||
[MO_LESL] = helper_le_ldsl_mmu,
|
||||
[MO_LEQ] = helper_le_ldq_mmu,
|
||||
[MO_LEUQ] = helper_le_ldq_mmu,
|
||||
[MO_BEUW] = helper_be_lduw_mmu,
|
||||
[MO_BESW] = helper_be_ldsw_mmu,
|
||||
[MO_BEUL] = helper_be_ldul_mmu,
|
||||
[MO_BESL] = helper_be_ldsl_mmu,
|
||||
[MO_BEQ] = helper_be_ldq_mmu,
|
||||
[MO_BEUQ] = helper_be_ldq_mmu,
|
||||
};
|
||||
|
||||
static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
|
||||
[MO_UB] = helper_ret_stb_mmu,
|
||||
[MO_LEUW] = helper_le_stw_mmu,
|
||||
[MO_LEUL] = helper_le_stl_mmu,
|
||||
[MO_LEQ] = helper_le_stq_mmu,
|
||||
[MO_LEUQ] = helper_le_stq_mmu,
|
||||
[MO_BEUW] = helper_be_stw_mmu,
|
||||
[MO_BEUL] = helper_be_stl_mmu,
|
||||
[MO_BEQ] = helper_be_stq_mmu,
|
||||
[MO_BEUQ] = helper_be_stq_mmu,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1745,10 +1745,10 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data,
|
|||
tcg_out_insn(s, RXY, LGF, data, base, index, disp);
|
||||
break;
|
||||
|
||||
case MO_Q | MO_BSWAP:
|
||||
case MO_UQ | MO_BSWAP:
|
||||
tcg_out_insn(s, RXY, LRVG, data, base, index, disp);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
tcg_out_insn(s, RXY, LG, data, base, index, disp);
|
||||
break;
|
||||
|
||||
|
@ -1791,10 +1791,10 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg data,
|
|||
}
|
||||
break;
|
||||
|
||||
case MO_Q | MO_BSWAP:
|
||||
case MO_UQ | MO_BSWAP:
|
||||
tcg_out_insn(s, RXY, STRVG, data, base, index, disp);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
tcg_out_insn(s, RXY, STG, data, base, index, disp);
|
||||
break;
|
||||
|
||||
|
@ -1928,7 +1928,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
|
|||
case MO_UL:
|
||||
tgen_ext32u(s, TCG_REG_R4, data_reg);
|
||||
break;
|
||||
case MO_Q:
|
||||
case MO_UQ:
|
||||
tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R4, data_reg);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -889,20 +889,20 @@ static void build_trampolines(TCGContext *s)
|
|||
[MO_LEUW] = helper_le_lduw_mmu,
|
||||
[MO_LESW] = helper_le_ldsw_mmu,
|
||||
[MO_LEUL] = helper_le_ldul_mmu,
|
||||
[MO_LEQ] = helper_le_ldq_mmu,
|
||||
[MO_LEUQ] = helper_le_ldq_mmu,
|
||||
[MO_BEUW] = helper_be_lduw_mmu,
|
||||
[MO_BESW] = helper_be_ldsw_mmu,
|
||||
[MO_BEUL] = helper_be_ldul_mmu,
|
||||
[MO_BEQ] = helper_be_ldq_mmu,
|
||||
[MO_BEUQ] = helper_be_ldq_mmu,
|
||||
};
|
||||
static void * const qemu_st_helpers[] = {
|
||||
[MO_UB] = helper_ret_stb_mmu,
|
||||
[MO_LEUW] = helper_le_stw_mmu,
|
||||
[MO_LEUL] = helper_le_stl_mmu,
|
||||
[MO_LEQ] = helper_le_stq_mmu,
|
||||
[MO_LEUQ] = helper_le_stq_mmu,
|
||||
[MO_BEUW] = helper_be_stw_mmu,
|
||||
[MO_BEUL] = helper_be_stl_mmu,
|
||||
[MO_BEQ] = helper_be_stq_mmu,
|
||||
[MO_BEUQ] = helper_be_stq_mmu,
|
||||
};
|
||||
|
||||
int i;
|
||||
|
@ -1126,13 +1126,13 @@ static const int qemu_ld_opc[(MO_SSIZE | MO_BSWAP) + 1] = {
|
|||
[MO_BESW] = LDSH,
|
||||
[MO_BEUL] = LDUW,
|
||||
[MO_BESL] = LDSW,
|
||||
[MO_BEQ] = LDX,
|
||||
[MO_BEUQ] = LDX,
|
||||
|
||||
[MO_LEUW] = LDUH_LE,
|
||||
[MO_LESW] = LDSH_LE,
|
||||
[MO_LEUL] = LDUW_LE,
|
||||
[MO_LESL] = LDSW_LE,
|
||||
[MO_LEQ] = LDX_LE,
|
||||
[MO_LEUQ] = LDX_LE,
|
||||
};
|
||||
|
||||
static const int qemu_st_opc[(MO_SIZE | MO_BSWAP) + 1] = {
|
||||
|
@ -1140,11 +1140,11 @@ static const int qemu_st_opc[(MO_SIZE | MO_BSWAP) + 1] = {
|
|||
|
||||
[MO_BEUW] = STH,
|
||||
[MO_BEUL] = STW,
|
||||
[MO_BEQ] = STX,
|
||||
[MO_BEUQ] = STX,
|
||||
|
||||
[MO_LEUW] = STH_LE,
|
||||
[MO_LEUL] = STW_LE,
|
||||
[MO_LEQ] = STX_LE,
|
||||
[MO_LEUQ] = STX_LE,
|
||||
};
|
||||
|
||||
static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
|
||||
|
|
|
@ -1751,12 +1751,12 @@ static const char * const ldst_name[] =
|
|||
[MO_LESW] = "lesw",
|
||||
[MO_LEUL] = "leul",
|
||||
[MO_LESL] = "lesl",
|
||||
[MO_LEQ] = "leq",
|
||||
[MO_LEUQ] = "leq",
|
||||
[MO_BEUW] = "beuw",
|
||||
[MO_BESW] = "besw",
|
||||
[MO_BEUL] = "beul",
|
||||
[MO_BESL] = "besl",
|
||||
[MO_BEQ] = "beq",
|
||||
[MO_BEUQ] = "beq",
|
||||
};
|
||||
|
||||
static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
|
||||
|
|
16
tcg/tci.c
16
tcg/tci.c
|
@ -309,7 +309,7 @@ static uint64_t tci_qemu_ld(CPUArchState *env, target_ulong taddr,
|
|||
return helper_le_ldul_mmu(env, taddr, oi, ra);
|
||||
case MO_LESL:
|
||||
return helper_le_ldsl_mmu(env, taddr, oi, ra);
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
return helper_le_ldq_mmu(env, taddr, oi, ra);
|
||||
case MO_BEUW:
|
||||
return helper_be_lduw_mmu(env, taddr, oi, ra);
|
||||
|
@ -319,7 +319,7 @@ static uint64_t tci_qemu_ld(CPUArchState *env, target_ulong taddr,
|
|||
return helper_be_ldul_mmu(env, taddr, oi, ra);
|
||||
case MO_BESL:
|
||||
return helper_be_ldsl_mmu(env, taddr, oi, ra);
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
return helper_be_ldq_mmu(env, taddr, oi, ra);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
|
@ -348,7 +348,7 @@ static uint64_t tci_qemu_ld(CPUArchState *env, target_ulong taddr,
|
|||
case MO_LESL:
|
||||
ret = (int32_t)ldl_le_p(haddr);
|
||||
break;
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
ret = ldq_le_p(haddr);
|
||||
break;
|
||||
case MO_BEUW:
|
||||
|
@ -363,7 +363,7 @@ static uint64_t tci_qemu_ld(CPUArchState *env, target_ulong taddr,
|
|||
case MO_BESL:
|
||||
ret = (int32_t)ldl_be_p(haddr);
|
||||
break;
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
ret = ldq_be_p(haddr);
|
||||
break;
|
||||
default:
|
||||
|
@ -391,7 +391,7 @@ static void tci_qemu_st(CPUArchState *env, target_ulong taddr, uint64_t val,
|
|||
case MO_LEUL:
|
||||
helper_le_stl_mmu(env, taddr, val, oi, ra);
|
||||
break;
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
helper_le_stq_mmu(env, taddr, val, oi, ra);
|
||||
break;
|
||||
case MO_BEUW:
|
||||
|
@ -400,7 +400,7 @@ static void tci_qemu_st(CPUArchState *env, target_ulong taddr, uint64_t val,
|
|||
case MO_BEUL:
|
||||
helper_be_stl_mmu(env, taddr, val, oi, ra);
|
||||
break;
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
helper_be_stq_mmu(env, taddr, val, oi, ra);
|
||||
break;
|
||||
default:
|
||||
|
@ -420,7 +420,7 @@ static void tci_qemu_st(CPUArchState *env, target_ulong taddr, uint64_t val,
|
|||
case MO_LEUL:
|
||||
stl_le_p(haddr, val);
|
||||
break;
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
stq_le_p(haddr, val);
|
||||
break;
|
||||
case MO_BEUW:
|
||||
|
@ -429,7 +429,7 @@ static void tci_qemu_st(CPUArchState *env, target_ulong taddr, uint64_t val,
|
|||
case MO_BEUL:
|
||||
stl_be_p(haddr, val);
|
||||
break;
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
stq_be_p(haddr, val);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 128-bit division and remainder for compilers not supporting __int128
|
||||
*
|
||||
* Copyright (c) 2021 Frédéric Pétrot <frederic.petrot@univ-grenoble-alpes.fr>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/int128.h"
|
||||
|
||||
#ifndef CONFIG_INT128
|
||||
|
||||
/*
|
||||
* Division and remainder algorithms for 128-bit due to Stefan Kanthak,
|
||||
* https://skanthak.homepage.t-online.de/integer.html#udivmodti4
|
||||
* Preconditions:
|
||||
* - function should never be called with v equals to 0, it has to
|
||||
* be dealt with beforehand
|
||||
* - quotien pointer must be valid
|
||||
*/
|
||||
static Int128 divrem128(Int128 u, Int128 v, Int128 *q)
|
||||
{
|
||||
Int128 qq;
|
||||
uint64_t hi, lo, tmp;
|
||||
int s = clz64(v.hi);
|
||||
|
||||
if (s == 64) {
|
||||
/* we have uu÷0v => let's use divu128 */
|
||||
hi = u.hi;
|
||||
lo = u.lo;
|
||||
tmp = divu128(&lo, &hi, v.lo);
|
||||
*q = int128_make128(lo, hi);
|
||||
return int128_make128(tmp, 0);
|
||||
} else {
|
||||
hi = int128_gethi(int128_lshift(v, s));
|
||||
|
||||
if (hi > u.hi) {
|
||||
lo = u.lo;
|
||||
tmp = u.hi;
|
||||
divu128(&lo, &tmp, hi);
|
||||
lo = int128_gethi(int128_lshift(int128_make128(lo, 0), s));
|
||||
} else { /* prevent overflow */
|
||||
lo = u.lo;
|
||||
tmp = u.hi - hi;
|
||||
divu128(&lo, &tmp, hi);
|
||||
lo = int128_gethi(int128_lshift(int128_make128(lo, 1), s));
|
||||
}
|
||||
|
||||
qq = int128_make64(lo);
|
||||
|
||||
tmp = lo * v.hi;
|
||||
mulu64(&lo, &hi, lo, v.lo);
|
||||
hi += tmp;
|
||||
|
||||
if (hi < tmp /* quotient * divisor >= 2**128 > dividend */
|
||||
|| hi > u.hi /* quotient * divisor > dividend */
|
||||
|| (hi == u.hi && lo > u.lo)) {
|
||||
qq.lo -= 1;
|
||||
mulu64(&lo, &hi, qq.lo, v.lo);
|
||||
hi += qq.lo * v.hi;
|
||||
}
|
||||
|
||||
*q = qq;
|
||||
u.hi -= hi + (u.lo < lo);
|
||||
u.lo -= lo;
|
||||
return u;
|
||||
}
|
||||
}
|
||||
|
||||
Int128 int128_divu(Int128 a, Int128 b)
|
||||
{
|
||||
Int128 q;
|
||||
divrem128(a, b, &q);
|
||||
return q;
|
||||
}
|
||||
|
||||
Int128 int128_remu(Int128 a, Int128 b)
|
||||
{
|
||||
Int128 q;
|
||||
return divrem128(a, b, &q);
|
||||
}
|
||||
|
||||
Int128 int128_divs(Int128 a, Int128 b)
|
||||
{
|
||||
Int128 q;
|
||||
bool sgna = !int128_nonneg(a);
|
||||
bool sgnb = !int128_nonneg(b);
|
||||
|
||||
if (sgna) {
|
||||
a = int128_neg(a);
|
||||
}
|
||||
|
||||
if (sgnb) {
|
||||
b = int128_neg(b);
|
||||
}
|
||||
|
||||
divrem128(a, b, &q);
|
||||
|
||||
if (sgna != sgnb) {
|
||||
q = int128_neg(q);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
Int128 int128_rems(Int128 a, Int128 b)
|
||||
{
|
||||
Int128 q, r;
|
||||
bool sgna = !int128_nonneg(a);
|
||||
bool sgnb = !int128_nonneg(b);
|
||||
|
||||
if (sgna) {
|
||||
a = int128_neg(a);
|
||||
}
|
||||
|
||||
if (sgnb) {
|
||||
b = int128_neg(b);
|
||||
}
|
||||
|
||||
r = divrem128(a, b, &q);
|
||||
|
||||
if (sgna) {
|
||||
r = int128_neg(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -48,6 +48,7 @@ util_ss.add(files('transactions.c'))
|
|||
util_ss.add(when: 'CONFIG_POSIX', if_true: files('drm.c'))
|
||||
util_ss.add(files('guest-random.c'))
|
||||
util_ss.add(files('yank.c'))
|
||||
util_ss.add(files('int128.c'))
|
||||
|
||||
if have_user
|
||||
util_ss.add(files('selfmap.c'))
|
||||
|
|
Loading…
Reference in New Issue