diff --git a/disas/riscv.c b/disas/riscv.c index 489c2ae5e8..f107d94c4c 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1304,8 +1304,6 @@ static const char *csr_name(int csrno) case 0x0043: return "utval"; case 0x0044: return "uip"; case 0x0100: return "sstatus"; - case 0x0102: return "sedeleg"; - case 0x0103: return "sideleg"; case 0x0104: return "sie"; case 0x0105: return "stvec"; case 0x0106: return "scounteren"; diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index f8ecec95f3..4b16e41d7f 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -168,14 +168,19 @@ Enabling TPM A TPM device can be connected to the virt board by following the steps below. -First launch the TPM emulator +First launch the TPM emulator: - swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \ +.. code-block:: bash + + $ swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \ --ctrl type=unixio,path=swtpm-sock -Then launch QEMU with: +Then launch QEMU with some additional arguments to link a TPM device to the backend: - ... +.. code-block:: bash + + $ qemu-system-riscv64 \ + ... other args .... \ -chardev socket,id=chrtpm,path=swtpm-sock \ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -device tpm-tis-device,tpmdev=tpm0 diff --git a/gdb-xml/riscv-32bit-cpu.xml b/gdb-xml/riscv-32bit-cpu.xml index 0d07aaec85..466f2c0648 100644 --- a/gdb-xml/riscv-32bit-cpu.xml +++ b/gdb-xml/riscv-32bit-cpu.xml @@ -5,13 +5,9 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - - + diff --git a/gdb-xml/riscv-32bit-fpu.xml b/gdb-xml/riscv-32bit-fpu.xml index 1eaae9119e..24aa087031 100644 --- a/gdb-xml/riscv-32bit-fpu.xml +++ b/gdb-xml/riscv-32bit-fpu.xml @@ -5,13 +5,9 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - - + @@ -43,8 +39,4 @@ - - - - diff --git a/gdb-xml/riscv-64bit-cpu.xml b/gdb-xml/riscv-64bit-cpu.xml index b8aa424ae4..c4d83de09b 100644 --- a/gdb-xml/riscv-64bit-cpu.xml +++ b/gdb-xml/riscv-64bit-cpu.xml @@ -5,13 +5,9 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - - + diff --git a/gdb-xml/riscv-64bit-fpu.xml b/gdb-xml/riscv-64bit-fpu.xml index 794854cc01..d0f17f9984 100644 --- a/gdb-xml/riscv-64bit-fpu.xml +++ b/gdb-xml/riscv-64bit-fpu.xml @@ -5,10 +5,6 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - @@ -17,7 +13,7 @@ - + @@ -49,8 +45,4 @@ - - - - diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index af13dbe3b1..be7ff1eea0 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -142,7 +142,7 @@ 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", 0x20000490, + object_property_set_int(OBJECT(&s->cpus), "resetvec", s->resetvec, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); @@ -297,10 +297,16 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_DEV_PERI].base, memmap[IBEX_DEV_PERI].size); } +static Property lowrisc_ibex_soc_props[] = { + DEFINE_PROP_UINT32("resetvec", LowRISCIbexSoCState, resetvec, 0x20000400), + DEFINE_PROP_END_OF_LIST() +}; + static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, lowrisc_ibex_soc_props); dc->realize = lowrisc_ibex_soc_realize; /* Reason: Uses serial_hds in realize function, thus can't be used twice */ dc->user_creatable = false; diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c index d14580b409..94d7da9cc2 100644 --- a/hw/ssi/ibex_spi_host.c +++ b/hw/ssi/ibex_spi_host.c @@ -93,7 +93,7 @@ REG32(ERROR_STATUS, 0x30) FIELD(ERROR_STATUS, CMDINVAL, 3, 1) FIELD(ERROR_STATUS, CSIDINVAL, 4, 1) FIELD(ERROR_STATUS, ACCESSINVAL, 5, 1) -REG32(EVENT_ENABLE, 0x30) +REG32(EVENT_ENABLE, 0x34) FIELD(EVENT_ENABLE, RXFULL, 0, 1) FIELD(EVENT_ENABLE, TXEMPTY, 1, 1) FIELD(EVENT_ENABLE, RXWM, 2, 1) @@ -172,7 +172,7 @@ static void ibex_spi_host_irq(IbexSPIHostState *s) & R_INTR_STATE_SPI_EVENT_MASK; int err_irq = 0, event_irq = 0; - /* Error IRQ enabled and Error IRQ Cleared*/ + /* Error IRQ enabled and Error IRQ Cleared */ if (error_en && !err_pending) { /* Event enabled, Interrupt Test Error */ if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_ERROR_MASK) { @@ -434,7 +434,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr, case IBEX_SPI_HOST_TXDATA: /* * This is a hardware `feature` where - * the first word written TXDATA after init is omitted entirely + * the first word written to TXDATA after init is omitted entirely */ if (s->init_status) { s->init_status = false; @@ -487,7 +487,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr, break; case IBEX_SPI_HOST_ERROR_STATUS: /* - * Indicates that any errors that have occurred. + * Indicates any errors that have occurred. * When an error occurs, the corresponding bit must be cleared * here before issuing any further commands */ diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 26d960f288..6665cd5794 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -46,6 +46,8 @@ struct LowRISCIbexSoCState { IbexTimerState timer; IbexSPIHostState spi_host[OPENTITAN_NUM_SPI_HOSTS]; + uint32_t resetvec; + MemoryRegion flash_mem; MemoryRegion rom; MemoryRegion flash_alias; diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 83604da805..d738745925 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -22,6 +22,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_cpu.h" #include "hw/gpio/sifive_gpio.h" +#include "hw/boards.h" #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" #define RISCV_E_SOC(obj) \ @@ -41,7 +42,7 @@ typedef struct SiFiveESoCState { typedef struct SiFiveEState { /*< private >*/ - SysBusDevice parent_obj; + MachineState parent_obj; /*< public >*/ SiFiveESoCState soc; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index aee14a239a..b29c88b9f0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -228,13 +228,6 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } -static void set_resetvec(CPURISCVState *env, target_ulong resetvec) -{ -#ifndef CONFIG_USER_ONLY - env->resetvec = resetvec; -#endif -} - static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -336,7 +329,6 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); cpu->cfg.mmu = false; } #endif @@ -676,7 +668,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) riscv_set_feature(env, RISCV_FEATURE_DEBUG); } - set_resetvec(env, cpu->cfg.resetvec); #ifndef CONFIG_USER_ONLY if (cpu->cfg.ext_sstc) { @@ -1079,7 +1070,9 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID), DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID), - DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), +#ifndef CONFIG_USER_ONLY + DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), +#endif DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 06751e1e3e..b131fa8c8e 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -190,7 +190,7 @@ struct CPUArchState { /* This contains QEMU specific information about the virt state. */ target_ulong virt; target_ulong geilen; - target_ulong resetvec; + uint64_t resetvec; target_ulong mhartid; /* @@ -324,7 +324,11 @@ struct CPUArchState { /* trigger module */ target_ulong trigger_cur; - type2_trigger_t type2_trig[TRIGGER_TYPE2_NUM]; + target_ulong tdata1[RV_MAX_TRIGGERS]; + target_ulong tdata2[RV_MAX_TRIGGERS]; + target_ulong tdata3[RV_MAX_TRIGGERS]; + struct CPUBreakpoint *cpu_breakpoint[RV_MAX_TRIGGERS]; + struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS]; /* machine specific rdtime callback */ uint64_t (*rdtime_fn)(void *); @@ -474,7 +478,6 @@ struct RISCVCPUConfig { bool pmp; bool epmp; bool debug; - uint64_t resetvec; bool short_isa_string; }; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 7be12cac2e..d8f5f0abed 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -190,8 +190,6 @@ /* Supervisor Trap Setup */ #define CSR_SSTATUS 0x100 -#define CSR_SEDELEG 0x102 -#define CSR_SIDELEG 0x103 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 @@ -321,6 +319,7 @@ #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 +#define CSR_TINFO 0x7a4 /* Debug Mode Registers */ #define CSR_DCSR 0x7b0 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index b96db1b62b..5c9a7ee287 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -98,17 +98,22 @@ static RISCVException ctr(CPURISCVState *env, int csrno) skip_ext_pmu_check: - if (((env->priv == PRV_S) && (!get_field(env->mcounteren, ctr_mask))) || - ((env->priv == PRV_U) && (!get_field(env->scounteren, ctr_mask)))) { + if (env->priv < PRV_M && !get_field(env->mcounteren, ctr_mask)) { return RISCV_EXCP_ILLEGAL_INST; } if (riscv_cpu_virt_enabled(env)) { - if (!get_field(env->hcounteren, ctr_mask) && - get_field(env->mcounteren, ctr_mask)) { + if (!get_field(env->hcounteren, ctr_mask) || + (env->priv == PRV_U && !get_field(env->scounteren, ctr_mask))) { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } } + + if (riscv_has_ext(env, RVS) && env->priv == PRV_U && + !get_field(env->scounteren, ctr_mask)) { + return RISCV_EXCP_ILLEGAL_INST; + } + #endif return RISCV_EXCP_NONE; } @@ -3065,7 +3070,7 @@ static RISCVException read_tdata(CPURISCVState *env, int csrno, target_ulong *val) { /* return 0 in tdata1 to end the trigger enumeration */ - if (env->trigger_cur >= TRIGGER_NUM && csrno == CSR_TDATA1) { + if (env->trigger_cur >= RV_MAX_TRIGGERS && csrno == CSR_TDATA1) { *val = 0; return RISCV_EXCP_NONE; } @@ -3089,6 +3094,13 @@ static RISCVException write_tdata(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException read_tinfo(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = tinfo_csr_read(env); + return RISCV_EXCP_NONE; +} + /* * Functions to access Pointer Masking feature registers * We have to check if current priv lvl could modify @@ -3893,6 +3905,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata }, [CSR_TDATA2] = { "tdata2", debug, read_tdata, write_tdata }, [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata }, + [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore }, /* User Pointer Masking */ [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte }, diff --git a/target/riscv/debug.c b/target/riscv/debug.c index fc6e13222f..26ea764407 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -37,11 +37,9 @@ * - tdata1 * - tdata2 * - tdata3 + * - tinfo * - * We don't support writable 'type' field in the tdata1 register, so there is - * no need to implement the "tinfo" CSR. - * - * The following triggers are implemented: + * The following triggers are initialized by default: * * Index | Type | tdata mapping | Description * ------+------+------------------------+------------ @@ -52,8 +50,15 @@ /* tdata availability of a trigger */ typedef bool tdata_avail[TDATA_NUM]; -static tdata_avail tdata_mapping[TRIGGER_NUM] = { - [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = { true, true, false }, +static tdata_avail tdata_mapping[TRIGGER_TYPE_NUM] = { + [TRIGGER_TYPE_NO_EXIST] = { false, false, false }, + [TRIGGER_TYPE_AD_MATCH] = { true, true, true }, + [TRIGGER_TYPE_INST_CNT] = { true, false, true }, + [TRIGGER_TYPE_INT] = { true, true, true }, + [TRIGGER_TYPE_EXCP] = { true, true, true }, + [TRIGGER_TYPE_AD_MATCH6] = { true, true, true }, + [TRIGGER_TYPE_EXT_SRC] = { true, false, false }, + [TRIGGER_TYPE_UNAVAIL] = { true, true, true } }; /* only breakpoint size 1/2/4/8 supported */ @@ -67,18 +72,76 @@ static int access_size[SIZE_NUM] = { [6 ... 15] = -1, }; -static inline target_ulong trigger_type(CPURISCVState *env, - trigger_type_t type) +static inline target_ulong extract_trigger_type(CPURISCVState *env, + target_ulong tdata1) +{ + switch (riscv_cpu_mxl(env)) { + case MXL_RV32: + return extract32(tdata1, 28, 4); + case MXL_RV64: + case MXL_RV128: + return extract64(tdata1, 60, 4); + default: + g_assert_not_reached(); + } +} + +static inline target_ulong get_trigger_type(CPURISCVState *env, + target_ulong trigger_index) +{ + return extract_trigger_type(env, env->tdata1[trigger_index]); +} + +static trigger_action_t get_trigger_action(CPURISCVState *env, + target_ulong trigger_index) +{ + target_ulong tdata1 = env->tdata1[trigger_index]; + int trigger_type = get_trigger_type(env, trigger_index); + trigger_action_t action = DBG_ACTION_NONE; + + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + action = (tdata1 & TYPE2_ACTION) >> 12; + break; + case TRIGGER_TYPE_AD_MATCH6: + action = (tdata1 & TYPE6_ACTION) >> 12; + break; + case TRIGGER_TYPE_INST_CNT: + case TRIGGER_TYPE_INT: + case TRIGGER_TYPE_EXCP: + case TRIGGER_TYPE_EXT_SRC: + qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", + trigger_type); + break; + case TRIGGER_TYPE_NO_EXIST: + case TRIGGER_TYPE_UNAVAIL: + qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", + trigger_type); + break; + default: + g_assert_not_reached(); + } + + return action; +} + +static inline target_ulong build_tdata1(CPURISCVState *env, + trigger_type_t type, + bool dmode, target_ulong data) { target_ulong tdata1; switch (riscv_cpu_mxl(env)) { case MXL_RV32: - tdata1 = RV32_TYPE(type); + tdata1 = RV32_TYPE(type) | + (dmode ? RV32_DMODE : 0) | + (data & RV32_DATA_MASK); break; case MXL_RV64: case MXL_RV128: - tdata1 = RV64_TYPE(type); + tdata1 = RV64_TYPE(type) | + (dmode ? RV64_DMODE : 0) | + (data & RV64_DATA_MASK); break; default: g_assert_not_reached(); @@ -89,15 +152,13 @@ static inline target_ulong trigger_type(CPURISCVState *env, bool tdata_available(CPURISCVState *env, int tdata_index) { + int trigger_type = get_trigger_type(env, env->trigger_cur); + if (unlikely(tdata_index >= TDATA_NUM)) { return false; } - if (unlikely(env->trigger_cur >= TRIGGER_NUM)) { - return false; - } - - return tdata_mapping[env->trigger_cur][tdata_index]; + return tdata_mapping[trigger_type][tdata_index]; } target_ulong tselect_csr_read(CPURISCVState *env) @@ -107,8 +168,9 @@ target_ulong tselect_csr_read(CPURISCVState *env) void tselect_csr_write(CPURISCVState *env, target_ulong val) { - /* all target_ulong bits of tselect are implemented */ - env->trigger_cur = val; + if (val < RV_MAX_TRIGGERS) { + env->trigger_cur = val; + } } static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, @@ -137,6 +199,7 @@ static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, qemu_log_mask(LOG_GUEST_ERROR, "ignoring type write to tdata1 register\n"); } + if (dmode != 0) { qemu_log_mask(LOG_UNIMP, "debug mode is not supported\n"); } @@ -152,6 +215,32 @@ static inline void warn_always_zero_bit(target_ulong val, target_ulong mask, } } +static void do_trigger_action(CPURISCVState *env, target_ulong trigger_index) +{ + trigger_action_t action = get_trigger_action(env, trigger_index); + + switch (action) { + case DBG_ACTION_NONE: + break; + case DBG_ACTION_BP: + riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); + break; + case DBG_ACTION_DBG_MODE: + case DBG_ACTION_TRACE0: + case DBG_ACTION_TRACE1: + case DBG_ACTION_TRACE2: + case DBG_ACTION_TRACE3: + case DBG_ACTION_EXT_DBG0: + case DBG_ACTION_EXT_DBG1: + qemu_log_mask(LOG_UNIMP, "action: %d is not supported\n", action); + break; + default: + g_assert_not_reached(); + } +} + +/* type 2 trigger */ + static uint32_t type2_breakpoint_size(CPURISCVState *env, target_ulong ctrl) { uint32_t size, sizelo, sizehi = 0; @@ -211,8 +300,8 @@ static target_ulong type2_mcontrol_validate(CPURISCVState *env, static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) { - target_ulong ctrl = env->type2_trig[index].mcontrol; - target_ulong addr = env->type2_trig[index].maddress; + target_ulong ctrl = env->tdata1[index]; + target_ulong addr = env->tdata2[index]; bool enabled = type2_breakpoint_enabled(ctrl); CPUState *cs = env_cpu(env); int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; @@ -223,7 +312,7 @@ static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) } if (ctrl & TYPE2_EXEC) { - cpu_breakpoint_insert(cs, addr, flags, &env->type2_trig[index].bp); + cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); } if (ctrl & TYPE2_LOAD) { @@ -237,10 +326,10 @@ static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) size = type2_breakpoint_size(env, ctrl); if (size != 0) { cpu_watchpoint_insert(cs, addr, size, flags, - &env->type2_trig[index].wp); + &env->cpu_watchpoint[index]); } else { cpu_watchpoint_insert(cs, addr, 8, flags, - &env->type2_trig[index].wp); + &env->cpu_watchpoint[index]); } } } @@ -249,59 +338,42 @@ static void type2_breakpoint_remove(CPURISCVState *env, target_ulong index) { CPUState *cs = env_cpu(env); - if (env->type2_trig[index].bp) { - cpu_breakpoint_remove_by_ref(cs, env->type2_trig[index].bp); - env->type2_trig[index].bp = NULL; + if (env->cpu_breakpoint[index]) { + cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); + env->cpu_breakpoint[index] = NULL; } - if (env->type2_trig[index].wp) { - cpu_watchpoint_remove_by_ref(cs, env->type2_trig[index].wp); - env->type2_trig[index].wp = NULL; + if (env->cpu_watchpoint[index]) { + cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); + env->cpu_watchpoint[index] = NULL; } } -static target_ulong type2_reg_read(CPURISCVState *env, - target_ulong trigger_index, int tdata_index) -{ - uint32_t index = trigger_index - TRIGGER_TYPE2_IDX_0; - target_ulong tdata; - - switch (tdata_index) { - case TDATA1: - tdata = env->type2_trig[index].mcontrol; - break; - case TDATA2: - tdata = env->type2_trig[index].maddress; - break; - default: - g_assert_not_reached(); - } - - return tdata; -} - -static void type2_reg_write(CPURISCVState *env, target_ulong trigger_index, +static void type2_reg_write(CPURISCVState *env, target_ulong index, int tdata_index, target_ulong val) { - uint32_t index = trigger_index - TRIGGER_TYPE2_IDX_0; target_ulong new_val; switch (tdata_index) { case TDATA1: new_val = type2_mcontrol_validate(env, val); - if (new_val != env->type2_trig[index].mcontrol) { - env->type2_trig[index].mcontrol = new_val; + if (new_val != env->tdata1[index]) { + env->tdata1[index] = new_val; type2_breakpoint_remove(env, index); type2_breakpoint_insert(env, index); } break; case TDATA2: - if (val != env->type2_trig[index].maddress) { - env->type2_trig[index].maddress = val; + if (val != env->tdata2[index]) { + env->tdata2[index] = val; type2_breakpoint_remove(env, index); type2_breakpoint_insert(env, index); } break; + case TDATA3: + qemu_log_mask(LOG_UNIMP, + "tdata3 is not supported for type 2 trigger\n"); + break; default: g_assert_not_reached(); } @@ -309,35 +381,176 @@ static void type2_reg_write(CPURISCVState *env, target_ulong trigger_index, return; } -typedef target_ulong (*tdata_read_func)(CPURISCVState *env, - target_ulong trigger_index, - int tdata_index); +/* type 6 trigger */ -static tdata_read_func trigger_read_funcs[TRIGGER_NUM] = { - [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = type2_reg_read, -}; +static inline bool type6_breakpoint_enabled(target_ulong ctrl) +{ + bool mode = !!(ctrl & (TYPE6_VU | TYPE6_VS | TYPE6_U | TYPE6_S | TYPE6_M)); + bool rwx = !!(ctrl & (TYPE6_LOAD | TYPE6_STORE | TYPE6_EXEC)); -typedef void (*tdata_write_func)(CPURISCVState *env, - target_ulong trigger_index, - int tdata_index, - target_ulong val); + return mode && rwx; +} -static tdata_write_func trigger_write_funcs[TRIGGER_NUM] = { - [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = type2_reg_write, -}; +static target_ulong type6_mcontrol6_validate(CPURISCVState *env, + target_ulong ctrl) +{ + target_ulong val; + uint32_t size; + + /* validate the generic part first */ + val = tdata1_validate(env, ctrl, TRIGGER_TYPE_AD_MATCH6); + + /* validate unimplemented (always zero) bits */ + warn_always_zero_bit(ctrl, TYPE6_MATCH, "match"); + warn_always_zero_bit(ctrl, TYPE6_CHAIN, "chain"); + warn_always_zero_bit(ctrl, TYPE6_ACTION, "action"); + warn_always_zero_bit(ctrl, TYPE6_TIMING, "timing"); + warn_always_zero_bit(ctrl, TYPE6_SELECT, "select"); + warn_always_zero_bit(ctrl, TYPE6_HIT, "hit"); + + /* validate size encoding */ + size = extract32(ctrl, 16, 4); + if (access_size[size] == -1) { + qemu_log_mask(LOG_UNIMP, "access size %d is not supported, using SIZE_ANY\n", + size); + } else { + val |= (ctrl & TYPE6_SIZE); + } + + /* keep the mode and attribute bits */ + val |= (ctrl & (TYPE6_VU | TYPE6_VS | TYPE6_U | TYPE6_S | TYPE6_M | + TYPE6_LOAD | TYPE6_STORE | TYPE6_EXEC)); + + return val; +} + +static void type6_breakpoint_insert(CPURISCVState *env, target_ulong index) +{ + target_ulong ctrl = env->tdata1[index]; + target_ulong addr = env->tdata2[index]; + bool enabled = type6_breakpoint_enabled(ctrl); + CPUState *cs = env_cpu(env); + int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; + uint32_t size; + + if (!enabled) { + return; + } + + if (ctrl & TYPE6_EXEC) { + cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); + } + + if (ctrl & TYPE6_LOAD) { + flags |= BP_MEM_READ; + } + + if (ctrl & TYPE6_STORE) { + flags |= BP_MEM_WRITE; + } + + if (flags & BP_MEM_ACCESS) { + size = extract32(ctrl, 16, 4); + if (size != 0) { + cpu_watchpoint_insert(cs, addr, size, flags, + &env->cpu_watchpoint[index]); + } else { + cpu_watchpoint_insert(cs, addr, 8, flags, + &env->cpu_watchpoint[index]); + } + } +} + +static void type6_breakpoint_remove(CPURISCVState *env, target_ulong index) +{ + type2_breakpoint_remove(env, index); +} + +static void type6_reg_write(CPURISCVState *env, target_ulong index, + int tdata_index, target_ulong val) +{ + target_ulong new_val; + + switch (tdata_index) { + case TDATA1: + new_val = type6_mcontrol6_validate(env, val); + if (new_val != env->tdata1[index]) { + env->tdata1[index] = new_val; + type6_breakpoint_remove(env, index); + type6_breakpoint_insert(env, index); + } + break; + case TDATA2: + if (val != env->tdata2[index]) { + env->tdata2[index] = val; + type6_breakpoint_remove(env, index); + type6_breakpoint_insert(env, index); + } + break; + case TDATA3: + qemu_log_mask(LOG_UNIMP, + "tdata3 is not supported for type 6 trigger\n"); + break; + default: + g_assert_not_reached(); + } + + return; +} target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index) { - tdata_read_func read_func = trigger_read_funcs[env->trigger_cur]; - - return read_func(env, env->trigger_cur, tdata_index); + switch (tdata_index) { + case TDATA1: + return env->tdata1[env->trigger_cur]; + case TDATA2: + return env->tdata2[env->trigger_cur]; + case TDATA3: + return env->tdata3[env->trigger_cur]; + default: + g_assert_not_reached(); + } } void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val) { - tdata_write_func write_func = trigger_write_funcs[env->trigger_cur]; + int trigger_type; - return write_func(env, env->trigger_cur, tdata_index, val); + if (tdata_index == TDATA1) { + trigger_type = extract_trigger_type(env, val); + } else { + trigger_type = get_trigger_type(env, env->trigger_cur); + } + + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + type2_reg_write(env, env->trigger_cur, tdata_index, val); + break; + case TRIGGER_TYPE_AD_MATCH6: + type6_reg_write(env, env->trigger_cur, tdata_index, val); + break; + case TRIGGER_TYPE_INST_CNT: + case TRIGGER_TYPE_INT: + case TRIGGER_TYPE_EXCP: + case TRIGGER_TYPE_EXT_SRC: + qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", + trigger_type); + break; + case TRIGGER_TYPE_NO_EXIST: + case TRIGGER_TYPE_UNAVAIL: + qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", + trigger_type); + break; + default: + g_assert_not_reached(); + } +} + +target_ulong tinfo_csr_read(CPURISCVState *env) +{ + /* assume all triggers support the same types of triggers */ + return BIT(TRIGGER_TYPE_AD_MATCH) | + BIT(TRIGGER_TYPE_AD_MATCH6); } void riscv_cpu_debug_excp_handler(CPUState *cs) @@ -348,11 +561,11 @@ void riscv_cpu_debug_excp_handler(CPUState *cs) if (cs->watchpoint_hit) { if (cs->watchpoint_hit->flags & BP_CPU) { cs->watchpoint_hit = NULL; - riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); + do_trigger_action(env, DBG_ACTION_BP); } } else { if (cpu_breakpoint_test(cs, env->pc, BP_CPU)) { - riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); + do_trigger_action(env, DBG_ACTION_BP); } } } @@ -364,18 +577,51 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs) CPUBreakpoint *bp; target_ulong ctrl; target_ulong pc; + int trigger_type; int i; QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - for (i = 0; i < TRIGGER_TYPE2_NUM; i++) { - ctrl = env->type2_trig[i].mcontrol; - pc = env->type2_trig[i].maddress; + for (i = 0; i < RV_MAX_TRIGGERS; i++) { + trigger_type = get_trigger_type(env, i); - if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) { - /* check U/S/M bit against current privilege level */ - if ((ctrl >> 3) & BIT(env->priv)) { - return true; + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + /* type 2 trigger cannot be fired in VU/VS mode */ + if (riscv_cpu_virt_enabled(env)) { + return false; } + + ctrl = env->tdata1[i]; + pc = env->tdata2[i]; + + if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + break; + case TRIGGER_TYPE_AD_MATCH6: + ctrl = env->tdata1[i]; + pc = env->tdata2[i]; + + if ((ctrl & TYPE6_EXEC) && (bp->pc == pc)) { + if (riscv_cpu_virt_enabled(env)) { + /* check VU/VS bit against current privilege level */ + if ((ctrl >> 23) & BIT(env->priv)) { + return true; + } + } else { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + } + break; + default: + /* other trigger types are not supported or irrelevant */ + break; } } } @@ -389,26 +635,67 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) CPURISCVState *env = &cpu->env; target_ulong ctrl; target_ulong addr; + int trigger_type; int flags; int i; - for (i = 0; i < TRIGGER_TYPE2_NUM; i++) { - ctrl = env->type2_trig[i].mcontrol; - addr = env->type2_trig[i].maddress; - flags = 0; + for (i = 0; i < RV_MAX_TRIGGERS; i++) { + trigger_type = get_trigger_type(env, i); - if (ctrl & TYPE2_LOAD) { - flags |= BP_MEM_READ; - } - if (ctrl & TYPE2_STORE) { - flags |= BP_MEM_WRITE; - } - - if ((wp->flags & flags) && (wp->vaddr == addr)) { - /* check U/S/M bit against current privilege level */ - if ((ctrl >> 3) & BIT(env->priv)) { - return true; + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + /* type 2 trigger cannot be fired in VU/VS mode */ + if (riscv_cpu_virt_enabled(env)) { + return false; } + + ctrl = env->tdata1[i]; + addr = env->tdata2[i]; + flags = 0; + + if (ctrl & TYPE2_LOAD) { + flags |= BP_MEM_READ; + } + if (ctrl & TYPE2_STORE) { + flags |= BP_MEM_WRITE; + } + + if ((wp->flags & flags) && (wp->vaddr == addr)) { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + break; + case TRIGGER_TYPE_AD_MATCH6: + ctrl = env->tdata1[i]; + addr = env->tdata2[i]; + flags = 0; + + if (ctrl & TYPE6_LOAD) { + flags |= BP_MEM_READ; + } + if (ctrl & TYPE6_STORE) { + flags |= BP_MEM_WRITE; + } + + if ((wp->flags & flags) && (wp->vaddr == addr)) { + if (riscv_cpu_virt_enabled(env)) { + /* check VU/VS bit against current privilege level */ + if ((ctrl >> 23) & BIT(env->priv)) { + return true; + } + } else { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + } + break; + default: + /* other trigger types are not supported */ + break; } } @@ -417,11 +704,11 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) void riscv_trigger_init(CPURISCVState *env) { - target_ulong type2 = trigger_type(env, TRIGGER_TYPE_AD_MATCH); + target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0); int i; - /* type 2 triggers */ - for (i = 0; i < TRIGGER_TYPE2_NUM; i++) { + /* init to type 2 triggers */ + for (i = 0; i < RV_MAX_TRIGGERS; i++) { /* * type = TRIGGER_TYPE_AD_MATCH * dmode = 0 (both debug and M-mode can write tdata) @@ -435,9 +722,10 @@ void riscv_trigger_init(CPURISCVState *env) * chain = 0 (unimplemented, always 0) * match = 0 (always 0, when any compare value equals tdata2) */ - env->type2_trig[i].mcontrol = type2; - env->type2_trig[i].maddress = 0; - env->type2_trig[i].bp = NULL; - env->type2_trig[i].wp = NULL; + env->tdata1[i] = tdata1; + env->tdata2[i] = 0; + env->tdata3[i] = 0; + env->cpu_breakpoint[i] = NULL; + env->cpu_watchpoint[i] = NULL; } } diff --git a/target/riscv/debug.h b/target/riscv/debug.h index 27b9cac6b4..a1226b4d29 100644 --- a/target/riscv/debug.h +++ b/target/riscv/debug.h @@ -22,13 +22,7 @@ #ifndef RISCV_DEBUG_H #define RISCV_DEBUG_H -/* trigger indexes implemented */ -enum { - TRIGGER_TYPE2_IDX_0 = 0, - TRIGGER_TYPE2_IDX_1, - TRIGGER_TYPE2_NUM, - TRIGGER_NUM = TRIGGER_TYPE2_NUM -}; +#define RV_MAX_TRIGGERS 2 /* register index of tdata CSRs */ enum { @@ -46,24 +40,33 @@ typedef enum { TRIGGER_TYPE_EXCP = 5, /* exception trigger */ TRIGGER_TYPE_AD_MATCH6 = 6, /* new address/data match trigger */ TRIGGER_TYPE_EXT_SRC = 7, /* external source trigger */ - TRIGGER_TYPE_UNAVAIL = 15 /* trigger exists, but unavailable */ + TRIGGER_TYPE_UNAVAIL = 15, /* trigger exists, but unavailable */ + TRIGGER_TYPE_NUM } trigger_type_t; -typedef struct { - target_ulong mcontrol; - target_ulong maddress; - struct CPUBreakpoint *bp; - struct CPUWatchpoint *wp; -} type2_trigger_t; +/* actions */ +typedef enum { + DBG_ACTION_NONE = -1, /* sentinel value */ + DBG_ACTION_BP = 0, + DBG_ACTION_DBG_MODE, + DBG_ACTION_TRACE0, + DBG_ACTION_TRACE1, + DBG_ACTION_TRACE2, + DBG_ACTION_TRACE3, + DBG_ACTION_EXT_DBG0 = 8, + DBG_ACTION_EXT_DBG1 +} trigger_action_t; -/* tdata field masks */ +/* tdata1 field masks */ #define RV32_TYPE(t) ((uint32_t)(t) << 28) #define RV32_TYPE_MASK (0xf << 28) #define RV32_DMODE BIT(27) +#define RV32_DATA_MASK 0x7ffffff #define RV64_TYPE(t) ((uint64_t)(t) << 60) #define RV64_TYPE_MASK (0xfULL << 60) #define RV64_DMODE BIT_ULL(59) +#define RV64_DATA_MASK 0x7ffffffffffffff /* mcontrol field masks */ @@ -82,6 +85,24 @@ typedef struct { #define TYPE2_HIT BIT(20) #define TYPE2_SIZEHI (0x3 << 21) /* RV64 only */ +/* mcontrol6 field masks */ + +#define TYPE6_LOAD BIT(0) +#define TYPE6_STORE BIT(1) +#define TYPE6_EXEC BIT(2) +#define TYPE6_U BIT(3) +#define TYPE6_S BIT(4) +#define TYPE6_M BIT(6) +#define TYPE6_MATCH (0xf << 7) +#define TYPE6_CHAIN BIT(11) +#define TYPE6_ACTION (0xf << 12) +#define TYPE6_SIZE (0xf << 16) +#define TYPE6_TIMING BIT(20) +#define TYPE6_SELECT BIT(21) +#define TYPE6_HIT BIT(22) +#define TYPE6_VU BIT(23) +#define TYPE6_VS BIT(24) + /* access size */ enum { SIZE_ANY = 0, @@ -105,6 +126,8 @@ void tselect_csr_write(CPURISCVState *env, target_ulong val); target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index); void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val); +target_ulong tinfo_csr_read(CPURISCVState *env); + void riscv_cpu_debug_excp_handler(CPUState *cs); bool riscv_cpu_debug_check_breakpoint(CPUState *cs); bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp); diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 9ed049c29e..6e7bbdbd5e 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -114,20 +114,6 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) if (env->misa_ext & RVF) { return gdb_get_reg32(buf, env->fpr[n]); } - /* there is hole between ft11 and fflags in fpu.xml */ - } else if (n < 36 && n > 32) { - target_ulong val = 0; - int result; - /* - * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP - * register 33, so we recalculate the map index. - * This also works for CSR_FRM and CSR_FCSR. - */ - result = riscv_csrrw_debug(env, n - 32, &val, - 0, 0); - if (result == RISCV_EXCP_NONE) { - return gdb_get_regl(buf, val); - } } return 0; } @@ -137,20 +123,6 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) if (n < 32) { env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */ return sizeof(uint64_t); - /* there is hole between ft11 and fflags in fpu.xml */ - } else if (n < 36 && n > 32) { - target_ulong val = ldtul_p(mem_buf); - int result; - /* - * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP - * register 33, so we recalculate the map index. - * This also works for CSR_FRM and CSR_FCSR. - */ - result = riscv_csrrw_debug(env, n - 32, NULL, - val, -1); - if (result == RISCV_EXCP_NONE) { - return sizeof(target_ulong); - } } return 0; } @@ -211,7 +183,7 @@ static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n) target_ulong val = 0; int result = riscv_csrrw_debug(env, csrno, &val, 0, 0); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return gdb_get_regl(buf, val); } @@ -238,7 +210,7 @@ static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n) target_ulong val = ldtul_p(mem_buf); int result = riscv_csrrw_debug(env, csrno, NULL, val, -1); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return sizeof(target_ulong); } @@ -404,10 +376,10 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) CPURISCVState *env = &cpu->env; if (env->misa_ext & RVD) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, - 36, "riscv-64bit-fpu.xml", 0); + 32, "riscv-64bit-fpu.xml", 0); } else if (env->misa_ext & RVF) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, - 36, "riscv-32bit-fpu.xml", 0); + 32, "riscv-32bit-fpu.xml", 0); } if (env->misa_ext & RVV) { gdb_register_coprocessor(cs, riscv_gdb_get_vector, riscv_gdb_set_vector, diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 4ef3b2251d..a03014fe67 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1009,9 +1009,12 @@ DEF_HELPER_6(vwredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfredsum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredusum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredusum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredusum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredosum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredosum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredosum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmax_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmax_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32) @@ -1019,8 +1022,10 @@ DEF_HELPER_6(vfredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredusum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredusum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredosum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredosum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmand_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmnand_mm, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 595fdcdad8..d0253b8104 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -664,11 +664,13 @@ vredmax_vs 000111 . ..... ..... 010 ..... 1010111 @r_vm vwredsumu_vs 110000 . ..... ..... 000 ..... 1010111 @r_vm vwredsum_vs 110001 . ..... ..... 000 ..... 1010111 @r_vm # Vector ordered and unordered reduction sum -vfredsum_vs 0000-1 . ..... ..... 001 ..... 1010111 @r_vm +vfredusum_vs 000001 . ..... ..... 001 ..... 1010111 @r_vm +vfredosum_vs 000011 . ..... ..... 001 ..... 1010111 @r_vm vfredmin_vs 000101 . ..... ..... 001 ..... 1010111 @r_vm vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm # Vector widening ordered and unordered float reduction sum -vfwredsum_vs 1100-1 . ..... ..... 001 ..... 1010111 @r_vm +vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm +vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index e58208f363..4dea4413ae 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -3136,7 +3136,8 @@ static bool freduction_check(DisasContext *s, arg_rmrr *a) require_zve64f(s); } -GEN_OPFVV_TRANS(vfredsum_vs, freduction_check) +GEN_OPFVV_TRANS(vfredusum_vs, freduction_check) +GEN_OPFVV_TRANS(vfredosum_vs, freduction_check) GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) @@ -3148,7 +3149,8 @@ static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) (s->sew != MO_8); } -GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwredosum_vs, freduction_widen_check) /* *** Vector Mask Operations diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 41098f6ad0..c2a94a82b3 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -229,26 +229,16 @@ static bool debug_needed(void *opaque) return riscv_feature(env, RISCV_FEATURE_DEBUG); } -static const VMStateDescription vmstate_debug_type2 = { - .name = "cpu/debug/type2", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINTTL(mcontrol, type2_trigger_t), - VMSTATE_UINTTL(maddress, type2_trigger_t), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_debug = { .name = "cpu/debug", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = debug_needed, .fields = (VMStateField[]) { VMSTATE_UINTTL(env.trigger_cur, RISCVCPU), - VMSTATE_STRUCT_ARRAY(env.type2_trig, RISCVCPU, TRIGGER_TYPE2_NUM, - 0, vmstate_debug_type2, type2_trigger_t), + VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS), + VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS), + VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS), VMSTATE_END_OF_LIST() } }; @@ -308,8 +298,8 @@ static const VMStateDescription vmstate_pmu_ctr_state = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 4, - .minimum_version_id = 4, + .version_id = 5, + .minimum_version_id = 5, .post_load = riscv_cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), @@ -331,7 +321,7 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT32(env.features, RISCVCPU), VMSTATE_UINTTL(env.priv, RISCVCPU), VMSTATE_UINTTL(env.virt, RISCVCPU), - VMSTATE_UINTTL(env.resetvec, RISCVCPU), + VMSTATE_UINT64(env.resetvec, RISCVCPU), VMSTATE_UINTTL(env.mhartid, RISCVCPU), VMSTATE_UINT64(env.mstatus, RISCVCPU), VMSTATE_UINT64(env.mip, RISCVCPU), diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index d224861c2c..b94f809eb3 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4714,9 +4714,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ } /* Unordered sum */ -GEN_VEXT_FRED(vfredsum_vs_h, uint16_t, uint16_t, H2, H2, float16_add) -GEN_VEXT_FRED(vfredsum_vs_w, uint32_t, uint32_t, H4, H4, float32_add) -GEN_VEXT_FRED(vfredsum_vs_d, uint64_t, uint64_t, H8, H8, float64_add) +GEN_VEXT_FRED(vfredusum_vs_h, uint16_t, uint16_t, H2, H2, float16_add) +GEN_VEXT_FRED(vfredusum_vs_w, uint32_t, uint32_t, H4, H4, float32_add) +GEN_VEXT_FRED(vfredusum_vs_d, uint64_t, uint64_t, H8, H8, float64_add) + +/* Ordered sum */ +GEN_VEXT_FRED(vfredosum_vs_h, uint16_t, uint16_t, H2, H2, float16_add) +GEN_VEXT_FRED(vfredosum_vs_w, uint32_t, uint32_t, H4, H4, float32_add) +GEN_VEXT_FRED(vfredosum_vs_d, uint64_t, uint64_t, H8, H8, float64_add) /* Maximum value */ GEN_VEXT_FRED(vfredmax_vs_h, uint16_t, uint16_t, H2, H2, float16_maximum_number) @@ -4728,57 +4733,23 @@ GEN_VEXT_FRED(vfredmin_vs_h, uint16_t, uint16_t, H2, H2, float16_minimum_number) GEN_VEXT_FRED(vfredmin_vs_w, uint32_t, uint32_t, H4, H4, float32_minimum_number) GEN_VEXT_FRED(vfredmin_vs_d, uint64_t, uint64_t, H8, H8, float64_minimum_number) +/* Vector Widening Floating-Point Add Instructions */ +static uint32_t fwadd16(uint32_t a, uint16_t b, float_status *s) +{ + return float32_add(a, float16_to_float32(b, true, s), s); +} + +static uint64_t fwadd32(uint64_t a, uint32_t b, float_status *s) +{ + return float64_add(a, float32_to_float64(b, s), s); +} + /* Vector Widening Floating-Point Reduction Instructions */ -/* Unordered reduce 2*SEW = 2*SEW + sum(promote(SEW)) */ -void HELPER(vfwredsum_vs_h)(void *vd, void *v0, void *vs1, - void *vs2, CPURISCVState *env, uint32_t desc) -{ - uint32_t vm = vext_vm(desc); - uint32_t vl = env->vl; - uint32_t esz = sizeof(uint32_t); - uint32_t vlenb = simd_maxsz(desc); - uint32_t vta = vext_vta(desc); - uint32_t i; - uint32_t s1 = *((uint32_t *)vs1 + H4(0)); - - for (i = env->vstart; i < vl; i++) { - uint16_t s2 = *((uint16_t *)vs2 + H2(i)); - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - s1 = float32_add(s1, float16_to_float32(s2, true, &env->fp_status), - &env->fp_status); - } - *((uint32_t *)vd + H4(0)) = s1; - env->vstart = 0; - /* set tail elements to 1s */ - vext_set_elems_1s(vd, vta, esz, vlenb); -} - -void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, - void *vs2, CPURISCVState *env, uint32_t desc) -{ - uint32_t vm = vext_vm(desc); - uint32_t vl = env->vl; - uint32_t esz = sizeof(uint64_t); - uint32_t vlenb = simd_maxsz(desc); - uint32_t vta = vext_vta(desc); - uint32_t i; - uint64_t s1 = *((uint64_t *)vs1); - - for (i = env->vstart; i < vl; i++) { - uint32_t s2 = *((uint32_t *)vs2 + H4(i)); - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - s1 = float64_add(s1, float32_to_float64(s2, &env->fp_status), - &env->fp_status); - } - *((uint64_t *)vd) = s1; - env->vstart = 0; - /* set tail elements to 1s */ - vext_set_elems_1s(vd, vta, esz, vlenb); -} +/* Ordered/unordered reduce 2*SEW = 2*SEW + sum(promote(SEW)) */ +GEN_VEXT_FRED(vfwredusum_vs_h, uint32_t, uint16_t, H4, H2, fwadd16) +GEN_VEXT_FRED(vfwredusum_vs_w, uint64_t, uint32_t, H8, H4, fwadd32) +GEN_VEXT_FRED(vfwredosum_vs_h, uint32_t, uint16_t, H4, H2, fwadd16) +GEN_VEXT_FRED(vfwredosum_vs_w, uint64_t, uint32_t, H8, H4, fwadd32) /* *** Vector Mask Operations