mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-riscv-to-apply-20230614' of https://github.com/alistair23/qemu into staging
Second RISC-V PR for 8.1 * Skip Vector set tail when vta is zero * Move zc* out of the experimental properties * Mask the implicitly enabled extensions in isa_string based on priv version * Rework CPU extension validation and validate MISA changes * Fixup PMP TLB cacheing errors * Writing to pmpaddr and MML/MMWP correctly triggers TLB flushes * Fixup PMP bypass checks * Deny access if access is partially inside a PMP entry * Correct OpenTitanState parent type/size * Fix QEMU crash when NUMA nodes exceed available CPUs * Fix pointer mask transformation for vector address * Updates and improvements for Smstateen * Support disas for Zcm* extensions * Support disas for Z*inx extensions * Remove unused decomp_rv32/64 value for vector instructions * Enable PC-relative translation * Assume M-mode FW in pflash0 only when "-bios none" * Support using pflash via -blockdev option * Add vector registers to log * Clean up reference of Vector MTYPE * Remove the check for extra Vector tail elements * Smepmp: Return error when access permission not allowed in PMP * Fixes for smsiaddrcfg and smsiaddrcfgh in AIA # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmSJFRoACgkQr3yVEwxT # gBMUkg/8Cuhqpx+zy7MeouVkyhEjUuhtCWyr0WVZBJzDkVEOrlY6TyR0hb5/o1Js # LZf6ZMF6JQDN78bmUct8yFBZBGafey5tyonDCsnD7CNQuLPf2NSjTHhu9n5hKFqF # F8Mpn9iFu6k1pr0iF7FbCccVWuDb3P4h2PaM0iFhmf4uz42BCMYdgJThhvv38xlt # jr6A3dcjTpp8yB+iRCuhL2IU2XVee0XBiDUECqRXd0gmtOtqJNST8L+l8YkLy1VO # WUMe8RCO6NMP7BLJ383WwCDeiFTo0mJebZQ0eR/G1xEhy7c8BBMh/CgQmq2F3wDZ # Q0biaeozADgAaCC7aOAHI+1sAoMhOm1v2WhIVmh+XXUqT9856cKwc7DUPBmzb9Sj # N5Zh+t9WCnZG7qpfxvkDF0Y/aRODMHZ1BW5L/ky9yBtyuRwXOJ6VycZTFyRkSwnN # Gd/s9IClDOP1IP5s4TSMGGdelk4lH97x7fZE/2hxn59lp761JtMxbaEceBtqaBh8 # zNMTNN/KHs8LeiIBI2ZZ+nQav452Y6XYBivQ7OdsI8xkjnjG9gfgXXjvX1TIh0ow # Hy5ZxtAtjXty49Gmjkx5VcBx4auJcnRDlLTzoZjTxq1te+gEWpw6O1EsEKasVLZe # uN6PxTOxS3nHvRvPgQc1xNUdhDRqBaYsju6b9YmMxz1uefAjGM0= # =fOTc # -----END PGP SIGNATURE----- # gpg: Signature made Wed 14 Jun 2023 03:17:14 AM CEST # gpg: using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013 # 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: 6AE9 02B6 A7CA 877D 6D65 9296 AF7C 9513 0C53 8013 * tag 'pull-riscv-to-apply-20230614' of https://github.com/alistair23/qemu: (60 commits) hw/intc: If mmsiaddrcfgh.L == 1, smsiaddrcfg and smsiaddrcfgh are read-only. target/riscv: Smepmp: Return error when access permission not allowed in PMP target/riscv/vector_helper.c: Remove the check for extra tail elements target/riscv/vector_helper.c: clean up reference of MTYPE target/riscv: Fix initialized value for cur_pmmask util/log: Add vector registers to log docs/system: riscv: Add pflash usage details riscv/virt: Support using pflash via -blockdev option hw/riscv: virt: Assume M-mode FW in pflash0 only when "-bios none" target/riscv: Remove pc_succ_insn from DisasContext target/riscv: Enable PC-relative translation target/riscv: Use true diff for gen_pc_plus_diff target/riscv: Change gen_set_pc_imm to gen_update_pc target/riscv: Change gen_goto_tb to work on displacements target/riscv: Introduce cur_insn_len into DisasContext target/riscv: Fix target address to update badaddr disas/riscv.c: Remove redundant parentheses disas/riscv.c: Fix lines with over 80 characters disas/riscv.c: Remove unused decomp_rv32/64 value for vector instructions disas/riscv.c: Support disas for Z*inx extensions ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -313,6 +313,9 @@ static void log_cpu_exec(target_ulong pc, CPUState *cpu,
|
||||
#if defined(TARGET_I386)
|
||||
flags |= CPU_DUMP_CCOP;
|
||||
#endif
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_VPU)) {
|
||||
flags |= CPU_DUMP_VPU;
|
||||
}
|
||||
cpu_dump_state(cpu, logfile, flags);
|
||||
qemu_log_unlock(logfile);
|
||||
}
|
||||
|
||||
+646
-548
File diff suppressed because it is too large
Load Diff
@@ -53,6 +53,37 @@ with the default OpenSBI firmware image as the -bios. It also supports
|
||||
the recommended RISC-V bootflow: U-Boot SPL (M-mode) loads OpenSBI fw_dynamic
|
||||
firmware and U-Boot proper (S-mode), using the standard -bios functionality.
|
||||
|
||||
Using flash devices
|
||||
-------------------
|
||||
|
||||
By default, the first flash device (pflash0) is expected to contain
|
||||
S-mode firmware code. It can be configured as read-only, with the
|
||||
second flash device (pflash1) available to store configuration data.
|
||||
|
||||
For example, booting edk2 looks like
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-riscv64 \
|
||||
-blockdev node-name=pflash0,driver=file,read-only=on,filename=<edk2_code> \
|
||||
-blockdev node-name=pflash1,driver=file,filename=<edk2_vars> \
|
||||
-M virt,pflash0=pflash0,pflash1=pflash1 \
|
||||
... other args ....
|
||||
|
||||
For TCG guests only, it is also possible to boot M-mode firmware from
|
||||
the first flash device (pflash0) by additionally passing ``-bios
|
||||
none``, as in
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-riscv64 \
|
||||
-bios none \
|
||||
-blockdev node-name=pflash0,driver=file,read-only=on,filename=<m_mode_code> \
|
||||
-M virt,pflash0=pflash0 \
|
||||
... other args ....
|
||||
|
||||
Firmware images used for pflash must be exactly 32 MiB in size.
|
||||
|
||||
Machine-specific options
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -688,13 +688,13 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
* domains).
|
||||
*/
|
||||
if (aplic->num_children &&
|
||||
!(aplic->smsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
|
||||
!(aplic->mmsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
|
||||
aplic->smsicfgaddr = value;
|
||||
}
|
||||
} else if (aplic->mmode && aplic->msimode &&
|
||||
(addr == APLIC_SMSICFGADDRH)) {
|
||||
if (aplic->num_children &&
|
||||
!(aplic->smsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
|
||||
!(aplic->mmsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
|
||||
aplic->smsicfgaddrH = value & APLIC_xMSICFGADDRH_VALID_MASK;
|
||||
}
|
||||
} else if ((APLIC_SETIP_BASE <= addr) &&
|
||||
|
||||
@@ -207,6 +207,12 @@ int64_t riscv_numa_get_default_cpu_node_id(const MachineState *ms, int idx)
|
||||
{
|
||||
int64_t nidx = 0;
|
||||
|
||||
if (ms->numa_state->num_nodes > ms->smp.cpus) {
|
||||
error_report("Number of NUMA nodes (%d)"
|
||||
" cannot exceed the number of available CPUs (%d).",
|
||||
ms->numa_state->num_nodes, ms->smp.max_cpus);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ms->numa_state->num_nodes) {
|
||||
nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
|
||||
if (ms->numa_state->num_nodes <= nidx) {
|
||||
|
||||
+20
-18
@@ -75,11 +75,11 @@ static const MemMapEntry ibex_memmap[] = {
|
||||
[IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 },
|
||||
};
|
||||
|
||||
static void opentitan_board_init(MachineState *machine)
|
||||
static void opentitan_machine_init(MachineState *machine)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
OpenTitanState *s = OPENTITAN_MACHINE(machine);
|
||||
const MemMapEntry *memmap = ibex_memmap;
|
||||
OpenTitanState *s = g_new0(OpenTitanState, 1);
|
||||
MemoryRegion *sys_mem = get_system_memory();
|
||||
|
||||
if (machine->ram_size != mc->default_ram_size) {
|
||||
@@ -108,18 +108,18 @@ static void opentitan_board_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
static void opentitan_machine_init(MachineClass *mc)
|
||||
static void opentitan_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "RISC-V Board compatible with OpenTitan";
|
||||
mc->init = opentitan_board_init;
|
||||
mc->init = opentitan_machine_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->default_cpu_type = TYPE_RISCV_CPU_IBEX;
|
||||
mc->default_ram_id = "riscv.lowrisc.ibex.ram";
|
||||
mc->default_ram_size = ibex_memmap[IBEX_DEV_RAM].size;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("opentitan", opentitan_machine_init)
|
||||
|
||||
static void lowrisc_ibex_soc_init(Object *obj)
|
||||
{
|
||||
LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj);
|
||||
@@ -320,17 +320,19 @@ static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data)
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo lowrisc_ibex_soc_type_info = {
|
||||
.name = TYPE_RISCV_IBEX_SOC,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(LowRISCIbexSoCState),
|
||||
.instance_init = lowrisc_ibex_soc_init,
|
||||
.class_init = lowrisc_ibex_soc_class_init,
|
||||
static const TypeInfo open_titan_types[] = {
|
||||
{
|
||||
.name = TYPE_RISCV_IBEX_SOC,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(LowRISCIbexSoCState),
|
||||
.instance_init = lowrisc_ibex_soc_init,
|
||||
.class_init = lowrisc_ibex_soc_class_init,
|
||||
}, {
|
||||
.name = TYPE_OPENTITAN_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(OpenTitanState),
|
||||
.class_init = opentitan_machine_class_init,
|
||||
}
|
||||
};
|
||||
|
||||
static void lowrisc_ibex_soc_register_types(void)
|
||||
{
|
||||
type_register_static(&lowrisc_ibex_soc_type_info);
|
||||
}
|
||||
|
||||
type_init(lowrisc_ibex_soc_register_types)
|
||||
DEFINE_TYPES(open_titan_types)
|
||||
|
||||
+25
-34
@@ -1245,7 +1245,8 @@ static void virt_machine_done(Notifier *notifier, void *data)
|
||||
target_ulong firmware_end_addr, kernel_start_addr;
|
||||
const char *firmware_name = riscv_default_firmware_name(&s->soc[0]);
|
||||
uint32_t fdt_load_addr;
|
||||
uint64_t kernel_entry;
|
||||
uint64_t kernel_entry = 0;
|
||||
BlockBackend *pflash_blk0;
|
||||
|
||||
/*
|
||||
* Only direct boot kernel is currently supported for KVM VM,
|
||||
@@ -1266,42 +1267,32 @@ static void virt_machine_done(Notifier *notifier, void *data)
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
|
||||
start_addr, NULL);
|
||||
|
||||
if (drive_get(IF_PFLASH, 0, 1)) {
|
||||
/*
|
||||
* S-mode FW like EDK2 will be kept in second plash (unit 1).
|
||||
* When both kernel, initrd and pflash options are provided in the
|
||||
* command line, the kernel and initrd will be copied to the fw_cfg
|
||||
* table and opensbi will jump to the flash address which is the
|
||||
* entry point of S-mode FW. It is the job of the S-mode FW to load
|
||||
* the kernel and initrd using fw_cfg table.
|
||||
*
|
||||
* If only pflash is given but not -kernel, then it is the job of
|
||||
* of the S-mode firmware to locate and load the kernel.
|
||||
* In either case, the next_addr for opensbi will be the flash address.
|
||||
*/
|
||||
riscv_setup_firmware_boot(machine);
|
||||
kernel_entry = virt_memmap[VIRT_FLASH].base +
|
||||
virt_memmap[VIRT_FLASH].size / 2;
|
||||
} else if (machine->kernel_filename) {
|
||||
pflash_blk0 = pflash_cfi01_get_blk(s->flash[0]);
|
||||
if (pflash_blk0) {
|
||||
if (machine->firmware && !strcmp(machine->firmware, "none") &&
|
||||
!kvm_enabled()) {
|
||||
/*
|
||||
* Pflash was supplied but bios is none and not KVM guest,
|
||||
* let's overwrite the address we jump to after reset to
|
||||
* the base of the flash.
|
||||
*/
|
||||
start_addr = virt_memmap[VIRT_FLASH].base;
|
||||
} else {
|
||||
/*
|
||||
* Pflash was supplied but either KVM guest or bios is not none.
|
||||
* In this case, base of the flash would contain S-mode payload.
|
||||
*/
|
||||
riscv_setup_firmware_boot(machine);
|
||||
kernel_entry = virt_memmap[VIRT_FLASH].base;
|
||||
}
|
||||
}
|
||||
|
||||
if (machine->kernel_filename && !kernel_entry) {
|
||||
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
|
||||
firmware_end_addr);
|
||||
|
||||
kernel_entry = riscv_load_kernel(machine, &s->soc[0],
|
||||
kernel_start_addr, true, NULL);
|
||||
} else {
|
||||
/*
|
||||
* If dynamic firmware is used, it doesn't know where is the next mode
|
||||
* if kernel argument is not set.
|
||||
*/
|
||||
kernel_entry = 0;
|
||||
}
|
||||
|
||||
if (drive_get(IF_PFLASH, 0, 0)) {
|
||||
/*
|
||||
* Pflash was supplied, let's overwrite the address we jump to after
|
||||
* reset to the base of the flash.
|
||||
*/
|
||||
start_addr = virt_memmap[VIRT_FLASH].base;
|
||||
}
|
||||
|
||||
fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base,
|
||||
@@ -1510,8 +1501,6 @@ static void virt_machine_init(MachineState *machine)
|
||||
sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base,
|
||||
qdev_get_gpio_in(mmio_irqchip, RTC_IRQ));
|
||||
|
||||
virt_flash_create(s);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->flash); i++) {
|
||||
/* Map legacy -drive if=pflash to machine properties */
|
||||
pflash_cfi01_legacy_drive(s->flash[i],
|
||||
@@ -1538,6 +1527,8 @@ static void virt_machine_instance_init(Object *obj)
|
||||
{
|
||||
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
|
||||
|
||||
virt_flash_create(s);
|
||||
|
||||
s->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
|
||||
s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
||||
s->acpi = ON_OFF_AUTO_AUTO;
|
||||
|
||||
@@ -397,7 +397,7 @@ typedef struct disassemble_info {
|
||||
char * disassembler_options;
|
||||
|
||||
/* Field intended to be used by targets in any way they deem suitable. */
|
||||
int64_t target_info;
|
||||
void *target_info;
|
||||
|
||||
/* Options for Capstone disassembly. */
|
||||
int cap_arch;
|
||||
|
||||
@@ -544,11 +544,13 @@ GuestPanicInformation *cpu_get_crash_info(CPUState *cpu);
|
||||
* @CPU_DUMP_CODE:
|
||||
* @CPU_DUMP_FPU: dump FPU register state, not just integer
|
||||
* @CPU_DUMP_CCOP: dump info about TCG QEMU's condition code optimization state
|
||||
* @CPU_DUMP_VPU: dump VPU registers
|
||||
*/
|
||||
enum CPUDumpFlags {
|
||||
CPU_DUMP_CODE = 0x00010000,
|
||||
CPU_DUMP_FPU = 0x00020000,
|
||||
CPU_DUMP_CCOP = 0x00040000,
|
||||
CPU_DUMP_VPU = 0x00080000,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "hw/char/ibex_uart.h"
|
||||
#include "hw/timer/ibex_timer.h"
|
||||
#include "hw/ssi/ibex_spi_host.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
|
||||
@@ -53,9 +54,12 @@ struct LowRISCIbexSoCState {
|
||||
MemoryRegion flash_alias;
|
||||
};
|
||||
|
||||
#define TYPE_OPENTITAN_MACHINE MACHINE_TYPE_NAME("opentitan")
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(OpenTitanState, OPENTITAN_MACHINE)
|
||||
|
||||
typedef struct OpenTitanState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
MachineState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
LowRISCIbexSoCState soc;
|
||||
|
||||
@@ -35,6 +35,7 @@ bool qemu_log_separate(void);
|
||||
/* LOG_STRACE is used for user-mode strace logging. */
|
||||
#define LOG_STRACE (1 << 19)
|
||||
#define LOG_PER_THREAD (1 << 20)
|
||||
#define CPU_LOG_TB_VPU (1 << 21)
|
||||
|
||||
/* Lock/unlock output. */
|
||||
|
||||
|
||||
+232
-152
File diff suppressed because it is too large
Load Diff
+4
-113
@@ -27,6 +27,7 @@
|
||||
#include "qom/object.h"
|
||||
#include "qemu/int128.h"
|
||||
#include "cpu_bits.h"
|
||||
#include "cpu_cfg.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "cpu-qom.h"
|
||||
|
||||
@@ -61,6 +62,8 @@ enum {
|
||||
PRIV_VERSION_1_10_0 = 0,
|
||||
PRIV_VERSION_1_11_0,
|
||||
PRIV_VERSION_1_12_0,
|
||||
|
||||
PRIV_VERSION_LATEST = PRIV_VERSION_1_12_0,
|
||||
};
|
||||
|
||||
#define VEXT_VERSION_1_00_0 0x00010000
|
||||
@@ -368,119 +371,6 @@ struct CPUArchState {
|
||||
uint64_t kvm_timer_frequency;
|
||||
};
|
||||
|
||||
/*
|
||||
* map is a 16-bit bitmap: the most significant set bit in map is the maximum
|
||||
* satp mode that is supported. It may be chosen by the user and must respect
|
||||
* what qemu implements (valid_1_10_32/64) and what the hw is capable of
|
||||
* (supported bitmap below).
|
||||
*
|
||||
* init is a 16-bit bitmap used to make sure the user selected a correct
|
||||
* configuration as per the specification.
|
||||
*
|
||||
* supported is a 16-bit bitmap used to reflect the hw capabilities.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t map, init, supported;
|
||||
} RISCVSATPMap;
|
||||
|
||||
struct RISCVCPUConfig {
|
||||
bool ext_zba;
|
||||
bool ext_zbb;
|
||||
bool ext_zbc;
|
||||
bool ext_zbkb;
|
||||
bool ext_zbkc;
|
||||
bool ext_zbkx;
|
||||
bool ext_zbs;
|
||||
bool ext_zca;
|
||||
bool ext_zcb;
|
||||
bool ext_zcd;
|
||||
bool ext_zce;
|
||||
bool ext_zcf;
|
||||
bool ext_zcmp;
|
||||
bool ext_zcmt;
|
||||
bool ext_zk;
|
||||
bool ext_zkn;
|
||||
bool ext_zknd;
|
||||
bool ext_zkne;
|
||||
bool ext_zknh;
|
||||
bool ext_zkr;
|
||||
bool ext_zks;
|
||||
bool ext_zksed;
|
||||
bool ext_zksh;
|
||||
bool ext_zkt;
|
||||
bool ext_ifencei;
|
||||
bool ext_icsr;
|
||||
bool ext_icbom;
|
||||
bool ext_icboz;
|
||||
bool ext_zicond;
|
||||
bool ext_zihintpause;
|
||||
bool ext_smstateen;
|
||||
bool ext_sstc;
|
||||
bool ext_svadu;
|
||||
bool ext_svinval;
|
||||
bool ext_svnapot;
|
||||
bool ext_svpbmt;
|
||||
bool ext_zdinx;
|
||||
bool ext_zawrs;
|
||||
bool ext_zfh;
|
||||
bool ext_zfhmin;
|
||||
bool ext_zfinx;
|
||||
bool ext_zhinx;
|
||||
bool ext_zhinxmin;
|
||||
bool ext_zve32f;
|
||||
bool ext_zve64f;
|
||||
bool ext_zve64d;
|
||||
bool ext_zmmul;
|
||||
bool ext_zvfh;
|
||||
bool ext_zvfhmin;
|
||||
bool ext_smaia;
|
||||
bool ext_ssaia;
|
||||
bool ext_sscofpmf;
|
||||
bool rvv_ta_all_1s;
|
||||
bool rvv_ma_all_1s;
|
||||
|
||||
uint32_t mvendorid;
|
||||
uint64_t marchid;
|
||||
uint64_t mimpid;
|
||||
|
||||
/* Vendor-specific custom extensions */
|
||||
bool ext_xtheadba;
|
||||
bool ext_xtheadbb;
|
||||
bool ext_xtheadbs;
|
||||
bool ext_xtheadcmo;
|
||||
bool ext_xtheadcondmov;
|
||||
bool ext_xtheadfmemidx;
|
||||
bool ext_xtheadfmv;
|
||||
bool ext_xtheadmac;
|
||||
bool ext_xtheadmemidx;
|
||||
bool ext_xtheadmempair;
|
||||
bool ext_xtheadsync;
|
||||
bool ext_XVentanaCondOps;
|
||||
|
||||
uint8_t pmu_num;
|
||||
char *priv_spec;
|
||||
char *user_spec;
|
||||
char *bext_spec;
|
||||
char *vext_spec;
|
||||
uint16_t vlen;
|
||||
uint16_t elen;
|
||||
uint16_t cbom_blocksize;
|
||||
uint16_t cboz_blocksize;
|
||||
bool mmu;
|
||||
bool pmp;
|
||||
bool epmp;
|
||||
bool debug;
|
||||
bool misa_w;
|
||||
|
||||
bool short_isa_string;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
RISCVSATPMap satp_mode;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct RISCVCPUConfig RISCVCPUConfig;
|
||||
|
||||
/*
|
||||
* RISCVCPU:
|
||||
* @env: #CPURISCVState
|
||||
@@ -546,6 +436,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
bool probe, uintptr_t retaddr);
|
||||
char *riscv_isa_string(RISCVCPU *cpu);
|
||||
void riscv_cpu_list(void);
|
||||
void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
|
||||
|
||||
#define cpu_list riscv_cpu_list
|
||||
#define cpu_mmu_index riscv_cpu_mmu_index
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* QEMU RISC-V CPU CFG
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2017-2018 SiFive, Inc.
|
||||
* Copyright (c) 2021-2023 PLCT Lab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RISCV_CPU_CFG_H
|
||||
#define RISCV_CPU_CFG_H
|
||||
|
||||
/*
|
||||
* map is a 16-bit bitmap: the most significant set bit in map is the maximum
|
||||
* satp mode that is supported. It may be chosen by the user and must respect
|
||||
* what qemu implements (valid_1_10_32/64) and what the hw is capable of
|
||||
* (supported bitmap below).
|
||||
*
|
||||
* init is a 16-bit bitmap used to make sure the user selected a correct
|
||||
* configuration as per the specification.
|
||||
*
|
||||
* supported is a 16-bit bitmap used to reflect the hw capabilities.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t map, init, supported;
|
||||
} RISCVSATPMap;
|
||||
|
||||
struct RISCVCPUConfig {
|
||||
bool ext_zba;
|
||||
bool ext_zbb;
|
||||
bool ext_zbc;
|
||||
bool ext_zbkb;
|
||||
bool ext_zbkc;
|
||||
bool ext_zbkx;
|
||||
bool ext_zbs;
|
||||
bool ext_zca;
|
||||
bool ext_zcb;
|
||||
bool ext_zcd;
|
||||
bool ext_zce;
|
||||
bool ext_zcf;
|
||||
bool ext_zcmp;
|
||||
bool ext_zcmt;
|
||||
bool ext_zk;
|
||||
bool ext_zkn;
|
||||
bool ext_zknd;
|
||||
bool ext_zkne;
|
||||
bool ext_zknh;
|
||||
bool ext_zkr;
|
||||
bool ext_zks;
|
||||
bool ext_zksed;
|
||||
bool ext_zksh;
|
||||
bool ext_zkt;
|
||||
bool ext_ifencei;
|
||||
bool ext_icsr;
|
||||
bool ext_icbom;
|
||||
bool ext_icboz;
|
||||
bool ext_zicond;
|
||||
bool ext_zihintpause;
|
||||
bool ext_smstateen;
|
||||
bool ext_sstc;
|
||||
bool ext_svadu;
|
||||
bool ext_svinval;
|
||||
bool ext_svnapot;
|
||||
bool ext_svpbmt;
|
||||
bool ext_zdinx;
|
||||
bool ext_zawrs;
|
||||
bool ext_zfh;
|
||||
bool ext_zfhmin;
|
||||
bool ext_zfinx;
|
||||
bool ext_zhinx;
|
||||
bool ext_zhinxmin;
|
||||
bool ext_zve32f;
|
||||
bool ext_zve64f;
|
||||
bool ext_zve64d;
|
||||
bool ext_zmmul;
|
||||
bool ext_zvfh;
|
||||
bool ext_zvfhmin;
|
||||
bool ext_smaia;
|
||||
bool ext_ssaia;
|
||||
bool ext_sscofpmf;
|
||||
bool rvv_ta_all_1s;
|
||||
bool rvv_ma_all_1s;
|
||||
|
||||
uint32_t mvendorid;
|
||||
uint64_t marchid;
|
||||
uint64_t mimpid;
|
||||
|
||||
/* Vendor-specific custom extensions */
|
||||
bool ext_xtheadba;
|
||||
bool ext_xtheadbb;
|
||||
bool ext_xtheadbs;
|
||||
bool ext_xtheadcmo;
|
||||
bool ext_xtheadcondmov;
|
||||
bool ext_xtheadfmemidx;
|
||||
bool ext_xtheadfmv;
|
||||
bool ext_xtheadmac;
|
||||
bool ext_xtheadmemidx;
|
||||
bool ext_xtheadmempair;
|
||||
bool ext_xtheadsync;
|
||||
bool ext_XVentanaCondOps;
|
||||
|
||||
uint8_t pmu_num;
|
||||
char *priv_spec;
|
||||
char *user_spec;
|
||||
char *bext_spec;
|
||||
char *vext_spec;
|
||||
uint16_t vlen;
|
||||
uint16_t elen;
|
||||
uint16_t cbom_blocksize;
|
||||
uint16_t cboz_blocksize;
|
||||
bool mmu;
|
||||
bool pmp;
|
||||
bool epmp;
|
||||
bool debug;
|
||||
bool misa_w;
|
||||
|
||||
bool short_isa_string;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
RISCVSATPMap satp_mode;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct RISCVCPUConfig RISCVCPUConfig;
|
||||
#endif
|
||||
+18
-19
@@ -120,6 +120,12 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
vs = MIN(vs, get_field(env->mstatus_hs, MSTATUS_VS));
|
||||
}
|
||||
|
||||
/* With Zfinx, floating point is enabled/disabled by Smstateen. */
|
||||
if (!riscv_has_ext(env, RVF)) {
|
||||
fs = (smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR) == RISCV_EXCP_NONE)
|
||||
? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
|
||||
}
|
||||
|
||||
if (cpu->cfg.debug && !icount_enabled()) {
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
|
||||
}
|
||||
@@ -128,7 +134,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, FS, fs);
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, VS, vs);
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl);
|
||||
if (env->cur_pmmask < (env->xl == MXL_RV32 ? UINT32_MAX : UINT64_MAX)) {
|
||||
if (env->cur_pmmask != 0) {
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, PM_MASK_ENABLED, 1);
|
||||
}
|
||||
if (env->cur_pmbase != 0) {
|
||||
@@ -140,7 +146,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
|
||||
void riscv_cpu_update_mask(CPURISCVState *env)
|
||||
{
|
||||
target_ulong mask = -1, base = 0;
|
||||
target_ulong mask = 0, base = 0;
|
||||
/*
|
||||
* TODO: Current RVJ spec does not specify
|
||||
* how the extension interacts with XLEN.
|
||||
@@ -688,39 +694,30 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
|
||||
*
|
||||
* @env: CPURISCVState
|
||||
* @prot: The returned protection attributes
|
||||
* @tlb_size: TLB page size containing addr. It could be modified after PMP
|
||||
* permission checking. NULL if not set TLB page for addr.
|
||||
* @addr: The physical address to be checked permission
|
||||
* @access_type: The type of MMU access
|
||||
* @mode: Indicates current privilege level.
|
||||
*/
|
||||
static int get_physical_address_pmp(CPURISCVState *env, int *prot,
|
||||
target_ulong *tlb_size, hwaddr addr,
|
||||
static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
|
||||
int size, MMUAccessType access_type,
|
||||
int mode)
|
||||
{
|
||||
pmp_priv_t pmp_priv;
|
||||
int pmp_index = -1;
|
||||
bool pmp_has_privs;
|
||||
|
||||
if (!riscv_cpu_cfg(env)->pmp) {
|
||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
return TRANSLATE_SUCCESS;
|
||||
}
|
||||
|
||||
pmp_index = pmp_hart_has_privs(env, addr, size, 1 << access_type,
|
||||
&pmp_priv, mode);
|
||||
if (pmp_index < 0) {
|
||||
pmp_has_privs = pmp_hart_has_privs(env, addr, size, 1 << access_type,
|
||||
&pmp_priv, mode);
|
||||
if (!pmp_has_privs) {
|
||||
*prot = 0;
|
||||
return TRANSLATE_PMP_FAIL;
|
||||
}
|
||||
|
||||
*prot = pmp_priv_to_page_prot(pmp_priv);
|
||||
if ((tlb_size != NULL) && pmp_index != MAX_RISCV_PMPS) {
|
||||
target_ulong tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1);
|
||||
target_ulong tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1;
|
||||
|
||||
*tlb_size = pmp_get_tlb_size(env, pmp_index, tlb_sa, tlb_ea);
|
||||
}
|
||||
|
||||
return TRANSLATE_SUCCESS;
|
||||
}
|
||||
@@ -909,7 +906,7 @@ restart:
|
||||
}
|
||||
|
||||
int pmp_prot;
|
||||
int pmp_ret = get_physical_address_pmp(env, &pmp_prot, NULL, pte_addr,
|
||||
int pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
|
||||
sizeof(target_ulong),
|
||||
MMU_DATA_LOAD, PRV_S);
|
||||
if (pmp_ret != TRANSLATE_SUCCESS) {
|
||||
@@ -1305,8 +1302,9 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
prot &= prot2;
|
||||
|
||||
if (ret == TRANSLATE_SUCCESS) {
|
||||
ret = get_physical_address_pmp(env, &prot_pmp, &tlb_size, pa,
|
||||
ret = get_physical_address_pmp(env, &prot_pmp, pa,
|
||||
size, access_type, mode);
|
||||
tlb_size = pmp_get_tlb_size(env, pa);
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s PMP address=" HWADDR_FMT_plx " ret %d prot"
|
||||
@@ -1338,8 +1336,9 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
__func__, address, ret, pa, prot);
|
||||
|
||||
if (ret == TRANSLATE_SUCCESS) {
|
||||
ret = get_physical_address_pmp(env, &prot_pmp, &tlb_size, pa,
|
||||
ret = get_physical_address_pmp(env, &prot_pmp, pa,
|
||||
size, access_type, mode);
|
||||
tlb_size = pmp_get_tlb_size(env, pa);
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s PMP address=" HWADDR_FMT_plx " ret %d prot"
|
||||
|
||||
+47
-28
@@ -82,6 +82,10 @@ static RISCVException fs(CPURISCVState *env, int csrno)
|
||||
!riscv_cpu_cfg(env)->ext_zfinx) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR);
|
||||
}
|
||||
#endif
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
@@ -1324,8 +1328,15 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
|
||||
mstatus = set_field(mstatus, MSTATUS64_SXL, xl);
|
||||
}
|
||||
env->mstatus = mstatus;
|
||||
env->xl = cpu_recompute_xl(env);
|
||||
|
||||
/*
|
||||
* Except in debug mode, UXL/SXL can only be modified by higher
|
||||
* privilege mode. So xl will not be changed in normal mode.
|
||||
*/
|
||||
if (env->debugger) {
|
||||
env->xl = cpu_recompute_xl(env);
|
||||
riscv_cpu_update_mask(env);
|
||||
}
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
@@ -1387,39 +1398,18 @@ static RISCVException read_misa(CPURISCVState *env, int csrno,
|
||||
static RISCVException write_misa(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
RISCVCPU *cpu = env_archcpu(env);
|
||||
uint32_t orig_misa_ext = env->misa_ext;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!riscv_cpu_cfg(env)->misa_w) {
|
||||
/* drop write to misa */
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
/* 'I' or 'E' must be present */
|
||||
if (!(val & (RVI | RVE))) {
|
||||
/* It is not, drop write to misa */
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
/* 'E' excludes all other extensions */
|
||||
if (val & RVE) {
|
||||
/*
|
||||
* when we support 'E' we can do "val = RVE;" however
|
||||
* for now we just drop writes if 'E' is present.
|
||||
*/
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* misa.MXL writes are not supported by QEMU.
|
||||
* Drop writes to those bits.
|
||||
*/
|
||||
|
||||
/* Mask extensions that are not supported by this hart */
|
||||
val &= env->misa_ext_mask;
|
||||
|
||||
/* 'D' depends on 'F', so clear 'D' if 'F' is not present */
|
||||
if ((val & RVD) && !(val & RVF)) {
|
||||
val &= ~RVD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Suppress 'C' if next instruction is not aligned
|
||||
* TODO: this should check next_pc
|
||||
@@ -1428,18 +1418,36 @@ static RISCVException write_misa(CPURISCVState *env, int csrno,
|
||||
val &= ~RVC;
|
||||
}
|
||||
|
||||
/* Disable RVG if any of its dependencies are disabled */
|
||||
if (!(val & RVI && val & RVM && val & RVA &&
|
||||
val & RVF && val & RVD)) {
|
||||
val &= ~RVG;
|
||||
}
|
||||
|
||||
/* If nothing changed, do nothing. */
|
||||
if (val == env->misa_ext) {
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
if (!(val & RVF)) {
|
||||
env->misa_ext = val;
|
||||
riscv_cpu_validate_set_extensions(cpu, &local_err);
|
||||
if (local_err != NULL) {
|
||||
/* Rollback on validation error */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Unable to write MISA ext value "
|
||||
"0x%x, keeping existing MISA ext 0x%x\n",
|
||||
env->misa_ext, orig_misa_ext);
|
||||
|
||||
env->misa_ext = orig_misa_ext;
|
||||
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
if (!(env->misa_ext & RVF)) {
|
||||
env->mstatus &= ~MSTATUS_FS;
|
||||
}
|
||||
|
||||
/* flush translation cache */
|
||||
tb_flush(env_cpu(env));
|
||||
env->misa_ext = val;
|
||||
env->xl = riscv_cpu_mxl(env);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
@@ -2100,6 +2108,9 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
|
||||
target_ulong new_val)
|
||||
{
|
||||
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
|
||||
if (!riscv_has_ext(env, RVF)) {
|
||||
wr_mask |= SMSTATEEN0_FCSR;
|
||||
}
|
||||
|
||||
return write_mstateen(env, csrno, wr_mask, new_val);
|
||||
}
|
||||
@@ -2173,6 +2184,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
|
||||
{
|
||||
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
|
||||
|
||||
if (!riscv_has_ext(env, RVF)) {
|
||||
wr_mask |= SMSTATEEN0_FCSR;
|
||||
}
|
||||
|
||||
return write_hstateen(env, csrno, wr_mask, new_val);
|
||||
}
|
||||
|
||||
@@ -2259,6 +2274,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
|
||||
{
|
||||
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
|
||||
|
||||
if (!riscv_has_ext(env, RVF)) {
|
||||
wr_mask |= SMSTATEEN0_FCSR;
|
||||
}
|
||||
|
||||
return write_sstateen(env, csrno, wr_mask, new_val);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
decode_save_opc(ctx);
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
gen_update_pc(ctx, ctx->cur_insn_len);
|
||||
gen_helper_wfi(cpu_env);
|
||||
return true;
|
||||
#else
|
||||
|
||||
@@ -31,9 +31,11 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_ZCD(ctx) do { \
|
||||
if (!ctx->cfg_ptr->ext_zcd) { \
|
||||
return false; \
|
||||
#define REQUIRE_ZCD_OR_DC(ctx) do { \
|
||||
if (!ctx->cfg_ptr->ext_zcd) { \
|
||||
if (!has_ext(ctx, RVD) || !has_ext(ctx, RVC)) { \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -67,13 +69,13 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
|
||||
|
||||
static bool trans_c_fld(DisasContext *ctx, arg_fld *a)
|
||||
{
|
||||
REQUIRE_ZCD(ctx);
|
||||
REQUIRE_ZCD_OR_DC(ctx);
|
||||
return trans_fld(ctx, a);
|
||||
}
|
||||
|
||||
static bool trans_c_fsd(DisasContext *ctx, arg_fsd *a)
|
||||
{
|
||||
REQUIRE_ZCD(ctx);
|
||||
REQUIRE_ZCD_OR_DC(ctx);
|
||||
return trans_fsd(ctx, a);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
*/
|
||||
|
||||
#define REQUIRE_FPU do {\
|
||||
if (ctx->mstatus_fs == EXT_STATUS_DISABLED) \
|
||||
if (!ctx->cfg_ptr->ext_zfinx) \
|
||||
return false; \
|
||||
if (ctx->mstatus_fs == EXT_STATUS_DISABLED) { \
|
||||
ctx->virt_inst_excp = ctx->virt_enabled && ctx->cfg_ptr->ext_zfinx; \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_ZFINX_OR_F(ctx) do {\
|
||||
@@ -30,10 +31,12 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_ZCF(ctx) do { \
|
||||
if (!ctx->cfg_ptr->ext_zcf) { \
|
||||
return false; \
|
||||
} \
|
||||
#define REQUIRE_ZCF_OR_FC(ctx) do { \
|
||||
if (!ctx->cfg_ptr->ext_zcf) { \
|
||||
if (!has_ext(ctx, RVF) || !has_ext(ctx, RVC)) { \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool trans_flw(DisasContext *ctx, arg_flw *a)
|
||||
@@ -69,13 +72,13 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
|
||||
|
||||
static bool trans_c_flw(DisasContext *ctx, arg_flw *a)
|
||||
{
|
||||
REQUIRE_ZCF(ctx);
|
||||
REQUIRE_ZCF_OR_FC(ctx);
|
||||
return trans_flw(ctx, a);
|
||||
}
|
||||
|
||||
static bool trans_c_fsw(DisasContext *ctx, arg_fsw *a)
|
||||
{
|
||||
REQUIRE_ZCF(ctx);
|
||||
REQUIRE_ZCF_OR_FC(ctx);
|
||||
return trans_fsw(ctx, a);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ static bool trans_lui(DisasContext *ctx, arg_lui *a)
|
||||
|
||||
static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
|
||||
{
|
||||
gen_set_gpri(ctx, a->rd, a->imm + ctx->base.pc_next);
|
||||
TCGv target_pc = dest_gpr(ctx, a->rd);
|
||||
gen_pc_plus_diff(target_pc, ctx, a->imm);
|
||||
gen_set_gpr(ctx, a->rd, target_pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,25 +53,33 @@ static bool trans_jal(DisasContext *ctx, arg_jal *a)
|
||||
static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
|
||||
{
|
||||
TCGLabel *misaligned = NULL;
|
||||
TCGv target_pc = tcg_temp_new();
|
||||
TCGv succ_pc = dest_gpr(ctx, a->rd);
|
||||
|
||||
tcg_gen_addi_tl(cpu_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
|
||||
tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
|
||||
tcg_gen_addi_tl(target_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
|
||||
tcg_gen_andi_tl(target_pc, target_pc, (target_ulong)-2);
|
||||
|
||||
gen_set_pc(ctx, cpu_pc);
|
||||
if (!ctx->cfg_ptr->ext_zca) {
|
||||
if (get_xl(ctx) == MXL_RV32) {
|
||||
tcg_gen_ext32s_tl(target_pc, target_pc);
|
||||
}
|
||||
|
||||
if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca) {
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
misaligned = gen_new_label();
|
||||
tcg_gen_andi_tl(t0, cpu_pc, 0x2);
|
||||
tcg_gen_andi_tl(t0, target_pc, 0x2);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
|
||||
}
|
||||
|
||||
gen_set_gpri(ctx, a->rd, ctx->pc_succ_insn);
|
||||
gen_pc_plus_diff(succ_pc, ctx, ctx->cur_insn_len);
|
||||
gen_set_gpr(ctx, a->rd, succ_pc);
|
||||
|
||||
tcg_gen_mov_tl(cpu_pc, target_pc);
|
||||
lookup_and_goto_ptr(ctx);
|
||||
|
||||
if (misaligned) {
|
||||
gen_set_label(misaligned);
|
||||
gen_exception_inst_addr_mis(ctx);
|
||||
gen_exception_inst_addr_mis(ctx, target_pc);
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
@@ -153,6 +163,7 @@ static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
|
||||
TCGLabel *l = gen_new_label();
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_SIGN);
|
||||
TCGv src2 = get_gpr(ctx, a->rs2, EXT_SIGN);
|
||||
target_ulong orig_pc_save = ctx->pc_save;
|
||||
|
||||
if (get_xl(ctx) == MXL_RV128) {
|
||||
TCGv src1h = get_gprh(ctx, a->rs1);
|
||||
@@ -165,16 +176,21 @@ static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
|
||||
} else {
|
||||
tcg_gen_brcond_tl(cond, src1, src2, l);
|
||||
}
|
||||
gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
|
||||
gen_goto_tb(ctx, 1, ctx->cur_insn_len);
|
||||
ctx->pc_save = orig_pc_save;
|
||||
|
||||
gen_set_label(l); /* branch taken */
|
||||
|
||||
if (!ctx->cfg_ptr->ext_zca && ((ctx->base.pc_next + a->imm) & 0x3)) {
|
||||
if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca &&
|
||||
(a->imm & 0x3)) {
|
||||
/* misaligned */
|
||||
gen_exception_inst_addr_mis(ctx);
|
||||
TCGv target_pc = tcg_temp_new();
|
||||
gen_pc_plus_diff(target_pc, ctx, a->imm);
|
||||
gen_exception_inst_addr_mis(ctx, target_pc);
|
||||
} else {
|
||||
gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm);
|
||||
gen_goto_tb(ctx, 0, a->imm);
|
||||
}
|
||||
ctx->pc_save = -1;
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
return true;
|
||||
@@ -767,7 +783,7 @@ static bool trans_pause(DisasContext *ctx, arg_pause *a)
|
||||
* PAUSE is a no-op in QEMU,
|
||||
* end the TB and return to main loop
|
||||
*/
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
gen_update_pc(ctx, ctx->cur_insn_len);
|
||||
exit_tb(ctx);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
@@ -791,7 +807,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
|
||||
* FENCE_I is a no-op in QEMU,
|
||||
* however we need to end the translation block
|
||||
*/
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
gen_update_pc(ctx, ctx->cur_insn_len);
|
||||
exit_tb(ctx);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
@@ -802,7 +818,7 @@ static bool do_csr_post(DisasContext *ctx)
|
||||
/* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
|
||||
decode_save_opc(ctx);
|
||||
/* We may have changed important cpu state -- exit to main loop. */
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
gen_update_pc(ctx, ctx->cur_insn_len);
|
||||
exit_tb(ctx);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user