mirror of https://github.com/xemu-project/xemu.git
First RISC-V PR for QEMU 7.2
* Update [m|h]tinst CSR in interrupt handling * Force disable extensions if priv spec version does not match * fix shifts shamt value for rv128c * move zmmul out of the experimental * virt: pass random seed to fdt * Add checks for supported extension combinations * Upgrade OpenSBI to v1.1 * Fix typo and restore Pointer Masking functionality for RISC-V * Add mask agnostic behaviour (rvv_ma_all_1s) for vector extension * Add Zihintpause support * opentitan: bump opentitan version * microchip_pfsoc: fix kernel panics due to missing peripherals * Remove additional priv version check for mcountinhibit * virt machine device tree improvements * Add xicondops in ISA entry * Use official extension names for AIA CSRs -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmMYUCUACgkQIeENKd+X cFRpEQf/T1FFcGq3TZrEPmqMdFPUSb+SEJNgwYFfloqkNjB2HIFbd2tKWAE1Tgjr esV00p7YPyox1Ct+fKdwSxDxRSN9OI56v+nI8ZFwluVu7vpChuTFmOHur8rNxl1T 8MZgP2kMxMOJSnyHCS2iV9AUFdTExS65DbmlAKzi5fpBtt9jYTPSXsI49MP8+Ku/ 1gdv5ZF5BXDJsGs7xHvE92dRzQEVN+As64IjlknFHHpmCM1b+Ah3GekXUbKmBuDG /NaZyZNPCYxdRmPm/D7k0SOMZSJ9sLyhXTetZ0ZpBxG1ioClX37yS5wn4NLsCz/2 fXrnML+MQFUKZ03AZ9lWvxcu7kXfWA== =7mGD -----END PGP SIGNATURE----- Merge tag 'pull-riscv-to-apply-20220907' of https://github.com/alistair23/qemu into staging First RISC-V PR for QEMU 7.2 * Update [m|h]tinst CSR in interrupt handling * Force disable extensions if priv spec version does not match * fix shifts shamt value for rv128c * move zmmul out of the experimental * virt: pass random seed to fdt * Add checks for supported extension combinations * Upgrade OpenSBI to v1.1 * Fix typo and restore Pointer Masking functionality for RISC-V * Add mask agnostic behaviour (rvv_ma_all_1s) for vector extension * Add Zihintpause support * opentitan: bump opentitan version * microchip_pfsoc: fix kernel panics due to missing peripherals * Remove additional priv version check for mcountinhibit * virt machine device tree improvements * Add xicondops in ISA entry * Use official extension names for AIA CSRs # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmMYUCUACgkQIeENKd+X # cFRpEQf/T1FFcGq3TZrEPmqMdFPUSb+SEJNgwYFfloqkNjB2HIFbd2tKWAE1Tgjr # esV00p7YPyox1Ct+fKdwSxDxRSN9OI56v+nI8ZFwluVu7vpChuTFmOHur8rNxl1T # 8MZgP2kMxMOJSnyHCS2iV9AUFdTExS65DbmlAKzi5fpBtt9jYTPSXsI49MP8+Ku/ # 1gdv5ZF5BXDJsGs7xHvE92dRzQEVN+As64IjlknFHHpmCM1b+Ah3GekXUbKmBuDG # /NaZyZNPCYxdRmPm/D7k0SOMZSJ9sLyhXTetZ0ZpBxG1ioClX37yS5wn4NLsCz/2 # fXrnML+MQFUKZ03AZ9lWvxcu7kXfWA== # =7mGD # -----END PGP SIGNATURE----- # gpg: Signature made Wed 07 Sep 2022 04:02:45 EDT # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * tag 'pull-riscv-to-apply-20220907' of https://github.com/alistair23/qemu: (44 commits) target/riscv: Update the privilege field for sscofpmf CSRs hw/riscv: virt: Add PMU DT node to the device tree target/riscv: Add few cache related PMU events target/riscv: Simplify counter predicate function target/riscv: Add sscofpmf extension support target/riscv: Add vstimecmp support target/riscv: Add stimecmp support hw/intc: Move mtimer/mtimecmp to aclint target/riscv: Use official extension names for AIA CSRs target/riscv: Add xicondops in ISA entry hw/core: fix platform bus node name hw/riscv: virt: fix syscon subnode paths hw/riscv: virt: fix the plic's address cells hw/riscv: virt: fix uart node name target/riscv: Remove additional priv version check for mcountinhibit hw/riscv: microchip_pfsoc: fix kernel panics due to missing peripherals hw/riscv: opentitan: bump opentitan version target/riscv: Fix priority of csr related check in riscv_csrrw_check hw/riscv: remove 'fdt' param from riscv_setup_rom_reset_vec() target/riscv: Add Zihintpause support ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
e46e2628e9
|
@ -2402,10 +2402,25 @@ static int32_t operand_sbimm12(rv_inst inst)
|
|||
((inst << 56) >> 63) << 11;
|
||||
}
|
||||
|
||||
static uint32_t operand_cimmsh6(rv_inst inst)
|
||||
static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa)
|
||||
{
|
||||
return ((inst << 51) >> 63) << 5 |
|
||||
int imm = ((inst << 51) >> 63) << 5 |
|
||||
(inst << 57) >> 59;
|
||||
if (isa == rv128) {
|
||||
imm = imm ? imm : 64;
|
||||
}
|
||||
return imm;
|
||||
}
|
||||
|
||||
static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa)
|
||||
{
|
||||
int imm = ((inst << 51) >> 63) << 5 |
|
||||
(inst << 57) >> 59;
|
||||
if (isa == rv128) {
|
||||
imm = imm | (imm & 32) << 1;
|
||||
imm = imm ? imm : 64;
|
||||
}
|
||||
return imm;
|
||||
}
|
||||
|
||||
static int32_t operand_cimmi(rv_inst inst)
|
||||
|
@ -2529,7 +2544,7 @@ static uint32_t operand_rnum(rv_inst inst)
|
|||
|
||||
/* decode operands */
|
||||
|
||||
static void decode_inst_operands(rv_decode *dec)
|
||||
static void decode_inst_operands(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
dec->codec = opcode_data[dec->op].codec;
|
||||
|
@ -2652,7 +2667,7 @@ static void decode_inst_operands(rv_decode *dec)
|
|||
case rv_codec_cb_sh6:
|
||||
dec->rd = dec->rs1 = operand_crs1rdq(inst) + 8;
|
||||
dec->rs2 = rv_ireg_zero;
|
||||
dec->imm = operand_cimmsh6(inst);
|
||||
dec->imm = operand_cimmshr6(inst, isa);
|
||||
break;
|
||||
case rv_codec_ci:
|
||||
dec->rd = dec->rs1 = operand_crs1rd(inst);
|
||||
|
@ -2667,7 +2682,7 @@ static void decode_inst_operands(rv_decode *dec)
|
|||
case rv_codec_ci_sh6:
|
||||
dec->rd = dec->rs1 = operand_crs1rd(inst);
|
||||
dec->rs2 = rv_ireg_zero;
|
||||
dec->imm = operand_cimmsh6(inst);
|
||||
dec->imm = operand_cimmshl6(inst, isa);
|
||||
break;
|
||||
case rv_codec_ci_16sp:
|
||||
dec->rd = rv_ireg_sp;
|
||||
|
@ -3193,7 +3208,7 @@ disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst)
|
|||
dec.pc = pc;
|
||||
dec.inst = inst;
|
||||
decode_inst_opcode(&dec, isa);
|
||||
decode_inst_operands(&dec);
|
||||
decode_inst_operands(&dec, isa);
|
||||
decode_inst_decompress(&dec, isa);
|
||||
decode_inst_lift_pseudo(&dec);
|
||||
format_inst(buf, buflen, 16, &dec);
|
||||
|
|
|
@ -46,7 +46,7 @@ Those hosts are officially supported, with various accelerators:
|
|||
* - PPC
|
||||
- kvm, tcg
|
||||
* - RISC-V
|
||||
- tcg
|
||||
- kvm, tcg
|
||||
* - s390x
|
||||
- kvm, tcg
|
||||
* - SPARC
|
||||
|
|
|
@ -539,7 +539,7 @@ void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr,
|
|||
|
||||
assert(fdt);
|
||||
|
||||
node = g_strdup_printf("/platform@%"PRIx64, addr);
|
||||
node = g_strdup_printf("/platform-bus@%"PRIx64, addr);
|
||||
|
||||
/* Create a /platform node that we can put all devices into */
|
||||
qemu_fdt_add_subnode(fdt, node);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "hw/intc/riscv_aclint.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
typedef struct riscv_aclint_mtimer_callback {
|
||||
RISCVAclintMTimerState *s;
|
||||
|
@ -65,19 +66,22 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
|
|||
|
||||
uint64_t rtc_r = cpu_riscv_read_rtc(mtimer);
|
||||
|
||||
cpu->env.timecmp = value;
|
||||
if (cpu->env.timecmp <= rtc_r) {
|
||||
/* Compute the relative hartid w.r.t the socket */
|
||||
hartid = hartid - mtimer->hartid_base;
|
||||
|
||||
mtimer->timecmp[hartid] = value;
|
||||
if (mtimer->timecmp[hartid] <= rtc_r) {
|
||||
/*
|
||||
* If we're setting an MTIMECMP value in the "past",
|
||||
* immediately raise the timer interrupt
|
||||
*/
|
||||
qemu_irq_raise(mtimer->timer_irqs[hartid - mtimer->hartid_base]);
|
||||
qemu_irq_raise(mtimer->timer_irqs[hartid]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise, set up the future timer interrupt */
|
||||
qemu_irq_lower(mtimer->timer_irqs[hartid - mtimer->hartid_base]);
|
||||
diff = cpu->env.timecmp - rtc_r;
|
||||
qemu_irq_lower(mtimer->timer_irqs[hartid]);
|
||||
diff = mtimer->timecmp[hartid] - rtc_r;
|
||||
/* back to ns (note args switched in muldiv64) */
|
||||
uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
|
||||
|
||||
|
@ -102,7 +106,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
|
|||
next = MIN(next, INT64_MAX);
|
||||
}
|
||||
|
||||
timer_mod(cpu->env.timer, next);
|
||||
timer_mod(mtimer->timers[hartid], next);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -133,11 +137,11 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
|
|||
"aclint-mtimer: invalid hartid: %zu", hartid);
|
||||
} else if ((addr & 0x7) == 0) {
|
||||
/* timecmp_lo for RV32/RV64 or timecmp for RV64 */
|
||||
uint64_t timecmp = env->timecmp;
|
||||
uint64_t timecmp = mtimer->timecmp[hartid];
|
||||
return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp;
|
||||
} else if ((addr & 0x7) == 4) {
|
||||
/* timecmp_hi */
|
||||
uint64_t timecmp = env->timecmp;
|
||||
uint64_t timecmp = mtimer->timecmp[hartid];
|
||||
return (timecmp >> 32) & 0xFFFFFFFF;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
|
@ -177,7 +181,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
} else if ((addr & 0x7) == 0) {
|
||||
if (size == 4) {
|
||||
/* timecmp_lo for RV32/RV64 */
|
||||
uint64_t timecmp_hi = env->timecmp >> 32;
|
||||
uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32;
|
||||
riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
|
||||
timecmp_hi << 32 | (value & 0xFFFFFFFF));
|
||||
} else {
|
||||
|
@ -188,7 +192,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
} else if ((addr & 0x7) == 4) {
|
||||
if (size == 4) {
|
||||
/* timecmp_hi for RV32/RV64 */
|
||||
uint64_t timecmp_lo = env->timecmp;
|
||||
uint64_t timecmp_lo = mtimer->timecmp[hartid];
|
||||
riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
|
||||
value << 32 | (timecmp_lo & 0xFFFFFFFF));
|
||||
} else {
|
||||
|
@ -234,7 +238,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
}
|
||||
riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu),
|
||||
mtimer->hartid_base + i,
|
||||
env->timecmp);
|
||||
mtimer->timecmp[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -284,6 +288,8 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
|
|||
s->timer_irqs = g_new(qemu_irq, s->num_harts);
|
||||
qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts);
|
||||
|
||||
s->timers = g_new0(QEMUTimer *, s->num_harts);
|
||||
s->timecmp = g_new0(uint64_t, s->num_harts);
|
||||
/* Claim timer interrupt bits */
|
||||
for (i = 0; i < s->num_harts; i++) {
|
||||
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
|
||||
|
@ -310,6 +316,18 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
|
|||
riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_riscv_mtimer = {
|
||||
.name = "riscv_mtimer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
|
||||
num_harts, 0,
|
||||
vmstate_info_uint64, uint64_t),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
@ -317,6 +335,7 @@ static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
|
|||
device_class_set_props(dc, riscv_aclint_mtimer_properties);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
rc->phases.enter = riscv_aclint_mtimer_reset_enter;
|
||||
dc->vmsd = &vmstate_riscv_mtimer;
|
||||
}
|
||||
|
||||
static const TypeInfo riscv_aclint_mtimer_info = {
|
||||
|
@ -336,6 +355,7 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
|
|||
{
|
||||
int i;
|
||||
DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
|
||||
RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
|
||||
|
||||
assert(num_harts <= RISCV_ACLINT_MAX_HARTS);
|
||||
assert(!(addr & 0x7));
|
||||
|
@ -366,11 +386,11 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
|
|||
riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev);
|
||||
}
|
||||
|
||||
cb->s = RISCV_ACLINT_MTIMER(dev);
|
||||
cb->s = s;
|
||||
cb->num = i;
|
||||
env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
&riscv_aclint_mtimer_cb, cb);
|
||||
env->timecmp = 0;
|
||||
s->timecmp[i] = 0;
|
||||
|
||||
qdev_connect_gpio_out(dev, i,
|
||||
qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER));
|
||||
|
|
|
@ -344,9 +344,11 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
/* Force select AIA feature and setup CSR read-modify-write callback */
|
||||
if (env) {
|
||||
riscv_set_feature(env, RISCV_FEATURE_AIA);
|
||||
if (!imsic->mmode) {
|
||||
rcpu->cfg.ext_ssaia = true;
|
||||
riscv_cpu_set_geilen(env, imsic->num_pages - 1);
|
||||
} else {
|
||||
rcpu->cfg.ext_smaia = true;
|
||||
}
|
||||
riscv_cpu_set_aia_ireg_rmw_fn(env, (imsic->mmode) ? PRV_M : PRV_S,
|
||||
riscv_imsic_rmw, imsic);
|
||||
|
|
|
@ -286,7 +286,7 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
|
|||
hwaddr start_addr,
|
||||
hwaddr rom_base, hwaddr rom_size,
|
||||
uint64_t kernel_entry,
|
||||
uint64_t fdt_load_addr, void *fdt)
|
||||
uint64_t fdt_load_addr)
|
||||
{
|
||||
int i;
|
||||
uint32_t start_addr_hi32 = 0x00000000;
|
||||
|
@ -326,8 +326,6 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
|
|||
rom_base, &address_space_memory);
|
||||
riscv_rom_copy_firmware_info(machine, rom_base, rom_size, sizeof(reset_vec),
|
||||
kernel_entry);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr)
|
||||
|
|
|
@ -100,8 +100,11 @@ static const MemMapEntry microchip_pfsoc_memmap[] = {
|
|||
[MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 },
|
||||
[MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_WDOG0] = { 0x20001000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_AXISW] = { 0x20004000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_FMETER] = { 0x20006000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 },
|
||||
|
@ -109,19 +112,28 @@ static const MemMapEntry microchip_pfsoc_memmap[] = {
|
|||
[MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_WDOG1] = { 0x20101000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_WDOG2] = { 0x20103000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_WDOG3] = { 0x20105000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_WDOG4] = { 0x20106000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_I2C0] = { 0x2010a000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_CAN0] = { 0x2010c000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_CAN1] = { 0x2010d000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_RTC] = { 0x20124000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 },
|
||||
[MICROCHIP_PFSOC_USB] = { 0x20201000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 },
|
||||
[MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 },
|
||||
[MICROCHIP_PFSOC_EMMC_SD_MUX] = { 0x4f000000, 0x4 },
|
||||
[MICROCHIP_PFSOC_FABRIC_FIC3] = { 0x40000000, 0x20000000 },
|
||||
[MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 },
|
||||
[MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 },
|
||||
[MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 },
|
||||
|
@ -292,11 +304,21 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0,
|
||||
memmap[MICROCHIP_PFSOC_SYSREG].base);
|
||||
|
||||
/* AXISW */
|
||||
create_unimplemented_device("microchip.pfsoc.axisw",
|
||||
memmap[MICROCHIP_PFSOC_AXISW].base,
|
||||
memmap[MICROCHIP_PFSOC_AXISW].size);
|
||||
|
||||
/* MPUCFG */
|
||||
create_unimplemented_device("microchip.pfsoc.mpucfg",
|
||||
memmap[MICROCHIP_PFSOC_MPUCFG].base,
|
||||
memmap[MICROCHIP_PFSOC_MPUCFG].size);
|
||||
|
||||
/* FMETER */
|
||||
create_unimplemented_device("microchip.pfsoc.fmeter",
|
||||
memmap[MICROCHIP_PFSOC_FMETER].base,
|
||||
memmap[MICROCHIP_PFSOC_FMETER].size);
|
||||
|
||||
/* DDR SGMII PHY */
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), 0,
|
||||
|
@ -336,6 +358,23 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
|||
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ),
|
||||
serial_hd(4));
|
||||
|
||||
/* Watchdogs */
|
||||
create_unimplemented_device("microchip.pfsoc.watchdog0",
|
||||
memmap[MICROCHIP_PFSOC_WDOG0].base,
|
||||
memmap[MICROCHIP_PFSOC_WDOG0].size);
|
||||
create_unimplemented_device("microchip.pfsoc.watchdog1",
|
||||
memmap[MICROCHIP_PFSOC_WDOG1].base,
|
||||
memmap[MICROCHIP_PFSOC_WDOG1].size);
|
||||
create_unimplemented_device("microchip.pfsoc.watchdog2",
|
||||
memmap[MICROCHIP_PFSOC_WDOG2].base,
|
||||
memmap[MICROCHIP_PFSOC_WDOG2].size);
|
||||
create_unimplemented_device("microchip.pfsoc.watchdog3",
|
||||
memmap[MICROCHIP_PFSOC_WDOG3].base,
|
||||
memmap[MICROCHIP_PFSOC_WDOG3].size);
|
||||
create_unimplemented_device("microchip.pfsoc.watchdog4",
|
||||
memmap[MICROCHIP_PFSOC_WDOG4].base,
|
||||
memmap[MICROCHIP_PFSOC_WDOG4].size);
|
||||
|
||||
/* SPI */
|
||||
create_unimplemented_device("microchip.pfsoc.spi0",
|
||||
memmap[MICROCHIP_PFSOC_SPI0].base,
|
||||
|
@ -344,11 +383,27 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
|||
memmap[MICROCHIP_PFSOC_SPI1].base,
|
||||
memmap[MICROCHIP_PFSOC_SPI1].size);
|
||||
|
||||
/* I2C1 */
|
||||
/* I2C */
|
||||
create_unimplemented_device("microchip.pfsoc.i2c0",
|
||||
memmap[MICROCHIP_PFSOC_I2C0].base,
|
||||
memmap[MICROCHIP_PFSOC_I2C0].size);
|
||||
create_unimplemented_device("microchip.pfsoc.i2c1",
|
||||
memmap[MICROCHIP_PFSOC_I2C1].base,
|
||||
memmap[MICROCHIP_PFSOC_I2C1].size);
|
||||
|
||||
/* CAN */
|
||||
create_unimplemented_device("microchip.pfsoc.can0",
|
||||
memmap[MICROCHIP_PFSOC_CAN0].base,
|
||||
memmap[MICROCHIP_PFSOC_CAN0].size);
|
||||
create_unimplemented_device("microchip.pfsoc.can1",
|
||||
memmap[MICROCHIP_PFSOC_CAN1].base,
|
||||
memmap[MICROCHIP_PFSOC_CAN1].size);
|
||||
|
||||
/* USB */
|
||||
create_unimplemented_device("microchip.pfsoc.usb",
|
||||
memmap[MICROCHIP_PFSOC_USB].base,
|
||||
memmap[MICROCHIP_PFSOC_USB].size);
|
||||
|
||||
/* GEMs */
|
||||
|
||||
nd = &nd_table[0];
|
||||
|
@ -402,10 +457,10 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0,
|
||||
memmap[MICROCHIP_PFSOC_IOSCB].base);
|
||||
|
||||
/* eMMC/SD mux */
|
||||
create_unimplemented_device("microchip.pfsoc.emmc_sd_mux",
|
||||
memmap[MICROCHIP_PFSOC_EMMC_SD_MUX].base,
|
||||
memmap[MICROCHIP_PFSOC_EMMC_SD_MUX].size);
|
||||
/* FPGA Fabric */
|
||||
create_unimplemented_device("microchip.pfsoc.fabricfic3",
|
||||
memmap[MICROCHIP_PFSOC_FABRIC_FIC3].base,
|
||||
memmap[MICROCHIP_PFSOC_FABRIC_FIC3].size);
|
||||
|
||||
/* QSPI Flash */
|
||||
memory_region_init_rom(qspi_xip_mem, OBJECT(dev),
|
||||
|
@ -583,7 +638,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
|||
riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr,
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
|
||||
kernel_entry, fdt_load_addr, machine->fdt);
|
||||
kernel_entry, fdt_load_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
#include "sysemu/sysemu.h"
|
||||
|
||||
static const MemMapEntry ibex_memmap[] = {
|
||||
[IBEX_DEV_ROM] = { 0x00008000, 16 * KiB },
|
||||
[IBEX_DEV_RAM] = { 0x10000000, 0x10000 },
|
||||
[IBEX_DEV_FLASH] = { 0x20000000, 0x80000 },
|
||||
[IBEX_DEV_ROM] = { 0x00008000, 0x8000 },
|
||||
[IBEX_DEV_RAM] = { 0x10000000, 0x20000 },
|
||||
[IBEX_DEV_FLASH] = { 0x20000000, 0x100000 },
|
||||
[IBEX_DEV_UART] = { 0x40000000, 0x1000 },
|
||||
[IBEX_DEV_GPIO] = { 0x40040000, 0x1000 },
|
||||
[IBEX_DEV_SPI_DEVICE] = { 0x40050000, 0x1000 },
|
||||
|
@ -40,6 +40,7 @@ static const MemMapEntry ibex_memmap[] = {
|
|||
[IBEX_DEV_TIMER] = { 0x40100000, 0x1000 },
|
||||
[IBEX_DEV_SENSOR_CTRL] = { 0x40110000, 0x1000 },
|
||||
[IBEX_DEV_OTP_CTRL] = { 0x40130000, 0x4000 },
|
||||
[IBEX_DEV_LC_CTRL] = { 0x40140000, 0x1000 },
|
||||
[IBEX_DEV_USBDEV] = { 0x40150000, 0x1000 },
|
||||
[IBEX_DEV_SPI_HOST0] = { 0x40300000, 0x1000 },
|
||||
[IBEX_DEV_SPI_HOST1] = { 0x40310000, 0x1000 },
|
||||
|
@ -141,7 +142,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x20000490,
|
||||
&error_abort);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal);
|
||||
|
||||
/* Boot ROM */
|
||||
|
@ -253,6 +255,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
memmap[IBEX_DEV_SENSOR_CTRL].base, memmap[IBEX_DEV_SENSOR_CTRL].size);
|
||||
create_unimplemented_device("riscv.lowrisc.ibex.otp_ctrl",
|
||||
memmap[IBEX_DEV_OTP_CTRL].base, memmap[IBEX_DEV_OTP_CTRL].size);
|
||||
create_unimplemented_device("riscv.lowrisc.ibex.lc_ctrl",
|
||||
memmap[IBEX_DEV_LC_CTRL].base, memmap[IBEX_DEV_LC_CTRL].size);
|
||||
create_unimplemented_device("riscv.lowrisc.ibex.pwrmgr",
|
||||
memmap[IBEX_DEV_PWRMGR].base, memmap[IBEX_DEV_PWRMGR].size);
|
||||
create_unimplemented_device("riscv.lowrisc.ibex.rstmgr",
|
||||
|
|
|
@ -66,8 +66,7 @@ static void shakti_c_machine_state_init(MachineState *mstate)
|
|||
riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus,
|
||||
shakti_c_memmap[SHAKTI_C_RAM].base,
|
||||
shakti_c_memmap[SHAKTI_C_ROM].base,
|
||||
shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0,
|
||||
NULL);
|
||||
shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0);
|
||||
if (mstate->firmware) {
|
||||
riscv_load_firmware(mstate->firmware,
|
||||
shakti_c_memmap[SHAKTI_C_RAM].base,
|
||||
|
|
|
@ -308,7 +308,7 @@ static void spike_board_init(MachineState *machine)
|
|||
riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base,
|
||||
memmap[SPIKE_MROM].base,
|
||||
memmap[SPIKE_MROM].size, kernel_entry,
|
||||
fdt_load_addr, s->fdt);
|
||||
fdt_load_addr);
|
||||
|
||||
/* initialize HTIF using symbols found in load_kernel */
|
||||
htif_mm_init(system_memory, mask_rom,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include "hw/char/serial.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/core/sysbus-fdt.h"
|
||||
#include "target/riscv/pmu.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/virt.h"
|
||||
#include "hw/riscv/boot.h"
|
||||
|
@ -259,17 +261,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
|
|||
qemu_fdt_add_subnode(mc->fdt, intc_name);
|
||||
qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
|
||||
intc_phandles[cpu]);
|
||||
if (riscv_feature(&s->soc[socket].harts[cpu].env,
|
||||
RISCV_FEATURE_AIA)) {
|
||||
static const char * const compat[2] = {
|
||||
"riscv,cpu-intc-aia", "riscv,cpu-intc"
|
||||
};
|
||||
qemu_fdt_setprop_string_array(mc->fdt, intc_name, "compatible",
|
||||
(char **)&compat, ARRAY_SIZE(compat));
|
||||
} else {
|
||||
qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
|
||||
"riscv,cpu-intc");
|
||||
}
|
||||
qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
|
||||
"riscv,cpu-intc");
|
||||
qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
|
||||
|
||||
|
@ -465,6 +458,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
|
|||
qemu_fdt_add_subnode(mc->fdt, plic_name);
|
||||
qemu_fdt_setprop_cell(mc->fdt, plic_name,
|
||||
"#interrupt-cells", FDT_PLIC_INT_CELLS);
|
||||
qemu_fdt_setprop_cell(mc->fdt, plic_name,
|
||||
"#address-cells", FDT_PLIC_ADDR_CELLS);
|
||||
qemu_fdt_setprop_string_array(mc->fdt, plic_name, "compatible",
|
||||
(char **)&plic_compat,
|
||||
ARRAY_SIZE(plic_compat));
|
||||
|
@ -714,6 +709,20 @@ static void create_fdt_socket_aplic(RISCVVirtState *s,
|
|||
aplic_phandles[socket] = aplic_s_phandle;
|
||||
}
|
||||
|
||||
static void create_fdt_pmu(RISCVVirtState *s)
|
||||
{
|
||||
char *pmu_name;
|
||||
MachineState *mc = MACHINE(s);
|
||||
RISCVCPU hart = s->soc[0].harts[0];
|
||||
|
||||
pmu_name = g_strdup_printf("/soc/pmu");
|
||||
qemu_fdt_add_subnode(mc->fdt, pmu_name);
|
||||
qemu_fdt_setprop_string(mc->fdt, pmu_name, "compatible", "riscv,pmu");
|
||||
riscv_pmu_generate_fdt_node(mc->fdt, hart.cfg.pmu_num, pmu_name);
|
||||
|
||||
g_free(pmu_name);
|
||||
}
|
||||
|
||||
static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
bool is_32_bit, uint32_t *phandle,
|
||||
uint32_t *irq_mmio_phandle,
|
||||
|
@ -894,7 +903,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
|
||||
g_free(name);
|
||||
|
||||
name = g_strdup_printf("/soc/reboot");
|
||||
name = g_strdup_printf("/reboot");
|
||||
qemu_fdt_add_subnode(mc->fdt, name);
|
||||
qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
|
||||
qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
|
||||
|
@ -902,7 +911,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
|
||||
g_free(name);
|
||||
|
||||
name = g_strdup_printf("/soc/poweroff");
|
||||
name = g_strdup_printf("/poweroff");
|
||||
qemu_fdt_add_subnode(mc->fdt, name);
|
||||
qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
|
||||
qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
|
||||
|
@ -917,7 +926,7 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
char *name;
|
||||
MachineState *mc = MACHINE(s);
|
||||
|
||||
name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
|
||||
name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base);
|
||||
qemu_fdt_add_subnode(mc->fdt, name);
|
||||
qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
|
||||
qemu_fdt_setprop_cells(mc->fdt, name, "reg",
|
||||
|
@ -998,6 +1007,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
MachineState *mc = MACHINE(s);
|
||||
uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1;
|
||||
uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
|
||||
uint8_t rng_seed[32];
|
||||
|
||||
if (mc->dtb) {
|
||||
mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
|
||||
|
@ -1041,11 +1051,16 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
|||
|
||||
create_fdt_flash(s, memmap);
|
||||
create_fdt_fw_cfg(s, memmap);
|
||||
create_fdt_pmu(s);
|
||||
|
||||
update_bootargs:
|
||||
if (cmdline && *cmdline) {
|
||||
qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
|
||||
/* Pass seed to RNG */
|
||||
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
|
||||
qemu_fdt_setprop(mc->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
|
||||
}
|
||||
|
||||
static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
|
||||
|
@ -1299,7 +1314,7 @@ static void virt_machine_done(Notifier *notifier, void *data)
|
|||
riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr,
|
||||
virt_memmap[VIRT_MROM].base,
|
||||
virt_memmap[VIRT_MROM].size, kernel_entry,
|
||||
fdt_load_addr, machine->fdt);
|
||||
fdt_load_addr);
|
||||
|
||||
/*
|
||||
* Only direct boot kernel is currently supported for KVM VM,
|
||||
|
|
|
@ -60,8 +60,6 @@ static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
|
|||
|
||||
static void ibex_timer_update_irqs(IbexTimerState *s)
|
||||
{
|
||||
CPUState *cs = qemu_get_cpu(0);
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
uint64_t value = s->timer_compare_lower0 |
|
||||
((uint64_t)s->timer_compare_upper0 << 32);
|
||||
uint64_t next, diff;
|
||||
|
@ -73,9 +71,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
|
|||
}
|
||||
|
||||
/* Update the CPUs mtimecmp */
|
||||
cpu->env.timecmp = value;
|
||||
s->mtimecmp = value;
|
||||
|
||||
if (cpu->env.timecmp <= now) {
|
||||
if (s->mtimecmp <= now) {
|
||||
/*
|
||||
* If the mtimecmp was in the past raise the interrupt now.
|
||||
*/
|
||||
|
@ -91,7 +89,7 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
|
|||
qemu_irq_lower(s->m_timer_irq);
|
||||
qemu_set_irq(s->irq, false);
|
||||
|
||||
diff = cpu->env.timecmp - now;
|
||||
diff = s->mtimecmp - now;
|
||||
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
muldiv64(diff,
|
||||
NANOSECONDS_PER_SECOND,
|
||||
|
@ -99,9 +97,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
|
|||
|
||||
if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
|
||||
/* We overflowed the timer, just set it as large as we can */
|
||||
timer_mod(cpu->env.timer, 0x7FFFFFFFFFFFFFFF);
|
||||
timer_mod(s->mtimer, 0x7FFFFFFFFFFFFFFF);
|
||||
} else {
|
||||
timer_mod(cpu->env.timer, next);
|
||||
timer_mod(s->mtimer, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,11 +118,9 @@ static void ibex_timer_reset(DeviceState *dev)
|
|||
{
|
||||
IbexTimerState *s = IBEX_TIMER(dev);
|
||||
|
||||
CPUState *cpu = qemu_get_cpu(0);
|
||||
CPURISCVState *env = cpu->env_ptr;
|
||||
env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
s->mtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
&ibex_timer_cb, s);
|
||||
env->timecmp = 0;
|
||||
s->mtimecmp = 0;
|
||||
|
||||
s->timer_ctrl = 0x00000000;
|
||||
s->timer_cfg0 = 0x00010000;
|
||||
|
|
|
@ -32,6 +32,8 @@ typedef struct RISCVAclintMTimerState {
|
|||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
uint64_t time_delta;
|
||||
uint64_t *timecmp;
|
||||
QEMUTimer **timers;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion mmio;
|
||||
|
|
|
@ -51,7 +51,7 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
|
|||
hwaddr saddr,
|
||||
hwaddr rom_base, hwaddr rom_size,
|
||||
uint64_t kernel_entry,
|
||||
uint64_t fdt_load_addr, void *fdt);
|
||||
uint64_t fdt_load_addr);
|
||||
void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
|
||||
hwaddr rom_size,
|
||||
uint32_t reset_vec_size,
|
||||
|
|
|
@ -88,8 +88,11 @@ enum {
|
|||
MICROCHIP_PFSOC_L2LIM,
|
||||
MICROCHIP_PFSOC_PLIC,
|
||||
MICROCHIP_PFSOC_MMUART0,
|
||||
MICROCHIP_PFSOC_WDOG0,
|
||||
MICROCHIP_PFSOC_SYSREG,
|
||||
MICROCHIP_PFSOC_AXISW,
|
||||
MICROCHIP_PFSOC_MPUCFG,
|
||||
MICROCHIP_PFSOC_FMETER,
|
||||
MICROCHIP_PFSOC_DDR_SGMII_PHY,
|
||||
MICROCHIP_PFSOC_EMMC_SD,
|
||||
MICROCHIP_PFSOC_DDR_CFG,
|
||||
|
@ -97,19 +100,28 @@ enum {
|
|||
MICROCHIP_PFSOC_MMUART2,
|
||||
MICROCHIP_PFSOC_MMUART3,
|
||||
MICROCHIP_PFSOC_MMUART4,
|
||||
MICROCHIP_PFSOC_WDOG1,
|
||||
MICROCHIP_PFSOC_WDOG2,
|
||||
MICROCHIP_PFSOC_WDOG3,
|
||||
MICROCHIP_PFSOC_WDOG4,
|
||||
MICROCHIP_PFSOC_SPI0,
|
||||
MICROCHIP_PFSOC_SPI1,
|
||||
MICROCHIP_PFSOC_I2C0,
|
||||
MICROCHIP_PFSOC_I2C1,
|
||||
MICROCHIP_PFSOC_CAN0,
|
||||
MICROCHIP_PFSOC_CAN1,
|
||||
MICROCHIP_PFSOC_GEM0,
|
||||
MICROCHIP_PFSOC_GEM1,
|
||||
MICROCHIP_PFSOC_GPIO0,
|
||||
MICROCHIP_PFSOC_GPIO1,
|
||||
MICROCHIP_PFSOC_GPIO2,
|
||||
MICROCHIP_PFSOC_RTC,
|
||||
MICROCHIP_PFSOC_ENVM_CFG,
|
||||
MICROCHIP_PFSOC_ENVM_DATA,
|
||||
MICROCHIP_PFSOC_USB,
|
||||
MICROCHIP_PFSOC_QSPI_XIP,
|
||||
MICROCHIP_PFSOC_IOSCB,
|
||||
MICROCHIP_PFSOC_EMMC_SD_MUX,
|
||||
MICROCHIP_PFSOC_FABRIC_FIC3,
|
||||
MICROCHIP_PFSOC_DRAM_LO,
|
||||
MICROCHIP_PFSOC_DRAM_LO_ALIAS,
|
||||
MICROCHIP_PFSOC_DRAM_HI,
|
||||
|
|
|
@ -74,6 +74,7 @@ enum {
|
|||
IBEX_DEV_TIMER,
|
||||
IBEX_DEV_SENSOR_CTRL,
|
||||
IBEX_DEV_OTP_CTRL,
|
||||
IBEX_DEV_LC_CTRL,
|
||||
IBEX_DEV_PWRMGR,
|
||||
IBEX_DEV_RSTMGR,
|
||||
IBEX_DEV_CLKMGR,
|
||||
|
@ -105,11 +106,11 @@ enum {
|
|||
IBEX_UART0_RX_BREAK_ERR_IRQ = 6,
|
||||
IBEX_UART0_RX_TIMEOUT_IRQ = 7,
|
||||
IBEX_UART0_RX_PARITY_ERR_IRQ = 8,
|
||||
IBEX_TIMER_TIMEREXPIRED0_0 = 126,
|
||||
IBEX_SPI_HOST0_ERR_IRQ = 150,
|
||||
IBEX_SPI_HOST0_SPI_EVENT_IRQ = 151,
|
||||
IBEX_SPI_HOST1_ERR_IRQ = 152,
|
||||
IBEX_SPI_HOST1_SPI_EVENT_IRQ = 153,
|
||||
IBEX_TIMER_TIMEREXPIRED0_0 = 127,
|
||||
IBEX_SPI_HOST0_ERR_IRQ = 151,
|
||||
IBEX_SPI_HOST0_SPI_EVENT_IRQ = 152,
|
||||
IBEX_SPI_HOST1_ERR_IRQ = 153,
|
||||
IBEX_SPI_HOST1_SPI_EVENT_IRQ = 154,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -111,6 +111,7 @@ enum {
|
|||
|
||||
#define FDT_PCI_ADDR_CELLS 3
|
||||
#define FDT_PCI_INT_CELLS 1
|
||||
#define FDT_PLIC_ADDR_CELLS 0
|
||||
#define FDT_PLIC_INT_CELLS 1
|
||||
#define FDT_APLIC_INT_CELLS 2
|
||||
#define FDT_IMSIC_INT_CELLS 0
|
||||
|
|
|
@ -33,6 +33,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IbexTimerState, IBEX_TIMER)
|
|||
struct IbexTimerState {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
uint64_t mtimecmp;
|
||||
QEMUTimer *mtimer; /* Internal timer for M-mode interrupt */
|
||||
|
||||
/* <public> */
|
||||
MemoryRegion mmio;
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit 48f91ee9c960f048c4a7d1da4447d31e04931e38
|
||||
Subproject commit 4489876e933d8ba0d8bc6c64bae71e295d45faac
|
|
@ -22,7 +22,9 @@
|
|||
#include "qemu/ctype.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "pmu.h"
|
||||
#include "internals.h"
|
||||
#include "time_helper.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@ -43,9 +45,88 @@ static const char riscv_single_letter_exts[] = "IEMAFDQCPVH";
|
|||
|
||||
struct isa_ext_data {
|
||||
const char *name;
|
||||
bool enabled;
|
||||
bool multi_letter;
|
||||
int min_version;
|
||||
int ext_enable_offset;
|
||||
};
|
||||
|
||||
#define ISA_EXT_DATA_ENTRY(_name, _m_letter, _min_ver, _prop) \
|
||||
{#_name, _m_letter, _min_ver, offsetof(struct RISCVCPUConfig, _prop)}
|
||||
|
||||
/**
|
||||
* Here are the ordering rules of extension naming defined by RISC-V
|
||||
* specification :
|
||||
* 1. All extensions should be separated from other multi-letter extensions
|
||||
* by an underscore.
|
||||
* 2. The first letter following the 'Z' conventionally indicates the most
|
||||
* closely related alphabetical extension category, IMAFDQLCBKJTPVH.
|
||||
* If multiple 'Z' extensions are named, they should be ordered first
|
||||
* by category, then alphabetically within a category.
|
||||
* 3. Standard supervisor-level extensions (starts with 'S') should be
|
||||
* listed after standard unprivileged extensions. If multiple
|
||||
* supervisor-level extensions are listed, they should be ordered
|
||||
* alphabetically.
|
||||
* 4. Non-standard extensions (starts with 'X') must be listed after all
|
||||
* standard extensions. They must be separated from other multi-letter
|
||||
* extensions by an underscore.
|
||||
*/
|
||||
static const struct isa_ext_data isa_edata_arr[] = {
|
||||
ISA_EXT_DATA_ENTRY(h, false, PRIV_VERSION_1_12_0, ext_h),
|
||||
ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_12_0, ext_v),
|
||||
ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr),
|
||||
ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei),
|
||||
ISA_EXT_DATA_ENTRY(zihintpause, true, PRIV_VERSION_1_10_0, ext_zihintpause),
|
||||
ISA_EXT_DATA_ENTRY(zfh, true, PRIV_VERSION_1_12_0, ext_zfh),
|
||||
ISA_EXT_DATA_ENTRY(zfhmin, true, PRIV_VERSION_1_12_0, ext_zfhmin),
|
||||
ISA_EXT_DATA_ENTRY(zfinx, true, PRIV_VERSION_1_12_0, ext_zfinx),
|
||||
ISA_EXT_DATA_ENTRY(zdinx, true, PRIV_VERSION_1_12_0, ext_zdinx),
|
||||
ISA_EXT_DATA_ENTRY(zba, true, PRIV_VERSION_1_12_0, ext_zba),
|
||||
ISA_EXT_DATA_ENTRY(zbb, true, PRIV_VERSION_1_12_0, ext_zbb),
|
||||
ISA_EXT_DATA_ENTRY(zbc, true, PRIV_VERSION_1_12_0, ext_zbc),
|
||||
ISA_EXT_DATA_ENTRY(zbkb, true, PRIV_VERSION_1_12_0, ext_zbkb),
|
||||
ISA_EXT_DATA_ENTRY(zbkc, true, PRIV_VERSION_1_12_0, ext_zbkc),
|
||||
ISA_EXT_DATA_ENTRY(zbkx, true, PRIV_VERSION_1_12_0, ext_zbkx),
|
||||
ISA_EXT_DATA_ENTRY(zbs, true, PRIV_VERSION_1_12_0, ext_zbs),
|
||||
ISA_EXT_DATA_ENTRY(zk, true, PRIV_VERSION_1_12_0, ext_zk),
|
||||
ISA_EXT_DATA_ENTRY(zkn, true, PRIV_VERSION_1_12_0, ext_zkn),
|
||||
ISA_EXT_DATA_ENTRY(zknd, true, PRIV_VERSION_1_12_0, ext_zknd),
|
||||
ISA_EXT_DATA_ENTRY(zkne, true, PRIV_VERSION_1_12_0, ext_zkne),
|
||||
ISA_EXT_DATA_ENTRY(zknh, true, PRIV_VERSION_1_12_0, ext_zknh),
|
||||
ISA_EXT_DATA_ENTRY(zkr, true, PRIV_VERSION_1_12_0, ext_zkr),
|
||||
ISA_EXT_DATA_ENTRY(zks, true, PRIV_VERSION_1_12_0, ext_zks),
|
||||
ISA_EXT_DATA_ENTRY(zksed, true, PRIV_VERSION_1_12_0, ext_zksed),
|
||||
ISA_EXT_DATA_ENTRY(zksh, true, PRIV_VERSION_1_12_0, ext_zksh),
|
||||
ISA_EXT_DATA_ENTRY(zkt, true, PRIV_VERSION_1_12_0, ext_zkt),
|
||||
ISA_EXT_DATA_ENTRY(zve32f, true, PRIV_VERSION_1_12_0, ext_zve32f),
|
||||
ISA_EXT_DATA_ENTRY(zve64f, true, PRIV_VERSION_1_12_0, ext_zve64f),
|
||||
ISA_EXT_DATA_ENTRY(zhinx, true, PRIV_VERSION_1_12_0, ext_zhinx),
|
||||
ISA_EXT_DATA_ENTRY(zhinxmin, true, PRIV_VERSION_1_12_0, ext_zhinxmin),
|
||||
ISA_EXT_DATA_ENTRY(smaia, true, PRIV_VERSION_1_12_0, ext_smaia),
|
||||
ISA_EXT_DATA_ENTRY(ssaia, true, PRIV_VERSION_1_12_0, ext_ssaia),
|
||||
ISA_EXT_DATA_ENTRY(sscofpmf, true, PRIV_VERSION_1_12_0, ext_sscofpmf),
|
||||
ISA_EXT_DATA_ENTRY(sstc, true, PRIV_VERSION_1_12_0, ext_sstc),
|
||||
ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval),
|
||||
ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot),
|
||||
ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt),
|
||||
ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps),
|
||||
};
|
||||
|
||||
static bool isa_ext_is_enabled(RISCVCPU *cpu,
|
||||
const struct isa_ext_data *edata)
|
||||
{
|
||||
bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset;
|
||||
|
||||
return *ext_enabled;
|
||||
}
|
||||
|
||||
static void isa_ext_update_enabled(RISCVCPU *cpu,
|
||||
const struct isa_ext_data *edata, bool en)
|
||||
{
|
||||
bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset;
|
||||
|
||||
*ext_enabled = en;
|
||||
}
|
||||
|
||||
const char * const riscv_int_regnames[] = {
|
||||
"x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
|
||||
"x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
|
||||
|
@ -530,7 +611,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
CPURISCVState *env = &cpu->env;
|
||||
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
|
||||
CPUClass *cc = CPU_CLASS(mcc);
|
||||
int priv_version = -1;
|
||||
int i, priv_version = -1;
|
||||
Error *local_err = NULL;
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
|
@ -558,6 +639,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
set_priv_version(env, priv_version);
|
||||
}
|
||||
|
||||
/* Force disable extensions if priv spec version does not match */
|
||||
for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
|
||||
if (isa_ext_is_enabled(cpu, &isa_edata_arr[i]) &&
|
||||
(env->priv_ver < isa_edata_arr[i].min_version)) {
|
||||
isa_ext_update_enabled(cpu, &isa_edata_arr[i], false);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
warn_report("disabling %s extension for hart 0x%lx because "
|
||||
"privilege spec version does not match",
|
||||
isa_edata_arr[i].name, (unsigned long)env->mhartid);
|
||||
#else
|
||||
warn_report("disabling %s extension because "
|
||||
"privilege spec version does not match",
|
||||
isa_edata_arr[i].name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu->cfg.mmu) {
|
||||
riscv_set_feature(env, RISCV_FEATURE_MMU);
|
||||
}
|
||||
|
@ -574,16 +672,18 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
if (cpu->cfg.aia) {
|
||||
riscv_set_feature(env, RISCV_FEATURE_AIA);
|
||||
}
|
||||
|
||||
if (cpu->cfg.debug) {
|
||||
riscv_set_feature(env, RISCV_FEATURE_DEBUG);
|
||||
}
|
||||
|
||||
set_resetvec(env, cpu->cfg.resetvec);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->cfg.ext_sstc) {
|
||||
riscv_timer_init(cpu);
|
||||
}
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
/* Validate that MISA_MXL is set properly. */
|
||||
switch (env->misa_mxl_max) {
|
||||
#ifdef TARGET_RISCV64
|
||||
|
@ -631,6 +731,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_s && !cpu->cfg.ext_u) {
|
||||
error_setg(errp,
|
||||
"Setting S extension without U extension is illegal");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_h && !cpu->cfg.ext_i) {
|
||||
error_setg(errp,
|
||||
"H depends on an I base integer ISA with 32 x registers");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_h && !cpu->cfg.ext_s) {
|
||||
error_setg(errp, "H extension implicitly requires S-mode");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) {
|
||||
error_setg(errp, "F extension requires Zicsr");
|
||||
return;
|
||||
|
@ -774,6 +891,15 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
|||
set_misa(env, env->misa_mxl, ext);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->cfg.pmu_num) {
|
||||
if (!riscv_pmu_init(cpu, cpu->cfg.pmu_num) && cpu->cfg.ext_sscofpmf) {
|
||||
cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
riscv_pmu_timer_cb, cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
riscv_cpu_register_gdb_regs_for_features(cs);
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
@ -878,14 +1004,17 @@ static Property riscv_cpu_extensions[] = {
|
|||
DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false),
|
||||
DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, true),
|
||||
DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16),
|
||||
DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false),
|
||||
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
|
||||
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
|
||||
DEFINE_PROP_BOOL("Zihintpause", RISCVCPU, cfg.ext_zihintpause, true),
|
||||
DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false),
|
||||
DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false),
|
||||
DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false),
|
||||
DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false),
|
||||
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
|
||||
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
|
||||
DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true),
|
||||
|
||||
DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
|
||||
DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
|
||||
|
@ -919,15 +1048,17 @@ static Property riscv_cpu_extensions[] = {
|
|||
DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false),
|
||||
DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false),
|
||||
|
||||
DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false),
|
||||
|
||||
/* Vendor-specific custom extensions */
|
||||
DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false),
|
||||
|
||||
/* These are experimental so mark with 'x-' */
|
||||
DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
|
||||
DEFINE_PROP_BOOL("x-zmmul", RISCVCPU, cfg.ext_zmmul, false),
|
||||
/* ePMP 0.9.3 */
|
||||
DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
|
||||
DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
|
||||
DEFINE_PROP_BOOL("x-smaia", RISCVCPU, cfg.ext_smaia, false),
|
||||
DEFINE_PROP_BOOL("x-ssaia", RISCVCPU, cfg.ext_ssaia, false),
|
||||
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
@ -953,6 +1084,7 @@ static Property riscv_cpu_properties[] = {
|
|||
DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false),
|
||||
|
||||
DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false),
|
||||
DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -1044,67 +1176,15 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
|
|||
device_class_set_props(dc, riscv_cpu_properties);
|
||||
}
|
||||
|
||||
#define ISA_EDATA_ENTRY(name, prop) {#name, cpu->cfg.prop}
|
||||
|
||||
static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len)
|
||||
{
|
||||
char *old = *isa_str;
|
||||
char *new = *isa_str;
|
||||
int i;
|
||||
|
||||
/**
|
||||
* Here are the ordering rules of extension naming defined by RISC-V
|
||||
* specification :
|
||||
* 1. All extensions should be separated from other multi-letter extensions
|
||||
* by an underscore.
|
||||
* 2. The first letter following the 'Z' conventionally indicates the most
|
||||
* closely related alphabetical extension category, IMAFDQLCBKJTPVH.
|
||||
* If multiple 'Z' extensions are named, they should be ordered first
|
||||
* by category, then alphabetically within a category.
|
||||
* 3. Standard supervisor-level extensions (starts with 'S') should be
|
||||
* listed after standard unprivileged extensions. If multiple
|
||||
* supervisor-level extensions are listed, they should be ordered
|
||||
* alphabetically.
|
||||
* 4. Non-standard extensions (starts with 'X') must be listed after all
|
||||
* standard extensions. They must be separated from other multi-letter
|
||||
* extensions by an underscore.
|
||||
*/
|
||||
struct isa_ext_data isa_edata_arr[] = {
|
||||
ISA_EDATA_ENTRY(zicsr, ext_icsr),
|
||||
ISA_EDATA_ENTRY(zifencei, ext_ifencei),
|
||||
ISA_EDATA_ENTRY(zmmul, ext_zmmul),
|
||||
ISA_EDATA_ENTRY(zfh, ext_zfh),
|
||||
ISA_EDATA_ENTRY(zfhmin, ext_zfhmin),
|
||||
ISA_EDATA_ENTRY(zfinx, ext_zfinx),
|
||||
ISA_EDATA_ENTRY(zdinx, ext_zdinx),
|
||||
ISA_EDATA_ENTRY(zba, ext_zba),
|
||||
ISA_EDATA_ENTRY(zbb, ext_zbb),
|
||||
ISA_EDATA_ENTRY(zbc, ext_zbc),
|
||||
ISA_EDATA_ENTRY(zbkb, ext_zbkb),
|
||||
ISA_EDATA_ENTRY(zbkc, ext_zbkc),
|
||||
ISA_EDATA_ENTRY(zbkx, ext_zbkx),
|
||||
ISA_EDATA_ENTRY(zbs, ext_zbs),
|
||||
ISA_EDATA_ENTRY(zk, ext_zk),
|
||||
ISA_EDATA_ENTRY(zkn, ext_zkn),
|
||||
ISA_EDATA_ENTRY(zknd, ext_zknd),
|
||||
ISA_EDATA_ENTRY(zkne, ext_zkne),
|
||||
ISA_EDATA_ENTRY(zknh, ext_zknh),
|
||||
ISA_EDATA_ENTRY(zkr, ext_zkr),
|
||||
ISA_EDATA_ENTRY(zks, ext_zks),
|
||||
ISA_EDATA_ENTRY(zksed, ext_zksed),
|
||||
ISA_EDATA_ENTRY(zksh, ext_zksh),
|
||||
ISA_EDATA_ENTRY(zkt, ext_zkt),
|
||||
ISA_EDATA_ENTRY(zve32f, ext_zve32f),
|
||||
ISA_EDATA_ENTRY(zve64f, ext_zve64f),
|
||||
ISA_EDATA_ENTRY(zhinx, ext_zhinx),
|
||||
ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin),
|
||||
ISA_EDATA_ENTRY(svinval, ext_svinval),
|
||||
ISA_EDATA_ENTRY(svnapot, ext_svnapot),
|
||||
ISA_EDATA_ENTRY(svpbmt, ext_svpbmt),
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
|
||||
if (isa_edata_arr[i].enabled) {
|
||||
if (isa_edata_arr[i].multi_letter &&
|
||||
isa_ext_is_enabled(cpu, &isa_edata_arr[i])) {
|
||||
new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL);
|
||||
g_free(old);
|
||||
old = new;
|
||||
|
|
|
@ -85,7 +85,6 @@ enum {
|
|||
RISCV_FEATURE_PMP,
|
||||
RISCV_FEATURE_EPMP,
|
||||
RISCV_FEATURE_MISA,
|
||||
RISCV_FEATURE_AIA,
|
||||
RISCV_FEATURE_DEBUG
|
||||
};
|
||||
|
||||
|
@ -137,6 +136,8 @@ typedef struct PMUCTRState {
|
|||
/* Snapshort value of a counter in RV32 */
|
||||
target_ulong mhpmcounterh_prev;
|
||||
bool started;
|
||||
/* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */
|
||||
target_ulong irq_overflow_left;
|
||||
} PMUCTRState;
|
||||
|
||||
struct CPUArchState {
|
||||
|
@ -285,6 +286,11 @@ struct CPUArchState {
|
|||
/* Signals whether the current exception occurred with two-stage address
|
||||
translation active. */
|
||||
bool two_stage_lookup;
|
||||
/*
|
||||
* Signals whether the current exception occurred while doing two-stage
|
||||
* address translation for the VS-stage page table walk.
|
||||
*/
|
||||
bool two_stage_indirect_lookup;
|
||||
|
||||
target_ulong scounteren;
|
||||
target_ulong mcounteren;
|
||||
|
@ -297,13 +303,20 @@ struct CPUArchState {
|
|||
/* PMU event selector configured values. First three are unused*/
|
||||
target_ulong mhpmevent_val[RV_MAX_MHPMEVENTS];
|
||||
|
||||
/* PMU event selector configured values for RV32*/
|
||||
target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS];
|
||||
|
||||
target_ulong sscratch;
|
||||
target_ulong mscratch;
|
||||
|
||||
/* temporary htif regs */
|
||||
uint64_t mfromhost;
|
||||
uint64_t mtohost;
|
||||
uint64_t timecmp;
|
||||
|
||||
/* Sstc CSRs */
|
||||
uint64_t stimecmp;
|
||||
|
||||
uint64_t vstimecmp;
|
||||
|
||||
/* physical memory protection */
|
||||
pmp_table_t pmp_state;
|
||||
|
@ -358,7 +371,9 @@ struct CPUArchState {
|
|||
float_status fp_status;
|
||||
|
||||
/* Fields from here on are preserved across CPU reset. */
|
||||
QEMUTimer *timer; /* Internal timer */
|
||||
QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
|
||||
QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */
|
||||
bool vstime_irq;
|
||||
|
||||
hwaddr kernel_addr;
|
||||
hwaddr fdt_addr;
|
||||
|
@ -421,6 +436,8 @@ struct RISCVCPUConfig {
|
|||
bool ext_zkt;
|
||||
bool ext_ifencei;
|
||||
bool ext_icsr;
|
||||
bool ext_zihintpause;
|
||||
bool ext_sstc;
|
||||
bool ext_svinval;
|
||||
bool ext_svnapot;
|
||||
bool ext_svpbmt;
|
||||
|
@ -433,7 +450,11 @@ struct RISCVCPUConfig {
|
|||
bool ext_zve32f;
|
||||
bool ext_zve64f;
|
||||
bool ext_zmmul;
|
||||
bool ext_smaia;
|
||||
bool ext_ssaia;
|
||||
bool ext_sscofpmf;
|
||||
bool rvv_ta_all_1s;
|
||||
bool rvv_ma_all_1s;
|
||||
|
||||
uint32_t mvendorid;
|
||||
uint64_t marchid;
|
||||
|
@ -452,7 +473,6 @@ struct RISCVCPUConfig {
|
|||
bool mmu;
|
||||
bool pmp;
|
||||
bool epmp;
|
||||
bool aia;
|
||||
bool debug;
|
||||
uint64_t resetvec;
|
||||
|
||||
|
@ -479,6 +499,12 @@ struct ArchCPU {
|
|||
|
||||
/* Configuration Settings */
|
||||
RISCVCPUConfig cfg;
|
||||
|
||||
QEMUTimer *pmu_timer;
|
||||
/* A bitmask of Available programmable counters */
|
||||
uint32_t pmu_avail_ctrs;
|
||||
/* Mapping of events to counters */
|
||||
GHashTable *pmu_event_ctr_map;
|
||||
};
|
||||
|
||||
static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext)
|
||||
|
@ -591,6 +617,7 @@ FIELD(TB_FLAGS, XL, 20, 2)
|
|||
FIELD(TB_FLAGS, PM_MASK_ENABLED, 22, 1)
|
||||
FIELD(TB_FLAGS, PM_BASE_ENABLED, 23, 1)
|
||||
FIELD(TB_FLAGS, VTA, 24, 1)
|
||||
FIELD(TB_FLAGS, VMA, 25, 1)
|
||||
|
||||
#ifdef TARGET_RISCV32
|
||||
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
|
||||
|
@ -738,6 +765,19 @@ enum {
|
|||
CSR_TABLE_SIZE = 0x1000
|
||||
};
|
||||
|
||||
/**
|
||||
* The event id are encoded based on the encoding specified in the
|
||||
* SBI specification v0.3
|
||||
*/
|
||||
|
||||
enum riscv_pmu_event_idx {
|
||||
RISCV_PMU_EVENT_HW_CPU_CYCLES = 0x01,
|
||||
RISCV_PMU_EVENT_HW_INSTRUCTIONS = 0x02,
|
||||
RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS = 0x10019,
|
||||
RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS = 0x1001B,
|
||||
RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021,
|
||||
};
|
||||
|
||||
/* CSR function table */
|
||||
extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
|
||||
|
||||
|
|
|
@ -206,6 +206,10 @@
|
|||
#define CSR_STVAL 0x143
|
||||
#define CSR_SIP 0x144
|
||||
|
||||
/* Sstc supervisor CSRs */
|
||||
#define CSR_STIMECMP 0x14D
|
||||
#define CSR_STIMECMPH 0x15D
|
||||
|
||||
/* Supervisor Protection and Translation */
|
||||
#define CSR_SPTBR 0x180
|
||||
#define CSR_SATP 0x180
|
||||
|
@ -253,6 +257,10 @@
|
|||
#define CSR_VSIP 0x244
|
||||
#define CSR_VSATP 0x280
|
||||
|
||||
/* Sstc virtual CSRs */
|
||||
#define CSR_VSTIMECMP 0x24D
|
||||
#define CSR_VSTIMECMPH 0x25D
|
||||
|
||||
#define CSR_MTINST 0x34a
|
||||
#define CSR_MTVAL2 0x34b
|
||||
|
||||
|
@ -382,6 +390,37 @@
|
|||
#define CSR_MHPMEVENT29 0x33d
|
||||
#define CSR_MHPMEVENT30 0x33e
|
||||
#define CSR_MHPMEVENT31 0x33f
|
||||
|
||||
#define CSR_MHPMEVENT3H 0x723
|
||||
#define CSR_MHPMEVENT4H 0x724
|
||||
#define CSR_MHPMEVENT5H 0x725
|
||||
#define CSR_MHPMEVENT6H 0x726
|
||||
#define CSR_MHPMEVENT7H 0x727
|
||||
#define CSR_MHPMEVENT8H 0x728
|
||||
#define CSR_MHPMEVENT9H 0x729
|
||||
#define CSR_MHPMEVENT10H 0x72a
|
||||
#define CSR_MHPMEVENT11H 0x72b
|
||||
#define CSR_MHPMEVENT12H 0x72c
|
||||
#define CSR_MHPMEVENT13H 0x72d
|
||||
#define CSR_MHPMEVENT14H 0x72e
|
||||
#define CSR_MHPMEVENT15H 0x72f
|
||||
#define CSR_MHPMEVENT16H 0x730
|
||||
#define CSR_MHPMEVENT17H 0x731
|
||||
#define CSR_MHPMEVENT18H 0x732
|
||||
#define CSR_MHPMEVENT19H 0x733
|
||||
#define CSR_MHPMEVENT20H 0x734
|
||||
#define CSR_MHPMEVENT21H 0x735
|
||||
#define CSR_MHPMEVENT22H 0x736
|
||||
#define CSR_MHPMEVENT23H 0x737
|
||||
#define CSR_MHPMEVENT24H 0x738
|
||||
#define CSR_MHPMEVENT25H 0x739
|
||||
#define CSR_MHPMEVENT26H 0x73a
|
||||
#define CSR_MHPMEVENT27H 0x73b
|
||||
#define CSR_MHPMEVENT28H 0x73c
|
||||
#define CSR_MHPMEVENT29H 0x73d
|
||||
#define CSR_MHPMEVENT30H 0x73e
|
||||
#define CSR_MHPMEVENT31H 0x73f
|
||||
|
||||
#define CSR_MHPMCOUNTER3H 0xb83
|
||||
#define CSR_MHPMCOUNTER4H 0xb84
|
||||
#define CSR_MHPMCOUNTER5H 0xb85
|
||||
|
@ -443,6 +482,7 @@
|
|||
#define CSR_VSMTE 0x2c0
|
||||
#define CSR_VSPMMASK 0x2c1
|
||||
#define CSR_VSPMBASE 0x2c2
|
||||
#define CSR_SCOUNTOVF 0xda0
|
||||
|
||||
/* Crypto Extension */
|
||||
#define CSR_SEED 0x015
|
||||
|
@ -620,6 +660,7 @@ typedef enum RISCVException {
|
|||
#define IRQ_VS_EXT 10
|
||||
#define IRQ_M_EXT 11
|
||||
#define IRQ_S_GEXT 12
|
||||
#define IRQ_PMU_OVF 13
|
||||
#define IRQ_LOCAL_MAX 16
|
||||
#define IRQ_LOCAL_GUEST_MAX (TARGET_LONG_BITS - 1)
|
||||
|
||||
|
@ -637,11 +678,13 @@ typedef enum RISCVException {
|
|||
#define MIP_VSEIP (1 << IRQ_VS_EXT)
|
||||
#define MIP_MEIP (1 << IRQ_M_EXT)
|
||||
#define MIP_SGEIP (1 << IRQ_S_GEXT)
|
||||
#define MIP_LCOFIP (1 << IRQ_PMU_OVF)
|
||||
|
||||
/* sip masks */
|
||||
#define SIP_SSIP MIP_SSIP
|
||||
#define SIP_STIP MIP_STIP
|
||||
#define SIP_SEIP MIP_SEIP
|
||||
#define SIP_LCOFIP MIP_LCOFIP
|
||||
|
||||
/* MIE masks */
|
||||
#define MIE_SEIE (1 << IRQ_S_EXT)
|
||||
|
@ -795,4 +838,24 @@ typedef enum RISCVException {
|
|||
#define SEED_OPST_WAIT (0b01 << 30)
|
||||
#define SEED_OPST_ES16 (0b10 << 30)
|
||||
#define SEED_OPST_DEAD (0b11 << 30)
|
||||
/* PMU related bits */
|
||||
#define MIE_LCOFIE (1 << IRQ_PMU_OVF)
|
||||
|
||||
#define MHPMEVENT_BIT_OF BIT_ULL(63)
|
||||
#define MHPMEVENTH_BIT_OF BIT(31)
|
||||
#define MHPMEVENT_BIT_MINH BIT_ULL(62)
|
||||
#define MHPMEVENTH_BIT_MINH BIT(30)
|
||||
#define MHPMEVENT_BIT_SINH BIT_ULL(61)
|
||||
#define MHPMEVENTH_BIT_SINH BIT(29)
|
||||
#define MHPMEVENT_BIT_UINH BIT_ULL(60)
|
||||
#define MHPMEVENTH_BIT_UINH BIT(28)
|
||||
#define MHPMEVENT_BIT_VSINH BIT_ULL(59)
|
||||
#define MHPMEVENTH_BIT_VSINH BIT(27)
|
||||
#define MHPMEVENT_BIT_VUINH BIT_ULL(58)
|
||||
#define MHPMEVENTH_BIT_VUINH BIT(26)
|
||||
|
||||
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
|
||||
#define MHPMEVENT_IDX_MASK 0xFFFFF
|
||||
#define MHPMEVENT_SSCOF_RESVD 16
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,10 +21,13 @@
|
|||
#include "qemu/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "cpu.h"
|
||||
#include "pmu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "instmap.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "trace.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#include "cpu_bits.h"
|
||||
|
||||
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
|
||||
{
|
||||
|
@ -67,6 +70,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
|||
flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax);
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, VTA,
|
||||
FIELD_EX64(env->vtype, VTYPE, VTA));
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, VMA,
|
||||
FIELD_EX64(env->vtype, VTYPE, VMA));
|
||||
} else {
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
|
||||
}
|
||||
|
@ -304,6 +309,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
|
|||
int extirq, unsigned int extirq_def_prio,
|
||||
uint64_t pending, uint8_t *iprio)
|
||||
{
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
int irq, best_irq = RISCV_EXCP_NONE;
|
||||
unsigned int prio, best_prio = UINT_MAX;
|
||||
|
||||
|
@ -312,7 +318,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
|
|||
}
|
||||
|
||||
irq = ctz64(pending);
|
||||
if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
|
||||
if (!((extirq == IRQ_M_EXT) ? cpu->cfg.ext_smaia : cpu->cfg.ext_ssaia)) {
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
@ -342,8 +348,9 @@ uint64_t riscv_cpu_all_pending(CPURISCVState *env)
|
|||
{
|
||||
uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
|
||||
uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
|
||||
uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0;
|
||||
|
||||
return (env->mip | vsgein) & env->mie;
|
||||
return (env->mip | vsgein | vstip) & env->mie;
|
||||
}
|
||||
|
||||
int riscv_cpu_mirq_pending(CPURISCVState *env)
|
||||
|
@ -602,7 +609,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
|
|||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
CPUState *cs = CPU(cpu);
|
||||
uint64_t gein, vsgein = 0, old = env->mip;
|
||||
uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
|
||||
bool locked = false;
|
||||
|
||||
if (riscv_cpu_virt_enabled(env)) {
|
||||
|
@ -610,6 +617,10 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
|
|||
vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
|
||||
}
|
||||
|
||||
/* No need to update mip for VSTIP */
|
||||
mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
|
||||
vstip = env->vstime_irq ? MIP_VSTIP : 0;
|
||||
|
||||
if (!qemu_mutex_iothread_locked()) {
|
||||
locked = true;
|
||||
qemu_mutex_lock_iothread();
|
||||
|
@ -617,7 +628,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
|
|||
|
||||
env->mip = (env->mip & ~mask) | (value & mask);
|
||||
|
||||
if (env->mip | vsgein) {
|
||||
if (env->mip | vsgein | vstip) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
|
@ -1053,7 +1064,8 @@ restart:
|
|||
|
||||
static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
|
||||
MMUAccessType access_type, bool pmp_violation,
|
||||
bool first_stage, bool two_stage)
|
||||
bool first_stage, bool two_stage,
|
||||
bool two_stage_indirect)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int page_fault_exceptions, vm;
|
||||
|
@ -1103,6 +1115,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
|
|||
}
|
||||
env->badaddr = address;
|
||||
env->two_stage_lookup = two_stage;
|
||||
env->two_stage_indirect_lookup = two_stage_indirect;
|
||||
}
|
||||
|
||||
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
|
@ -1148,6 +1161,7 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
|||
env->badaddr = addr;
|
||||
env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
|
||||
riscv_cpu_two_stage_lookup(mmu_idx);
|
||||
env->two_stage_indirect_lookup = false;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
|
@ -1173,9 +1187,32 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
|||
env->badaddr = addr;
|
||||
env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
|
||||
riscv_cpu_two_stage_lookup(mmu_idx);
|
||||
env->two_stage_indirect_lookup = false;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
|
||||
static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type)
|
||||
{
|
||||
enum riscv_pmu_event_idx pmu_event_type;
|
||||
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
pmu_event_type = RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS;
|
||||
break;
|
||||
case MMU_DATA_LOAD:
|
||||
pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS;
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
riscv_pmu_incr_ctr(cpu, pmu_event_type);
|
||||
}
|
||||
|
||||
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
|
@ -1188,6 +1225,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
|||
bool pmp_violation = false;
|
||||
bool first_stage_error = true;
|
||||
bool two_stage_lookup = false;
|
||||
bool two_stage_indirect_error = false;
|
||||
int ret = TRANSLATE_FAIL;
|
||||
int mode = mmu_idx;
|
||||
/* default TLB page size */
|
||||
|
@ -1225,6 +1263,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
|||
*/
|
||||
if (ret == TRANSLATE_G_STAGE_FAIL) {
|
||||
first_stage_error = false;
|
||||
two_stage_indirect_error = true;
|
||||
access_type = MMU_DATA_LOAD;
|
||||
}
|
||||
|
||||
|
@ -1272,6 +1311,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
pmu_tlb_fill_incr_ctr(cpu, access_type);
|
||||
/* Single stage lookup */
|
||||
ret = get_physical_address(env, &pa, &prot, address, NULL,
|
||||
access_type, mmu_idx, true, false, false);
|
||||
|
@ -1308,12 +1348,218 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
|||
raise_mmu_exception(env, address, access_type, pmp_violation,
|
||||
first_stage_error,
|
||||
riscv_cpu_virt_enabled(env) ||
|
||||
riscv_cpu_two_stage_lookup(mmu_idx));
|
||||
riscv_cpu_two_stage_lookup(mmu_idx),
|
||||
two_stage_indirect_error);
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static target_ulong riscv_transformed_insn(CPURISCVState *env,
|
||||
target_ulong insn,
|
||||
target_ulong taddr)
|
||||
{
|
||||
target_ulong xinsn = 0;
|
||||
target_ulong access_rs1 = 0, access_imm = 0, access_size = 0;
|
||||
|
||||
/*
|
||||
* Only Quadrant 0 and Quadrant 2 of RVC instruction space need to
|
||||
* be uncompressed. The Quadrant 1 of RVC instruction space need
|
||||
* not be transformed because these instructions won't generate
|
||||
* any load/store trap.
|
||||
*/
|
||||
|
||||
if ((insn & 0x3) != 0x3) {
|
||||
/* Transform 16bit instruction into 32bit instruction */
|
||||
switch (GET_C_OP(insn)) {
|
||||
case OPC_RISC_C_OP_QUAD0: /* Quadrant 0 */
|
||||
switch (GET_C_FUNC(insn)) {
|
||||
case OPC_RISC_C_FUNC_FLD_LQ:
|
||||
if (riscv_cpu_xlen(env) != 128) { /* C.FLD (RV32/64) */
|
||||
xinsn = OPC_RISC_FLD;
|
||||
xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_LD_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_LW: /* C.LW */
|
||||
xinsn = OPC_RISC_LW;
|
||||
xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_LW_IMM(insn);
|
||||
access_size = 4;
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_FLW_LD:
|
||||
if (riscv_cpu_xlen(env) == 32) { /* C.FLW (RV32) */
|
||||
xinsn = OPC_RISC_FLW;
|
||||
xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_LW_IMM(insn);
|
||||
access_size = 4;
|
||||
} else { /* C.LD (RV64/RV128) */
|
||||
xinsn = OPC_RISC_LD;
|
||||
xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_LD_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_FSD_SQ:
|
||||
if (riscv_cpu_xlen(env) != 128) { /* C.FSD (RV32/64) */
|
||||
xinsn = OPC_RISC_FSD;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_SD_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_SW: /* C.SW */
|
||||
xinsn = OPC_RISC_SW;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_SW_IMM(insn);
|
||||
access_size = 4;
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_FSW_SD:
|
||||
if (riscv_cpu_xlen(env) == 32) { /* C.FSW (RV32) */
|
||||
xinsn = OPC_RISC_FSW;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_SW_IMM(insn);
|
||||
access_size = 4;
|
||||
} else { /* C.SD (RV64/RV128) */
|
||||
xinsn = OPC_RISC_SD;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
|
||||
access_rs1 = GET_C_RS1S(insn);
|
||||
access_imm = GET_C_SD_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_OP_QUAD2: /* Quadrant 2 */
|
||||
switch (GET_C_FUNC(insn)) {
|
||||
case OPC_RISC_C_FUNC_FLDSP_LQSP:
|
||||
if (riscv_cpu_xlen(env) != 128) { /* C.FLDSP (RV32/64) */
|
||||
xinsn = OPC_RISC_FLD;
|
||||
xinsn = SET_RD(xinsn, GET_C_RD(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_LDSP_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_LWSP: /* C.LWSP */
|
||||
xinsn = OPC_RISC_LW;
|
||||
xinsn = SET_RD(xinsn, GET_C_RD(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_LWSP_IMM(insn);
|
||||
access_size = 4;
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_FLWSP_LDSP:
|
||||
if (riscv_cpu_xlen(env) == 32) { /* C.FLWSP (RV32) */
|
||||
xinsn = OPC_RISC_FLW;
|
||||
xinsn = SET_RD(xinsn, GET_C_RD(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_LWSP_IMM(insn);
|
||||
access_size = 4;
|
||||
} else { /* C.LDSP (RV64/RV128) */
|
||||
xinsn = OPC_RISC_LD;
|
||||
xinsn = SET_RD(xinsn, GET_C_RD(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_LDSP_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_FSDSP_SQSP:
|
||||
if (riscv_cpu_xlen(env) != 128) { /* C.FSDSP (RV32/64) */
|
||||
xinsn = OPC_RISC_FSD;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_SDSP_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
case OPC_RISC_C_FUNC_SWSP: /* C.SWSP */
|
||||
xinsn = OPC_RISC_SW;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_SWSP_IMM(insn);
|
||||
access_size = 4;
|
||||
break;
|
||||
case 7:
|
||||
if (riscv_cpu_xlen(env) == 32) { /* C.FSWSP (RV32) */
|
||||
xinsn = OPC_RISC_FSW;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_SWSP_IMM(insn);
|
||||
access_size = 4;
|
||||
} else { /* C.SDSP (RV64/RV128) */
|
||||
xinsn = OPC_RISC_SD;
|
||||
xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
|
||||
access_rs1 = 2;
|
||||
access_imm = GET_C_SDSP_IMM(insn);
|
||||
access_size = 8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear Bit1 of transformed instruction to indicate that
|
||||
* original insruction was a 16bit instruction
|
||||
*/
|
||||
xinsn &= ~((target_ulong)0x2);
|
||||
} else {
|
||||
/* Transform 32bit (or wider) instructions */
|
||||
switch (MASK_OP_MAJOR(insn)) {
|
||||
case OPC_RISC_ATOMIC:
|
||||
xinsn = insn;
|
||||
access_rs1 = GET_RS1(insn);
|
||||
access_size = 1 << GET_FUNCT3(insn);
|
||||
break;
|
||||
case OPC_RISC_LOAD:
|
||||
case OPC_RISC_FP_LOAD:
|
||||
xinsn = SET_I_IMM(insn, 0);
|
||||
access_rs1 = GET_RS1(insn);
|
||||
access_imm = GET_IMM(insn);
|
||||
access_size = 1 << GET_FUNCT3(insn);
|
||||
break;
|
||||
case OPC_RISC_STORE:
|
||||
case OPC_RISC_FP_STORE:
|
||||
xinsn = SET_S_IMM(insn, 0);
|
||||
access_rs1 = GET_RS1(insn);
|
||||
access_imm = GET_STORE_IMM(insn);
|
||||
access_size = 1 << GET_FUNCT3(insn);
|
||||
break;
|
||||
case OPC_RISC_SYSTEM:
|
||||
if (MASK_OP_SYSTEM(insn) == OPC_RISC_HLVHSV) {
|
||||
xinsn = insn;
|
||||
access_rs1 = GET_RS1(insn);
|
||||
access_size = 1 << ((GET_FUNCT7(insn) >> 1) & 0x3);
|
||||
access_size = 1 << access_size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (access_size) {
|
||||
xinsn = SET_RS1(xinsn, (taddr - (env->gpr[access_rs1] + access_imm)) &
|
||||
(access_size - 1));
|
||||
}
|
||||
|
||||
return xinsn;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/*
|
||||
|
@ -1338,6 +1584,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
|
||||
uint64_t deleg = async ? env->mideleg : env->medeleg;
|
||||
target_ulong tval = 0;
|
||||
target_ulong tinst = 0;
|
||||
target_ulong htval = 0;
|
||||
target_ulong mtval2 = 0;
|
||||
|
||||
|
@ -1353,20 +1600,43 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
if (!async) {
|
||||
/* set tval to badaddr for traps with address information */
|
||||
switch (cause) {
|
||||
case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
|
||||
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
|
||||
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
|
||||
case RISCV_EXCP_INST_ADDR_MIS:
|
||||
case RISCV_EXCP_INST_ACCESS_FAULT:
|
||||
case RISCV_EXCP_LOAD_ADDR_MIS:
|
||||
case RISCV_EXCP_STORE_AMO_ADDR_MIS:
|
||||
case RISCV_EXCP_LOAD_ACCESS_FAULT:
|
||||
case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
|
||||
case RISCV_EXCP_INST_PAGE_FAULT:
|
||||
case RISCV_EXCP_LOAD_PAGE_FAULT:
|
||||
case RISCV_EXCP_STORE_PAGE_FAULT:
|
||||
write_gva = env->two_stage_lookup;
|
||||
tval = env->badaddr;
|
||||
if (env->two_stage_indirect_lookup) {
|
||||
/*
|
||||
* special pseudoinstruction for G-stage fault taken while
|
||||
* doing VS-stage page table walk.
|
||||
*/
|
||||
tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
|
||||
} else {
|
||||
/*
|
||||
* The "Addr. Offset" field in transformed instruction is
|
||||
* non-zero only for misaligned access.
|
||||
*/
|
||||
tinst = riscv_transformed_insn(env, env->bins, tval);
|
||||
}
|
||||
break;
|
||||
case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
|
||||
case RISCV_EXCP_INST_ADDR_MIS:
|
||||
case RISCV_EXCP_INST_ACCESS_FAULT:
|
||||
case RISCV_EXCP_INST_PAGE_FAULT:
|
||||
write_gva = env->two_stage_lookup;
|
||||
tval = env->badaddr;
|
||||
if (env->two_stage_indirect_lookup) {
|
||||
/*
|
||||
* special pseudoinstruction for G-stage fault taken while
|
||||
* doing VS-stage page table walk.
|
||||
*/
|
||||
tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
|
||||
}
|
||||
break;
|
||||
case RISCV_EXCP_ILLEGAL_INST:
|
||||
case RISCV_EXCP_VIRT_INSTRUCTION_FAULT:
|
||||
|
@ -1446,6 +1716,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
env->sepc = env->pc;
|
||||
env->stval = tval;
|
||||
env->htval = htval;
|
||||
env->htinst = tinst;
|
||||
env->pc = (env->stvec >> 2 << 2) +
|
||||
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
|
||||
riscv_cpu_set_mode(env, PRV_S);
|
||||
|
@ -1476,6 +1747,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
env->mepc = env->pc;
|
||||
env->mtval = tval;
|
||||
env->mtval2 = mtval2;
|
||||
env->mtinst = tinst;
|
||||
env->pc = (env->mtvec >> 2 << 2) +
|
||||
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
|
||||
riscv_cpu_set_mode(env, PRV_M);
|
||||
|
@ -1488,6 +1760,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
*/
|
||||
|
||||
env->two_stage_lookup = false;
|
||||
env->two_stage_indirect_lookup = false;
|
||||
#endif
|
||||
cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */
|
||||
}
|
||||
|
|
1032
target/riscv/csr.c
1032
target/riscv/csr.c
File diff suppressed because it is too large
Load Diff
|
@ -31,7 +31,8 @@
|
|||
%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
|
||||
%shlimm_6bit 12:1 2:5 !function=ex_rvc_shiftli
|
||||
%shrimm_6bit 12:1 2:5 !function=ex_rvc_shiftri
|
||||
%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
|
||||
|
@ -82,9 +83,9 @@
|
|||
@c_addi16sp ... . ..... ..... .. &i imm=%imm_addi16sp rs1=2 rd=2
|
||||
|
||||
@c_shift ... . .. ... ..... .. \
|
||||
&shift rd=%rs1_3 rs1=%rs1_3 shamt=%shimm_6bit
|
||||
&shift rd=%rs1_3 rs1=%rs1_3 shamt=%shrimm_6bit
|
||||
@c_shift2 ... . .. ... ..... .. \
|
||||
&shift rd=%rd rs1=%rd shamt=%shimm_6bit
|
||||
&shift rd=%rd rs1=%rd shamt=%shlimm_6bit
|
||||
|
||||
@c_andi ... . .. ... ..... .. &i imm=%imm_ci rs1=%rs1_3 rd=%rs1_3
|
||||
|
||||
|
|
|
@ -149,7 +149,12 @@ srl 0000000 ..... ..... 101 ..... 0110011 @r
|
|||
sra 0100000 ..... ..... 101 ..... 0110011 @r
|
||||
or 0000000 ..... ..... 110 ..... 0110011 @r
|
||||
and 0000000 ..... ..... 111 ..... 0110011 @r
|
||||
fence ---- pred:4 succ:4 ----- 000 ----- 0001111
|
||||
|
||||
{
|
||||
pause 0000 0001 0000 00000 000 00000 0001111
|
||||
fence ---- pred:4 succ:4 ----- 000 ----- 0001111
|
||||
}
|
||||
|
||||
fence_i ---- ---- ---- ----- 001 ----- 0001111
|
||||
csrrw ............ ..... 001 ..... 1110011 @csr
|
||||
csrrs ............ ..... 010 ..... 1110011 @csr
|
||||
|
|
|
@ -792,6 +792,22 @@ static bool trans_srad(DisasContext *ctx, arg_srad *a)
|
|||
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl, NULL);
|
||||
}
|
||||
|
||||
static bool trans_pause(DisasContext *ctx, arg_pause *a)
|
||||
{
|
||||
if (!ctx->cfg_ptr->ext_zihintpause) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* PAUSE is a no-op in QEMU,
|
||||
* end the TB and return to main loop
|
||||
*/
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fence(DisasContext *ctx, arg_fence *a)
|
||||
{
|
||||
|
|
|
@ -712,6 +712,7 @@ static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
|
|||
data = FIELD_DP32(data, VDATA, LMUL, emul);
|
||||
data = FIELD_DP32(data, VDATA, NF, a->nf);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
|
||||
}
|
||||
|
||||
|
@ -777,6 +778,7 @@ static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew)
|
|||
data = FIELD_DP32(data, VDATA, NF, 1);
|
||||
/* Mask destination register are always tail-agnostic */
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->cfg_vta_all_1s);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
|
||||
}
|
||||
|
||||
|
@ -866,6 +868,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
|
|||
data = FIELD_DP32(data, VDATA, LMUL, emul);
|
||||
data = FIELD_DP32(data, VDATA, NF, a->nf);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
|
||||
}
|
||||
|
||||
|
@ -996,6 +999,7 @@ static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
|
|||
data = FIELD_DP32(data, VDATA, LMUL, emul);
|
||||
data = FIELD_DP32(data, VDATA, NF, a->nf);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
|
||||
}
|
||||
|
||||
|
@ -1114,6 +1118,7 @@ static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
|
|||
data = FIELD_DP32(data, VDATA, LMUL, emul);
|
||||
data = FIELD_DP32(data, VDATA, NF, a->nf);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
return ldff_trans(a->rd, a->rs1, data, fn, s);
|
||||
}
|
||||
|
||||
|
@ -1247,6 +1252,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
|
||||
cpu_env, s->cfg_ptr->vlen / 8,
|
||||
|
@ -1295,6 +1301,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
|
|||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
|
||||
s->cfg_ptr->vlen / 8, data));
|
||||
|
||||
|
@ -1462,6 +1469,7 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
|
|||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
|
||||
s->cfg_ptr->vlen / 8, data));
|
||||
|
||||
|
@ -1545,6 +1553,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1),
|
||||
vreg_ofs(s, a->rs2),
|
||||
|
@ -1627,6 +1636,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1),
|
||||
vreg_ofs(s, a->rs2),
|
||||
|
@ -1708,6 +1718,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = \
|
||||
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
|
@ -1891,6 +1902,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
|
@ -2349,6 +2361,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = \
|
||||
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
|
@ -2434,6 +2447,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \
|
||||
s->cfg_vta_all_1s); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
|
||||
fns[s->sew - 1], s); \
|
||||
} \
|
||||
|
@ -2473,6 +2487,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
|
@ -2513,6 +2528,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
|
||||
fns[s->sew - 1], s); \
|
||||
} \
|
||||
|
@ -2550,6 +2566,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
|
@ -2590,6 +2607,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
|
||||
fns[s->sew - 1], s); \
|
||||
} \
|
||||
|
@ -2674,6 +2692,7 @@ static bool do_opfv(DisasContext *s, arg_rmr *a,
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs2), cpu_env,
|
||||
s->cfg_ptr->vlen / 8,
|
||||
|
@ -2778,6 +2797,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
|
|||
TCGv_i32 desc;
|
||||
uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
static gen_helper_vmv_vx * const fns[3] = {
|
||||
gen_helper_vmv_v_x_h,
|
||||
gen_helper_vmv_v_x_w,
|
||||
|
@ -2879,6 +2899,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, \
|
||||
|
@ -2932,6 +2953,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, \
|
||||
|
@ -3000,6 +3022,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, \
|
||||
|
@ -3055,6 +3078,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->cfg_ptr->vlen / 8, \
|
||||
|
@ -3251,6 +3275,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
|||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
data = \
|
||||
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \
|
||||
vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \
|
||||
cpu_env, s->cfg_ptr->vlen / 8, \
|
||||
|
@ -3289,6 +3314,7 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
static gen_helper_gvec_3_ptr * const fns[4] = {
|
||||
gen_helper_viota_m_b, gen_helper_viota_m_h,
|
||||
gen_helper_viota_m_w, gen_helper_viota_m_d,
|
||||
|
@ -3319,6 +3345,7 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
static gen_helper_gvec_2_ptr * const fns[4] = {
|
||||
gen_helper_vid_v_b, gen_helper_vid_v_h,
|
||||
gen_helper_vid_v_w, gen_helper_vid_v_d,
|
||||
|
@ -3864,6 +3891,7 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq)
|
|||
data = FIELD_DP32(data, VDATA, VM, a->vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
data = FIELD_DP32(data, VDATA, VTA, s->vta);
|
||||
data = FIELD_DP32(data, VDATA, VMA, s->vma);
|
||||
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs2), cpu_env,
|
||||
|
|
|
@ -184,6 +184,8 @@ enum {
|
|||
OPC_RISC_CSRRWI = OPC_RISC_SYSTEM | (0x5 << 12),
|
||||
OPC_RISC_CSRRSI = OPC_RISC_SYSTEM | (0x6 << 12),
|
||||
OPC_RISC_CSRRCI = OPC_RISC_SYSTEM | (0x7 << 12),
|
||||
|
||||
OPC_RISC_HLVHSV = OPC_RISC_SYSTEM | (0x4 << 12),
|
||||
};
|
||||
|
||||
#define MASK_OP_FP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
|
||||
|
@ -310,12 +312,20 @@ enum {
|
|||
| (extract32(inst, 12, 8) << 12) \
|
||||
| (sextract64(inst, 31, 1) << 20))
|
||||
|
||||
#define GET_FUNCT3(inst) extract32(inst, 12, 3)
|
||||
#define GET_FUNCT7(inst) extract32(inst, 25, 7)
|
||||
#define GET_RM(inst) extract32(inst, 12, 3)
|
||||
#define GET_RS3(inst) extract32(inst, 27, 5)
|
||||
#define GET_RS1(inst) extract32(inst, 15, 5)
|
||||
#define GET_RS2(inst) extract32(inst, 20, 5)
|
||||
#define GET_RD(inst) extract32(inst, 7, 5)
|
||||
#define GET_IMM(inst) sextract64(inst, 20, 12)
|
||||
#define SET_RS1(inst, val) deposit32(inst, 15, 5, val)
|
||||
#define SET_RS2(inst, val) deposit32(inst, 20, 5, val)
|
||||
#define SET_RD(inst, val) deposit32(inst, 7, 5, val)
|
||||
#define SET_I_IMM(inst, val) deposit32(inst, 20, 12, val)
|
||||
#define SET_S_IMM(inst, val) \
|
||||
deposit32(deposit32(inst, 7, 5, val), 25, 7, (val) >> 5)
|
||||
|
||||
/* RVC decoding macros */
|
||||
#define GET_C_IMM(inst) (extract32(inst, 2, 5) \
|
||||
|
@ -346,6 +356,8 @@ enum {
|
|||
| (extract32(inst, 5, 1) << 6))
|
||||
#define GET_C_LD_IMM(inst) ((extract16(inst, 10, 3) << 3) \
|
||||
| (extract16(inst, 5, 2) << 6))
|
||||
#define GET_C_SW_IMM(inst) GET_C_LW_IMM(inst)
|
||||
#define GET_C_SD_IMM(inst) GET_C_LD_IMM(inst)
|
||||
#define GET_C_J_IMM(inst) ((extract32(inst, 3, 3) << 1) \
|
||||
| (extract32(inst, 11, 1) << 4) \
|
||||
| (extract32(inst, 2, 1) << 5) \
|
||||
|
@ -366,4 +378,37 @@ enum {
|
|||
#define GET_C_RS1S(inst) (8 + extract16(inst, 7, 3))
|
||||
#define GET_C_RS2S(inst) (8 + extract16(inst, 2, 3))
|
||||
|
||||
#define GET_C_FUNC(inst) extract32(inst, 13, 3)
|
||||
#define GET_C_OP(inst) extract32(inst, 0, 2)
|
||||
|
||||
enum {
|
||||
/* RVC Quadrants */
|
||||
OPC_RISC_C_OP_QUAD0 = 0x0,
|
||||
OPC_RISC_C_OP_QUAD1 = 0x1,
|
||||
OPC_RISC_C_OP_QUAD2 = 0x2
|
||||
};
|
||||
|
||||
enum {
|
||||
/* RVC Quadrant 0 */
|
||||
OPC_RISC_C_FUNC_ADDI4SPN = 0x0,
|
||||
OPC_RISC_C_FUNC_FLD_LQ = 0x1,
|
||||
OPC_RISC_C_FUNC_LW = 0x2,
|
||||
OPC_RISC_C_FUNC_FLW_LD = 0x3,
|
||||
OPC_RISC_C_FUNC_FSD_SQ = 0x5,
|
||||
OPC_RISC_C_FUNC_SW = 0x6,
|
||||
OPC_RISC_C_FUNC_FSW_SD = 0x7
|
||||
};
|
||||
|
||||
enum {
|
||||
/* RVC Quadrant 2 */
|
||||
OPC_RISC_C_FUNC_SLLI_SLLI64 = 0x0,
|
||||
OPC_RISC_C_FUNC_FLDSP_LQSP = 0x1,
|
||||
OPC_RISC_C_FUNC_LWSP = 0x2,
|
||||
OPC_RISC_C_FUNC_FLWSP_LDSP = 0x3,
|
||||
OPC_RISC_C_FUNC_JR_MV_EBREAK_JALR_ADD = 0x4,
|
||||
OPC_RISC_C_FUNC_FSDSP_SQSP = 0x5,
|
||||
OPC_RISC_C_FUNC_SWSP = 0x6,
|
||||
OPC_RISC_C_FUNC_FSWSP_SDSP = 0x7
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,8 +26,9 @@ FIELD(VDATA, VM, 0, 1)
|
|||
FIELD(VDATA, LMUL, 1, 3)
|
||||
FIELD(VDATA, VTA, 4, 1)
|
||||
FIELD(VDATA, VTA_ALL_1S, 5, 1)
|
||||
FIELD(VDATA, NF, 6, 4)
|
||||
FIELD(VDATA, WD, 6, 1)
|
||||
FIELD(VDATA, VMA, 6, 1)
|
||||
FIELD(VDATA, NF, 7, 4)
|
||||
FIELD(VDATA, WD, 7, 1)
|
||||
|
||||
/* float point classify helpers */
|
||||
target_ulong fclass_h(uint64_t frs1);
|
||||
|
|
|
@ -92,6 +92,7 @@ static const VMStateDescription vmstate_hyper = {
|
|||
VMSTATE_UINTTL(env.hgeie, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.hgeip, RISCVCPU),
|
||||
VMSTATE_UINT64(env.htimedelta, RISCVCPU),
|
||||
VMSTATE_UINT64(env.vstimecmp, RISCVCPU),
|
||||
|
||||
VMSTATE_UINTTL(env.hvictl, RISCVCPU),
|
||||
VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
|
||||
|
@ -307,8 +308,8 @@ static const VMStateDescription vmstate_pmu_ctr_state = {
|
|||
|
||||
const VMStateDescription vmstate_riscv_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.version_id = 4,
|
||||
.minimum_version_id = 4,
|
||||
.post_load = riscv_cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
|
||||
|
@ -355,11 +356,12 @@ const VMStateDescription vmstate_riscv_cpu = {
|
|||
VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, 0,
|
||||
vmstate_pmu_ctr_state, PMUCTRState),
|
||||
VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS),
|
||||
VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS),
|
||||
VMSTATE_UINTTL(env.sscratch, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mscratch, RISCVCPU),
|
||||
VMSTATE_UINT64(env.mfromhost, RISCVCPU),
|
||||
VMSTATE_UINT64(env.mtohost, RISCVCPU),
|
||||
VMSTATE_UINT64(env.timecmp, RISCVCPU),
|
||||
VMSTATE_UINT64(env.stimecmp, RISCVCPU),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
|
|
@ -29,7 +29,8 @@ riscv_softmmu_ss.add(files(
|
|||
'debug.c',
|
||||
'monitor.c',
|
||||
'machine.c',
|
||||
'pmu.c'
|
||||
'pmu.c',
|
||||
'time_helper.c'
|
||||
))
|
||||
|
||||
target_arch += {'riscv': riscv_ss}
|
||||
|
|
|
@ -19,14 +19,435 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "pmu.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
|
||||
#define RISCV_TIMEBASE_FREQ 1000000000 /* 1Ghz */
|
||||
#define MAKE_32BIT_MASK(shift, length) \
|
||||
(((uint32_t)(~0UL) >> (32 - (length))) << (shift))
|
||||
|
||||
/*
|
||||
* To keep it simple, any event can be mapped to any programmable counters in
|
||||
* QEMU. The generic cycle & instruction count events can also be monitored
|
||||
* using programmable counters. In that case, mcycle & minstret must continue
|
||||
* to provide the correct value as well. Heterogeneous PMU per hart is not
|
||||
* supported yet. Thus, number of counters are same across all harts.
|
||||
*/
|
||||
void riscv_pmu_generate_fdt_node(void *fdt, int num_ctrs, char *pmu_name)
|
||||
{
|
||||
uint32_t fdt_event_ctr_map[20] = {};
|
||||
uint32_t cmask;
|
||||
|
||||
/* All the programmable counters can map to any event */
|
||||
cmask = MAKE_32BIT_MASK(3, num_ctrs);
|
||||
|
||||
/*
|
||||
* The event encoding is specified in the SBI specification
|
||||
* Event idx is a 20bits wide number encoded as follows:
|
||||
* event_idx[19:16] = type
|
||||
* event_idx[15:0] = code
|
||||
* The code field in cache events are encoded as follows:
|
||||
* event_idx.code[15:3] = cache_id
|
||||
* event_idx.code[2:1] = op_id
|
||||
* event_idx.code[0:0] = result_id
|
||||
*/
|
||||
|
||||
/* SBI_PMU_HW_CPU_CYCLES: 0x01 : type(0x00) */
|
||||
fdt_event_ctr_map[0] = cpu_to_be32(0x00000001);
|
||||
fdt_event_ctr_map[1] = cpu_to_be32(0x00000001);
|
||||
fdt_event_ctr_map[2] = cpu_to_be32(cmask | 1 << 0);
|
||||
|
||||
/* SBI_PMU_HW_INSTRUCTIONS: 0x02 : type(0x00) */
|
||||
fdt_event_ctr_map[3] = cpu_to_be32(0x00000002);
|
||||
fdt_event_ctr_map[4] = cpu_to_be32(0x00000002);
|
||||
fdt_event_ctr_map[5] = cpu_to_be32(cmask | 1 << 2);
|
||||
|
||||
/* SBI_PMU_HW_CACHE_DTLB : 0x03 READ : 0x00 MISS : 0x00 type(0x01) */
|
||||
fdt_event_ctr_map[6] = cpu_to_be32(0x00010019);
|
||||
fdt_event_ctr_map[7] = cpu_to_be32(0x00010019);
|
||||
fdt_event_ctr_map[8] = cpu_to_be32(cmask);
|
||||
|
||||
/* SBI_PMU_HW_CACHE_DTLB : 0x03 WRITE : 0x01 MISS : 0x00 type(0x01) */
|
||||
fdt_event_ctr_map[9] = cpu_to_be32(0x0001001B);
|
||||
fdt_event_ctr_map[10] = cpu_to_be32(0x0001001B);
|
||||
fdt_event_ctr_map[11] = cpu_to_be32(cmask);
|
||||
|
||||
/* SBI_PMU_HW_CACHE_ITLB : 0x04 READ : 0x00 MISS : 0x00 type(0x01) */
|
||||
fdt_event_ctr_map[12] = cpu_to_be32(0x00010021);
|
||||
fdt_event_ctr_map[13] = cpu_to_be32(0x00010021);
|
||||
fdt_event_ctr_map[14] = cpu_to_be32(cmask);
|
||||
|
||||
/* This a OpenSBI specific DT property documented in OpenSBI docs */
|
||||
qemu_fdt_setprop(fdt, pmu_name, "riscv,event-to-mhpmcounters",
|
||||
fdt_event_ctr_map, sizeof(fdt_event_ctr_map));
|
||||
}
|
||||
|
||||
static bool riscv_pmu_counter_valid(RISCVCPU *cpu, uint32_t ctr_idx)
|
||||
{
|
||||
if (ctr_idx < 3 || ctr_idx >= RV_MAX_MHPMCOUNTERS ||
|
||||
!(cpu->pmu_avail_ctrs & BIT(ctr_idx))) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
if (riscv_pmu_counter_valid(cpu, ctr_idx) &&
|
||||
!get_field(env->mcountinhibit, BIT(ctr_idx))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
target_ulong max_val = UINT32_MAX;
|
||||
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
|
||||
bool virt_on = riscv_cpu_virt_enabled(env);
|
||||
|
||||
/* Privilege mode filtering */
|
||||
if ((env->priv == PRV_M &&
|
||||
(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_MINH)) ||
|
||||
(env->priv == PRV_S && virt_on &&
|
||||
(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VSINH)) ||
|
||||
(env->priv == PRV_U && virt_on &&
|
||||
(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VUINH)) ||
|
||||
(env->priv == PRV_S && !virt_on &&
|
||||
(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_SINH)) ||
|
||||
(env->priv == PRV_U && !virt_on &&
|
||||
(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_UINH))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle the overflow scenario */
|
||||
if (counter->mhpmcounter_val == max_val) {
|
||||
if (counter->mhpmcounterh_val == max_val) {
|
||||
counter->mhpmcounter_val = 0;
|
||||
counter->mhpmcounterh_val = 0;
|
||||
/* Generate interrupt only if OF bit is clear */
|
||||
if (!(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_OF)) {
|
||||
env->mhpmeventh_val[ctr_idx] |= MHPMEVENTH_BIT_OF;
|
||||
riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1));
|
||||
}
|
||||
} else {
|
||||
counter->mhpmcounterh_val++;
|
||||
}
|
||||
} else {
|
||||
counter->mhpmcounter_val++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
|
||||
uint64_t max_val = UINT64_MAX;
|
||||
bool virt_on = riscv_cpu_virt_enabled(env);
|
||||
|
||||
/* Privilege mode filtering */
|
||||
if ((env->priv == PRV_M &&
|
||||
(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) ||
|
||||
(env->priv == PRV_S && virt_on &&
|
||||
(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) ||
|
||||
(env->priv == PRV_U && virt_on &&
|
||||
(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) ||
|
||||
(env->priv == PRV_S && !virt_on &&
|
||||
(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) ||
|
||||
(env->priv == PRV_U && !virt_on &&
|
||||
(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle the overflow scenario */
|
||||
if (counter->mhpmcounter_val == max_val) {
|
||||
counter->mhpmcounter_val = 0;
|
||||
/* Generate interrupt only if OF bit is clear */
|
||||
if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) {
|
||||
env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF;
|
||||
riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1));
|
||||
}
|
||||
} else {
|
||||
counter->mhpmcounter_val++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
|
||||
{
|
||||
uint32_t ctr_idx;
|
||||
int ret;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
gpointer value;
|
||||
|
||||
if (!cpu->cfg.pmu_num) {
|
||||
return 0;
|
||||
}
|
||||
value = g_hash_table_lookup(cpu->pmu_event_ctr_map,
|
||||
GUINT_TO_POINTER(event_idx));
|
||||
if (!value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctr_idx = GPOINTER_TO_UINT(value);
|
||||
if (!riscv_pmu_counter_enabled(cpu, ctr_idx) ||
|
||||
get_field(env->mcountinhibit, BIT(ctr_idx))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (riscv_cpu_mxl(env) == MXL_RV32) {
|
||||
ret = riscv_pmu_incr_ctr_rv32(cpu, ctr_idx);
|
||||
} else {
|
||||
ret = riscv_pmu_incr_ctr_rv64(cpu, ctr_idx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
|
||||
uint32_t target_ctr)
|
||||
{
|
||||
return (target_ctr == 0) ? true : false;
|
||||
RISCVCPU *cpu;
|
||||
uint32_t event_idx;
|
||||
uint32_t ctr_idx;
|
||||
|
||||
/* Fixed instret counter */
|
||||
if (target_ctr == 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cpu = RISCV_CPU(env_cpu(env));
|
||||
if (!cpu->pmu_event_ctr_map) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event_idx = RISCV_PMU_EVENT_HW_INSTRUCTIONS;
|
||||
ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
|
||||
GUINT_TO_POINTER(event_idx)));
|
||||
if (!ctr_idx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return target_ctr == ctr_idx ? true : false;
|
||||
}
|
||||
|
||||
bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr)
|
||||
{
|
||||
return (target_ctr == 2) ? true : false;
|
||||
RISCVCPU *cpu;
|
||||
uint32_t event_idx;
|
||||
uint32_t ctr_idx;
|
||||
|
||||
/* Fixed mcycle counter */
|
||||
if (target_ctr == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cpu = RISCV_CPU(env_cpu(env));
|
||||
if (!cpu->pmu_event_ctr_map) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event_idx = RISCV_PMU_EVENT_HW_CPU_CYCLES;
|
||||
ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
|
||||
GUINT_TO_POINTER(event_idx)));
|
||||
|
||||
/* Counter zero is not used for event_ctr_map */
|
||||
if (!ctr_idx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (target_ctr == ctr_idx) ? true : false;
|
||||
}
|
||||
|
||||
static gboolean pmu_remove_event_map(gpointer key, gpointer value,
|
||||
gpointer udata)
|
||||
{
|
||||
return (GPOINTER_TO_UINT(value) == GPOINTER_TO_UINT(udata)) ? true : false;
|
||||
}
|
||||
|
||||
static int64_t pmu_icount_ticks_to_ns(int64_t value)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
|
||||
if (icount_enabled()) {
|
||||
ret = icount_to_ns(value);
|
||||
} else {
|
||||
ret = (NANOSECONDS_PER_SECOND / RISCV_TIMEBASE_FREQ) * value;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
|
||||
uint32_t ctr_idx)
|
||||
{
|
||||
uint32_t event_idx;
|
||||
RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
|
||||
|
||||
if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->pmu_event_ctr_map) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expected mhpmevent value is zero for reset case. Remove the current
|
||||
* mapping.
|
||||
*/
|
||||
if (!value) {
|
||||
g_hash_table_foreach_remove(cpu->pmu_event_ctr_map,
|
||||
pmu_remove_event_map,
|
||||
GUINT_TO_POINTER(ctr_idx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
event_idx = value & MHPMEVENT_IDX_MASK;
|
||||
if (g_hash_table_lookup(cpu->pmu_event_ctr_map,
|
||||
GUINT_TO_POINTER(event_idx))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (event_idx) {
|
||||
case RISCV_PMU_EVENT_HW_CPU_CYCLES:
|
||||
case RISCV_PMU_EVENT_HW_INSTRUCTIONS:
|
||||
case RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS:
|
||||
case RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS:
|
||||
case RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS:
|
||||
break;
|
||||
default:
|
||||
/* We don't support any raw events right now */
|
||||
return -1;
|
||||
}
|
||||
g_hash_table_insert(cpu->pmu_event_ctr_map, GUINT_TO_POINTER(event_idx),
|
||||
GUINT_TO_POINTER(ctr_idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pmu_timer_trigger_irq(RISCVCPU *cpu,
|
||||
enum riscv_pmu_event_idx evt_idx)
|
||||
{
|
||||
uint32_t ctr_idx;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
PMUCTRState *counter;
|
||||
target_ulong *mhpmevent_val;
|
||||
uint64_t of_bit_mask;
|
||||
int64_t irq_trigger_at;
|
||||
|
||||
if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
|
||||
evt_idx != RISCV_PMU_EVENT_HW_INSTRUCTIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
|
||||
GUINT_TO_POINTER(evt_idx)));
|
||||
if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (riscv_cpu_mxl(env) == MXL_RV32) {
|
||||
mhpmevent_val = &env->mhpmeventh_val[ctr_idx];
|
||||
of_bit_mask = MHPMEVENTH_BIT_OF;
|
||||
} else {
|
||||
mhpmevent_val = &env->mhpmevent_val[ctr_idx];
|
||||
of_bit_mask = MHPMEVENT_BIT_OF;
|
||||
}
|
||||
|
||||
counter = &env->pmu_ctrs[ctr_idx];
|
||||
if (counter->irq_overflow_left > 0) {
|
||||
irq_trigger_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
counter->irq_overflow_left;
|
||||
timer_mod_anticipate_ns(cpu->pmu_timer, irq_trigger_at);
|
||||
counter->irq_overflow_left = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) {
|
||||
/* Generate interrupt only if OF bit is clear */
|
||||
if (!(*mhpmevent_val & of_bit_mask)) {
|
||||
*mhpmevent_val |= of_bit_mask;
|
||||
riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Timer callback for instret and cycle counter overflow */
|
||||
void riscv_pmu_timer_cb(void *priv)
|
||||
{
|
||||
RISCVCPU *cpu = priv;
|
||||
|
||||
/* Timer event was triggered only for these events */
|
||||
pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES);
|
||||
pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS);
|
||||
}
|
||||
|
||||
int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx)
|
||||
{
|
||||
uint64_t overflow_delta, overflow_at;
|
||||
int64_t overflow_ns, overflow_left = 0;
|
||||
RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
|
||||
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
|
||||
|
||||
if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
overflow_delta = UINT64_MAX - value + 1;
|
||||
} else {
|
||||
overflow_delta = UINT64_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* QEMU supports only int64_t timers while RISC-V counters are uint64_t.
|
||||
* Compute the leftover and save it so that it can be reprogrammed again
|
||||
* when timer expires.
|
||||
*/
|
||||
if (overflow_delta > INT64_MAX) {
|
||||
overflow_left = overflow_delta - INT64_MAX;
|
||||
}
|
||||
|
||||
if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
|
||||
riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
|
||||
overflow_ns = pmu_icount_ticks_to_ns((int64_t)overflow_delta);
|
||||
overflow_left = pmu_icount_ticks_to_ns(overflow_left) ;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + overflow_ns;
|
||||
|
||||
if (overflow_at > INT64_MAX) {
|
||||
overflow_left += overflow_at - INT64_MAX;
|
||||
counter->irq_overflow_left = overflow_left;
|
||||
overflow_at = INT64_MAX;
|
||||
}
|
||||
timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int riscv_pmu_init(RISCVCPU *cpu, int num_counters)
|
||||
{
|
||||
if (num_counters > (RV_MAX_MHPMCOUNTERS - 3)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cpu->pmu_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
if (!cpu->pmu_event_ctr_map) {
|
||||
/* PMU support can not be enabled */
|
||||
qemu_log_mask(LOG_UNIMP, "PMU events can't be supported\n");
|
||||
cpu->cfg.pmu_num = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a bitmask of available programmable counters */
|
||||
cpu->pmu_avail_ctrs = MAKE_32BIT_MASK(3, num_counters);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,3 +26,11 @@ bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
|
|||
uint32_t target_ctr);
|
||||
bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env,
|
||||
uint32_t target_ctr);
|
||||
void riscv_pmu_timer_cb(void *priv);
|
||||
int riscv_pmu_init(RISCVCPU *cpu, int num_counters);
|
||||
int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
|
||||
uint32_t ctr_idx);
|
||||
int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx);
|
||||
void riscv_pmu_generate_fdt_node(void *fdt, int num_counters, char *pmu_name);
|
||||
int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value,
|
||||
uint32_t ctr_idx);
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* RISC-V timer helper implementation.
|
||||
*
|
||||
* Copyright (c) 2022 Rivos 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 "qemu/log.h"
|
||||
#include "cpu_bits.h"
|
||||
#include "time_helper.h"
|
||||
#include "hw/intc/riscv_aclint.h"
|
||||
|
||||
static void riscv_vstimer_cb(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
env->vstime_irq = 1;
|
||||
riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1));
|
||||
}
|
||||
|
||||
static void riscv_stimer_cb(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when timecmp is written to update the QEMU timer or immediately
|
||||
* trigger timer interrupt if mtimecmp <= current timer value.
|
||||
*/
|
||||
void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
|
||||
uint64_t timecmp, uint64_t delta,
|
||||
uint32_t timer_irq)
|
||||
{
|
||||
uint64_t diff, ns_diff, next;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
|
||||
uint32_t timebase_freq = mtimer->timebase_freq;
|
||||
uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
|
||||
|
||||
if (timecmp <= rtc_r) {
|
||||
/*
|
||||
* If we're setting an stimecmp value in the "past",
|
||||
* immediately raise the timer interrupt
|
||||
*/
|
||||
if (timer_irq == MIP_VSTIP) {
|
||||
env->vstime_irq = 1;
|
||||
}
|
||||
riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer_irq == MIP_VSTIP) {
|
||||
env->vstime_irq = 0;
|
||||
}
|
||||
/* Clear the [V]STIP bit in mip */
|
||||
riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0));
|
||||
|
||||
/* otherwise, set up the future timer interrupt */
|
||||
diff = timecmp - rtc_r;
|
||||
/* back to ns (note args switched in muldiv64) */
|
||||
ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
|
||||
|
||||
/*
|
||||
* check if ns_diff overflowed and check if the addition would potentially
|
||||
* overflow
|
||||
*/
|
||||
if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
|
||||
ns_diff > INT64_MAX) {
|
||||
next = INT64_MAX;
|
||||
} else {
|
||||
/*
|
||||
* as it is very unlikely qemu_clock_get_ns will return a value
|
||||
* greater than INT64_MAX, no additional check is needed for an
|
||||
* unsigned integer overflow.
|
||||
*/
|
||||
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
|
||||
/*
|
||||
* if ns_diff is INT64_MAX next may still be outside the range
|
||||
* of a signed integer.
|
||||
*/
|
||||
next = MIN(next, INT64_MAX);
|
||||
}
|
||||
|
||||
timer_mod(timer, next);
|
||||
}
|
||||
|
||||
void riscv_timer_init(RISCVCPU *cpu)
|
||||
{
|
||||
CPURISCVState *env;
|
||||
|
||||
if (!cpu) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = &cpu->env;
|
||||
env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu);
|
||||
env->stimecmp = 0;
|
||||
|
||||
env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu);
|
||||
env->vstimecmp = 0;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* RISC-V timer header file.
|
||||
*
|
||||
* Copyright (c) 2022 Rivos 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/>.
|
||||
*/
|
||||
|
||||
#ifndef RISCV_TIME_HELPER_H
|
||||
#define RISCV_TIME_HELPER_H
|
||||
|
||||
#include "cpu.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
|
||||
uint64_t timecmp, uint64_t delta,
|
||||
uint32_t timer_irq);
|
||||
void riscv_timer_init(RISCVCPU *cpu);
|
||||
|
||||
#endif
|
|
@ -95,6 +95,7 @@ typedef struct DisasContext {
|
|||
int8_t lmul;
|
||||
uint8_t sew;
|
||||
uint8_t vta;
|
||||
uint8_t vma;
|
||||
bool cfg_vta_all_1s;
|
||||
target_ulong vstart;
|
||||
bool vl_eq_vlmax;
|
||||
|
@ -544,7 +545,7 @@ static TCGv get_address(DisasContext *ctx, int rs1, int imm)
|
|||
|
||||
tcg_gen_addi_tl(addr, src1, imm);
|
||||
if (ctx->pm_mask_enabled) {
|
||||
tcg_gen_and_tl(addr, addr, pm_mask);
|
||||
tcg_gen_andc_tl(addr, addr, pm_mask);
|
||||
} else if (get_xl(ctx) == MXL_RV32) {
|
||||
tcg_gen_ext32u_tl(addr, addr);
|
||||
}
|
||||
|
@ -705,10 +706,26 @@ static int ex_rvc_register(DisasContext *ctx, int reg)
|
|||
return 8 + reg;
|
||||
}
|
||||
|
||||
static int ex_rvc_shifti(DisasContext *ctx, int imm)
|
||||
static int ex_rvc_shiftli(DisasContext *ctx, int imm)
|
||||
{
|
||||
/* For RV128 a shamt of 0 means a shift by 64. */
|
||||
return imm ? imm : 64;
|
||||
if (get_ol(ctx) == MXL_RV128) {
|
||||
imm = imm ? imm : 64;
|
||||
}
|
||||
return imm;
|
||||
}
|
||||
|
||||
static int ex_rvc_shiftri(DisasContext *ctx, int imm)
|
||||
{
|
||||
/*
|
||||
* For RV128 a shamt of 0 means a shift by 64, furthermore, for right
|
||||
* shifts, the shamt is sign-extended.
|
||||
*/
|
||||
if (get_ol(ctx) == MXL_RV128) {
|
||||
imm = imm | (imm & 32) << 1;
|
||||
imm = imm ? imm : 64;
|
||||
}
|
||||
return imm;
|
||||
}
|
||||
|
||||
/* Include the auto-generated decoder for 32 bit insn */
|
||||
|
@ -1105,6 +1122,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|||
ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW);
|
||||
ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3);
|
||||
ctx->vta = FIELD_EX32(tb_flags, TB_FLAGS, VTA) && cpu->cfg.rvv_ta_all_1s;
|
||||
ctx->vma = FIELD_EX32(tb_flags, TB_FLAGS, VMA) && cpu->cfg.rvv_ma_all_1s;
|
||||
ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s;
|
||||
ctx->vstart = env->vstart;
|
||||
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
|
||||
|
|
|
@ -127,6 +127,11 @@ static inline uint32_t vext_vta(uint32_t desc)
|
|||
return FIELD_EX32(simd_data(desc), VDATA, VTA);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vma(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VMA);
|
||||
}
|
||||
|
||||
static inline uint32_t vext_vta_all_1s(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, VTA_ALL_1S);
|
||||
|
@ -278,14 +283,18 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base,
|
|||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
for (i = env->vstart; i < env->vl; i++, env->vstart++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz,
|
||||
(i + k * max_elems + 1) * esz);
|
||||
k++;
|
||||
continue;
|
||||
}
|
||||
target_ulong addr = base + stride * i + (k << log2_esz);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
|
@ -477,15 +486,19 @@ vext_ldst_index(void *vd, void *v0, target_ulong base,
|
|||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
/* load bytes from guest memory */
|
||||
for (i = env->vstart; i < env->vl; i++, env->vstart++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz,
|
||||
(i + k * max_elems + 1) * esz);
|
||||
k++;
|
||||
continue;
|
||||
}
|
||||
abi_ptr addr = get_index_addr(base, i, vs2) + (k << log2_esz);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
|
@ -574,6 +587,7 @@ vext_ldff(void *vd, void *v0, target_ulong base,
|
|||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
target_ulong addr, offset, remain;
|
||||
|
||||
/* probe every access*/
|
||||
|
@ -619,10 +633,14 @@ ProbeSuccess:
|
|||
}
|
||||
for (i = env->vstart; i < env->vl; i++) {
|
||||
k = 0;
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
continue;
|
||||
}
|
||||
while (k < nf) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz,
|
||||
(i + k * max_elems + 1) * esz);
|
||||
k++;
|
||||
continue;
|
||||
}
|
||||
target_ulong addr = base + ((i * nf + k) << log2_esz);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
|
@ -812,10 +830,13 @@ static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
|
|||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, vs1, vs2, i);
|
||||
|
@ -878,10 +899,13 @@ static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
|
|||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, s1, vs2, i);
|
||||
|
@ -1274,10 +1298,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
|||
uint32_t esz = sizeof(TS1); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
TS1 s1 = *((TS1 *)vs1 + HS1(i)); \
|
||||
|
@ -1315,10 +1342,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
|||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, \
|
||||
(i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
|
||||
|
@ -1373,12 +1404,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
|||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
if (vma) { \
|
||||
vext_set_elem_mask(vd, i, 1); \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
vext_set_elem_mask(vd, i, DO_OP(s2, s1)); \
|
||||
|
@ -1431,11 +1467,16 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
|||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
if (vma) { \
|
||||
vext_set_elem_mask(vd, i, 1); \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
vext_set_elem_mask(vd, i, \
|
||||
|
@ -2088,10 +2129,12 @@ static inline void
|
|||
vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2,
|
||||
CPURISCVState *env,
|
||||
uint32_t vl, uint32_t vm, int vxrm,
|
||||
opivv2_rm_fn *fn)
|
||||
opivv2_rm_fn *fn, uint32_t vma, uint32_t esz)
|
||||
{
|
||||
for (uint32_t i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, vs1, vs2, i, env, vxrm);
|
||||
|
@ -2109,23 +2152,24 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2,
|
|||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
switch (env->vxrm) {
|
||||
case 0: /* rnu */
|
||||
vext_vv_rm_1(vd, v0, vs1, vs2,
|
||||
env, vl, vm, 0, fn);
|
||||
env, vl, vm, 0, fn, vma, esz);
|
||||
break;
|
||||
case 1: /* rne */
|
||||
vext_vv_rm_1(vd, v0, vs1, vs2,
|
||||
env, vl, vm, 1, fn);
|
||||
env, vl, vm, 1, fn, vma, esz);
|
||||
break;
|
||||
case 2: /* rdn */
|
||||
vext_vv_rm_1(vd, v0, vs1, vs2,
|
||||
env, vl, vm, 2, fn);
|
||||
env, vl, vm, 2, fn, vma, esz);
|
||||
break;
|
||||
default: /* rod */
|
||||
vext_vv_rm_1(vd, v0, vs1, vs2,
|
||||
env, vl, vm, 3, fn);
|
||||
env, vl, vm, 3, fn, vma, esz);
|
||||
break;
|
||||
}
|
||||
/* set tail elements to 1s */
|
||||
|
@ -2209,10 +2253,12 @@ static inline void
|
|||
vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2,
|
||||
CPURISCVState *env,
|
||||
uint32_t vl, uint32_t vm, int vxrm,
|
||||
opivx2_rm_fn *fn)
|
||||
opivx2_rm_fn *fn, uint32_t vma, uint32_t esz)
|
||||
{
|
||||
for (uint32_t i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
|
||||
continue;
|
||||
}
|
||||
fn(vd, s1, vs2, i, env, vxrm);
|
||||
|
@ -2230,23 +2276,24 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2,
|
|||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
switch (env->vxrm) {
|
||||
case 0: /* rnu */
|
||||
vext_vx_rm_1(vd, v0, s1, vs2,
|
||||
env, vl, vm, 0, fn);
|
||||
env, vl, vm, 0, fn, vma, esz);
|
||||
break;
|
||||
case 1: /* rne */
|
||||
vext_vx_rm_1(vd, v0, s1, vs2,
|
||||
env, vl, vm, 1, fn);
|
||||
env, vl, vm, 1, fn, vma, esz);
|
||||
break;
|
||||
case 2: /* rdn */
|
||||
vext_vx_rm_1(vd, v0, s1, vs2,
|
||||
env, vl, vm, 2, fn);
|
||||
env, vl, vm, 2, fn, vma, esz);
|
||||
break;
|
||||
default: /* rod */
|
||||
vext_vx_rm_1(vd, v0, s1, vs2,
|
||||
env, vl, vm, 3, fn);
|
||||
env, vl, vm, 3, fn, vma, esz);
|
||||
break;
|
||||
}
|
||||
/* set tail elements to 1s */
|
||||
|
@ -3004,10 +3051,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
|||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, ESZ); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * ESZ, \
|
||||
(i + 1) * ESZ); \
|
||||
continue; \
|
||||
} \
|
||||
do_##NAME(vd, vs1, vs2, i, env); \
|
||||
|
@ -3043,10 +3094,14 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \
|
|||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, ESZ); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * ESZ, \
|
||||
(i + 1) * ESZ); \
|
||||
continue; \
|
||||
} \
|
||||
do_##NAME(vd, s1, vs2, i, env); \
|
||||
|
@ -3618,6 +3673,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
|||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, ESZ); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
if (vl == 0) { \
|
||||
|
@ -3625,6 +3681,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
|||
} \
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * ESZ, \
|
||||
(i + 1) * ESZ); \
|
||||
continue; \
|
||||
} \
|
||||
do_##NAME(vd, vs2, i, env); \
|
||||
|
@ -4135,12 +4194,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
|||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
if (vma) { \
|
||||
vext_set_elem_mask(vd, i, 1); \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
vext_set_elem_mask(vd, i, \
|
||||
|
@ -4168,11 +4232,16 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
|
|||
uint32_t vl = env->vl; \
|
||||
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
if (vma) { \
|
||||
vext_set_elem_mask(vd, i, 1); \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
vext_set_elem_mask(vd, i, \
|
||||
|
@ -4295,10 +4364,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
|||
uint32_t total_elems = \
|
||||
vext_get_total_elems(env, desc, ESZ); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * ESZ, \
|
||||
(i + 1) * ESZ); \
|
||||
continue; \
|
||||
} \
|
||||
do_##NAME(vd, vs2, i); \
|
||||
|
@ -4806,11 +4879,16 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env,
|
|||
uint32_t vl = env->vl;
|
||||
uint32_t total_elems = env_archcpu(env)->cfg.vlen;
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
int i;
|
||||
bool first_mask_bit = false;
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
if (vma) {
|
||||
vext_set_elem_mask(vd, i, 1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* write a zero to all following active elements */
|
||||
|
@ -4871,11 +4949,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t sum = 0; \
|
||||
int i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
*((ETYPE *)vd + H(i)) = sum; \
|
||||
|
@ -4902,10 +4983,13 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
int i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
*((ETYPE *)vd + H(i)) = i; \
|
||||
|
@ -4934,11 +5018,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
target_ulong offset = s1, i_min, i; \
|
||||
\
|
||||
i_min = MAX(env->vstart, offset); \
|
||||
for (i = i_min; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
*((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \
|
||||
|
@ -4963,13 +5050,17 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
target_ulong i_max, i; \
|
||||
\
|
||||
i_max = MAX(MIN(s1 < vlmax ? vlmax - s1 : 0, vl), env->vstart); \
|
||||
for (i = env->vstart; i < i_max; ++i) { \
|
||||
if (vm || vext_elem_mask(v0, i)) { \
|
||||
*((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + s1)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
*((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + s1)); \
|
||||
} \
|
||||
\
|
||||
for (i = i_max; i < vl; ++i) { \
|
||||
|
@ -4999,10 +5090,13 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
if (i == 0) { \
|
||||
|
@ -5044,10 +5138,13 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
if (i == vl - 1) { \
|
||||
|
@ -5115,11 +5212,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
|||
uint32_t esz = sizeof(TS2); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint64_t index; \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
index = *((TS1 *)vs1 + HS1(i)); \
|
||||
|
@ -5155,11 +5255,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint64_t index = s1; \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
if (index >= vlmax) { \
|
||||
|
@ -5234,10 +5337,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
|||
uint32_t esz = sizeof(ETYPE); \
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
*((ETYPE *)vd + HD(i)) = *((DTYPE *)vs2 + HS1(i)); \
|
||||
|
|
Loading…
Reference in New Issue