aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2022-09-27 07:56:56 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2022-09-27 07:56:56 -0400
commit8b077615b3fd3041c6e7105ec3a178a2a0ed3cad (patch)
tree97287926c26dd80fd7114e74057962669808453c
parent15aa08a405e449c5ab88b479dd2728920d829c61 (diff)
parenta3ab69f9f6c000481c439923d16416b8941d5b37 (diff)
downloadqemu-8b077615b3fd3041c6e7105ec3a178a2a0ed3cad.zip
qemu-8b077615b3fd3041c6e7105ec3a178a2a0ed3cad.tar.gz
qemu-8b077615b3fd3041c6e7105ec3a178a2a0ed3cad.tar.bz2
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>
-rw-r--r--disas/riscv.c2
-rw-r--r--docs/system/riscv/virt.rst13
-rw-r--r--gdb-xml/riscv-32bit-cpu.xml6
-rw-r--r--gdb-xml/riscv-32bit-fpu.xml10
-rw-r--r--gdb-xml/riscv-64bit-cpu.xml6
-rw-r--r--gdb-xml/riscv-64bit-fpu.xml10
-rw-r--r--hw/riscv/opentitan.c8
-rw-r--r--hw/ssi/ibex_spi_host.c8
-rw-r--r--include/hw/riscv/opentitan.h2
-rw-r--r--include/hw/riscv/sifive_e.h3
-rw-r--r--target/riscv/cpu.c13
-rw-r--r--target/riscv/cpu.h9
-rw-r--r--target/riscv/cpu_bits.h3
-rw-r--r--target/riscv/csr.c23
-rw-r--r--target/riscv/debug.c484
-rw-r--r--target/riscv/debug.h55
-rw-r--r--target/riscv/gdbstub.c36
-rw-r--r--target/riscv/helper.h15
-rw-r--r--target/riscv/insn32.decode6
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc6
-rw-r--r--target/riscv/machine.c26
-rw-r--r--target/riscv/vector_helper.c69
22 files changed, 531 insertions, 282 deletions
diff --git a/disas/riscv.c b/disas/riscv.c
index 489c2ae..f107d94 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 f8ecec9..4b16e41 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 0d07aae..466f2c0 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. -->
-<!-- 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"/>
diff --git a/gdb-xml/riscv-32bit-fpu.xml b/gdb-xml/riscv-32bit-fpu.xml
index 1eaae91..24aa087 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. -->
-<!-- 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>
diff --git a/gdb-xml/riscv-64bit-cpu.xml b/gdb-xml/riscv-64bit-cpu.xml
index b8aa424..c4d83de 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. -->
-<!-- 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"/>
diff --git a/gdb-xml/riscv-64bit-fpu.xml b/gdb-xml/riscv-64bit-fpu.xml
index 794854c..d0f17f9 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. -->
-<!-- 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>
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index af13dbe..be7ff1e 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 d14580b..94d7da9 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 26d960f..6665cd5 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 83604da..d738745 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 aee14a2..b29c88b 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 06751e1..b131fa8 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 7be12ca..d8f5f0a 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 b96db1b..5c9a7ee 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 fc6e132..26ea764 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)
{
- if (unlikely(tdata_index >= TDATA_NUM)) {
- return false;
- }
+ int trigger_type = get_trigger_type(env, env->trigger_cur);
- if (unlikely(env->trigger_cur >= TRIGGER_NUM)) {
+ if (unlikely(tdata_index >= TDATA_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,159 @@ 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)
+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 tdata;
+ target_ulong new_val;
switch (tdata_index) {
case TDATA1:
- tdata = env->type2_trig[index].mcontrol;
+ new_val = type2_mcontrol_validate(env, 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:
- tdata = env->type2_trig[index].maddress;
+ 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();
}
- return tdata;
+ return;
+}
+
+/* type 6 trigger */
+
+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));
+
+ return mode && rwx;
}
-static void type2_reg_write(CPURISCVState *env, target_ulong trigger_index,
+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)
{
- 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;
- type2_breakpoint_remove(env, index);
- type2_breakpoint_insert(env, index);
+ 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->type2_trig[index].maddress) {
- env->type2_trig[index].maddress = val;
- type2_breakpoint_remove(env, index);
- type2_breakpoint_insert(env, index);
+ 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();
}
@@ -309,35 +498,59 @@ 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);
-
-static tdata_read_func trigger_read_funcs[TRIGGER_NUM] = {
- [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = type2_reg_read,
-};
-
-typedef void (*tdata_write_func)(CPURISCVState *env,
- target_ulong trigger_index,
- int tdata_index,
- target_ulong val);
-
-static tdata_write_func trigger_write_funcs[TRIGGER_NUM] = {
- [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = type2_reg_write,
-};
-
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;
+
+ 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();
+ }
+}
- return write_func(env, env->trigger_cur, tdata_index, val);
+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);
+
+ 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;
+ }
- if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) {
- /* check U/S/M bit against current privilege level */
- if ((ctrl >> 3) & BIT(env->priv)) {
- return true;
+ 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;
- }
+ 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)) {
- /* check U/S/M bit against current privilege level */
- if ((ctrl >> 3) & BIT(env->priv)) {
- return true;
+ 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 27b9cac..a1226b4 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;
-
-/* tdata field masks */
+/* 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;
+
+/* 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 9ed049c..6e7bbdb 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 4ef3b22..a03014f 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 595fdcd..d0253b8 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 e58208f..4dea441 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 41098f6..c2a94a8 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 d224861..b94f809 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,58 +4733,24 @@ 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 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)
+/* Vector Widening Floating-Point Add Instructions */
+static uint32_t fwadd16(uint32_t a, uint16_t b, float_status *s)
{
- 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);
+ return float32_add(a, float16_to_float32(b, true, s), s);
}
-void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1,
- void *vs2, CPURISCVState *env, uint32_t desc)
+static uint64_t fwadd32(uint64_t a, uint32_t b, float_status *s)
{
- 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);
+ return float64_add(a, float32_to_float64(b, s), s);
}
+/* Vector Widening Floating-Point Reduction Instructions */
+/* 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
*/