mirror of https://github.com/xemu-project/xemu.git
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:
commit
8b077615b3
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue