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>
master
Stefan Hajnoczi 2022-09-07 08:02:43 -04:00
commit e46e2628e9
40 changed files with 2226 additions and 556 deletions

View File

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

View File

@ -46,7 +46,7 @@ Those hosts are officially supported, with various accelerators:
* - PPC
- kvm, tcg
* - RISC-V
- tcg
- kvm, tcg
* - s390x
- kvm, tcg
* - SPARC

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -32,6 +32,8 @@ typedef struct RISCVAclintMTimerState {
/*< private >*/
SysBusDevice parent_obj;
uint64_t time_delta;
uint64_t *timecmp;
QEMUTimer **timers;
/*< public >*/
MemoryRegion mmio;

View File

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

View File

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

View File

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

View File

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

View File

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

@ -1 +1 @@
Subproject commit 48f91ee9c960f048c4a7d1da4447d31e04931e38
Subproject commit 4489876e933d8ba0d8bc6c64bae71e295d45faac

View File

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

View File

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

View File

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

View File

@ -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 */
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

114
target/riscv/time_helper.c Normal file
View File

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

View File

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

View File

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

View File

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