Second RISC-V PR for QEMU 7.2

* Fixup typos and register addresses for Ibex SPI
 * Cleanup the RISC-V virt machine documentation
 * Remove the sideleg and sedeleg CSR macros
 * Fix the CSR check for cycle{h}, instret{h}, time{h}, hpmcounter3-31{h}
 * Remove fixed numbering from GDB xml feature files
 * Allow setting the resetvec for the OpenTitan machine
 * Check the correct exception cause in vector GDB stub
 * Fix inheritance of SiFiveEState
 * Improvements to the RISC-V debugger spec
 * Simplify some vector code
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmMymHIACgkQIeENKd+X
 cFQPxwf8DhYeJ+Ctsi9/fFTIHLAE3ciZ15Hf/BJGc5maeVGupYG64+9Cs0fGX4bY
 CBlmE5xqn8hanEQXTQxmbC3AoNyykRV+arUrdawlUrJR5hQy/PNVq4yTxFPHcEjJ
 bOsQxkMvMzZiWbJfG8SZObXfFZ+6HjWd2qjbCUwyVAa5mWDHsuPy22/RDcaR9KSV
 Sb217kNIY3a2WkDUrY84zqOfks3NDFA1GuCge7EcQGV9iPxH06KO3ANpGvCE/31i
 FnfA9qUu7ts+ls2lSj+2ARsZUzMciZuC3ggTRYIKbyf0QNTK6fILuzlMPPvf0ORZ
 vbq8rSTDPrWzmrLskba1jADbWPtiXA==
 =b3zl
 -----END PGP SIGNATURE-----

Merge tag 'pull-riscv-to-apply-20220927' of https://github.com/alistair23/qemu into staging

Second RISC-V PR for QEMU 7.2

* Fixup typos and register addresses for Ibex SPI
* Cleanup the RISC-V virt machine documentation
* Remove the sideleg and sedeleg CSR macros
* Fix the CSR check for cycle{h}, instret{h}, time{h}, hpmcounter3-31{h}
* Remove fixed numbering from GDB xml feature files
* Allow setting the resetvec for the OpenTitan machine
* Check the correct exception cause in vector GDB stub
* Fix inheritance of SiFiveEState
* Improvements to the RISC-V debugger spec
* Simplify some vector code

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmMymHIACgkQIeENKd+X
# cFQPxwf8DhYeJ+Ctsi9/fFTIHLAE3ciZ15Hf/BJGc5maeVGupYG64+9Cs0fGX4bY
# CBlmE5xqn8hanEQXTQxmbC3AoNyykRV+arUrdawlUrJR5hQy/PNVq4yTxFPHcEjJ
# bOsQxkMvMzZiWbJfG8SZObXfFZ+6HjWd2qjbCUwyVAa5mWDHsuPy22/RDcaR9KSV
# Sb217kNIY3a2WkDUrY84zqOfks3NDFA1GuCge7EcQGV9iPxH06KO3ANpGvCE/31i
# FnfA9qUu7ts+ls2lSj+2ARsZUzMciZuC3ggTRYIKbyf0QNTK6fILuzlMPPvf0ORZ
# vbq8rSTDPrWzmrLskba1jADbWPtiXA==
# =b3zl
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Sep 2022 02:30:10 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-20220927' of https://github.com/alistair23/qemu: (22 commits)
  target/riscv: rvv-1.0: vf[w]redsum distinguish between ordered/unordered
  target/riscv: rvv-1.0: Simplify vfwredsum code
  target/riscv: debug: Add initial support of type 6 trigger
  target/riscv: debug: Check VU/VS modes for type 2 trigger
  target/riscv: debug: Create common trigger actions function
  target/riscv: debug: Introduce tinfo CSR
  target/riscv: debug: Restrict the range of tselect value can be written
  target/riscv: debug: Introduce tdata1, tdata2, and tdata3 CSRs
  target/riscv: debug: Introduce build_tdata1() to build tdata1 register content
  target/riscv: debug: Determine the trigger type from tdata1.type
  hw/riscv/sifive_e: Fix inheritance of SiFiveEState
  target/riscv: Check the correct exception cause in vector GDB stub
  hw/riscv: opentitan: Expose the resetvec as a SoC property
  hw/riscv: opentitan: Fixup resetvec
  target/riscv: Set the CPU resetvec directly
  target/riscv: remove fixed numbering from GDB xml feature files
  target/riscv: remove fflags, frm, and fcsr from riscv-*-fpu.xml
  target/riscv: fix csr check for cycle{h}, instret{h}, time{h}, hpmcounter3-31{h}
  target/riscv: Remove sideleg and sedeleg
  docs/system: clean up code escape for riscv virt platform
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-09-27 07:56:56 -04:00
commit 8b077615b3
22 changed files with 539 additions and 290 deletions

View File

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

View File

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

View File

@ -5,13 +5,9 @@
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!-- Register numbers are hard-coded in order to maintain backward
compatibility with older versions of tools that didn't use xml
register descriptions. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.riscv.cpu">
<reg name="zero" bitsize="32" type="int" regnum="0"/>
<reg name="zero" bitsize="32" type="int"/>
<reg name="ra" bitsize="32" type="code_ptr"/>
<reg name="sp" bitsize="32" type="data_ptr"/>
<reg name="gp" bitsize="32" type="data_ptr"/>

View File

@ -5,13 +5,9 @@
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!-- Register numbers are hard-coded in order to maintain backward
compatibility with older versions of tools that didn't use xml
register descriptions. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.riscv.fpu">
<reg name="ft0" bitsize="32" type="ieee_single" regnum="33"/>
<reg name="ft0" bitsize="32" type="ieee_single"/>
<reg name="ft1" bitsize="32" type="ieee_single"/>
<reg name="ft2" bitsize="32" type="ieee_single"/>
<reg name="ft3" bitsize="32" type="ieee_single"/>
@ -43,8 +39,4 @@
<reg name="ft9" bitsize="32" type="ieee_single"/>
<reg name="ft10" bitsize="32" type="ieee_single"/>
<reg name="ft11" bitsize="32" type="ieee_single"/>
<reg name="fflags" bitsize="32" type="int" regnum="66"/>
<reg name="frm" bitsize="32" type="int" regnum="67"/>
<reg name="fcsr" bitsize="32" type="int" regnum="68"/>
</feature>

View File

@ -5,13 +5,9 @@
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!-- Register numbers are hard-coded in order to maintain backward
compatibility with older versions of tools that didn't use xml
register descriptions. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.riscv.cpu">
<reg name="zero" bitsize="64" type="int" regnum="0"/>
<reg name="zero" bitsize="64" type="int"/>
<reg name="ra" bitsize="64" type="code_ptr"/>
<reg name="sp" bitsize="64" type="data_ptr"/>
<reg name="gp" bitsize="64" type="data_ptr"/>

View File

@ -5,10 +5,6 @@
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!-- Register numbers are hard-coded in order to maintain backward
compatibility with older versions of tools that didn't use xml
register descriptions. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.riscv.fpu">
@ -17,7 +13,7 @@
<field name="double" type="ieee_double"/>
</union>
<reg name="ft0" bitsize="64" type="riscv_double" regnum="33"/>
<reg name="ft0" bitsize="64" type="riscv_double"/>
<reg name="ft1" bitsize="64" type="riscv_double"/>
<reg name="ft2" bitsize="64" type="riscv_double"/>
<reg name="ft3" bitsize="64" type="riscv_double"/>
@ -49,8 +45,4 @@
<reg name="ft9" bitsize="64" type="riscv_double"/>
<reg name="ft10" bitsize="64" type="riscv_double"/>
<reg name="ft11" bitsize="64" type="riscv_double"/>
<reg name="fflags" bitsize="32" type="int" regnum="66"/>
<reg name="frm" bitsize="32" type="int" regnum="67"/>
<reg name="fcsr" bitsize="32" type="int" regnum="68"/>
</feature>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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