mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 03:29:43 +00:00
Second RISC-V PR for QEMU 6.1
- Update the PLIC and CLINT DT bindings - Improve documentation for RISC-V machines - Support direct kernel boot for microchip_pfsoc - Fix WFI exception behaviour - Improve CSR printing - Initial support for the experimental Bit Manip extension -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmC+uasACgkQIeENKd+X cFTUFwf/TqBBNl8oWFBMTeV+Puwy5s8l9LZpBzWq6W0Wd3y/RyetutMI0v2ir3lC ezGMLEmGSvYVugDzb2tdZI1DOx/ka8d3mzyU7+Jf8/LA9LCBp0Uj0kVKOw5wL8+V LoTT6/v0ymEr7Achp4LSpxY//A4BxcCfFRxH83BdUHeybl37UvUpXkaAraGUjfVR afoB4KQk/IrhT4KtCXnSqr3T/Q9vVHnXhkKOFiR6db3RqWtyq9VDI/lwx/X1Vg+V iaP/a5IGhfGJP+IHPyEINrp6LPJv8qBl1j0PXhbo2NbIJtZr7lJdB/hmfKOjcHag r5RtzGVa+JODY4JTTYa1UlXiLVsVHw== =Dhie -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20210608-1' into staging Second RISC-V PR for QEMU 6.1 - Update the PLIC and CLINT DT bindings - Improve documentation for RISC-V machines - Support direct kernel boot for microchip_pfsoc - Fix WFI exception behaviour - Improve CSR printing - Initial support for the experimental Bit Manip extension # gpg: Signature made Tue 08 Jun 2021 01:28:27 BST # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full] # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * remotes/alistair/tags/pull-riscv-to-apply-20210608-1: (32 commits) target/riscv: rvb: add b-ext version cpu option target/riscv: rvb: support and turn on B-extension from command line target/riscv: rvb: add/shift with prefix zero-extend target/riscv: rvb: address calculation target/riscv: rvb: generalized or-combine target/riscv: rvb: generalized reverse target/riscv: rvb: rotate (left/right) target/riscv: rvb: shift ones target/riscv: rvb: single-bit instructions target/riscv: add gen_shifti() and gen_shiftiw() helper functions target/riscv: rvb: sign-extend instructions target/riscv: rvb: min/max instructions target/riscv: rvb: pack two words into one register target/riscv: rvb: logic-with-negate target/riscv: rvb: count bits set target/riscv: rvb: count leading/trailing zeros target/riscv: reformat @sh format encoding for B-extension target/riscv: Pass the same value to oprsz and maxsz. target/riscv/pmp: Add assert for ePMP operations target/riscv: Dump CSR mscratch/sscratch/satp ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
a4716fd8d7
@ -52,25 +52,6 @@ pcspk-audiodev=<name>``.
|
||||
``tty`` and ``parport`` are aliases that will be removed. Instead, the
|
||||
actual backend names ``serial`` and ``parallel`` should be used.
|
||||
|
||||
RISC-V ``-bios`` (since 5.1)
|
||||
''''''''''''''''''''''''''''
|
||||
|
||||
QEMU 4.1 introduced support for the -bios option in QEMU for RISC-V for the
|
||||
RISC-V virt machine and sifive_u machine. QEMU 4.1 had no changes to the
|
||||
default behaviour to avoid breakages.
|
||||
|
||||
QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default``.
|
||||
|
||||
QEMU 5.1 has three options:
|
||||
1. ``-bios default`` - This is the current default behavior if no -bios option
|
||||
is included. This option will load the default OpenSBI firmware automatically.
|
||||
The firmware is included with the QEMU release and no user interaction is
|
||||
required. All a user needs to do is specify the kernel they want to boot
|
||||
with the -kernel option
|
||||
2. ``-bios none`` - QEMU will not automatically load any firmware. It is up
|
||||
to the user to load all the images they need.
|
||||
3. ``-bios <file>`` - Tells QEMU to load the specified file as the firmwrae.
|
||||
|
||||
Short-form boolean options (since 6.0)
|
||||
''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
@ -126,6 +126,11 @@ devices. Drives the board doesn't pick up can no longer be used with
|
||||
This option was undocumented and not used in the field.
|
||||
Use `-device usb-ccid`` instead.
|
||||
|
||||
RISC-V firmware not booted by default (removed in 5.1)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default``
|
||||
for the RISC-V ``virt`` machine and ``sifive_u`` machine.
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
|
@ -15,33 +15,53 @@ Supported devices
|
||||
|
||||
The ``microchip-icicle-kit`` machine supports the following devices:
|
||||
|
||||
* 1 E51 core
|
||||
* 4 U54 cores
|
||||
* Core Level Interruptor (CLINT)
|
||||
* Platform-Level Interrupt Controller (PLIC)
|
||||
* L2 Loosely Integrated Memory (L2-LIM)
|
||||
* DDR memory controller
|
||||
* 5 MMUARTs
|
||||
* 1 DMA controller
|
||||
* 2 GEM Ethernet controllers
|
||||
* 1 SDHC storage controller
|
||||
* 1 E51 core
|
||||
* 4 U54 cores
|
||||
* Core Level Interruptor (CLINT)
|
||||
* Platform-Level Interrupt Controller (PLIC)
|
||||
* L2 Loosely Integrated Memory (L2-LIM)
|
||||
* DDR memory controller
|
||||
* 5 MMUARTs
|
||||
* 1 DMA controller
|
||||
* 2 GEM Ethernet controllers
|
||||
* 1 SDHC storage controller
|
||||
|
||||
Boot options
|
||||
------------
|
||||
|
||||
The ``microchip-icicle-kit`` machine can start using the standard -bios
|
||||
functionality for loading its BIOS image, aka Hart Software Services (HSS_).
|
||||
HSS loads the second stage bootloader U-Boot from an SD card. It does not
|
||||
support direct kernel loading via the -kernel option. One has to load kernel
|
||||
from U-Boot.
|
||||
HSS loads the second stage bootloader U-Boot from an SD card. Then a kernel
|
||||
can be loaded from U-Boot. It also supports direct kernel booting via the
|
||||
-kernel option along with the device tree blob via -dtb. When direct kernel
|
||||
boot is used, the OpenSBI fw_dynamic BIOS image is used to boot a payload
|
||||
like U-Boot or OS kernel directly.
|
||||
|
||||
The user provided DTB should have the following requirements:
|
||||
|
||||
* The /cpus node should contain at least one subnode for E51 and the number
|
||||
of subnodes should match QEMU's ``-smp`` option
|
||||
* The /memory reg size should match QEMU’s selected ram_size via ``-m``
|
||||
* Should contain a node for the CLINT device with a compatible string
|
||||
"riscv,clint0"
|
||||
|
||||
QEMU follows below truth table to select which payload to execute:
|
||||
|
||||
===== ========== =======
|
||||
-bios -kernel payload
|
||||
===== ========== =======
|
||||
N N HSS
|
||||
Y don't care HSS
|
||||
N Y kernel
|
||||
===== ========== =======
|
||||
|
||||
The memory is set to 1537 MiB by default which is the minimum required high
|
||||
memory size by HSS. A sanity check on ram size is performed in the machine
|
||||
init routine to prompt user to increase the RAM size to > 1537 MiB when less
|
||||
than 1537 MiB ram is detected.
|
||||
|
||||
Boot the machine
|
||||
----------------
|
||||
Running HSS
|
||||
-----------
|
||||
|
||||
HSS 2020.12 release is tested at the time of writing. To build an HSS image
|
||||
that can be booted by the ``microchip-icicle-kit`` machine, type the following
|
||||
|
@ -9,21 +9,21 @@ Supported devices
|
||||
|
||||
The ``sifive_u`` machine supports the following devices:
|
||||
|
||||
* 1 E51 / E31 core
|
||||
* Up to 4 U54 / U34 cores
|
||||
* Core Level Interruptor (CLINT)
|
||||
* Platform-Level Interrupt Controller (PLIC)
|
||||
* Power, Reset, Clock, Interrupt (PRCI)
|
||||
* L2 Loosely Integrated Memory (L2-LIM)
|
||||
* DDR memory controller
|
||||
* 2 UARTs
|
||||
* 1 GEM Ethernet controller
|
||||
* 1 GPIO controller
|
||||
* 1 One-Time Programmable (OTP) memory with stored serial number
|
||||
* 1 DMA controller
|
||||
* 2 QSPI controllers
|
||||
* 1 ISSI 25WP256 flash
|
||||
* 1 SD card in SPI mode
|
||||
* 1 E51 / E31 core
|
||||
* Up to 4 U54 / U34 cores
|
||||
* Core Level Interruptor (CLINT)
|
||||
* Platform-Level Interrupt Controller (PLIC)
|
||||
* Power, Reset, Clock, Interrupt (PRCI)
|
||||
* L2 Loosely Integrated Memory (L2-LIM)
|
||||
* DDR memory controller
|
||||
* 2 UARTs
|
||||
* 1 GEM Ethernet controller
|
||||
* 1 GPIO controller
|
||||
* 1 One-Time Programmable (OTP) memory with stored serial number
|
||||
* 1 DMA controller
|
||||
* 2 QSPI controllers
|
||||
* 1 ISSI 25WP256 flash
|
||||
* 1 SD card in SPI mode
|
||||
|
||||
Please note the real world HiFive Unleashed board has a fixed configuration of
|
||||
1 E51 core and 4 U54 core combination and the RISC-V core boots in 64-bit mode.
|
||||
@ -36,12 +36,21 @@ Hardware configuration information
|
||||
----------------------------------
|
||||
|
||||
The ``sifive_u`` machine automatically generates a device tree blob ("dtb")
|
||||
which it passes to the guest. This provides information about the addresses,
|
||||
interrupt lines and other configuration of the various devices in the system.
|
||||
Guest software should discover the devices that are present in the generated
|
||||
DTB instead of using a DTB for the real hardware, as some of the devices are
|
||||
not modeled by QEMU and trying to access these devices may cause unexpected
|
||||
behavior.
|
||||
which it passes to the guest, if there is no ``-dtb`` option. This provides
|
||||
information about the addresses, interrupt lines and other configuration of
|
||||
the various devices in the system. Guest software should discover the devices
|
||||
that are present in the generated DTB instead of using a DTB for the real
|
||||
hardware, as some of the devices are not modeled by QEMU and trying to access
|
||||
these devices may cause unexpected behavior.
|
||||
|
||||
If users want to provide their own DTB, they can use the ``-dtb`` option.
|
||||
These DTBs should have the following requirements:
|
||||
|
||||
* The /cpus node should contain at least one subnode for E51 and the number
|
||||
of subnodes should match QEMU's ``-smp`` option
|
||||
* The /memory reg size should match QEMU’s selected ram_size via ``-m``
|
||||
* Should contain a node for the CLINT device with a compatible string
|
||||
"riscv,clint0" if using with OpenSBI BIOS images
|
||||
|
||||
Boot options
|
||||
------------
|
||||
@ -122,6 +131,32 @@ To boot the newly built Linux kernel in QEMU with the ``sifive_u`` machine:
|
||||
-initrd /path/to/rootfs.ext4 \
|
||||
-append "root=/dev/ram"
|
||||
|
||||
Alternatively, we can use a custom DTB to boot the machine by inserting a CLINT
|
||||
node in fu540-c000.dtsi in the Linux kernel,
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
clint: clint@2000000 {
|
||||
compatible = "riscv,clint0";
|
||||
interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7
|
||||
&cpu1_intc 3 &cpu1_intc 7
|
||||
&cpu2_intc 3 &cpu2_intc 7
|
||||
&cpu3_intc 3 &cpu3_intc 7
|
||||
&cpu4_intc 3 &cpu4_intc 7>;
|
||||
reg = <0x00 0x2000000 0x00 0x10000>;
|
||||
};
|
||||
|
||||
with the following command line options:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-riscv64 -M sifive_u -smp 5 -m 8G \
|
||||
-display none -serial stdio \
|
||||
-kernel arch/riscv/boot/Image \
|
||||
-dtb arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb \
|
||||
-initrd /path/to/rootfs.ext4 \
|
||||
-append "root=/dev/ram"
|
||||
|
||||
To build a Linux mainline kernel that can be booted by the ``sifive_u`` machine
|
||||
in 32-bit mode, use the rv32_defconfig configuration. A patch is required to
|
||||
fix the 32-bit boot issue for Linux kernel v5.10.
|
||||
|
@ -70,5 +70,16 @@ undocumented; you can get a complete list by running
|
||||
riscv/shakti-c
|
||||
riscv/sifive_u
|
||||
|
||||
RISC-V CPU features
|
||||
RISC-V CPU firmware
|
||||
-------------------
|
||||
|
||||
When using the ``sifive_u`` or ``virt`` machine there are three different
|
||||
firmware boot options:
|
||||
1. ``-bios default`` - This is the default behaviour if no -bios option
|
||||
is included. This option will load the default OpenSBI firmware automatically.
|
||||
The firmware is included with the QEMU release and no user interaction is
|
||||
required. All a user needs to do is specify the kernel they want to boot
|
||||
with the -kernel option
|
||||
2. ``-bios none`` - QEMU will not automatically load any firmware. It is up
|
||||
to the user to load all the images they need.
|
||||
3. ``-bios <file>`` - Tells QEMU to load the specified file as the firmware.
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "hw/riscv/microchip_pfsoc.h"
|
||||
#include "hw/intc/sifive_clint.h"
|
||||
#include "hw/intc/sifive_plic.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
/*
|
||||
@ -460,6 +461,12 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
MemoryRegion *mem_high = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mem_high_alias = g_new(MemoryRegion, 1);
|
||||
uint64_t mem_high_size;
|
||||
hwaddr firmware_load_addr;
|
||||
const char *firmware_name;
|
||||
bool kernel_as_payload = false;
|
||||
target_ulong firmware_end_addr, kernel_start_addr;
|
||||
uint64_t kernel_entry;
|
||||
uint32_t fdt_load_addr;
|
||||
DriveInfo *dinfo = drive_get_next(IF_SD);
|
||||
|
||||
/* Sanity check on RAM size */
|
||||
@ -504,9 +511,6 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
memmap[MICROCHIP_PFSOC_DRAM_HI_ALIAS].base,
|
||||
mem_high_alias);
|
||||
|
||||
/* Load the firmware */
|
||||
riscv_find_and_load_firmware(machine, BIOS_FILENAME, RESET_VECTOR, NULL);
|
||||
|
||||
/* Attach an SD card */
|
||||
if (dinfo) {
|
||||
CadenceSDHCIState *sdhci = &(s->soc.sdhci);
|
||||
@ -516,6 +520,77 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
&error_fatal);
|
||||
qdev_realize_and_unref(card, sdhci->bus, &error_fatal);
|
||||
}
|
||||
|
||||
/*
|
||||
* We follow the following table to select which payload we execute.
|
||||
*
|
||||
* -bios | -kernel | payload
|
||||
* -------+------------+--------
|
||||
* N | N | HSS
|
||||
* Y | don't care | HSS
|
||||
* N | Y | kernel
|
||||
*
|
||||
* This ensures backwards compatibility with how we used to expose -bios
|
||||
* to users but allows them to run through direct kernel booting as well.
|
||||
*
|
||||
* When -kernel is used for direct boot, -dtb must be present to provide
|
||||
* a valid device tree for the board, as we don't generate device tree.
|
||||
*/
|
||||
|
||||
if (machine->kernel_filename && machine->dtb) {
|
||||
int fdt_size;
|
||||
machine->fdt = load_device_tree(machine->dtb, &fdt_size);
|
||||
if (!machine->fdt) {
|
||||
error_report("load_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
firmware_name = RISCV64_BIOS_BIN;
|
||||
firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
|
||||
kernel_as_payload = true;
|
||||
}
|
||||
|
||||
if (!kernel_as_payload) {
|
||||
firmware_name = BIOS_FILENAME;
|
||||
firmware_load_addr = RESET_VECTOR;
|
||||
}
|
||||
|
||||
/* Load the firmware */
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
|
||||
firmware_load_addr, NULL);
|
||||
|
||||
if (kernel_as_payload) {
|
||||
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
|
||||
firmware_end_addr);
|
||||
|
||||
kernel_entry = riscv_load_kernel(machine->kernel_filename,
|
||||
kernel_start_addr, NULL);
|
||||
|
||||
if (machine->initrd_filename) {
|
||||
hwaddr start;
|
||||
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
||||
machine->ram_size, kernel_entry,
|
||||
&start);
|
||||
qemu_fdt_setprop_cell(machine->fdt, "/chosen",
|
||||
"linux,initrd-start", start);
|
||||
qemu_fdt_setprop_cell(machine->fdt, "/chosen",
|
||||
"linux,initrd-end", end);
|
||||
}
|
||||
|
||||
if (machine->kernel_cmdline) {
|
||||
qemu_fdt_setprop_string(machine->fdt, "/chosen",
|
||||
"bootargs", machine->kernel_cmdline);
|
||||
}
|
||||
|
||||
/* Compute the fdt load address in dram */
|
||||
fdt_load_addr = riscv_load_fdt(memmap[MICROCHIP_PFSOC_DRAM_LO].base,
|
||||
machine->ram_size, machine->fdt);
|
||||
/* Load the reset vector */
|
||||
riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr,
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
|
||||
kernel_entry, fdt_load_addr, machine->fdt);
|
||||
}
|
||||
}
|
||||
|
||||
static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
@ -95,9 +95,15 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
|
||||
int cpu;
|
||||
uint32_t *cells;
|
||||
char *nodename;
|
||||
char ethclk_names[] = "pclk\0hclk";
|
||||
uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1;
|
||||
uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
|
||||
static const char * const ethclk_names[2] = { "pclk", "hclk" };
|
||||
static const char * const clint_compat[2] = {
|
||||
"sifive,clint0", "riscv,clint0"
|
||||
};
|
||||
static const char * const plic_compat[2] = {
|
||||
"sifive,plic-1.0.0", "riscv,plic0"
|
||||
};
|
||||
|
||||
if (ms->dtb) {
|
||||
fdt = s->fdt = load_device_tree(ms->dtb, &s->fdt_size);
|
||||
@ -209,7 +215,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
|
||||
nodename = g_strdup_printf("/soc/clint@%lx",
|
||||
(long)memmap[SIFIVE_U_DEV_CLINT].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,clint0");
|
||||
qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
|
||||
(char **)&clint_compat, ARRAY_SIZE(clint_compat));
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[SIFIVE_U_DEV_CLINT].base,
|
||||
0x0, memmap[SIFIVE_U_DEV_CLINT].size);
|
||||
@ -266,7 +273,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
|
||||
(long)memmap[SIFIVE_U_DEV_PLIC].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
|
||||
qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
|
||||
(char **)&plic_compat, ARRAY_SIZE(plic_compat));
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
||||
cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
|
||||
@ -412,8 +420,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
||||
prci_phandle, PRCI_CLK_GEMGXLPLL, prci_phandle, PRCI_CLK_GEMGXLPLL);
|
||||
qemu_fdt_setprop(fdt, nodename, "clock-names", ethclk_names,
|
||||
sizeof(ethclk_names));
|
||||
qemu_fdt_setprop_string_array(fdt, nodename, "clock-names",
|
||||
(char **)ðclk_names, ARRAY_SIZE(ethclk_names));
|
||||
qemu_fdt_setprop(fdt, nodename, "local-mac-address",
|
||||
s->soc.gem.conf.macaddr.a, ETH_ALEN);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
|
||||
@ -552,12 +560,10 @@ static void sifive_u_machine_init(MachineState *machine)
|
||||
|
||||
if (riscv_is_32bit(&s->soc.u_cpus)) {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
"opensbi-riscv32-generic-fw_dynamic.bin",
|
||||
start_addr, NULL);
|
||||
RISCV32_BIOS_BIN, start_addr, NULL);
|
||||
} else {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
"opensbi-riscv64-generic-fw_dynamic.bin",
|
||||
start_addr, NULL);
|
||||
RISCV64_BIOS_BIN, start_addr, NULL);
|
||||
}
|
||||
|
||||
if (machine->kernel_filename) {
|
||||
|
@ -59,6 +59,9 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
|
||||
uint32_t cpu_phandle, intc_phandle, phandle = 1;
|
||||
char *name, *mem_name, *clint_name, *clust_name;
|
||||
char *core_name, *cpu_name, *intc_name;
|
||||
static const char * const clint_compat[2] = {
|
||||
"sifive,clint0", "riscv,clint0"
|
||||
};
|
||||
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
@ -152,7 +155,8 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
|
||||
(memmap[SPIKE_CLINT].size * socket);
|
||||
clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
|
||||
qemu_fdt_add_subnode(fdt, clint_name);
|
||||
qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
|
||||
qemu_fdt_setprop_string_array(fdt, clint_name, "compatible",
|
||||
(char **)&clint_compat, ARRAY_SIZE(clint_compat));
|
||||
qemu_fdt_setprop_cells(fdt, clint_name, "reg",
|
||||
0x0, clint_addr, 0x0, memmap[SPIKE_CLINT].size);
|
||||
qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
|
||||
@ -254,13 +258,11 @@ static void spike_board_init(MachineState *machine)
|
||||
*/
|
||||
if (riscv_is_32bit(&s->soc[0])) {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
"opensbi-riscv32-generic-fw_dynamic.elf",
|
||||
memmap[SPIKE_DRAM].base,
|
||||
RISCV32_BIOS_ELF, memmap[SPIKE_DRAM].base,
|
||||
htif_symbol_callback);
|
||||
} else {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
"opensbi-riscv64-generic-fw_dynamic.elf",
|
||||
memmap[SPIKE_DRAM].base,
|
||||
RISCV64_BIOS_ELF, memmap[SPIKE_DRAM].base,
|
||||
htif_symbol_callback);
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,12 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
char *name, *clint_name, *plic_name, *clust_name;
|
||||
hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
|
||||
static const char * const clint_compat[2] = {
|
||||
"sifive,clint0", "riscv,clint0"
|
||||
};
|
||||
static const char * const plic_compat[2] = {
|
||||
"sifive,plic-1.0.0", "riscv,plic0"
|
||||
};
|
||||
|
||||
if (mc->dtb) {
|
||||
fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
|
||||
@ -299,7 +305,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
(memmap[VIRT_CLINT].size * socket);
|
||||
clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
|
||||
qemu_fdt_add_subnode(fdt, clint_name);
|
||||
qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
|
||||
qemu_fdt_setprop_string_array(fdt, clint_name, "compatible",
|
||||
(char **)&clint_compat, ARRAY_SIZE(clint_compat));
|
||||
qemu_fdt_setprop_cells(fdt, clint_name, "reg",
|
||||
0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
|
||||
qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
|
||||
@ -315,7 +322,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
"#address-cells", FDT_PLIC_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cell(fdt, plic_name,
|
||||
"#interrupt-cells", FDT_PLIC_INT_CELLS);
|
||||
qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
|
||||
qemu_fdt_setprop_string_array(fdt, plic_name, "compatible",
|
||||
(char **)&plic_compat, ARRAY_SIZE(plic_compat));
|
||||
qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
|
||||
plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
|
||||
@ -394,8 +402,11 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
(long)memmap[VIRT_TEST].base);
|
||||
qemu_fdt_add_subnode(fdt, name);
|
||||
{
|
||||
const char compat[] = "sifive,test1\0sifive,test0\0syscon";
|
||||
qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
|
||||
static const char * const compat[3] = {
|
||||
"sifive,test1", "sifive,test0", "syscon"
|
||||
};
|
||||
qemu_fdt_setprop_string_array(fdt, name, "compatible", (char **)&compat,
|
||||
ARRAY_SIZE(compat));
|
||||
}
|
||||
qemu_fdt_setprop_cells(fdt, name, "reg",
|
||||
0x0, memmap[VIRT_TEST].base,
|
||||
@ -670,12 +681,10 @@ static void virt_machine_init(MachineState *machine)
|
||||
|
||||
if (riscv_is_32bit(&s->soc[0])) {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
"opensbi-riscv32-generic-fw_dynamic.bin",
|
||||
start_addr, NULL);
|
||||
RISCV32_BIOS_BIN, start_addr, NULL);
|
||||
} else {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
"opensbi-riscv64-generic-fw_dynamic.bin",
|
||||
start_addr, NULL);
|
||||
RISCV64_BIOS_BIN, start_addr, NULL);
|
||||
}
|
||||
|
||||
if (machine->kernel_filename) {
|
||||
|
@ -24,6 +24,11 @@
|
||||
#include "hw/loader.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
|
||||
#define RISCV32_BIOS_BIN "opensbi-riscv32-generic-fw_dynamic.bin"
|
||||
#define RISCV32_BIOS_ELF "opensbi-riscv32-generic-fw_dynamic.elf"
|
||||
#define RISCV64_BIOS_BIN "opensbi-riscv64-generic-fw_dynamic.bin"
|
||||
#define RISCV64_BIOS_ELF "opensbi-riscv64-generic-fw_dynamic.elf"
|
||||
|
||||
bool riscv_is_32bit(RISCVHartArrayState *harts);
|
||||
|
||||
target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts,
|
||||
|
90
target/riscv/bitmanip_helper.c
Normal file
90
target/riscv/bitmanip_helper.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* RISC-V Bitmanip Extension Helpers for QEMU.
|
||||
*
|
||||
* Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com
|
||||
* Copyright (c) 2020 Frank Chang, frank.chang@sifive.com
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
static const uint64_t adjacent_masks[] = {
|
||||
dup_const(MO_8, 0x55),
|
||||
dup_const(MO_8, 0x33),
|
||||
dup_const(MO_8, 0x0f),
|
||||
dup_const(MO_16, 0xff),
|
||||
dup_const(MO_32, 0xffff),
|
||||
UINT32_MAX
|
||||
};
|
||||
|
||||
static inline target_ulong do_swap(target_ulong x, uint64_t mask, int shift)
|
||||
{
|
||||
return ((x & mask) << shift) | ((x & ~mask) >> shift);
|
||||
}
|
||||
|
||||
static target_ulong do_grev(target_ulong rs1,
|
||||
target_ulong rs2,
|
||||
int bits)
|
||||
{
|
||||
target_ulong x = rs1;
|
||||
int i, shift;
|
||||
|
||||
for (i = 0, shift = 1; shift < bits; i++, shift <<= 1) {
|
||||
if (rs2 & shift) {
|
||||
x = do_swap(x, adjacent_masks[i], shift);
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
target_ulong HELPER(grev)(target_ulong rs1, target_ulong rs2)
|
||||
{
|
||||
return do_grev(rs1, rs2, TARGET_LONG_BITS);
|
||||
}
|
||||
|
||||
target_ulong HELPER(grevw)(target_ulong rs1, target_ulong rs2)
|
||||
{
|
||||
return do_grev(rs1, rs2, 32);
|
||||
}
|
||||
|
||||
static target_ulong do_gorc(target_ulong rs1,
|
||||
target_ulong rs2,
|
||||
int bits)
|
||||
{
|
||||
target_ulong x = rs1;
|
||||
int i, shift;
|
||||
|
||||
for (i = 0, shift = 1; shift < bits; i++, shift <<= 1) {
|
||||
if (rs2 & shift) {
|
||||
x |= do_swap(x, adjacent_masks[i], shift);
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
target_ulong HELPER(gorc)(target_ulong rs1, target_ulong rs2)
|
||||
{
|
||||
return do_gorc(rs1, rs2, TARGET_LONG_BITS);
|
||||
}
|
||||
|
||||
target_ulong HELPER(gorcw)(target_ulong rs1, target_ulong rs2)
|
||||
{
|
||||
return do_gorc(rs1, rs2, 32);
|
||||
}
|
@ -51,7 +51,7 @@ const char * const riscv_fpr_regnames[] = {
|
||||
"f30/ft10", "f31/ft11"
|
||||
};
|
||||
|
||||
const char * const riscv_excp_names[] = {
|
||||
static const char * const riscv_excp_names[] = {
|
||||
"misaligned_fetch",
|
||||
"fault_fetch",
|
||||
"illegal_instruction",
|
||||
@ -78,7 +78,7 @@ const char * const riscv_excp_names[] = {
|
||||
"guest_store_page_fault",
|
||||
};
|
||||
|
||||
const char * const riscv_intr_names[] = {
|
||||
static const char * const riscv_intr_names[] = {
|
||||
"u_software",
|
||||
"s_software",
|
||||
"vs_software",
|
||||
@ -127,6 +127,11 @@ static void set_priv_version(CPURISCVState *env, int priv_ver)
|
||||
env->priv_ver = priv_ver;
|
||||
}
|
||||
|
||||
static void set_bext_version(CPURISCVState *env, int bext_ver)
|
||||
{
|
||||
env->bext_ver = bext_ver;
|
||||
}
|
||||
|
||||
static void set_vext_version(CPURISCVState *env, int vext_ver)
|
||||
{
|
||||
env->vext_ver = vext_ver;
|
||||
@ -286,12 +291,15 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
if (riscv_has_ext(env, RVH)) {
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause);
|
||||
}
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval ", env->mtval);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->stval);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval ", env->mtval);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->stval);
|
||||
if (riscv_has_ext(env, RVH)) {
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "htval ", env->htval);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval2 ", env->mtval2);
|
||||
}
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mscratch", env->mscratch);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sscratch", env->sscratch);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "satp ", env->satp);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
@ -385,6 +393,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
CPURISCVState *env = &cpu->env;
|
||||
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
|
||||
int priv_version = PRIV_VERSION_1_11_0;
|
||||
int bext_version = BEXT_VERSION_0_93_0;
|
||||
int vext_version = VEXT_VERSION_0_07_1;
|
||||
target_ulong target_misa = env->misa;
|
||||
Error *local_err = NULL;
|
||||
@ -409,6 +418,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
set_priv_version(env, priv_version);
|
||||
set_bext_version(env, bext_version);
|
||||
set_vext_version(env, vext_version);
|
||||
|
||||
if (cpu->cfg.mmu) {
|
||||
@ -486,6 +496,24 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
if (cpu->cfg.ext_h) {
|
||||
target_misa |= RVH;
|
||||
}
|
||||
if (cpu->cfg.ext_b) {
|
||||
target_misa |= RVB;
|
||||
|
||||
if (cpu->cfg.bext_spec) {
|
||||
if (!g_strcmp0(cpu->cfg.bext_spec, "v0.93")) {
|
||||
bext_version = BEXT_VERSION_0_93_0;
|
||||
} else {
|
||||
error_setg(errp,
|
||||
"Unsupported bitmanip spec version '%s'",
|
||||
cpu->cfg.bext_spec);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qemu_log("bitmanip version is not specified, "
|
||||
"use the default value v0.93\n");
|
||||
}
|
||||
set_bext_version(env, bext_version);
|
||||
}
|
||||
if (cpu->cfg.ext_v) {
|
||||
target_misa |= RVV;
|
||||
if (!is_power_of_2(cpu->cfg.vlen)) {
|
||||
@ -556,12 +584,14 @@ static Property riscv_cpu_properties[] = {
|
||||
DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true),
|
||||
DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
|
||||
/* This is experimental so mark with 'x-' */
|
||||
DEFINE_PROP_BOOL("x-b", RISCVCPU, cfg.ext_b, false),
|
||||
DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
|
||||
DEFINE_PROP_BOOL("x-v", RISCVCPU, cfg.ext_v, false),
|
||||
DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
|
||||
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
|
||||
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
|
||||
DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
|
||||
DEFINE_PROP_STRING("bext_spec", RISCVCPU, cfg.bext_spec),
|
||||
DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
|
||||
DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128),
|
||||
DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
|
||||
|
@ -67,6 +67,7 @@
|
||||
#define RVS RV('S')
|
||||
#define RVU RV('U')
|
||||
#define RVH RV('H')
|
||||
#define RVB RV('B')
|
||||
|
||||
/* S extension denotes that Supervisor mode exists, however it is possible
|
||||
to have a core that support S mode but does not have an MMU and there
|
||||
@ -82,6 +83,7 @@ enum {
|
||||
#define PRIV_VERSION_1_10_0 0x00011000
|
||||
#define PRIV_VERSION_1_11_0 0x00011100
|
||||
|
||||
#define BEXT_VERSION_0_93_0 0x00009300
|
||||
#define VEXT_VERSION_0_07_1 0x00000701
|
||||
|
||||
enum {
|
||||
@ -131,6 +133,7 @@ struct CPURISCVState {
|
||||
target_ulong guest_phys_fault_addr;
|
||||
|
||||
target_ulong priv_ver;
|
||||
target_ulong bext_ver;
|
||||
target_ulong vext_ver;
|
||||
target_ulong misa;
|
||||
target_ulong misa_mask;
|
||||
@ -285,6 +288,7 @@ struct RISCVCPU {
|
||||
bool ext_f;
|
||||
bool ext_d;
|
||||
bool ext_c;
|
||||
bool ext_b;
|
||||
bool ext_s;
|
||||
bool ext_u;
|
||||
bool ext_h;
|
||||
@ -295,6 +299,7 @@ struct RISCVCPU {
|
||||
|
||||
char *priv_spec;
|
||||
char *user_spec;
|
||||
char *bext_spec;
|
||||
char *vext_spec;
|
||||
uint16_t vlen;
|
||||
uint16_t elen;
|
||||
@ -320,8 +325,6 @@ static inline bool riscv_feature(CPURISCVState *env, int feature)
|
||||
|
||||
extern const char * const riscv_int_regnames[];
|
||||
extern const char * const riscv_fpr_regnames[];
|
||||
extern const char * const riscv_excp_names[];
|
||||
extern const char * const riscv_intr_names[];
|
||||
|
||||
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async);
|
||||
void riscv_cpu_do_interrupt(CPUState *cpu);
|
||||
|
@ -390,6 +390,7 @@
|
||||
#define HSTATUS_HU 0x00000200
|
||||
#define HSTATUS_VGEIN 0x0003F000
|
||||
#define HSTATUS_VTVM 0x00100000
|
||||
#define HSTATUS_VTW 0x00200000
|
||||
#define HSTATUS_VTSR 0x00400000
|
||||
#define HSTATUS_VSXL 0x300000000
|
||||
|
||||
|
@ -58,6 +58,12 @@ DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, tl)
|
||||
DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, tl)
|
||||
DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64)
|
||||
|
||||
/* Bitmanip */
|
||||
DEF_HELPER_FLAGS_2(grev, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(grevw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(gorc, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(gorcw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
|
||||
/* Special functions */
|
||||
DEF_HELPER_3(csrrw, tl, env, tl, tl)
|
||||
DEF_HELPER_4(csrrs, tl, env, tl, tl, tl)
|
||||
|
@ -23,7 +23,7 @@
|
||||
%rd 7:5
|
||||
%sh5 20:5
|
||||
|
||||
%sh10 20:10
|
||||
%sh7 20:7
|
||||
%csr 20:12
|
||||
%rm 12:3
|
||||
%nf 29:3 !function=ex_plus_1
|
||||
@ -41,6 +41,7 @@
|
||||
&i imm rs1 rd
|
||||
&j imm rd
|
||||
&r rd rs1 rs2
|
||||
&r2 rd rs1
|
||||
&s imm rs1 rs2
|
||||
&u imm rd
|
||||
&shift shamt rs1 rd
|
||||
@ -59,7 +60,7 @@
|
||||
@u .................... ..... ....... &u imm=%imm_u %rd
|
||||
@j .................... ..... ....... &j imm=%imm_j %rd
|
||||
|
||||
@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd
|
||||
@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh7 %rs1 %rd
|
||||
@csr ............ ..... ... ..... ....... %csr %rs1 %rd
|
||||
|
||||
@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd
|
||||
@ -68,7 +69,7 @@
|
||||
@r4_rm ..... .. ..... ..... ... ..... ....... %rs3 %rs2 %rs1 %rm %rd
|
||||
@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
|
||||
@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd
|
||||
@r2 ....... ..... ..... ... ..... ....... %rs1 %rd
|
||||
@r2 ....... ..... ..... ... ..... ....... &r2 %rs1 %rd
|
||||
@r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd
|
||||
@r2_vm ...... vm:1 ..... ..... ... ..... ....... &rmr %rs2 %rd
|
||||
@r1_vm ...... vm:1 ..... ..... ... ..... ....... %rd
|
||||
@ -125,9 +126,9 @@ sltiu ............ ..... 011 ..... 0010011 @i
|
||||
xori ............ ..... 100 ..... 0010011 @i
|
||||
ori ............ ..... 110 ..... 0010011 @i
|
||||
andi ............ ..... 111 ..... 0010011 @i
|
||||
slli 00.... ...... ..... 001 ..... 0010011 @sh
|
||||
srli 00.... ...... ..... 101 ..... 0010011 @sh
|
||||
srai 01.... ...... ..... 101 ..... 0010011 @sh
|
||||
slli 00000. ...... ..... 001 ..... 0010011 @sh
|
||||
srli 00000. ...... ..... 101 ..... 0010011 @sh
|
||||
srai 01000. ...... ..... 101 ..... 0010011 @sh
|
||||
add 0000000 ..... ..... 000 ..... 0110011 @r
|
||||
sub 0100000 ..... ..... 000 ..... 0110011 @r
|
||||
sll 0000000 ..... ..... 001 ..... 0110011 @r
|
||||
@ -657,3 +658,77 @@ vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm
|
||||
vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm
|
||||
vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm
|
||||
vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm
|
||||
|
||||
# *** RV32B Standard Extension ***
|
||||
clz 011000 000000 ..... 001 ..... 0010011 @r2
|
||||
ctz 011000 000001 ..... 001 ..... 0010011 @r2
|
||||
cpop 011000 000010 ..... 001 ..... 0010011 @r2
|
||||
sext_b 011000 000100 ..... 001 ..... 0010011 @r2
|
||||
sext_h 011000 000101 ..... 001 ..... 0010011 @r2
|
||||
|
||||
andn 0100000 .......... 111 ..... 0110011 @r
|
||||
orn 0100000 .......... 110 ..... 0110011 @r
|
||||
xnor 0100000 .......... 100 ..... 0110011 @r
|
||||
pack 0000100 .......... 100 ..... 0110011 @r
|
||||
packu 0100100 .......... 100 ..... 0110011 @r
|
||||
packh 0000100 .......... 111 ..... 0110011 @r
|
||||
min 0000101 .......... 100 ..... 0110011 @r
|
||||
minu 0000101 .......... 101 ..... 0110011 @r
|
||||
max 0000101 .......... 110 ..... 0110011 @r
|
||||
maxu 0000101 .......... 111 ..... 0110011 @r
|
||||
bset 0010100 .......... 001 ..... 0110011 @r
|
||||
bclr 0100100 .......... 001 ..... 0110011 @r
|
||||
binv 0110100 .......... 001 ..... 0110011 @r
|
||||
bext 0100100 .......... 101 ..... 0110011 @r
|
||||
slo 0010000 .......... 001 ..... 0110011 @r
|
||||
sro 0010000 .......... 101 ..... 0110011 @r
|
||||
ror 0110000 .......... 101 ..... 0110011 @r
|
||||
rol 0110000 .......... 001 ..... 0110011 @r
|
||||
grev 0110100 .......... 101 ..... 0110011 @r
|
||||
gorc 0010100 .......... 101 ..... 0110011 @r
|
||||
sh1add 0010000 .......... 010 ..... 0110011 @r
|
||||
sh2add 0010000 .......... 100 ..... 0110011 @r
|
||||
sh3add 0010000 .......... 110 ..... 0110011 @r
|
||||
|
||||
bseti 00101. ........... 001 ..... 0010011 @sh
|
||||
bclri 01001. ........... 001 ..... 0010011 @sh
|
||||
binvi 01101. ........... 001 ..... 0010011 @sh
|
||||
bexti 01001. ........... 101 ..... 0010011 @sh
|
||||
sloi 00100. ........... 001 ..... 0010011 @sh
|
||||
sroi 00100. ........... 101 ..... 0010011 @sh
|
||||
rori 01100. ........... 101 ..... 0010011 @sh
|
||||
grevi 01101. ........... 101 ..... 0010011 @sh
|
||||
gorci 00101. ........... 101 ..... 0010011 @sh
|
||||
|
||||
# *** RV64B Standard Extension (in addition to RV32B) ***
|
||||
clzw 0110000 00000 ..... 001 ..... 0011011 @r2
|
||||
ctzw 0110000 00001 ..... 001 ..... 0011011 @r2
|
||||
cpopw 0110000 00010 ..... 001 ..... 0011011 @r2
|
||||
|
||||
packw 0000100 .......... 100 ..... 0111011 @r
|
||||
packuw 0100100 .......... 100 ..... 0111011 @r
|
||||
bsetw 0010100 .......... 001 ..... 0111011 @r
|
||||
bclrw 0100100 .......... 001 ..... 0111011 @r
|
||||
binvw 0110100 .......... 001 ..... 0111011 @r
|
||||
bextw 0100100 .......... 101 ..... 0111011 @r
|
||||
slow 0010000 .......... 001 ..... 0111011 @r
|
||||
srow 0010000 .......... 101 ..... 0111011 @r
|
||||
rorw 0110000 .......... 101 ..... 0111011 @r
|
||||
rolw 0110000 .......... 001 ..... 0111011 @r
|
||||
grevw 0110100 .......... 101 ..... 0111011 @r
|
||||
gorcw 0010100 .......... 101 ..... 0111011 @r
|
||||
sh1add_uw 0010000 .......... 010 ..... 0111011 @r
|
||||
sh2add_uw 0010000 .......... 100 ..... 0111011 @r
|
||||
sh3add_uw 0010000 .......... 110 ..... 0111011 @r
|
||||
add_uw 0000100 .......... 000 ..... 0111011 @r
|
||||
|
||||
bsetiw 0010100 .......... 001 ..... 0011011 @sh5
|
||||
bclriw 0100100 .......... 001 ..... 0011011 @sh5
|
||||
binviw 0110100 .......... 001 ..... 0011011 @sh5
|
||||
sloiw 0010000 .......... 001 ..... 0011011 @sh5
|
||||
sroiw 0010000 .......... 101 ..... 0011011 @sh5
|
||||
roriw 0110000 .......... 101 ..... 0011011 @sh5
|
||||
greviw 0110100 .......... 101 ..... 0011011 @sh5
|
||||
gorciw 0010100 .......... 101 ..... 0011011 @sh5
|
||||
|
||||
slli_uw 00001. ........... 001 ..... 0011011 @sh
|
||||
|
438
target/riscv/insn_trans/trans_rvb.c.inc
Normal file
438
target/riscv/insn_trans/trans_rvb.c.inc
Normal file
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RVB Standard Extension.
|
||||
*
|
||||
* Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com
|
||||
* Copyright (c) 2020 Frank Chang, frank.chang@sifive.com
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
static bool trans_clz(DisasContext *ctx, arg_clz *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, gen_clz);
|
||||
}
|
||||
|
||||
static bool trans_ctz(DisasContext *ctx, arg_ctz *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, gen_ctz);
|
||||
}
|
||||
|
||||
static bool trans_cpop(DisasContext *ctx, arg_cpop *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, tcg_gen_ctpop_tl);
|
||||
}
|
||||
|
||||
static bool trans_andn(DisasContext *ctx, arg_andn *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_andc_tl);
|
||||
}
|
||||
|
||||
static bool trans_orn(DisasContext *ctx, arg_orn *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_orc_tl);
|
||||
}
|
||||
|
||||
static bool trans_xnor(DisasContext *ctx, arg_xnor *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_eqv_tl);
|
||||
}
|
||||
|
||||
static bool trans_pack(DisasContext *ctx, arg_pack *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, gen_pack);
|
||||
}
|
||||
|
||||
static bool trans_packu(DisasContext *ctx, arg_packu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, gen_packu);
|
||||
}
|
||||
|
||||
static bool trans_packh(DisasContext *ctx, arg_packh *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, gen_packh);
|
||||
}
|
||||
|
||||
static bool trans_min(DisasContext *ctx, arg_min *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_smin_tl);
|
||||
}
|
||||
|
||||
static bool trans_max(DisasContext *ctx, arg_max *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_smax_tl);
|
||||
}
|
||||
|
||||
static bool trans_minu(DisasContext *ctx, arg_minu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_umin_tl);
|
||||
}
|
||||
|
||||
static bool trans_maxu(DisasContext *ctx, arg_maxu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, tcg_gen_umax_tl);
|
||||
}
|
||||
|
||||
static bool trans_sext_b(DisasContext *ctx, arg_sext_b *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, tcg_gen_ext8s_tl);
|
||||
}
|
||||
|
||||
static bool trans_sext_h(DisasContext *ctx, arg_sext_h *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, tcg_gen_ext16s_tl);
|
||||
}
|
||||
|
||||
static bool trans_bset(DisasContext *ctx, arg_bset *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_bset);
|
||||
}
|
||||
|
||||
static bool trans_bseti(DisasContext *ctx, arg_bseti *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_bset);
|
||||
}
|
||||
|
||||
static bool trans_bclr(DisasContext *ctx, arg_bclr *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_bclr);
|
||||
}
|
||||
|
||||
static bool trans_bclri(DisasContext *ctx, arg_bclri *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_bclr);
|
||||
}
|
||||
|
||||
static bool trans_binv(DisasContext *ctx, arg_binv *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_binv);
|
||||
}
|
||||
|
||||
static bool trans_binvi(DisasContext *ctx, arg_binvi *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_binv);
|
||||
}
|
||||
|
||||
static bool trans_bext(DisasContext *ctx, arg_bext *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_bext);
|
||||
}
|
||||
|
||||
static bool trans_bexti(DisasContext *ctx, arg_bexti *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_bext);
|
||||
}
|
||||
|
||||
static bool trans_slo(DisasContext *ctx, arg_slo *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_slo);
|
||||
}
|
||||
|
||||
static bool trans_sloi(DisasContext *ctx, arg_sloi *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_slo);
|
||||
}
|
||||
|
||||
static bool trans_sro(DisasContext *ctx, arg_sro *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_sro);
|
||||
}
|
||||
|
||||
static bool trans_sroi(DisasContext *ctx, arg_sroi *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_sro);
|
||||
}
|
||||
|
||||
static bool trans_ror(DisasContext *ctx, arg_ror *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, tcg_gen_rotr_tl);
|
||||
}
|
||||
|
||||
static bool trans_rori(DisasContext *ctx, arg_rori *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, tcg_gen_rotr_tl);
|
||||
}
|
||||
|
||||
static bool trans_rol(DisasContext *ctx, arg_rol *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, tcg_gen_rotl_tl);
|
||||
}
|
||||
|
||||
static bool trans_grev(DisasContext *ctx, arg_grev *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_helper_grev);
|
||||
}
|
||||
|
||||
static bool trans_grevi(DisasContext *ctx, arg_grevi *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return gen_grevi(ctx, a);
|
||||
}
|
||||
|
||||
static bool trans_gorc(DisasContext *ctx, arg_gorc *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shift(ctx, a, gen_helper_gorc);
|
||||
}
|
||||
|
||||
static bool trans_gorci(DisasContext *ctx, arg_gorci *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shifti(ctx, a, gen_helper_gorc);
|
||||
}
|
||||
|
||||
#define GEN_TRANS_SHADD(SHAMT) \
|
||||
static bool trans_sh##SHAMT##add(DisasContext *ctx, arg_sh##SHAMT##add *a) \
|
||||
{ \
|
||||
REQUIRE_EXT(ctx, RVB); \
|
||||
return gen_arith(ctx, a, gen_sh##SHAMT##add); \
|
||||
}
|
||||
|
||||
GEN_TRANS_SHADD(1)
|
||||
GEN_TRANS_SHADD(2)
|
||||
GEN_TRANS_SHADD(3)
|
||||
|
||||
static bool trans_clzw(DisasContext *ctx, arg_clzw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, gen_clzw);
|
||||
}
|
||||
|
||||
static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, gen_ctzw);
|
||||
}
|
||||
|
||||
static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_unary(ctx, a, gen_cpopw);
|
||||
}
|
||||
|
||||
static bool trans_packw(DisasContext *ctx, arg_packw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, gen_packw);
|
||||
}
|
||||
|
||||
static bool trans_packuw(DisasContext *ctx, arg_packuw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, gen_packuw);
|
||||
}
|
||||
|
||||
static bool trans_bsetw(DisasContext *ctx, arg_bsetw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_bset);
|
||||
}
|
||||
|
||||
static bool trans_bsetiw(DisasContext *ctx, arg_bsetiw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_bset);
|
||||
}
|
||||
|
||||
static bool trans_bclrw(DisasContext *ctx, arg_bclrw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_bclr);
|
||||
}
|
||||
|
||||
static bool trans_bclriw(DisasContext *ctx, arg_bclriw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_bclr);
|
||||
}
|
||||
|
||||
static bool trans_binvw(DisasContext *ctx, arg_binvw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_binv);
|
||||
}
|
||||
|
||||
static bool trans_binviw(DisasContext *ctx, arg_binviw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_binv);
|
||||
}
|
||||
|
||||
static bool trans_bextw(DisasContext *ctx, arg_bextw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_bext);
|
||||
}
|
||||
|
||||
static bool trans_slow(DisasContext *ctx, arg_slow *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_slo);
|
||||
}
|
||||
|
||||
static bool trans_sloiw(DisasContext *ctx, arg_sloiw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_slo);
|
||||
}
|
||||
|
||||
static bool trans_srow(DisasContext *ctx, arg_srow *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_sro);
|
||||
}
|
||||
|
||||
static bool trans_sroiw(DisasContext *ctx, arg_sroiw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_sro);
|
||||
}
|
||||
|
||||
static bool trans_rorw(DisasContext *ctx, arg_rorw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_rorw);
|
||||
}
|
||||
|
||||
static bool trans_roriw(DisasContext *ctx, arg_roriw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_rorw);
|
||||
}
|
||||
|
||||
static bool trans_rolw(DisasContext *ctx, arg_rolw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_rolw);
|
||||
}
|
||||
|
||||
static bool trans_grevw(DisasContext *ctx, arg_grevw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_grevw);
|
||||
}
|
||||
|
||||
static bool trans_greviw(DisasContext *ctx, arg_greviw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_grevw);
|
||||
}
|
||||
|
||||
static bool trans_gorcw(DisasContext *ctx, arg_gorcw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftw(ctx, a, gen_gorcw);
|
||||
}
|
||||
|
||||
static bool trans_gorciw(DisasContext *ctx, arg_gorciw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_shiftiw(ctx, a, gen_gorcw);
|
||||
}
|
||||
|
||||
#define GEN_TRANS_SHADD_UW(SHAMT) \
|
||||
static bool trans_sh##SHAMT##add_uw(DisasContext *ctx, \
|
||||
arg_sh##SHAMT##add_uw *a) \
|
||||
{ \
|
||||
REQUIRE_64BIT(ctx); \
|
||||
REQUIRE_EXT(ctx, RVB); \
|
||||
return gen_arith(ctx, a, gen_sh##SHAMT##add_uw); \
|
||||
}
|
||||
|
||||
GEN_TRANS_SHADD_UW(1)
|
||||
GEN_TRANS_SHADD_UW(2)
|
||||
GEN_TRANS_SHADD_UW(3)
|
||||
|
||||
static bool trans_add_uw(DisasContext *ctx, arg_add_uw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
return gen_arith(ctx, a, gen_add_uw);
|
||||
}
|
||||
|
||||
static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_EXT(ctx, RVB);
|
||||
|
||||
TCGv source1 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
|
||||
if (a->shamt < 32) {
|
||||
tcg_gen_deposit_z_tl(source1, source1, a->shamt, 32);
|
||||
} else {
|
||||
tcg_gen_shli_tl(source1, source1, a->shamt);
|
||||
}
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
return true;
|
||||
}
|
@ -268,54 +268,17 @@ static bool trans_andi(DisasContext *ctx, arg_andi *a)
|
||||
}
|
||||
static bool trans_slli(DisasContext *ctx, arg_slli *a)
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
|
||||
tcg_gen_shli_tl(t, t, a->shamt);
|
||||
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
return gen_shifti(ctx, a, tcg_gen_shl_tl);
|
||||
}
|
||||
|
||||
static bool trans_srli(DisasContext *ctx, arg_srli *a)
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
|
||||
tcg_gen_shri_tl(t, t, a->shamt);
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
return gen_shifti(ctx, a, tcg_gen_shr_tl);
|
||||
}
|
||||
|
||||
static bool trans_srai(DisasContext *ctx, arg_srai *a)
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
|
||||
tcg_gen_sari_tl(t, t, a->shamt);
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
return gen_shifti(ctx, a, tcg_gen_sar_tl);
|
||||
}
|
||||
|
||||
static bool trans_add(DisasContext *ctx, arg_add *a)
|
||||
@ -377,16 +340,7 @@ static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
|
||||
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
TCGv source1;
|
||||
source1 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
|
||||
tcg_gen_shli_tl(source1, source1, a->shamt);
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
gen_set_gpr(a->rd, source1);
|
||||
|
||||
tcg_temp_free(source1);
|
||||
return true;
|
||||
return gen_shiftiw(ctx, a, tcg_gen_shl_tl);
|
||||
}
|
||||
|
||||
static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
|
||||
|
@ -183,7 +183,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
* The first part is vlen in bytes, encoded in maxsz of simd_desc.
|
||||
* The second part is lmul, encoded in data of simd_desc.
|
||||
*/
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
@ -334,7 +334,7 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
|
||||
mask = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
stride = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
gen_get_gpr(stride, rs2);
|
||||
@ -462,7 +462,7 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
mask = tcg_temp_new_ptr();
|
||||
index = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
@ -594,7 +594,7 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
@ -671,7 +671,7 @@ static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
mask = tcg_temp_new_ptr();
|
||||
index = tcg_temp_new_ptr();
|
||||
base = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
gen_get_gpr(base, rs1);
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
@ -831,7 +831,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
|
||||
cpu_env, 0, s->vlen / 8, data, fn);
|
||||
cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
|
||||
}
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
@ -874,7 +874,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
|
||||
data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
|
||||
data = FIELD_DP32(data, VDATA, VM, vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
|
||||
@ -1021,7 +1021,7 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
|
||||
data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
|
||||
data = FIELD_DP32(data, VDATA, VM, vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
|
||||
@ -1119,7 +1119,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1),
|
||||
vreg_ofs(s, a->rs2),
|
||||
cpu_env, 0, s->vlen / 8,
|
||||
cpu_env, s->vlen / 8, s->vlen / 8,
|
||||
data, fn);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
@ -1207,7 +1207,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1),
|
||||
vreg_ofs(s, a->rs2),
|
||||
cpu_env, 0, s->vlen / 8, data, fn);
|
||||
cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@ -1284,8 +1284,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -1473,8 +1474,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -1690,7 +1692,7 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
|
||||
};
|
||||
|
||||
tcg_gen_ext_tl_i64(s1_i64, s1);
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
|
||||
fns[s->sew](dest, s1_i64, cpu_env, desc);
|
||||
|
||||
@ -1729,7 +1731,7 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
|
||||
|
||||
s1 = tcg_const_i64(simm);
|
||||
dest = tcg_temp_new_ptr();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
|
||||
fns[s->sew](dest, s1, cpu_env, desc);
|
||||
|
||||
@ -1838,8 +1840,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew - 1]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew - 1]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -1863,7 +1866,7 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
|
||||
@ -1950,8 +1953,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew - 1]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew - 1]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2024,8 +2028,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew - 1]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew - 1]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2138,8 +2143,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew - 1]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew - 1]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2225,7 +2231,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
|
||||
|
||||
dest = tcg_temp_new_ptr();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
|
||||
fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
|
||||
|
||||
@ -2278,8 +2284,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew - 1]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew - 1]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2326,8 +2333,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
data = FIELD_DP32(data, VDATA, VM, a->vm); \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fns[s->sew - 1]); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, \
|
||||
fns[s->sew - 1]); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2388,8 +2396,8 @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
|
||||
vreg_ofs(s, a->rs1), \
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0, \
|
||||
s->vlen / 8, data, fn); \
|
||||
vreg_ofs(s, a->rs2), cpu_env, \
|
||||
s->vlen / 8, s->vlen / 8, data, fn); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2420,7 +2428,7 @@ static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
dst = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
@ -2452,7 +2460,7 @@ static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
dst = tcg_temp_new();
|
||||
desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
|
||||
desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
|
||||
|
||||
tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
|
||||
tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
|
||||
@ -2486,7 +2494,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \
|
||||
vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \
|
||||
cpu_env, 0, s->vlen / 8, data, fn); \
|
||||
cpu_env, s->vlen / 8, s->vlen / 8, \
|
||||
data, fn); \
|
||||
gen_set_label(over); \
|
||||
return true; \
|
||||
} \
|
||||
@ -2516,8 +2525,8 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
|
||||
gen_helper_viota_m_w, gen_helper_viota_m_d,
|
||||
};
|
||||
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs2), cpu_env, 0,
|
||||
s->vlen / 8, data, fns[s->sew]);
|
||||
vreg_ofs(s, a->rs2), cpu_env,
|
||||
s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@ -2542,7 +2551,8 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
|
||||
gen_helper_vid_v_w, gen_helper_vid_v_d,
|
||||
};
|
||||
tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
cpu_env, 0, s->vlen / 8, data, fns[s->sew]);
|
||||
cpu_env, s->vlen / 8, s->vlen / 8,
|
||||
data, fns[s->sew]);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
@ -2895,7 +2905,8 @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
|
||||
vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
|
||||
cpu_env, 0, s->vlen / 8, data, fns[s->sew]);
|
||||
cpu_env, s->vlen / 8, s->vlen / 8, data,
|
||||
fns[s->sew]);
|
||||
gen_set_label(over);
|
||||
return true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ riscv_ss.add(files(
|
||||
'gdbstub.c',
|
||||
'op_helper.c',
|
||||
'vector_helper.c',
|
||||
'bitmanip_helper.c',
|
||||
'translate.c',
|
||||
))
|
||||
|
||||
|
@ -177,10 +177,15 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
void helper_wfi(CPURISCVState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
bool rvs = riscv_has_ext(env, RVS);
|
||||
bool prv_u = env->priv == PRV_U;
|
||||
bool prv_s = env->priv == PRV_S;
|
||||
|
||||
if ((env->priv == PRV_S &&
|
||||
get_field(env->mstatus, MSTATUS_TW)) ||
|
||||
riscv_cpu_virt_enabled(env)) {
|
||||
if (((prv_s || (!rvs && prv_u)) && get_field(env->mstatus, MSTATUS_TW)) ||
|
||||
(rvs && prv_u && !riscv_cpu_virt_enabled(env))) {
|
||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
||||
} else if (riscv_cpu_virt_enabled(env) && (prv_u ||
|
||||
(prv_s && get_field(env->hstatus, HSTATUS_VTW)))) {
|
||||
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
|
||||
} else {
|
||||
cs->halted = 1;
|
||||
|
@ -402,6 +402,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||
case 15:
|
||||
*allowed_privs = PMP_READ;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
} else {
|
||||
switch (epmp_operation) {
|
||||
@ -433,6 +435,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||
case 7:
|
||||
*allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -548,6 +548,229 @@ static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gen_pack(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_deposit_tl(ret, arg1, arg2,
|
||||
TARGET_LONG_BITS / 2,
|
||||
TARGET_LONG_BITS / 2);
|
||||
}
|
||||
|
||||
static void gen_packu(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
tcg_gen_shri_tl(t, arg1, TARGET_LONG_BITS / 2);
|
||||
tcg_gen_deposit_tl(ret, arg2, t, 0, TARGET_LONG_BITS / 2);
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_packh(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
tcg_gen_ext8u_tl(t, arg2);
|
||||
tcg_gen_deposit_tl(ret, arg1, t, 8, TARGET_LONG_BITS - 8);
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_sbop_mask(TCGv ret, TCGv shamt)
|
||||
{
|
||||
tcg_gen_movi_tl(ret, 1);
|
||||
tcg_gen_shl_tl(ret, ret, shamt);
|
||||
}
|
||||
|
||||
static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
|
||||
gen_sbop_mask(t, shamt);
|
||||
tcg_gen_or_tl(ret, arg1, t);
|
||||
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
|
||||
gen_sbop_mask(t, shamt);
|
||||
tcg_gen_andc_tl(ret, arg1, t);
|
||||
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
|
||||
gen_sbop_mask(t, shamt);
|
||||
tcg_gen_xor_tl(ret, arg1, t);
|
||||
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
|
||||
{
|
||||
tcg_gen_shr_tl(ret, arg1, shamt);
|
||||
tcg_gen_andi_tl(ret, ret, 1);
|
||||
}
|
||||
|
||||
static void gen_slo(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_not_tl(ret, arg1);
|
||||
tcg_gen_shl_tl(ret, ret, arg2);
|
||||
tcg_gen_not_tl(ret, ret);
|
||||
}
|
||||
|
||||
static void gen_sro(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_not_tl(ret, arg1);
|
||||
tcg_gen_shr_tl(ret, ret, arg2);
|
||||
tcg_gen_not_tl(ret, ret);
|
||||
}
|
||||
|
||||
static bool gen_grevi(DisasContext *ctx, arg_grevi *a)
|
||||
{
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2;
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
|
||||
if (a->shamt == (TARGET_LONG_BITS - 8)) {
|
||||
/* rev8, byte swaps */
|
||||
tcg_gen_bswap_tl(source1, source1);
|
||||
} else {
|
||||
source2 = tcg_temp_new();
|
||||
tcg_gen_movi_tl(source2, a->shamt);
|
||||
gen_helper_grev(source1, source1, source2);
|
||||
tcg_temp_free(source2);
|
||||
}
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define GEN_SHADD(SHAMT) \
|
||||
static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \
|
||||
{ \
|
||||
TCGv t = tcg_temp_new(); \
|
||||
\
|
||||
tcg_gen_shli_tl(t, arg1, SHAMT); \
|
||||
tcg_gen_add_tl(ret, t, arg2); \
|
||||
\
|
||||
tcg_temp_free(t); \
|
||||
}
|
||||
|
||||
GEN_SHADD(1)
|
||||
GEN_SHADD(2)
|
||||
GEN_SHADD(3)
|
||||
|
||||
static void gen_ctzw(TCGv ret, TCGv arg1)
|
||||
{
|
||||
tcg_gen_ori_tl(ret, arg1, (target_ulong)MAKE_64BIT_MASK(32, 32));
|
||||
tcg_gen_ctzi_tl(ret, ret, 64);
|
||||
}
|
||||
|
||||
static void gen_clzw(TCGv ret, TCGv arg1)
|
||||
{
|
||||
tcg_gen_ext32u_tl(ret, arg1);
|
||||
tcg_gen_clzi_tl(ret, ret, 64);
|
||||
tcg_gen_subi_tl(ret, ret, 32);
|
||||
}
|
||||
|
||||
static void gen_cpopw(TCGv ret, TCGv arg1)
|
||||
{
|
||||
tcg_gen_ext32u_tl(arg1, arg1);
|
||||
tcg_gen_ctpop_tl(ret, arg1);
|
||||
}
|
||||
|
||||
static void gen_packw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
tcg_gen_ext16s_tl(t, arg2);
|
||||
tcg_gen_deposit_tl(ret, arg1, t, 16, 48);
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_packuw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
tcg_gen_shri_tl(t, arg1, 16);
|
||||
tcg_gen_deposit_tl(ret, arg2, t, 0, 16);
|
||||
tcg_gen_ext32s_tl(ret, ret);
|
||||
tcg_temp_free(t);
|
||||
}
|
||||
|
||||
static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||
|
||||
/* truncate to 32-bits */
|
||||
tcg_gen_trunc_tl_i32(t1, arg1);
|
||||
tcg_gen_trunc_tl_i32(t2, arg2);
|
||||
|
||||
tcg_gen_rotr_i32(t1, t1, t2);
|
||||
|
||||
/* sign-extend 64-bits */
|
||||
tcg_gen_ext_i32_tl(ret, t1);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t2);
|
||||
}
|
||||
|
||||
static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||
|
||||
/* truncate to 32-bits */
|
||||
tcg_gen_trunc_tl_i32(t1, arg1);
|
||||
tcg_gen_trunc_tl_i32(t2, arg2);
|
||||
|
||||
tcg_gen_rotl_i32(t1, t1, t2);
|
||||
|
||||
/* sign-extend 64-bits */
|
||||
tcg_gen_ext_i32_tl(ret, t1);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t2);
|
||||
}
|
||||
|
||||
static void gen_grevw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_ext32u_tl(arg1, arg1);
|
||||
gen_helper_grev(ret, arg1, arg2);
|
||||
}
|
||||
|
||||
static void gen_gorcw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_ext32u_tl(arg1, arg1);
|
||||
gen_helper_gorcw(ret, arg1, arg2);
|
||||
}
|
||||
|
||||
#define GEN_SHADD_UW(SHAMT) \
|
||||
static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \
|
||||
{ \
|
||||
TCGv t = tcg_temp_new(); \
|
||||
\
|
||||
tcg_gen_ext32u_tl(t, arg1); \
|
||||
\
|
||||
tcg_gen_shli_tl(t, t, SHAMT); \
|
||||
tcg_gen_add_tl(ret, t, arg2); \
|
||||
\
|
||||
tcg_temp_free(t); \
|
||||
}
|
||||
|
||||
GEN_SHADD_UW(1)
|
||||
GEN_SHADD_UW(2)
|
||||
GEN_SHADD_UW(3)
|
||||
|
||||
static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_ext32u_tl(arg1, arg1);
|
||||
tcg_gen_add_tl(ret, arg1, arg2);
|
||||
}
|
||||
|
||||
static bool gen_arith(DisasContext *ctx, arg_r *a,
|
||||
void(*func)(TCGv, TCGv, TCGv))
|
||||
{
|
||||
@ -593,6 +816,88 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
|
||||
return cpu_ldl_code(env, pc);
|
||||
}
|
||||
|
||||
static bool gen_shifti(DisasContext *ctx, arg_shift *a,
|
||||
void(*func)(TCGv, TCGv, TCGv))
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
|
||||
tcg_gen_movi_tl(source2, a->shamt);
|
||||
(*func)(source1, source1, source2);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_shiftw(DisasContext *ctx, arg_r *a,
|
||||
void(*func)(TCGv, TCGv, TCGv))
|
||||
{
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_andi_tl(source2, source2, 31);
|
||||
(*func)(source1, source1, source2);
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_shiftiw(DisasContext *ctx, arg_shift *a,
|
||||
void(*func)(TCGv, TCGv, TCGv))
|
||||
{
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
tcg_gen_movi_tl(source2, a->shamt);
|
||||
|
||||
(*func)(source1, source1, source2);
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gen_ctz(TCGv ret, TCGv arg1)
|
||||
{
|
||||
tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS);
|
||||
}
|
||||
|
||||
static void gen_clz(TCGv ret, TCGv arg1)
|
||||
{
|
||||
tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS);
|
||||
}
|
||||
|
||||
static bool gen_unary(DisasContext *ctx, arg_r2 *a,
|
||||
void(*func)(TCGv, TCGv))
|
||||
{
|
||||
TCGv source = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source, a->rs1);
|
||||
|
||||
(*func)(source, source);
|
||||
|
||||
gen_set_gpr(a->rd, source);
|
||||
tcg_temp_free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Include insn module translation function */
|
||||
#include "insn_trans/trans_rvi.c.inc"
|
||||
#include "insn_trans/trans_rvm.c.inc"
|
||||
@ -601,6 +906,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
|
||||
#include "insn_trans/trans_rvd.c.inc"
|
||||
#include "insn_trans/trans_rvh.c.inc"
|
||||
#include "insn_trans/trans_rvv.c.inc"
|
||||
#include "insn_trans/trans_rvb.c.inc"
|
||||
#include "insn_trans/trans_privileged.c.inc"
|
||||
|
||||
/* Include the auto-generated decoder for 16 bit insn */
|
||||
|
Loading…
Reference in New Issue
Block a user