Update google_riscv-dv to google/riscv-dv@cc4b870

Update code from upstream repository https://github.com/google/riscv-
dv to revision cc4b87057cb38c91cb0c2ecb065e38281df7aa97

* Fix google/riscv-dv#857 (aneels3)
* [euvm] Fixed a typo in the README file (Puneet Goel)
* [euvm] updated the README file (Puneet Goel)
* [euvm] Moved euvm specific README to euvm folder (Puneet Goel)
* [euvm] ported some SV updates (Puneet Goel)
* [euvm] Fixed generated ASM code indentation (Puneet Goel)
* Add support for RV64IMC instr coverage (aneels3)
* Add register definitions for privilege spec 1.12 and debug spec
  1.0.0 (Henrik Fegran)
* Updated README note for EUVM (Puneet Goel)
* Use current date in output folder name (Puneet Goel)
* Try to create output file folder if it does not exist (Puneet Goel)
* Added a readme for EUVM port (Puneet Goel)
* Allow providing a randomization seed from command line (Puneet Goel)
* Make merging of directed instruction streams scalable (Puneet Goel)
* Create and use new class riscv_prog_instr_stream (Puneet Goel)
* Added and used append and prepend functions for instr_list (Puneet
  Goel)
* Added new targets and tests (Puneet Goel)
* Expose riscv instruction classes in the riscv gen package (Puneet
  Goel)
* Use mixin templates to create RISCV instruction classes (Puneet
  Goel)
* Fix a bug in asm section tag generation (Puneet Goel)
* EUVM upgrade for bitmanip (Puneet Goel)
* Use new clog2 implemented in esdl.data.bvec module (Puneet Goel)
* Add debug and clean targets to Makefile (Puneet Goel)
* Use Queue functions in place of array concatenation (Puneet Goel)
* Misc fixes after review (Puneet Goel)
* Fix broken run.py script (Puneet Goel)
* Use more verbose naming in main function in the test (Puneet Goel)
* Removed some redundant code comments (Puneet Goel)
* Allow verbosity and instr count specification from make run command
  (Puneet Goel)
* Handle riscv_loop_instr confliting constraint in post_randomize
  (Puneet Goel)
* Use variable names that do not conflict with outers (Puneet Goel)
* Use constraint in place of Constraint (Puneet Goel)
* Fixed a typo where '-' was getting printed in place of ' ' (Puneet
  Goel)
* Pick urandom from new location -- esdl.base.rand (Puneet Goel)
* Fixed an issue where newline character was not getting added to some
  instructions (Puneet Goel)
* Fixed an issue with sup program generation (Puneet Goel)
* Added EUVM riscv_instr_base_test (Puneet Goel)
* Added EUVM riscv_instr_register module (Puneet Goel)
* Moved EUVM files to euvm folder (Puneet Goel)
* Add makefile command to to run a test (Puneet Goel)
* Cast return value from ceil to integer (Puneet Goel)
* Miscelleneous fixes (Puneet Goel)
* Fixed some issues in riscv_loop_instr (Puneet Goel)
* Use variable for setting rand_mode (Puneet Goel)
* Use false in place of '0' for bools (Puneet Goel)
* Added build makefile (Puneet Goel)
* misc fixes (Puneet Goel)
* Added riscv instruction definitions (Puneet Goel)
* Added euvm module riscv_instr_registry (Puneet Goel)
* Added euvm module riscv_data_page_gen (Puneet Goel)
* Added euvm module riscv_privileged_common_seq (Puneet Goel)
* Added euvm module riscv_debug_rom_gen (Puneet Goel)
* Use urandom!bool in place of inappropriately named function toss
  (Puneet Goel)
* Added euvm module riscv_illegal_instr (Puneet Goel)
* Added euvm module riscv_asm_program_gen (Puneet Goel)
* Use esdl.rand: toss instead os uniform(0, 2) (Puneet Goel)
* Fixed randomization of avail_regs in euvm module riscv_instr_stream
  (Puneet Goel)
* Use esdl.rand: shuffle instead of randomShuffle (Puneet Goel)
* Added euvm module riscv_directed_instr_lib (Puneet Goel)
* added euvm module riscv_load_store_instr_lib (Puneet Goel)
* urandom has moved to package esdl.rand (Puneet Goel)
* Added euvm module riscv_instr_sequence (Puneet Goel)
* Added euvm module riscv_amo_instr_lib (Puneet Goel)
* Added euvm module riscv_instr_stream (Puneet Goel)
* A small fix in riscv_pmp_cfg module (Puneet Goel)
* Added euvm module riscv_loop_instr (Puneet Goel)
* Added euvm module riscv_pseudo_instr (Puneet Goel)
* Added euvm module riscv_vector_instr (Puneet Goel)
* Added euvm module riscv_floating_point_instr (Puneet Goel)
* Added euvm module riscv_b_instr (Puneet Goel)
* Added euvm module isa/riscv_compressed_instr (Puneet Goel)
* Added euvm module isa/riscv_amo_instr (Puneet Goel)
* Added euvm module isa/riscv_instr (Puneet Goel)
* Added euvm module riscv_callstack_gen (Puneet Goel)
* Added euvm module riscv_page_table_list (Puneet Goel)
* Used ranged switch case statements where required (Puneet Goel)
* Added euvm module riscv_privil_reg (Puneet Goel)
* Add @UVM_DEFAULT uda on the class members where required (Puneet
  Goel)
* Added euvm module riscv_reg (Puneet Goel)
* Added euvm module riscv_pmp_cfg (Puneet Goel)
* Added euvm module riscv_vector_cfg (Puneet Goel)
* Added euvm module riscv_page_table_exception_cfg (Puneet Goel)
* Added euvm module riscv_page_table_entry (Puneet Goel)
* Added euvm module riscv_page_table (Puneet Goel)
* Added riscv_core_setting module (Puneet Goel)
* Added new file riscv_instr_gen_config (Puneet Goel)
* Fixed some module imports (Puneet Goel)
* Added new file riscv_signature_pkg (Puneet Goel)
* Added D port of riscv_instr_pkg (Puneet Goel)

Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
This commit is contained in:
Pirmin Vogel 2022-05-24 15:28:29 +02:00
parent c5567e8f66
commit 223f7cd25b
88 changed files with 20941 additions and 4 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 6e0dc183a4678bfd581c1021b5ab7705f31d14a5
rev: cc4b87057cb38c91cb0c2ecb065e38281df7aa97
}
}

43
vendor/google_riscv-dv/euvm/README.md vendored Normal file
View file

@ -0,0 +1,43 @@
## About eUVM
eUVM is an opensource implementation of IEEE UVM-1800.2-2020 standard in the D Programming Language.
## About the RISCV-DV eUVM port
The RISCV-DV eUVM port is a line-by-line translation of the RISCV-DV SystemVerilog implementation. Except for functional coverage (a work in progress), all other RISCV-DV features have been implemented in eUVM port.
## Downloading and Installing eUVM
If you want to build/use the eUVM port, you need an eUVM installation. Please follow the instructions on https://github.com/coverify/euvm/releases to install and setup eUVM.
## Building eUVM port of RISCV-DV
A makefile to build and run the eUVM port is available in the euvm/build folder. To build the code, use the following commands (assuming bash shell):
```bash
cd euvm/build
make -j $(nproc)
```
Makefile builds RISCV-DV for RV64IMC architecture by default. If you want to build for an alternate architecture, you need to pass that to make command as TARGET parameter:
```bash
cd euvm/build
make clean
make -j $(nproc) TARGET=RV64IMCB
```
Remember to make clean before switching to a new target.
## Generating RISCV-DV tests
```bash
cd euvm/build
make run
```
You can change the number of instructions to be generated by passsing INSTRCOUNT parameter to the make command:
```bash
make run INSTRCOUNT=1000000
```

View file

@ -0,0 +1,68 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Custom instruction class
module riscv.gen.isa.custom.riscv_custom_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t,
riscv_instr_name_t, MAX_INSTR_STR_LEN, riscv_fpr_t,
riscv_instr_format_t, riscv_instr_category_t,
format_string, f_rounding_mode_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.string: toUpper, toLower;
import std.format: format;
import std.algorithm: canFind;
import esdl.rand: rand;
import esdl.data.bvec: ubvec;
import uvm;
class riscv_custom_instr: riscv_instr
{
// TODO: Add custom operands here, example:
// rand riscv_reg_t rs3;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override string get_instr_name() {
import std.conv: to;
return instr_name.to!string();
// TODO: Add custom instruction name encoding here
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
string asm_str;
asm_str = format_string("nop", MAX_INSTR_STR_LEN);
/* TODO: Convert custom instruction to assembly format. Example:
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
case (instr_name)
CUSTOM_1: asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
CUSTOM_2: asm_str = $sformatf("%0s %0s", asm_str, r3.name());
endcase
*/
comment = get_instr_name() ~ " " ~ comment;
if (comment != "") {
asm_str ~= " #" ~ comment;
}
return asm_str.toLower();
}
}

View file

@ -0,0 +1,4 @@
module riscv.gen.isa.custom.riscv_custom_instr_enum;
//TODO custom instruction added
// CUSTOM_i,

View file

@ -0,0 +1,41 @@
module riscv.gen.isa;
public import riscv.gen.isa.riscv_amo_instr;
public import riscv.gen.isa.riscv_b_instr;
public import riscv.gen.isa.riscv_zba_instr;
public import riscv.gen.isa.riscv_zbb_instr;
public import riscv.gen.isa.riscv_zbc_instr;
public import riscv.gen.isa.riscv_zbs_instr;
public import riscv.gen.isa.riscv_compressed_instr;
public import riscv.gen.isa.riscv_floating_point_instr;
public import riscv.gen.isa.riscv_instr;
public import riscv.gen.isa.riscv_vector_instr;
public import riscv.gen.isa.riscv_instr_register;
public import riscv.gen.isa.rv128c_instr;
public import riscv.gen.isa.rv32a_instr;
public import riscv.gen.isa.rv32b_instr;
public import riscv.gen.isa.rv32c_instr;
public import riscv.gen.isa.rv32dc_instr;
public import riscv.gen.isa.rv32d_instr;
public import riscv.gen.isa.rv32fc_instr;
public import riscv.gen.isa.rv32f_instr;
public import riscv.gen.isa.rv32i_instr;
public import riscv.gen.isa.rv32m_instr;
public import riscv.gen.isa.rv32v_instr;
public import riscv.gen.isa.rv64a_instr;
public import riscv.gen.isa.rv64b_instr;
public import riscv.gen.isa.rv64c_instr;
public import riscv.gen.isa.rv64d_instr;
public import riscv.gen.isa.rv64f_instr;
public import riscv.gen.isa.rv64i_instr;
public import riscv.gen.isa.rv64m_instr;
public import riscv.gen.isa.rv64zba_instr;
public import riscv.gen.isa.rv64zbb_instr;
public import riscv.gen.isa.rv32zba_instr;
public import riscv.gen.isa.rv32zbb_instr;
public import riscv.gen.isa.rv32zbc_instr;
public import riscv.gen.isa.rv32zbs_instr;
public import riscv.gen.isa.custom.riscv_custom_instr;
public import riscv.gen.isa.custom.riscv_custom_instr_enum;

View file

@ -0,0 +1,93 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_amo_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t, format_string,
riscv_instr_name_t, MAX_INSTR_STR_LEN;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import esdl.rand: constraint, rand;
import uvm;
class riscv_amo_instr: riscv_instr
{
mixin uvm_object_utils;
@rand bool aq;
@rand bool rl;
constraint! q{
(aq && rl) == false;
} aq_rl_c;
this(string name = "") {
super(name);
}
override string get_instr_name() {
import std.conv: to;
string instr_name_str = instr_name.to!string();
if (group == riscv_instr_group_t.RV32A) {
instr_name_str = instr_name_str[0..$ - 2] ~ ".w";
instr_name_str = aq ? instr_name_str ~ ".aq" :
rl ? instr_name_str ~ ".rl" : instr_name_str;
}
else if (group == riscv_instr_group_t.RV64A) {
instr_name_str = instr_name_str[0..$ - 2] ~ ".d";
instr_name_str = aq ? instr_name_str ~ ".aq" :
rl ? instr_name_str ~ ".rl" : instr_name_str;
}
else {
uvm_fatal(get_full_name(), format("Unexpected amo instr group: %0s / %0s",
group, instr_name));
}
return instr_name_str;
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
import std.string: toLower;
string asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
if (group.inside(riscv_instr_group_t.RV32A, riscv_instr_group_t.RV64A)) {
if (instr_name.inside(riscv_instr_name_t.LR_W, riscv_instr_name_t.LR_D)) {
asm_str = format("%0s %0s, (%0s)", asm_str, rd, rs1);
}
else {
asm_str = format("%0s %0s, %0s, (%0s)", asm_str, rd, rs2, rs1);
}
}
else {
uvm_fatal(get_full_name(), format("Unexpected amo instr group: %0s / %0s",
group, instr_name));
}
if(comment != "")
asm_str ~= " #" ~ comment;
return asm_str.toLower();
}
override void do_copy(uvm_object rhs) {
super.copy(rhs);
riscv_amo_instr rhs_ = cast(riscv_amo_instr) rhs;
assert (rhs_ !is null);
this.aq = rhs_.aq;
this.rl = rhs_.rl;
}
}

View file

@ -0,0 +1,495 @@
/*
* Copyright 2019 Google LLC
* Copyright 2019 Mellanox Technologies Ltd
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_b_instr;
import riscv.gen.riscv_instr_pkg: riscv_reg_t, riscv_instr_name_t, b_ext_group_t,
riscv_instr_category_t, riscv_instr_format_t, riscv_instr_group_t,
MAX_INSTR_STR_LEN, format_string;
import riscv.gen.target: XLEN;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import esdl.rand: rand;
import esdl.data.bvec: ubvec, toubvec, clog2;
import std.algorithm: canFind;
import std.string: toLower;
import uvm;
class riscv_b_instr: riscv_instr
{
mixin uvm_object_utils;
@rand riscv_reg_t rs3;
bool has_rs3 = false;
this(string name = "") {
super(name);
}
override void set_rand_mode() {
super.set_rand_mode();
has_rs3 = false;
switch (instr_format) {
case riscv_instr_format_t.R_FORMAT:
if ([riscv_instr_name_t.BMATFLIP, riscv_instr_name_t.CRC32_B,
riscv_instr_name_t.CRC32_H, riscv_instr_name_t.CRC32_W,
riscv_instr_name_t.CRC32C_B, riscv_instr_name_t.CRC32C_H,
riscv_instr_name_t.CRC32C_W, riscv_instr_name_t.CRC32_D,
riscv_instr_name_t.CRC32C_D].canFind(instr_name)) {
has_rs2 = false;
}
break;
case riscv_instr_format_t.R4_FORMAT:
has_imm = false;
has_rs3 = true;
break;
case riscv_instr_format_t.I_FORMAT:
has_rs2 = false;
if ([riscv_instr_name_t.FSRI,
riscv_instr_name_t.FSRIW].canFind(instr_name)) {
has_rs3 = true;
}
break;
default: break;
}
}
override void pre_randomize() {
super.pre_randomize();
rand_mode!q{rs3}(has_rs3);
}
override void set_imm_len() {
if ([riscv_instr_format_t.I_FORMAT].canFind(instr_format)) {
if ([riscv_instr_category_t.SHIFT,
riscv_instr_category_t.LOGICAL].canFind(category)) {
imm_len = toubvec!5(clog2(XLEN));
}
// ARITHMETIC RV32B
if ([riscv_instr_name_t.SHFLI,
riscv_instr_name_t.UNSHFLI].canFind(instr_name)) {
imm_len = toubvec!5(clog2(XLEN) - 1);
}
}
imm_mask <<= imm_len;
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
string asm_str_final, asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
switch (instr_format) {
case riscv_instr_format_t.I_FORMAT:
if ([riscv_instr_name_t.FSRI,
riscv_instr_name_t.FSRIW].canFind(instr_name)) { // instr rd,rs1,rs3,imm
asm_str_final = format("%0s%0s, %0s, %0s, %0s", asm_str, rd, rs1,
rs3, get_imm());
}
break;
case riscv_instr_format_t.R_FORMAT: //instr rd rs1
if (! has_rs2) {
asm_str_final = format("%0s%0s, %0s", asm_str, rd, rs1);
}
break;
case riscv_instr_format_t.R4_FORMAT: // instr rd,rs1,rs2,rs3
asm_str_final = format("%0s%0s, %0s, %0s, %0s", asm_str, rd, rs1,
rs2, rs3);
break;
default: uvm_info(get_full_name(), format("Unsupported format %0s", instr_format), UVM_LOW);
}
if (asm_str_final == "") {
return super.convert2asm(prefix);
}
if (comment != "") asm_str_final ~= " #" ~ comment;
return asm_str_final.toLower();
}
override ubvec!7 get_opcode() {
switch (instr_name) {
case riscv_instr_name_t.GORC,
riscv_instr_name_t.SLO,
riscv_instr_name_t.SRO,
riscv_instr_name_t.GREV,
riscv_instr_name_t.XPERM_N,
riscv_instr_name_t.XPERM_B,
riscv_instr_name_t.XPERM_H,
riscv_instr_name_t.XPERM_W: return toubvec!7(0b0110011);
case riscv_instr_name_t.GORCI,
riscv_instr_name_t.SLOI,
riscv_instr_name_t.SROI,
riscv_instr_name_t.GREVI,
riscv_instr_name_t.CMIX,
riscv_instr_name_t.CMOV,
riscv_instr_name_t.FSL: return toubvec!7(0b0010011);
case riscv_instr_name_t.FSR,
riscv_instr_name_t.FSRI,
riscv_instr_name_t.BMATFLIP,
riscv_instr_name_t.CRC32_B,
riscv_instr_name_t.CRC32_H,
riscv_instr_name_t.CRC32_W,
riscv_instr_name_t.CRC32C_B,
riscv_instr_name_t.CRC32C_H: return toubvec!7(0b0010011);
case riscv_instr_name_t.CRC32C_W,
riscv_instr_name_t.CRC32_D,
riscv_instr_name_t.CRC32C_D: return toubvec!7(0b0010011);
case riscv_instr_name_t.SHFL,
riscv_instr_name_t.UNSHFL,
riscv_instr_name_t.BCOMPRESS,
riscv_instr_name_t.BDECOMPRESS,
riscv_instr_name_t.PACK,
riscv_instr_name_t.PACKU,
riscv_instr_name_t.BMATOR,
riscv_instr_name_t.BMATXOR,
riscv_instr_name_t.PACKH,
riscv_instr_name_t.BFP: return toubvec!7(0b0110011);
case riscv_instr_name_t.SHFLI,
riscv_instr_name_t.UNSHFLI: return toubvec!7(0b0010011);
case riscv_instr_name_t.SLOW,
riscv_instr_name_t.SROW,
riscv_instr_name_t.GORCW,
riscv_instr_name_t.GREVW: return toubvec!7(0b0111011);
case riscv_instr_name_t.SLOIW,
riscv_instr_name_t.SROIW,
riscv_instr_name_t.GORCIW,
riscv_instr_name_t.GREVIW: return toubvec!7(0b0011011);
case riscv_instr_name_t.FSLW,
riscv_instr_name_t.FSRW: return toubvec!7(0b0111011);
case riscv_instr_name_t.FSRIW: return toubvec!7(0b0011011);
case riscv_instr_name_t.SHFLW,
riscv_instr_name_t.UNSHFLW,
riscv_instr_name_t.BCOMPRESSW,
riscv_instr_name_t.BDECOMPRESSW,
riscv_instr_name_t.PACKW,
riscv_instr_name_t.PACKUW,
riscv_instr_name_t.BFPW: return toubvec!7(0b0111011);
default: return super.get_opcode();
}
}
override ubvec!3 get_func3() {
switch (instr_name) {
case riscv_instr_name_t.GORC: return toubvec!3(0b101);
case riscv_instr_name_t.GORCI: return toubvec!3(0b101);
case riscv_instr_name_t.SLO: return toubvec!3(0b001);
case riscv_instr_name_t.SRO: return toubvec!3(0b101);
case riscv_instr_name_t.SLOI: return toubvec!3(0b001);
case riscv_instr_name_t.SROI: return toubvec!3(0b101);
case riscv_instr_name_t.GREV: return toubvec!3(0b101);
case riscv_instr_name_t.GREVI: return toubvec!3(0b101);
case riscv_instr_name_t.CMIX: return toubvec!3(0b001);
case riscv_instr_name_t.CMOV: return toubvec!3(0b101);
case riscv_instr_name_t.FSL: return toubvec!3(0b001);
case riscv_instr_name_t.FSR: return toubvec!3(0b101);
case riscv_instr_name_t.FSRI: return toubvec!3(0b101);
case riscv_instr_name_t.BMATFLIP: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32_B: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32_H: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32_W: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32C_B: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32C_H: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32C_W: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32_D: return toubvec!3(0b001);
case riscv_instr_name_t.CRC32C_D: return toubvec!3(0b001);
case riscv_instr_name_t.SHFL: return toubvec!3(0b001);
case riscv_instr_name_t.UNSHFL: return toubvec!3(0b101);
case riscv_instr_name_t.BCOMPRESS: return toubvec!3(0b110);
case riscv_instr_name_t.BDECOMPRESS: return toubvec!3(0b110);
case riscv_instr_name_t.PACK: return toubvec!3(0b100);
case riscv_instr_name_t.PACKU: return toubvec!3(0b100);
case riscv_instr_name_t.BMATOR: return toubvec!3(0b011);
case riscv_instr_name_t.BMATXOR: return toubvec!3(0b011);
case riscv_instr_name_t.PACKH: return toubvec!3(0b111);
case riscv_instr_name_t.BFP: return toubvec!3(0b111);
case riscv_instr_name_t.SHFLI: return toubvec!3(0b001);
case riscv_instr_name_t.UNSHFLI: return toubvec!3(0b101);
case riscv_instr_name_t.SLOW: return toubvec!3(0b001);
case riscv_instr_name_t.SROW: return toubvec!3(0b101);
case riscv_instr_name_t.ROLW: return toubvec!3(0b001);
case riscv_instr_name_t.GORCW: return toubvec!3(0b101);
case riscv_instr_name_t.GREVW: return toubvec!3(0b101);
case riscv_instr_name_t.SLOIW: return toubvec!3(0b001);
case riscv_instr_name_t.SROIW: return toubvec!3(0b101);
case riscv_instr_name_t.RORIW: return toubvec!3(0b101);
case riscv_instr_name_t.GORCIW: return toubvec!3(0b101);
case riscv_instr_name_t.GREVIW: return toubvec!3(0b101);
case riscv_instr_name_t.FSLW: return toubvec!3(0b001);
case riscv_instr_name_t.FSRW: return toubvec!3(0b101);
case riscv_instr_name_t.FSRIW: return toubvec!3(0b101);
case riscv_instr_name_t.SHFLW: return toubvec!3(0b001);
case riscv_instr_name_t.UNSHFLW: return toubvec!3(0b101);
case riscv_instr_name_t.BCOMPRESSW: return toubvec!3(0b110);
case riscv_instr_name_t.BDECOMPRESSW: return toubvec!3(0b110);
case riscv_instr_name_t.PACKW: return toubvec!3(0b100);
case riscv_instr_name_t.PACKUW: return toubvec!3(0b100);
case riscv_instr_name_t.BFPW: return toubvec!3(0b111);
case riscv_instr_name_t.XPERM_N: return toubvec!3(0b010);
case riscv_instr_name_t.XPERM_B: return toubvec!3(0b100);
case riscv_instr_name_t.XPERM_H: return toubvec!3(0b110);
case riscv_instr_name_t.XPERM_W: return toubvec!3(0b000);
default: return super.get_func3();
}
}
override ubvec!7 get_func7() {
switch (instr_name) {
case riscv_instr_name_t.ANDN: return toubvec!7(0b0100000);
case riscv_instr_name_t.ORN: return toubvec!7(0b0100000);
case riscv_instr_name_t.XNOR: return toubvec!7(0b0100000);
case riscv_instr_name_t.GORC: return toubvec!7(0b0010100);
case riscv_instr_name_t.SLO: return toubvec!7(0b0010000);
case riscv_instr_name_t.SRO: return toubvec!7(0b0010000);
case riscv_instr_name_t.ROL: return toubvec!7(0b0110000);
case riscv_instr_name_t.ROR: return toubvec!7(0b0110000);
case riscv_instr_name_t.GREV: return toubvec!7(0b0110100);
case riscv_instr_name_t.BMATFLIP: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32_B: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32_H: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32_W: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32C_B: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32C_H: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32C_W: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32_D: return toubvec!7(0b0110000);
case riscv_instr_name_t.CRC32C_D: return toubvec!7(0b0110000);
case riscv_instr_name_t.SHFL: return toubvec!7(0b0000100);
case riscv_instr_name_t.UNSHFL: return toubvec!7(0b0000100);
case riscv_instr_name_t.BCOMPRESS: return toubvec!7(0b0000100);
case riscv_instr_name_t.BDECOMPRESS: return toubvec!7(0b0100100);
case riscv_instr_name_t.PACK: return toubvec!7(0b0000100);
case riscv_instr_name_t.PACKU: return toubvec!7(0b0100100);
case riscv_instr_name_t.BMATOR: return toubvec!7(0b0000100);
case riscv_instr_name_t.BMATXOR: return toubvec!7(0b0100100);
case riscv_instr_name_t.PACKH: return toubvec!7(0b0000100);
case riscv_instr_name_t.BFP: return toubvec!7(0b0100100);
case riscv_instr_name_t.SLOW: return toubvec!7(0b0010000);
case riscv_instr_name_t.SROW: return toubvec!7(0b0010000);
case riscv_instr_name_t.GORCW: return toubvec!7(0b0010100);
case riscv_instr_name_t.GORCIW: return toubvec!7(0b0010100);
case riscv_instr_name_t.GREVW: return toubvec!7(0b0110100);
case riscv_instr_name_t.GREVIW: return toubvec!7(0b0110100);
case riscv_instr_name_t.SLOIW: return toubvec!7(0b0010000);
case riscv_instr_name_t.SROIW: return toubvec!7(0b0010000);
case riscv_instr_name_t.SHFLW: return toubvec!7(0b0000100);
case riscv_instr_name_t.UNSHFLW: return toubvec!7(0b0000100);
case riscv_instr_name_t.BCOMPRESSW: return toubvec!7(0b0000100);
case riscv_instr_name_t.BDECOMPRESSW: return toubvec!7(0b0100100);
case riscv_instr_name_t.PACKW: return toubvec!7(0b0000100);
case riscv_instr_name_t.PACKUW: return toubvec!7(0b0100100);
case riscv_instr_name_t.BFPW: return toubvec!7(0b0100100);
case riscv_instr_name_t.XPERM_N: return toubvec!7(0b0010100);
case riscv_instr_name_t.XPERM_B: return toubvec!7(0b0010100);
case riscv_instr_name_t.XPERM_H: return toubvec!7(0b0010100);
case riscv_instr_name_t.XPERM_W: return toubvec!7(0b0010100);
default: return super.get_func7();
}
}
ubvec!5 get_func5() {
switch (instr_name) {
case riscv_instr_name_t.SLOI: return toubvec!5(0b00100);
case riscv_instr_name_t.SROI: return toubvec!5(0b00100);
case riscv_instr_name_t.RORI: return toubvec!5(0b01100);
case riscv_instr_name_t.GORCI: return toubvec!5(0b00101);
case riscv_instr_name_t.GREVI: return toubvec!5(0b01101);
case riscv_instr_name_t.CRC32_B: return toubvec!5(0b10000);
case riscv_instr_name_t.CRC32_H: return toubvec!5(0b10001);
case riscv_instr_name_t.CRC32_W: return toubvec!5(0b10010);
case riscv_instr_name_t.CRC32C_B: return toubvec!5(0b11000);
case riscv_instr_name_t.CRC32C_H: return toubvec!5(0b11001);
case riscv_instr_name_t.CRC32C_W: return toubvec!5(0b11010);
case riscv_instr_name_t.CRC32_D: return toubvec!5(0b10011);
case riscv_instr_name_t.CRC32C_D: return toubvec!5(0b11011);
case riscv_instr_name_t.BMATFLIP: return toubvec!5(0b00011);
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
ubvec!2 get_func2() {
switch (instr_name) {
case riscv_instr_name_t.CMIX: return toubvec!2(0b11);
case riscv_instr_name_t.CMOV: return toubvec!2(0b11);
case riscv_instr_name_t.FSL: return toubvec!2(0b10);
case riscv_instr_name_t.FSR: return toubvec!2(0b10);
case riscv_instr_name_t.FSLW: return toubvec!2(0b10);
case riscv_instr_name_t.FSRW: return toubvec!2(0b10);
case riscv_instr_name_t.FSRIW: return toubvec!2(0b10);
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
// Convert the instruction to assembly code
override string convert2bin(string prefix = "") {
string binary = "";
switch (instr_format) {
case riscv_instr_format_t.R_FORMAT:
if ((category == riscv_instr_category_t.ARITHMETIC) &&
(group == riscv_instr_group_t.RV32B)) {
if ([riscv_instr_name_t.CRC32_B,
riscv_instr_name_t.CRC32_H,
riscv_instr_name_t.CRC32_W,
riscv_instr_name_t.CRC32C_B,
riscv_instr_name_t.CRC32C_H,
riscv_instr_name_t.CRC32C_W].canFind(instr_name)) {
binary =
format("%8h", get_func7() ~ get_func5() ~ toubvec!5(rs1) ~ get_func3() ~
toubvec!5(rd) ~ get_opcode());
}
}
if ((category == riscv_instr_category_t.ARITHMETIC) &&
(group == riscv_instr_group_t.RV64B)) {
if ([riscv_instr_name_t.CRC32_D,
riscv_instr_name_t.CRC32C_D,
riscv_instr_name_t.BMATFLIP].canFind(instr_name)) {
binary =
format("%8h", get_func7() ~ get_func5() ~ toubvec!5(rs1) ~ get_func3() ~
toubvec!5(rd) ~ get_opcode());
}
}
break;
case riscv_instr_format_t.I_FORMAT:
if (([riscv_instr_category_t.SHIFT,
riscv_instr_category_t.LOGICAL].canFind(category)) &&
(group == riscv_instr_group_t.RV32B)) {
binary = format("%8h", get_func5() ~ cast(ubvec!7) imm[0..7] ~ toubvec!5(rs1) ~
get_func3() ~ toubvec!5(rd) ~ get_opcode());
}
else if (([riscv_instr_category_t.SHIFT,
riscv_instr_category_t.LOGICAL].canFind(category)) &&
(group == riscv_instr_group_t.RV64B)) {
binary = format("%8h", get_func7() ~ cast(ubvec!5) imm[0..5] ~ toubvec!5(rs1) ~
get_func3() ~ toubvec!5(rd) ~ get_opcode());
}
if ([riscv_instr_name_t.FSRI].canFind(instr_name)) {
binary = format("%8h", toubvec!5(rs3) ~ toubvec!1(0b1) ~ cast(ubvec!6) imm[0..6] ~
toubvec!5(rs1) ~ get_func3() ~ toubvec!5(rd) ~ get_opcode());
}
if (([riscv_instr_category_t.ARITHMETIC].canFind(category)) &&
(group == riscv_instr_group_t.RV32B)) {
binary = format("%8h", toubvec!6(0b00_0010) ~ cast(ubvec!6) (imm[0..6]) ~
toubvec!5(rs1) ~ get_func3() ~ toubvec!5(rd) ~ get_opcode());
}
if (([riscv_instr_category_t.ARITHMETIC].canFind(category)) &&
(group == riscv_instr_group_t.RV64B)) {
binary = format("%8h", cast(ubvec!12) imm[0..12] ~ toubvec!5(rs1) ~ get_func3() ~
toubvec!5(rd) ~ get_opcode());
}
break;
case riscv_instr_format_t.R4_FORMAT:
binary = format("%8h", toubvec!5(rs3) ~ get_func2() ~ toubvec!5(rs2) ~ toubvec!5(rs1) ~
get_func3() ~ toubvec!5(rd) ~ get_opcode());
break;
default:
if (binary == "") binary = super.convert2bin(prefix);
}
return prefix ~ binary;
}
override void do_copy(uvm_object rhs) {
super.copy(rhs);
riscv_b_instr rhs_ = cast(riscv_b_instr) rhs;
assert (rhs_ !is null);
this.rs3 = rhs_.rs3;
this.has_rs3 = rhs_.has_rs3;
}
override bool is_supported(riscv_instr_gen_config cfg) {
return cfg.enable_b_extension &&
(((canFind(cfg.enable_bitmanip_groups, b_ext_group_t.ZBP)) &&
[riscv_instr_name_t.GREV, riscv_instr_name_t.GREVW,
riscv_instr_name_t.GREVI, riscv_instr_name_t.GREVIW,
riscv_instr_name_t.GORC, riscv_instr_name_t.GORCW,
riscv_instr_name_t.GORCI, riscv_instr_name_t.GORCIW,
riscv_instr_name_t.SHFL, riscv_instr_name_t.SHFLW,
riscv_instr_name_t.UNSHFL, riscv_instr_name_t.UNSHFLW,
riscv_instr_name_t.SHFLI, riscv_instr_name_t.UNSHFLI,
riscv_instr_name_t.XPERM_N, riscv_instr_name_t.XPERM_B,
riscv_instr_name_t.XPERM_H, riscv_instr_name_t.XPERM_W,
riscv_instr_name_t.SLO, riscv_instr_name_t.SLOW,
riscv_instr_name_t.SLOI, riscv_instr_name_t.SLOIW,
riscv_instr_name_t.SRO, riscv_instr_name_t.SROW,
riscv_instr_name_t.SROI, riscv_instr_name_t.SROIW].canFind(instr_name)) ||
((canFind(cfg.enable_bitmanip_groups, b_ext_group_t.ZBE)) &&
[riscv_instr_name_t.BCOMPRESS, riscv_instr_name_t.BDECOMPRESS,
riscv_instr_name_t.BCOMPRESSW, riscv_instr_name_t.BDECOMPRESSW].canFind(instr_name)) ||
((canFind(cfg.enable_bitmanip_groups, b_ext_group_t.ZBF)) &&
[riscv_instr_name_t.BFP, riscv_instr_name_t.BFPW].canFind(instr_name)) ||
((canFind(cfg.enable_bitmanip_groups, b_ext_group_t.ZBR)) &&
[riscv_instr_name_t.CRC32_B, riscv_instr_name_t.CRC32_H,
riscv_instr_name_t.CRC32_W, riscv_instr_name_t.CRC32_D,
riscv_instr_name_t.CRC32C_B, riscv_instr_name_t.CRC32C_H,
riscv_instr_name_t.CRC32C_W, riscv_instr_name_t.CRC32C_D].canFind(instr_name)) ||
((canFind(cfg.enable_bitmanip_groups, b_ext_group_t.ZBM)) &&
[riscv_instr_name_t.BMATOR, riscv_instr_name_t.BMATXOR,
riscv_instr_name_t.BMATFLIP].canFind(instr_name)) ||
((canFind(cfg.enable_bitmanip_groups, b_ext_group_t.ZBT)) &&
[riscv_instr_name_t.CMOV, riscv_instr_name_t.CMIX,
riscv_instr_name_t.FSL, riscv_instr_name_t.FSLW,
riscv_instr_name_t.FSR, riscv_instr_name_t.FSRW,
riscv_instr_name_t.FSRI, riscv_instr_name_t.FSRIW].canFind(instr_name)));
}
// // coverage related functons
// void update_src_regs(string[] operands) {
// // handle special I_FORMAT (FSRI, FSRIW) and R4_FORMAT
// switch(instr_format) {
// case riscv_instr_format_t.I_FORMAT:
// if ([riscv_instr_name_t.FSRI, riscv_instr_name_t.FSRIW].canFind(instr_name)) {
// assert (operands.length == 4);
// // fsri rd, rs1, rs3, imm
// rs1 = get_gpr(operands[1]);
// rs1_value = get_gpr_state(operands[1]);
// rs3 = get_gpr(operands[2]);
// rs3_value = get_gpr_state(operands[2]);
// get_val(operands[3], imm);
// return;
// }
// break;
// case riscv_instr_format_t.R4_FORMAT:
// assert (operands.length == 4);
// rs1 = get_gpr(operands[1]);
// rs1_value = get_gpr_state(operands[1]);
// rs2 = get_gpr(operands[2]);
// rs2_value = get_gpr_state(operands[2]);
// rs3 = get_gpr(operands[3]);
// rs3_value = get_gpr_state(operands[3]);
// return;
// default: break;
// }
// // reuse base function to handle the other instructions
// super.update_src_regs(operands);
// }
}

View file

@ -0,0 +1,561 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_compressed_instr;
import riscv.gen.riscv_instr_pkg: format_string, riscv_instr_name_t, MAX_INSTR_STR_LEN,
riscv_instr_format_t, riscv_reg_t, riscv_instr_category_t, imm_t;
import riscv.gen.target: XLEN;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import esdl.rand: constraint, rand;
import esdl.data.bvec: ubvec, toubvec;
import uvm;
class riscv_compressed_instr: riscv_instr
{
mixin uvm_object_utils;
int imm_align;
constraint! q{
// Registers specified by the three-bit rs1, rs2, and rd
if (instr_format inside [riscv_instr_format_t.CIW_FORMAT,
riscv_instr_format_t.CL_FORMAT,
riscv_instr_format_t.CS_FORMAT,
riscv_instr_format_t.CB_FORMAT,
riscv_instr_format_t.CA_FORMAT]) {
if (has_rs1) {
rs1 inside [riscv_reg_t.S0:riscv_reg_t.A5];
}
if (has_rs2) {
rs2 inside [riscv_reg_t.S0:riscv_reg_t.A5];
}
if (has_rd) {
rd inside [riscv_reg_t.S0:riscv_reg_t.A5];
}
}
// C_ADDI16SP is only valid when rd == SP
if (instr_name == riscv_instr_name_t.C_ADDI16SP) {
rd == riscv_reg_t.SP;
}
if (instr_name inside [riscv_instr_name_t.C_JR, riscv_instr_name_t.C_JALR]) {
rs2 == riscv_reg_t.ZERO;
rs1 != riscv_reg_t.ZERO;
}
} rvc_csr_c ;
constraint! q{
if(imm_type inside [imm_t.NZIMM, imm_t.NZUIMM]) {
imm[0..6] != 0;
if (instr_name == riscv_instr_name_t.C_LUI) {
// TODO(taliu) Check why bit 6 cannot be zero
imm[5..32] == 0;
}
if (instr_name inside [riscv_instr_name_t.C_SRAI,
riscv_instr_name_t.C_SRLI,
riscv_instr_name_t.C_SLLI]) {
imm[5..32] == 0;
}
}
if (instr_name == riscv_instr_name_t.C_ADDI4SPN) {
imm[0..2] == 0;
}
} imm_val_c ;
// C_JAL is RV32C only instruction
constraint! q{
if (XLEN != 32) {
instr_name != riscv_instr_name_t.C_JAL;
}
} jal_c ;
// Avoid generating HINT or illegal instruction by default as it's not supported by the compiler
constraint! q{
if (instr_name inside [riscv_instr_name_t.C_ADDI, riscv_instr_name_t.C_ADDIW,
riscv_instr_name_t.C_LI, riscv_instr_name_t.C_LUI,
riscv_instr_name_t.C_SLLI, riscv_instr_name_t.C_SLLI64,
riscv_instr_name_t.C_LQSP, riscv_instr_name_t.C_LDSP,
riscv_instr_name_t.C_MV, riscv_instr_name_t.C_ADD,
riscv_instr_name_t.C_LWSP]) {
rd != riscv_reg_t.ZERO;
}
if (instr_name == riscv_instr_name_t.C_JR) {
rs1 != riscv_reg_t.ZERO;
}
if (instr_name inside [riscv_instr_name_t.C_ADD, riscv_instr_name_t.C_MV]) {
rs2 != riscv_reg_t.ZERO;
}
(instr_name == riscv_instr_name_t.C_LUI) -> (rd != riscv_reg_t.SP);
} no_hint_illegal_instr_c ;
this(string name = "") {
super(name);
rs1 = riscv_reg_t.S0;
rs2 = riscv_reg_t.S0;
rd = riscv_reg_t.S0;
is_compressed = true;
}
override void set_imm_len() {
if ( instr_format.inside(riscv_instr_format_t.CI_FORMAT, riscv_instr_format_t.CSS_FORMAT)) {
imm_len = toubvec!5(6);
}
else if (instr_format.inside(riscv_instr_format_t.CL_FORMAT, riscv_instr_format_t.CS_FORMAT)) {
imm_len = toubvec!5(5);
}
else if (instr_format == riscv_instr_format_t.CJ_FORMAT) {
imm_len = toubvec!5(11);
}
else if (instr_format == riscv_instr_format_t.CB_FORMAT) {
if (instr_name == riscv_instr_name_t.C_ANDI) {
imm_len = toubvec!5(6);
}
else {
imm_len = toubvec!5(7);
}
}
else if (instr_format.inside(riscv_instr_format_t.CB_FORMAT, riscv_instr_format_t.CIW_FORMAT)) {
imm_len = toubvec!5(8);
}
if (instr_name.inside(riscv_instr_name_t.C_SQ, riscv_instr_name_t.C_LQ,
riscv_instr_name_t.C_LQSP, riscv_instr_name_t.C_SQSP,
riscv_instr_name_t.C_ADDI16SP)) {
imm_align = 4;
}
else if (instr_name.inside(riscv_instr_name_t.C_SD, riscv_instr_name_t.C_LD,
riscv_instr_name_t.C_LDSP, riscv_instr_name_t.C_SDSP)) {
imm_align = 3;
}
else if (instr_name.inside(riscv_instr_name_t.C_SW, riscv_instr_name_t.C_LW,
riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_SWSP,
riscv_instr_name_t.C_ADDI4SPN)) {
imm_align = 2;
}
else if (instr_name == riscv_instr_name_t.C_LUI) {
imm_align = 12;
}
else if (instr_name.inside(riscv_instr_name_t.C_J, riscv_instr_name_t.C_JAL,
riscv_instr_name_t.C_BNEZ, riscv_instr_name_t.C_BEQZ)) {
imm_align = 1;
}
}
override void do_copy(uvm_object rhs) {
riscv_compressed_instr rhs_;
super.copy(rhs);
rhs_ = cast(riscv_compressed_instr) rhs;
assert (rhs_ !is null);
this.imm_align = rhs_.imm_align;
}
override void extend_imm() {
if (instr_name != riscv_instr_name_t.C_LUI) {
super.extend_imm();
imm = imm << imm_align;
}
}
override void set_rand_mode() {
switch (instr_format) {
case riscv_instr_format_t.CR_FORMAT :
if (category == riscv_instr_category_t.JUMP) {
has_rd = false;
}
else {
has_rs1 = false;
}
has_imm = false;
break;
case riscv_instr_format_t.CSS_FORMAT :
has_rs1 = false;
has_rd = false;
break;
case riscv_instr_format_t.CL_FORMAT :
has_rs2 = false;
break;
case riscv_instr_format_t.CS_FORMAT :
has_rd = false;
break;
case riscv_instr_format_t.CA_FORMAT :
has_rs1 = false;
has_imm = false;
break;
case riscv_instr_format_t.CI_FORMAT, riscv_instr_format_t.CIW_FORMAT:
has_rs1 = false;
has_rs2 = false;
break;
case riscv_instr_format_t.CJ_FORMAT :
has_rs1 = false;
has_rs2 = false;
has_rd = false;
break;
case riscv_instr_format_t.CB_FORMAT :
if (instr_name != riscv_instr_name_t.C_ANDI) has_rd = false;
has_rs2 = false;
break;
default : break;
}
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
import std.string: toLower;
string asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
if (category != riscv_instr_category_t.SYSTEM) {
switch(instr_format) {
case riscv_instr_format_t.CI_FORMAT,
riscv_instr_format_t.CIW_FORMAT :
if (instr_name == riscv_instr_name_t.C_NOP)
asm_str = "c.nop";
else if (instr_name == riscv_instr_name_t.C_ADDI16SP)
asm_str = format("%0ssp, %0s", asm_str, get_imm());
else if (instr_name == riscv_instr_name_t.C_ADDI4SPN)
asm_str = format("%0s%0s, sp, %0s", asm_str, rd, get_imm());
else if (instr_name.inside(riscv_instr_name_t.C_LDSP, riscv_instr_name_t.C_LWSP,
riscv_instr_name_t.C_LQSP))
asm_str = format("%0s%0s, %0s(sp)", asm_str, rd, get_imm());
else
asm_str = format("%0s%0s, %0s", asm_str, rd, get_imm());
break;
case riscv_instr_format_t.CL_FORMAT :
asm_str = format("%0s%0s, %0s(%0s)", asm_str, rd, get_imm(), rs1);
break;
case riscv_instr_format_t.CS_FORMAT:
if (category == riscv_instr_category_t.STORE)
asm_str = format("%0s%0s, %0s(%0s)", asm_str, rs2, get_imm(), rs1);
else
asm_str = format("%0s%0s, %0s", asm_str, rs1, rs2);
break;
case riscv_instr_format_t.CA_FORMAT :
asm_str = format("%0s%0s, %0s", asm_str, rd, rs2);
break;
case riscv_instr_format_t.CB_FORMAT:
asm_str = format("%0s%0s, %0s", asm_str, rs1, get_imm());
break;
case riscv_instr_format_t.CSS_FORMAT:
if (category == riscv_instr_category_t.STORE)
asm_str = format("%0s%0s, %0s(sp)", asm_str, rs2, get_imm());
else
asm_str = format("%0s%0s, %0s", asm_str, rs2, get_imm());
break;
case riscv_instr_format_t.CR_FORMAT:
if (instr_name.inside(riscv_instr_name_t.C_JR, riscv_instr_name_t.C_JALR)) {
asm_str = format("%0s%0s", asm_str, rs1);
}
else {
asm_str = format("%0s%0s, %0s", asm_str, rd, rs2);
}
break;
case riscv_instr_format_t.CJ_FORMAT:
asm_str = format("%0s%0s", asm_str, get_imm());
break;
default: uvm_info(get_full_name(),
format("Unsupported format %0s", instr_format), UVM_LOW);
break;
}
}
else {
// For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
// This is needed to resume execution from epc+4 after ebreak handling
if (instr_name == riscv_instr_name_t.C_EBREAK) {
asm_str = "c.ebreak; c.nop;";
}
}
if (comment != "")
asm_str = asm_str ~ " #" ~ comment ;
return asm_str.toLower();
}
// Convert the instruction to assembly code
override string convert2bin(string prefix = "") {
string binary;
switch (instr_name) {
case riscv_instr_name_t.C_ADDI4SPN :
binary = format("%4h", (get_func3() ~ cast(ubvec!2) imm[4..6] ~ cast(ubvec!4) imm[6..10] ~
imm[2] ~ imm[3] ~ get_c_gpr(rd) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_LQ:
binary = format("%4h", (get_func3() ~ cast(ubvec!2) imm[4..6] ~ imm[8] ~
get_c_gpr(rs1) ~ cast(ubvec!2) imm[6..8] ~ get_c_gpr(rd) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_FLD, riscv_instr_name_t.C_LD:
binary = format("%4h", (get_func3() ~ cast(ubvec!3) imm[3..6] ~ get_c_gpr(rs1) ~
cast(ubvec!2) imm[6..8] ~ get_c_gpr(rd) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_LW, riscv_instr_name_t.C_FLW:
binary = format("%4h", (get_func3() ~ cast(ubvec!3) imm[3..6] ~ get_c_gpr(rs1) ~
imm[2] ~ imm[6] ~ get_c_gpr(rd) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SQ:
binary = format("%4h", (get_func3() ~ cast(ubvec!2) imm[4..6] ~ imm[8] ~
get_c_gpr(rs1) ~ cast(ubvec!2) imm[6..8] ~ get_c_gpr(rs2) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_FSD, riscv_instr_name_t.C_SD:
binary = format("%4h", (get_func3() ~ cast(ubvec!3) imm[3..6] ~ get_c_gpr(rs1) ~
cast(ubvec!2) imm[6..8] ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SW, riscv_instr_name_t.C_FSW:
binary = format("%4h", (get_func3() ~ cast(ubvec!3) imm[3..6] ~ get_c_gpr(rs1) ~
imm[2] ~ imm[6] ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_NOP, riscv_instr_name_t.C_ADDI,
riscv_instr_name_t.C_LI, riscv_instr_name_t.C_ADDIW:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!5(rd) ~ cast(ubvec!5) imm[0..5] ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_JAL, riscv_instr_name_t.C_J:
binary = format("%4h", (get_func3() ~ imm[11] ~ imm[4] ~ cast(ubvec!2) imm[8..10] ~
imm[10] ~ imm[6] ~ imm[7] ~ cast(ubvec!3) imm[1..4] ~ imm[5] ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_ADDI16SP:
binary = format("%4h", (get_func3() ~ imm[9] ~ toubvec!5(0b10) ~
imm[4] ~ imm[6] ~ cast(ubvec!2) imm[7..9] ~ imm[5] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_LUI:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!5(rd) ~ cast(ubvec!5) imm[0..5] ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_SRLI:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!2(0b0) ~ get_c_gpr(rd) ~
cast(ubvec!5) imm[0..5] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SRLI64:
binary = format("%4h", (get_func3() ~ toubvec!3(0b0) ~ get_c_gpr(rd) ~ toubvec!5(0b0) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_SRAI:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!2(0b01) ~ get_c_gpr(rd) ~
cast(ubvec!5) imm[0..5] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SRAI64:
binary = format("%4h", (get_func3() ~ toubvec!3(0b001) ~
get_c_gpr(rd) ~ toubvec!5(0b0) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_ANDI:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!2(0b10) ~ get_c_gpr(rd) ~
cast(ubvec!5) imm[0..5] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SUB:
binary = format("%4h", (get_func3() ~ toubvec!3(0b011) ~ get_c_gpr(rd) ~
toubvec!2(0b00) ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_XOR:
binary = format("%4h", (get_func3() ~ toubvec!3(0b011) ~ get_c_gpr(rd) ~
toubvec!2(0b01) ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_OR:
binary = format("%4h", (get_func3() ~ toubvec!3(0b011) ~ get_c_gpr(rd) ~
toubvec!2(0b10) ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_AND:
binary = format("%4h", (get_func3() ~ toubvec!3(0b011) ~ get_c_gpr(rd) ~
toubvec!2(0b11) ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SUBW:
binary = format("%4h", (get_func3() ~ toubvec!3(0b111) ~ get_c_gpr(rd) ~
toubvec!2(0b00) ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_ADDW:
binary = format("%4h", (get_func3() ~ toubvec!3(0b111) ~ get_c_gpr(rd) ~
toubvec!2(0b01) ~ get_c_gpr(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_BEQZ, riscv_instr_name_t.C_BNEZ:
binary = format("%4h", (get_func3() ~ imm[8] ~ cast(ubvec!2) imm[3..5] ~
get_c_gpr(rs1) ~ cast(ubvec!2) imm[6..8] ~ cast(ubvec!2) imm[1..3] ~
imm[5] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SLLI:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!5(rd) ~ cast(ubvec!5) imm[0..5] ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_SLLI64:
binary = format("%4h", (get_func3() ~ toubvec!1(0b0) ~ toubvec!5(rd) ~ toubvec!5(0b00000) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_FLDSP, riscv_instr_name_t.C_LDSP:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!5(rd) ~ cast(ubvec!2) imm[3..5] ~
cast(ubvec!3) imm[6..9] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_LQSP:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!5(rd) ~ imm[4] ~
cast(ubvec!4) imm[6..10] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_FLWSP:
binary = format("%4h", (get_func3() ~ imm[5] ~ toubvec!5(rd) ~ cast(ubvec!3) imm[2..5] ~
cast(ubvec!2) imm[6..8] ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_JR:
binary = format("%4h", (get_func3() ~ toubvec!1(0b0) ~ toubvec!5(rs1) ~ toubvec!5(0b0) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_MV:
binary = format("%4h", (get_func3() ~ toubvec!1(0b0) ~ toubvec!5(rd) ~ toubvec!5(rs2) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_EBREAK:
binary = format("%4h", (get_func3() ~ toubvec!1(0b1) ~ toubvec!10(0b0) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_JALR:
binary = format("%4h", (get_func3() ~ toubvec!1(0b1) ~ toubvec!10(0b0) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_ADD:
binary = format("%4h", (get_func3() ~ toubvec!1(0b1) ~ toubvec!5(rd) ~ toubvec!5(rs2) ~
get_c_opcode()));
break;
case riscv_instr_name_t.C_FSDSP, riscv_instr_name_t.C_SDSP:
binary = format("%4h", (get_func3() ~ cast(ubvec!3) imm[3..6] ~ cast(ubvec!3) imm[6..9] ~
toubvec!5(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SQSP :
binary = format("%4h", (get_func3() ~ cast(ubvec!2) imm[4..6] ~ cast(ubvec!4) imm[6..10] ~
toubvec!5(rs2) ~ get_c_opcode()));
break;
case riscv_instr_name_t.C_SWSP, riscv_instr_name_t.C_FSWSP :
binary = format("%4h", (get_func3() ~ cast(ubvec!4) imm[2..6] ~ cast(ubvec!2) imm[6..8] ~
toubvec!5(rs2) ~ get_c_opcode()));
break;
default : uvm_fatal(get_full_name(),
format("Unsupported instruction %0s", instr_name));
}
return prefix ~ binary;
}
// Get opcode for compressed instruction
// ubvec!2 get_c_opcode()
ubvec!2 get_c_opcode() {
switch(instr_name) {
case riscv_instr_name_t.C_ADDI4SPN,
riscv_instr_name_t.C_FLD,
riscv_instr_name_t.C_LQ,
riscv_instr_name_t.C_LW,
riscv_instr_name_t.C_FLW,
riscv_instr_name_t.C_LD,
riscv_instr_name_t.C_FSD,
riscv_instr_name_t.C_SQ,
riscv_instr_name_t.C_SW,
riscv_instr_name_t.C_FSW,
riscv_instr_name_t.C_SD : return toubvec!2(0b00);
case riscv_instr_name_t.C_NOP,
riscv_instr_name_t.C_ADDI,
riscv_instr_name_t.C_JAL,
riscv_instr_name_t.C_ADDIW,
riscv_instr_name_t.C_LI,
riscv_instr_name_t.C_ADDI16SP,
riscv_instr_name_t.C_LUI,
riscv_instr_name_t.C_SRLI,
riscv_instr_name_t.C_SRLI64,
riscv_instr_name_t.C_SRAI,
riscv_instr_name_t.C_SRAI64,
riscv_instr_name_t.C_ANDI,
riscv_instr_name_t.C_SUB,
riscv_instr_name_t.C_XOR,
riscv_instr_name_t.C_OR,
riscv_instr_name_t.C_AND,
riscv_instr_name_t.C_SUBW,
riscv_instr_name_t.C_ADDW,
riscv_instr_name_t.C_J,
riscv_instr_name_t.C_BEQZ,
riscv_instr_name_t.C_BNEZ : return toubvec!2(0b01);
case riscv_instr_name_t.C_SLLI,
riscv_instr_name_t.C_SLLI64,
riscv_instr_name_t.C_FLDSP,
riscv_instr_name_t.C_LQSP,
riscv_instr_name_t.C_LWSP,
riscv_instr_name_t.C_FLWSP,
riscv_instr_name_t.C_LDSP,
riscv_instr_name_t.C_JR,
riscv_instr_name_t.C_MV,
riscv_instr_name_t.C_EBREAK,
riscv_instr_name_t.C_JALR,
riscv_instr_name_t.C_ADD,
riscv_instr_name_t.C_FSDSP,
riscv_instr_name_t.C_SQSP,
riscv_instr_name_t.C_SWSP,
riscv_instr_name_t.C_FSWSP,
riscv_instr_name_t.C_SDSP : return toubvec!2(0b10);
default :
uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
//ubvec!3 get_func3()
override ubvec!3 get_func3() {
switch(instr_name) {
case riscv_instr_name_t.C_ADDI4SPN : return toubvec!3(0b000);
case riscv_instr_name_t.C_FLD : return toubvec!3(0b001);
case riscv_instr_name_t.C_LQ : return toubvec!3(0b001);
case riscv_instr_name_t.C_LW : return toubvec!3(0b010);
case riscv_instr_name_t.C_FLW : return toubvec!3(0b011);
case riscv_instr_name_t.C_LD : return toubvec!3(0b011);
case riscv_instr_name_t.C_FSD : return toubvec!3(0b101);
case riscv_instr_name_t.C_SQ : return toubvec!3(0b101);
case riscv_instr_name_t.C_SW : return toubvec!3(0b110);
case riscv_instr_name_t.C_FSW : return toubvec!3(0b111);
case riscv_instr_name_t.C_SD : return toubvec!3(0b111);
case riscv_instr_name_t.C_NOP : return toubvec!3(0b000);
case riscv_instr_name_t.C_ADDI : return toubvec!3(0b000);
case riscv_instr_name_t.C_JAL : return toubvec!3(0b001);
case riscv_instr_name_t.C_ADDIW : return toubvec!3(0b001);
case riscv_instr_name_t.C_LI : return toubvec!3(0b010);
case riscv_instr_name_t.C_ADDI16SP : return toubvec!3(0b011);
case riscv_instr_name_t.C_LUI : return toubvec!3(0b011);
case riscv_instr_name_t.C_SRLI : return toubvec!3(0b100);
case riscv_instr_name_t.C_SRLI64 : return toubvec!3(0b100);
case riscv_instr_name_t.C_SRAI : return toubvec!3(0b100);
case riscv_instr_name_t.C_SRAI64 : return toubvec!3(0b100);
case riscv_instr_name_t.C_ANDI : return toubvec!3(0b100);
case riscv_instr_name_t.C_SUB : return toubvec!3(0b100);
case riscv_instr_name_t.C_XOR : return toubvec!3(0b100);
case riscv_instr_name_t.C_OR : return toubvec!3(0b100);
case riscv_instr_name_t.C_AND : return toubvec!3(0b100);
case riscv_instr_name_t.C_SUBW : return toubvec!3(0b100);
case riscv_instr_name_t.C_ADDW : return toubvec!3(0b100);
case riscv_instr_name_t.C_J : return toubvec!3(0b101);
case riscv_instr_name_t.C_BEQZ : return toubvec!3(0b110);
case riscv_instr_name_t.C_BNEZ : return toubvec!3(0b111);
case riscv_instr_name_t.C_SLLI : return toubvec!3(0b000);
case riscv_instr_name_t.C_SLLI64 : return toubvec!3(0b000);
case riscv_instr_name_t.C_FLDSP : return toubvec!3(0b001);
case riscv_instr_name_t.C_LQSP : return toubvec!3(0b001);
case riscv_instr_name_t.C_LWSP : return toubvec!3(0b010);
case riscv_instr_name_t.C_FLWSP : return toubvec!3(0b011);
case riscv_instr_name_t.C_LDSP : return toubvec!3(0b011);
case riscv_instr_name_t.C_JR : return toubvec!3(0b100);
case riscv_instr_name_t.C_MV : return toubvec!3(0b100);
case riscv_instr_name_t.C_EBREAK : return toubvec!3(0b100);
case riscv_instr_name_t.C_JALR : return toubvec!3(0b100);
case riscv_instr_name_t.C_ADD : return toubvec!3(0b100);
case riscv_instr_name_t.C_FSDSP : return toubvec!3(0b101);
case riscv_instr_name_t.C_SQSP : return toubvec!3(0b101);
case riscv_instr_name_t.C_SWSP : return toubvec!3(0b110);
case riscv_instr_name_t.C_FSWSP : return toubvec!3(0b111);
case riscv_instr_name_t.C_SDSP : return toubvec!3(0b111);
default : uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
}

View file

@ -0,0 +1,412 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_floating_point_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t,
riscv_instr_name_t, MAX_INSTR_STR_LEN, riscv_fpr_t,
riscv_instr_format_t, riscv_instr_category_t,
format_string, f_rounding_mode_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.string: toUpper, toLower;
import std.format: format;
import std.algorithm: canFind;
import esdl.rand: rand;
import esdl.data.bvec: ubvec;
import uvm;
class riscv_floating_point_instr: riscv_instr
{
mixin uvm_object_utils;
@rand riscv_fpr_t fs1;
@rand riscv_fpr_t fs2;
@rand riscv_fpr_t fs3;
@rand riscv_fpr_t fd;
@rand f_rounding_mode_t rm;
@rand bool use_rounding_mode_from_instr;
bool has_fs1 = true;
bool has_fs2 = true;
bool has_fs3 = false;
bool has_fd = true;
this(string name = "") {
super(name);
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
import std.conv: to;
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
switch (instr_format) {
case riscv_instr_format_t.I_FORMAT:
if (category == riscv_instr_category_t.LOAD) {
asm_str = format("%0s%0s, %0s(%0s)", asm_str, fd, get_imm(), rs1);
}
else if (instr_name.inside (riscv_instr_name_t.FMV_X_W,
riscv_instr_name_t.FMV_X_D,
riscv_instr_name_t.FCVT_W_S,
riscv_instr_name_t.FCVT_WU_S,
riscv_instr_name_t.FCVT_L_S,
riscv_instr_name_t.FCVT_LU_S,
riscv_instr_name_t.FCVT_L_D,
riscv_instr_name_t.FCVT_LU_D,
riscv_instr_name_t.FCVT_W_D,
riscv_instr_name_t.FCVT_WU_D)) {
asm_str = format("%0s%0s, %0s", asm_str, rd, fs1);
}
else if (instr_name.inside(riscv_instr_name_t.FMV_W_X,
riscv_instr_name_t.FMV_D_X,
riscv_instr_name_t.FCVT_S_W,
riscv_instr_name_t.FCVT_S_WU,
riscv_instr_name_t.FCVT_S_L,
riscv_instr_name_t.FCVT_D_L,
riscv_instr_name_t.FCVT_S_LU,
riscv_instr_name_t.FCVT_D_W,
riscv_instr_name_t.FCVT_D_LU,
riscv_instr_name_t.FCVT_D_WU)) {
asm_str = format("%0s%0s, %0s", asm_str, fd, rs1);
}
else {
asm_str = format("%0s%0s, %0s", asm_str, fd, fs1);
}
break;
case riscv_instr_format_t.S_FORMAT:
asm_str = format("%0s%0s, %0s(%0s)", asm_str, fs2, get_imm(), rs1);
break;
case riscv_instr_format_t.R_FORMAT:
if (category == riscv_instr_category_t.COMPARE) {
asm_str = format("%0s%0s, %0s, %0s", asm_str, rd, fs1, fs2);
}
else if (instr_name.inside(riscv_instr_name_t.FCLASS_S, riscv_instr_name_t.FCLASS_D)) {
asm_str = format("%0s%0s, %0s", asm_str, rd, fs1);
}
else {
asm_str = format("%0s%0s, %0s, %0s", asm_str, fd, fs1, fs2);
}
break;
case riscv_instr_format_t.R4_FORMAT:
asm_str = format("%0s%0s, %0s, %0s, %0s", asm_str, fd, fs1, fs2, fs3);
break;
case riscv_instr_format_t.CL_FORMAT:
asm_str = format("%0s%0s, %0s(%0s)", asm_str, fd, get_imm(), rs1);
break;
case riscv_instr_format_t.CS_FORMAT:
asm_str = format("%0s%0s, %0s(%0s)", asm_str, fs2, get_imm(), rs1);
break;
default:
uvm_fatal(get_full_name(), format("Unsupported floating point format: %0s", instr_format));
}
if ((category == riscv_instr_category_t.ARITHMETIC) && use_rounding_mode_from_instr &&
!(instr_name.inside(riscv_instr_name_t.FMIN_S, riscv_instr_name_t.FMAX_S,
riscv_instr_name_t.FMIN_D, riscv_instr_name_t.FMAX_D,
riscv_instr_name_t.FMV_W_X, riscv_instr_name_t.FMV_X_W,
riscv_instr_name_t.FMV_D_X, riscv_instr_name_t.FMV_X_D,
riscv_instr_name_t.FCLASS_S, riscv_instr_name_t.FCLASS_D,
riscv_instr_name_t.FCVT_D_S, riscv_instr_name_t.FCVT_D_W,
riscv_instr_name_t.FCVT_D_WU, riscv_instr_name_t.FSGNJ_S,
riscv_instr_name_t.FSGNJN_S, riscv_instr_name_t.FSGNJX_S,
riscv_instr_name_t.FSGNJ_D, riscv_instr_name_t.FSGNJN_D,
riscv_instr_name_t.FSGNJX_D))) {
asm_str ~= ", " ~ rm.to!string();
}
if(comment != "") {
asm_str ~= " #" ~ comment;
}
return asm_str.toLower();
}
override void do_copy(uvm_object rhs) {
riscv_floating_point_instr rhs_;
super.copy(rhs);
rhs_ = cast(riscv_floating_point_instr) rhs;
if (rhs_ is null) {
assert (false);
}
else {
this.fs3 = rhs_.fs3;
this.fs2 = rhs_.fs2;
this.fs1 = rhs_.fs1;
this.fd = rhs_.fd;
this.has_fs3 = rhs_.has_fs3;
this.has_fs2 = rhs_.has_fs2;
this.has_fs1 = rhs_.has_fs1;
this.has_fd = rhs_.has_fd;
}
}
override void set_rand_mode() {
has_rs1 = false;
has_rs2 = false;
has_rd = false;
has_imm = false;
switch (instr_format) {
case riscv_instr_format_t.I_FORMAT:
has_fs2 = false;
if (category == riscv_instr_category_t.LOAD) {
has_imm = true;
}
else if (instr_name.inside(riscv_instr_name_t.FMV_X_W,
riscv_instr_name_t.FMV_X_D,
riscv_instr_name_t.FCVT_W_S,
riscv_instr_name_t.FCVT_WU_S,
riscv_instr_name_t.FCVT_L_S,
riscv_instr_name_t.FCVT_LU_S,
riscv_instr_name_t.FCVT_L_D,
riscv_instr_name_t.FCVT_LU_D,
riscv_instr_name_t.FCVT_LU_S,
riscv_instr_name_t.FCVT_W_D,
riscv_instr_name_t.FCVT_WU_D)) {
has_fd = false;
has_rd = true;
}
else if (instr_name.inside(riscv_instr_name_t.FMV_W_X,
riscv_instr_name_t.FMV_D_X,
riscv_instr_name_t.FCVT_S_W,
riscv_instr_name_t.FCVT_S_WU,
riscv_instr_name_t.FCVT_S_L,
riscv_instr_name_t.FCVT_D_L,
riscv_instr_name_t.FCVT_S_LU,
riscv_instr_name_t.FCVT_D_W,
riscv_instr_name_t.FCVT_D_LU,
riscv_instr_name_t.FCVT_D_WU)) {
has_rs1 = true;
has_fs1 = false;
}
break;
case riscv_instr_format_t.S_FORMAT:
has_imm = true;
has_rs1 = true;
has_fs1 = false;
has_fs3 = false;
break;
case riscv_instr_format_t.R_FORMAT:
if (category == riscv_instr_category_t.COMPARE) {
has_rd = true;
has_fd = false;
}
else if (instr_name.inside(riscv_instr_name_t.FCLASS_S,
riscv_instr_name_t.FCLASS_D)) {
has_rd = true;
has_fd = false;
has_fs2 = false;
}
break;
case riscv_instr_format_t.R4_FORMAT:
has_fs3 = true;
break;
case riscv_instr_format_t.CL_FORMAT:
has_imm = true;
has_rs1 = true;
has_fs1 = false;
has_fs2 = false;
break;
case riscv_instr_format_t.CS_FORMAT:
has_imm = true;
has_rs1 = true;
has_fs1 = false;
has_fd = false;
break;
default: uvm_info(get_full_name() , format("Unsupported format %0s", instr_format), UVM_LOW);
}
}
override void pre_randomize() {
super.pre_randomize();
rand_mode!q{fs1}(has_fs1);
rand_mode!q{fs2}(has_fs2);
rand_mode!q{fs3}(has_fs3);
rand_mode!q{fd}(has_fd);
}
// coverage related functons
// override void update_src_regs(string [] operands) {
// if(category.inside(riscv_instr_category_t.LOAD, riscv_instr_category_t.CSR)) {
// // commented as we are not incluing coverage now.
// // super.update_src_regs(operands);
// return;
// }
// switch (instr_format) {
// case riscv_instr_format_t.I_FORMAT:
// // TODO ovpsim has an extra operand rte as below
// // fcvt.d.s fs1,fs4,rte
// //`DV_CHECK_FATAL(operands.size() == 2)
// assert(operands.length == 2);
// if (has_fs1) {
// fs1 = get_fpr(operands[1]);
// fs1_value = get_gpr_state(operands[1]);
// } else if (has_rs1) {
// rs1 = get_gpr(operands[1]);
// rs1_value = get_gpr_state(operands[1]);
// }
// break;
// case riscv_instr_format_t.S_FORMAT:
// //DV_CHECK_FATAL(operands.size() == 3)
// // FSW rs2 is fp
// assert(operands.size() == 3);
// fs2 = get_fpr(operands[0]);
// fs2_value = get_gpr_state(operands[0]);
// rs1 = get_gpr(operands[2]);
// rs1_value = get_gpr_state(operands[2]);
// get_val(operands[1], imm);
// break;
// case riscv_instr_format_t.R_FORMAT:
// // convert Pseudoinstructions for ovpsim
// // fmv.s rd, rs -> fsgnj.s rd, rs, rs
// if (operands.size() == 2 && (canFind([riscv_instr_name_t.FSGNJ_S,
// riscv_instr_name_t.FSGNJX_S,
// riscv_instr_name_t.FSGNJN_S,
// riscv_instr_name_t.FSGNJ_D,
// riscv_instr_name_t.FSGNJX_D,
// riscv_instr_name_t.FSGNJN_D], instr_name))) {
// int len = operands.length();
// //operands.push_back(operands[$]);
// operands[len] = operands[$];
// }
// if (has_fs2 || category == riscv_instr_category_t.CSR) {
// //`DV_CHECK_FATAL(operands.size() == 3)
// assert( operands.size() == 3);
// }
// else
// {
// // `DV_CHECK_FATAL(operands.size() == 2)
// assert( operands.size() == 2);
// }
// if(category != riscv_instr_category_t.CSR) {
// fs1 = get_fpr(operands[1]);
// fs1_value = get_gpr_state(operands[1]);
// if (has_fs2) {
// fs2_value = get_fpr(operands[2]);
// fs2_value = get_gpr_state(operands[2]);
// }
// }
// break;
// case riscv_instr_format_t.R4_FORMAT:
// //`DV_CHECK_FATAL(operands.size() == 4)
// assert (operands.length == 4);
// fs1 = get_fpr(operands[1]);
// fs1_value = get_gpr_state(operands[1]);
// fs2 = get_fpr(operands[2]);
// fs2_value = get_gpr_state(operands[2]);
// fs3 = get_fpr(operands[3]);
// fs3_value = get_gpr_state(operands[3]);
// break;
// default: uvm_fatal(get_full_name(), format("Unsupported format %0s", instr_format));
// }
// }
// void update_dst_regs(string reg_name, string val_str) {
// get_val(val_str, gpr_state[reg_name], true);
// if (has_fd) {
// fd = get_fpr(reg_name);
// fd_value = get_gpr_state(reg_name);
// }
// else if (has_rd) {
// rd = get_gpr(reg_name);
// rd_value = get_gpr_state(reg_name);
// }
// }
// riscv_fpr_t get_fpr(in string str) {
// str = str.toUpper();
// if (!uvm_enum_wrapper!(riscv_fpr_t).from_name(str, get_fpr)) {
// uvm_fatal(get_full_name(), format("Cannot convert %0s to FPR", str));
// }
// }
// void pre_sample()
// {
// super.pre_sample();
// // for single precision sign bit is bit 31, upper 32 bits are all 1s
// // for double precision, it's 63
// if (canFind((riscv_instr_group_t.RV32F, riscv_instr_group_t.RV64F), group))
// {
// fs1_sign = get_fp_operand_sign(fs1_value, 31);
// fs2_sign = get_fp_operand_sign(fs2_value, 31);
// fs3_sign = get_fp_operand_sign(fs3_value, 31);
// fd_sign = get_fp_operand_sign(fd_value, 31);
// }
// else if (instr_name == riscv_instr_name_t.FCVT_S_D)
// {
// fs1_sign = get_fp_operand_sign(fs1_value, 63);
// fd_sign = get_fp_operand_sign(fd_value, 31);
// }
// else if (instr_name == riscv_instr_name_t.FCVT_D_S)
// {
// fs1_sign = get_fp_operand_sign(fs1_value, 31);
// fd_sign = get_fp_operand_sign(fd_value, 63);
// }
// else
// {
// fs1_sign = get_fp_operand_sign(fs1_value, 63);
// fs2_sign = get_fp_operand_sign(fs2_value, 63);
// fs3_sign = get_fp_operand_sign(fs3_value, 63);
// fd_sign = get_fp_operand_sign(fd_value, 63);
// }
// }
// operand_sign_e get_fp_operand_sign(ubvec!XLEN value, int idx)
// {
// if (value[idx])
// {
// return operand_sign_e.NEGATIVE;
// }
// else
// {
// return operand_sign_e.POSITIVE;
// }
// }
// override void check_hazard_condition(riscv_instr pre_instr)
// {
// riscv_floating_point_instr pre_fp_instr;
// super.check_hazard_condition(pre_instr);
// pre_fp_instr = cast(riscv_floating_point_instr) pre_instr;
// if (pre_fp_instr != null && pre_fp_instr.has_fd)
// {
// if ((has_fs1 && (fs1 == pre_fp_instr.fd)) || (has_fs2 && (fs2 == pre_fp_instr.fd))
// || (has_fs3 && (fs3 == pre_fp_instr.fd)))
// {
// gpr_hazard = hazard_e.RAW_HAZARD;
// }
// else if (has_fd && (fd == pre_fp_instr.fd))
// {
// gpr_hazard = hazard_e.WAW_HAZARD;
// }
// else if (has_fd && ((pre_fp_instr.has_fs1 && (pre_fp_instr.fs1 == fd)) ||
// (pre_fp_instr.has_fs2 && (pre_fp_instr.fs2 == fd)) ||
// (pre_fp_instr.has_fs3 && (pre_fp_instr.fs3 == fd))))
// {
// gpr_hazard = hazard_e.WAR_HAZARD;
// }
// else
// {
// gpr_hazard = hazard_e.NO_HAZARD;
// }
// }
// }
}

View file

@ -0,0 +1,652 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t, riscv_instr_format_t,
riscv_instr_category_t, riscv_instr_name_t, imm_t, riscv_reg_t, format_string,
MAX_INSTR_STR_LEN;
import riscv.gen.target: XLEN;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
// import riscv.gen.riscv_instr_registry: riscv_instr_registry;
import esdl.data.bvec: bvec, ubvec, toubvec;
import esdl.rand: rand, constraint;
import std.format: format;
import std.algorithm.searching: canFind;
import uvm;
class riscv_instr: uvm_object
{
mixin uvm_object_utils;
riscv_instr_gen_config m_cfg;
// riscv_instr_registry m_registry;
// Instruction attributes
riscv_instr_group_t group;
riscv_instr_format_t instr_format;
riscv_instr_category_t category;
riscv_instr_name_t instr_name;
imm_t imm_type;
ubvec!5 imm_len;
// Operands
@rand ubvec!12 csr;
@rand riscv_reg_t rs2;
@rand riscv_reg_t rs1;
@rand riscv_reg_t rd;
@rand ubvec!32 imm;
// Helper fields
ubvec!32 imm_mask = 0xFFFF_FFFF;
bool is_branch_target;
bool has_label = true;
bool atomic = false;
bool branch_assigned;
bool process_load_store = true;
bool is_compressed;
bool is_illegal_instr;
bool is_hint_instr;
bool is_floating_point;
string imm_str;
string comment;
string label;
bool is_local_numeric_label;
int idx = -1;
bool has_rs1 = true;
bool has_rs2 = true;
bool has_rd = true;
bool has_imm = true;
constraint! q{
if (instr_name inside [riscv_instr_name_t.SLLIW,
riscv_instr_name_t.SRLIW,
riscv_instr_name_t.SRAIW]) {
imm[5..12] == 0;
}
if (instr_name inside [riscv_instr_name_t.SLLI,
riscv_instr_name_t.SRLI,
riscv_instr_name_t.SRAI]) {
if (XLEN == 32) {
imm[5..12] == 0;
}
else {
imm[6..12] == 0;
}
}
} imm_c;
constraint! q{
if (category == riscv_instr_category_t.CSR) {
if (m_cfg.instr_registry.include_reg.length > 0) {
csr inside [m_cfg.instr_registry.include_reg];
}
if (m_cfg.instr_registry.exclude_reg.length > 0) {
csr !inside [m_cfg.instr_registry.exclude_reg];
}
}
} csr_c;
this(string name = "") {
super(name);
}
bool is_supported(riscv_instr_gen_config cfg) {
return true;
}
// // Disable the rand mode for unused operands to randomization performance
void set_rand_mode() {
switch (instr_format) {
case riscv_instr_format_t.R_FORMAT:
has_imm = false;
break;
case riscv_instr_format_t.I_FORMAT:
has_rs2 = false;
break;
case riscv_instr_format_t.S_FORMAT, riscv_instr_format_t.B_FORMAT:
has_rd = false;
break;
case riscv_instr_format_t.U_FORMAT, riscv_instr_format_t.J_FORMAT:
has_rs1 = false;
has_rs2 = false;
break;
default: break;
}
if (category == riscv_instr_category_t.CSR) {
has_rs2 = false;
if (instr_format ==riscv_instr_format_t.I_FORMAT) {
has_rs1 = false;
}
}
}
void pre_randomize() {
rand_mode!q{rs1}(has_rs1);
rand_mode!q{rs2}(has_rs2);
rand_mode!q{rd}(has_rd);
rand_mode!q{imm}(has_imm);
if (category != riscv_instr_category_t.CSR) {
rand_mode!q{csr}(0);
}
}
void set_imm_len() {
if (instr_format == riscv_instr_format_t.U_FORMAT ||
instr_format == riscv_instr_format_t.J_FORMAT) {
imm_len = toubvec!5(20);
}
else if (instr_format == riscv_instr_format_t.I_FORMAT ||
instr_format == riscv_instr_format_t.S_FORMAT ||
instr_format == riscv_instr_format_t.B_FORMAT) {
if (imm_type == imm_t.UIMM) {
imm_len = toubvec!5(5);
}
else {
imm_len = toubvec!5(11);
}
}
imm_mask = imm_mask << imm_len;
}
void extend_imm() {
bool sign;
imm = imm << (32 - imm_len);
sign = imm[31];
imm = imm >> (32 - imm_len);
// Signed extension
if (sign && !(instr_format == riscv_instr_format_t.U_FORMAT ||
imm_type == imm_t.UIMM ||
imm_type == imm_t.NZUIMM)) {
imm = imm_mask | imm;
}
}
void post_randomize() {
extend_imm();
update_imm_str();
}
// Convert the instruction to assembly code
string convert2asm(string prefix = "") {
import std.string: toLower;
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
if (category != riscv_instr_category_t.SYSTEM) {
switch (instr_format) {
case riscv_instr_format_t.J_FORMAT, riscv_instr_format_t.U_FORMAT: // instr rd,imm
asm_str = format("%0s%0s, %0s", asm_str, rd, get_imm());
break;
case riscv_instr_format_t.I_FORMAT: // instr rd,rs1,imm
if (instr_name == riscv_instr_name_t.NOP)
asm_str = "nop";
else if (instr_name == riscv_instr_name_t.WFI)
asm_str = "wfi";
else if (instr_name == riscv_instr_name_t.FENCE)
asm_str = format("fence"); // TODO: Support all fence combinations
else if (instr_name == riscv_instr_name_t.FENCE_I)
asm_str = "fence.i";
else if (category == riscv_instr_category_t.LOAD) // Use psuedo instruction format
asm_str = format("%0s%0s, %0s(%0s)", asm_str, rd, get_imm(), rs1);
else if (category == riscv_instr_category_t.CSR)
asm_str = format("%0s%0s, 0x%0x, %0s", asm_str,rd, csr, get_imm());
else
asm_str = format("%0s%0s, %0s, %0s", asm_str, rd, rs1, get_imm());
break;
case riscv_instr_format_t.S_FORMAT, riscv_instr_format_t.B_FORMAT: // instr rs1,rs2,imm
if (category == riscv_instr_category_t.STORE) // Use psuedo instruction format
asm_str = format("%0s%0s, %0s(%0s)", asm_str, rs2, get_imm(), rs1);
else
asm_str = format("%0s%0s, %0s, %0s", asm_str, rs1, rs2, get_imm());
break;
case riscv_instr_format_t.R_FORMAT: // instr rd,rs1,rs2
if (category == riscv_instr_category_t.CSR) {
asm_str = format("%0s%0s, 0x%0x, %0s", asm_str, rd, csr, rs1);
}
else if (instr_name == riscv_instr_name_t.SFENCE_VMA) {
asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence
}
else {
asm_str = format("%0s%0s, %0s, %0s", asm_str, rd, rs1, rs2);
}
break;
default: uvm_fatal(get_full_name(), format("Unsupported format %0s [%0s]",
instr_format, instr_name));
break;
}
}
else {
// For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
// This is needed to resume execution from epc+4 after ebreak handling
if (instr_name == riscv_instr_name_t.EBREAK) {
asm_str = ".4byte 0x00100073 # ebreak";
}
}
if (comment != "")
asm_str = asm_str ~ " #" ~comment;
return toLower(asm_str);
}
ubvec!7 get_opcode() {
switch (instr_name) {
case riscv_instr_name_t.LUI: return toubvec!7(0b0110111);
case riscv_instr_name_t.AUIPC: return toubvec!7(0b0010111);
case riscv_instr_name_t.JAL: return toubvec!7(0b1101111);
case riscv_instr_name_t.JALR: return toubvec!7(0b1100111);
case riscv_instr_name_t.BEQ,
riscv_instr_name_t.BNE,
riscv_instr_name_t.BLT,
riscv_instr_name_t.BGE,
riscv_instr_name_t.BLTU,
riscv_instr_name_t.BGEU: return toubvec!7(0b1100011);
case riscv_instr_name_t.LB,
riscv_instr_name_t.LH,
riscv_instr_name_t.LW,
riscv_instr_name_t.LBU,
riscv_instr_name_t.LHU,
riscv_instr_name_t.LWU,
riscv_instr_name_t.LD: return toubvec!7(0b0000011);
case riscv_instr_name_t.SB,
riscv_instr_name_t.SH,
riscv_instr_name_t.SW,
riscv_instr_name_t.SD: return toubvec!7(0b0100011);
case riscv_instr_name_t.ADDI,
riscv_instr_name_t.SLTI,
riscv_instr_name_t.SLTIU,
riscv_instr_name_t.XORI,
riscv_instr_name_t.ORI,
riscv_instr_name_t.ANDI,
riscv_instr_name_t.SLLI,
riscv_instr_name_t.SRLI,
riscv_instr_name_t.SRAI,
riscv_instr_name_t.NOP: return toubvec!7(0b0010011);
case riscv_instr_name_t.ADD,
riscv_instr_name_t.SUB,
riscv_instr_name_t.SLL,
riscv_instr_name_t.SLT,
riscv_instr_name_t.SLTU,
riscv_instr_name_t.XOR,
riscv_instr_name_t.SRL,
riscv_instr_name_t.SRA,
riscv_instr_name_t.OR,
riscv_instr_name_t.AND,
riscv_instr_name_t.MUL,
riscv_instr_name_t.MULH,
riscv_instr_name_t.MULHSU,
riscv_instr_name_t.MULHU,
riscv_instr_name_t.DIV,
riscv_instr_name_t.DIVU,
riscv_instr_name_t.REM,
riscv_instr_name_t.REMU: return toubvec!7(0b0110011);
case riscv_instr_name_t.ADDIW,
riscv_instr_name_t.SLLIW,
riscv_instr_name_t.SRLIW,
riscv_instr_name_t.SRAIW: return toubvec!7(0b0011011);
// case riscv_instr_name_t.MULH,
// riscv_instr_name_t.MULHSU,
// riscv_instr_name_t.MULHU,
// riscv_instr_name_t.DIV,
// riscv_instr_name_t.DIVU,
// riscv_instr_name_t.REM,
// riscv_instr_name_t.REMU: { return toubvec!0b0110011;
case riscv_instr_name_t.FENCE,
riscv_instr_name_t.FENCE_I: return toubvec!7(0b0001111);
case riscv_instr_name_t.CSRRW,
riscv_instr_name_t.CSRRS,
riscv_instr_name_t.CSRRC,
riscv_instr_name_t.CSRRWI,
riscv_instr_name_t.CSRRSI,
riscv_instr_name_t.CSRRCI: return toubvec!7(0b1110011);
case riscv_instr_name_t.ADDW,
riscv_instr_name_t.SUBW,
riscv_instr_name_t.SLLW,
riscv_instr_name_t.SRLW,
riscv_instr_name_t.SRAW,
riscv_instr_name_t.MULW,
riscv_instr_name_t.DIVW,
riscv_instr_name_t.DIVUW,
riscv_instr_name_t.REMW,
riscv_instr_name_t.REMUW: return toubvec!7(0b0111011);
case riscv_instr_name_t.ECALL,
riscv_instr_name_t.EBREAK,
riscv_instr_name_t.URET,
riscv_instr_name_t.SRET,
riscv_instr_name_t.MRET,
riscv_instr_name_t.DRET,
riscv_instr_name_t.WFI,
riscv_instr_name_t.SFENCE_VMA: return toubvec!7(0b1110011);
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
ubvec!3 get_func3() {
switch (instr_name) {
case riscv_instr_name_t.JALR: return toubvec!3(0b000);
case riscv_instr_name_t.BEQ: return toubvec!3(0b000);
case riscv_instr_name_t.BNE: return toubvec!3(0b001);
case riscv_instr_name_t.BLT: return toubvec!3(0b100);
case riscv_instr_name_t.BGE: return toubvec!3(0b101);
case riscv_instr_name_t.BLTU: return toubvec!3(0b110);
case riscv_instr_name_t.BGEU: return toubvec!3(0b111);
case riscv_instr_name_t.LB: return toubvec!3(0b000);
case riscv_instr_name_t.LH: return toubvec!3(0b001);
case riscv_instr_name_t.LW: return toubvec!3(0b010);
case riscv_instr_name_t.LBU: return toubvec!3(0b100);
case riscv_instr_name_t.LHU: return toubvec!3(0b101);
case riscv_instr_name_t.SB: return toubvec!3(0b000);
case riscv_instr_name_t.SH: return toubvec!3(0b001);
case riscv_instr_name_t.SW: return toubvec!3(0b010);
case riscv_instr_name_t.ADDI: return toubvec!3(0b000);
case riscv_instr_name_t.NOP: return toubvec!3(0b000);
case riscv_instr_name_t.SLTI: return toubvec!3(0b010);
case riscv_instr_name_t.SLTIU: return toubvec!3(0b011);
case riscv_instr_name_t.XORI: return toubvec!3(0b100);
case riscv_instr_name_t.ORI: return toubvec!3(0b110);
case riscv_instr_name_t.ANDI: return toubvec!3(0b111);
case riscv_instr_name_t.SLLI: return toubvec!3(0b001);
case riscv_instr_name_t.SRLI: return toubvec!3(0b101);
case riscv_instr_name_t.SRAI: return toubvec!3(0b101);
case riscv_instr_name_t.ADD: return toubvec!3(0b000);
case riscv_instr_name_t.SUB: return toubvec!3(0b000);
case riscv_instr_name_t.SLL: return toubvec!3(0b001);
case riscv_instr_name_t.SLT: return toubvec!3(0b010);
case riscv_instr_name_t.SLTU: return toubvec!3(0b011);
case riscv_instr_name_t.XOR: return toubvec!3(0b100);
case riscv_instr_name_t.SRL: return toubvec!3(0b101);
case riscv_instr_name_t.SRA: return toubvec!3(0b101);
case riscv_instr_name_t.OR: return toubvec!3(0b110);
case riscv_instr_name_t.AND: return toubvec!3(0b111);
case riscv_instr_name_t.FENCE: return toubvec!3(0b000);
case riscv_instr_name_t.FENCE_I: return toubvec!3(0b001);
// case riscv_instr_name_t.ECALL: return toubvec!3(0b000);
// case riscv_instr_name_t.EBREAK: return toubvec!3(0b000);
case riscv_instr_name_t.CSRRW: return toubvec!3(0b001);
case riscv_instr_name_t.CSRRS: return toubvec!3(0b010);
case riscv_instr_name_t.CSRRC: return toubvec!3(0b011);
case riscv_instr_name_t.CSRRWI: return toubvec!3(0b101);
case riscv_instr_name_t.CSRRSI: return toubvec!3(0b110);
case riscv_instr_name_t.CSRRCI: return toubvec!3(0b111);
case riscv_instr_name_t.LWU: return toubvec!3(0b110);
case riscv_instr_name_t.LD: return toubvec!3(0b011);
case riscv_instr_name_t.SD: return toubvec!3(0b011);
case riscv_instr_name_t.ADDIW: return toubvec!3(0b000);
case riscv_instr_name_t.SLLIW: return toubvec!3(0b001);
case riscv_instr_name_t.SRLIW: return toubvec!3(0b101);
case riscv_instr_name_t.SRAIW: return toubvec!3(0b101);
case riscv_instr_name_t.ADDW: return toubvec!3(0b000);
case riscv_instr_name_t.SUBW: return toubvec!3(0b000);
case riscv_instr_name_t.SLLW: return toubvec!3(0b001);
case riscv_instr_name_t.SRLW: return toubvec!3(0b101);
case riscv_instr_name_t.SRAW: return toubvec!3(0b101);
case riscv_instr_name_t.MUL: return toubvec!3(0b000);
case riscv_instr_name_t.MULH: return toubvec!3(0b001);
case riscv_instr_name_t.MULHSU: return toubvec!3(0b010);
case riscv_instr_name_t.MULHU: return toubvec!3(0b011);
case riscv_instr_name_t.DIV: return toubvec!3(0b100);
case riscv_instr_name_t.DIVU: return toubvec!3(0b101);
case riscv_instr_name_t.REM: return toubvec!3(0b110);
case riscv_instr_name_t.REMU: return toubvec!3(0b111);
case riscv_instr_name_t.MULW: return toubvec!3(0b000);
case riscv_instr_name_t.DIVW: return toubvec!3(0b100);
case riscv_instr_name_t.DIVUW: return toubvec!3(0b101);
case riscv_instr_name_t.REMW: return toubvec!3(0b110);
case riscv_instr_name_t.REMUW: return toubvec!3(0b111);
case riscv_instr_name_t.ECALL,
riscv_instr_name_t.EBREAK,
riscv_instr_name_t.URET,
riscv_instr_name_t.SRET,
riscv_instr_name_t.MRET,
riscv_instr_name_t.DRET,
riscv_instr_name_t.WFI,
riscv_instr_name_t.SFENCE_VMA: return toubvec!3(0b000);
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
ubvec!7 get_func7() {
switch (instr_name) {
case riscv_instr_name_t.SLLI: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRLI: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRAI: return toubvec!7(0b0100000);
case riscv_instr_name_t.ADD: return toubvec!7(0b0000000);
case riscv_instr_name_t.SUB: return toubvec!7(0b0100000);
case riscv_instr_name_t.SLL: return toubvec!7(0b0000000);
case riscv_instr_name_t.SLT: return toubvec!7(0b0000000);
case riscv_instr_name_t.SLTU: return toubvec!7(0b0000000);
case riscv_instr_name_t.XOR: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRL: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRA: return toubvec!7(0b0100000);
case riscv_instr_name_t.OR: return toubvec!7(0b0000000);
case riscv_instr_name_t.AND: return toubvec!7(0b0000000);
case riscv_instr_name_t.FENCE: return toubvec!7(0b0000000);
case riscv_instr_name_t.FENCE_I: return toubvec!7(0b0000000);
case riscv_instr_name_t.SLLIW: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRLIW: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRAIW: return toubvec!7(0b0100000);
case riscv_instr_name_t.ADDW: return toubvec!7(0b0000000);
case riscv_instr_name_t.SUBW: return toubvec!7(0b0100000);
case riscv_instr_name_t.SLLW: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRLW: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRAW: return toubvec!7(0b0100000);
case riscv_instr_name_t.MUL: return toubvec!7(0b0000001);
case riscv_instr_name_t.MULH: return toubvec!7(0b0000001);
case riscv_instr_name_t.MULHSU: return toubvec!7(0b0000001);
case riscv_instr_name_t.MULHU: return toubvec!7(0b0000001);
case riscv_instr_name_t.DIV: return toubvec!7(0b0000001);
case riscv_instr_name_t.DIVU: return toubvec!7(0b0000001);
case riscv_instr_name_t.REM: return toubvec!7(0b0000001);
case riscv_instr_name_t.REMU: return toubvec!7(0b0000001);
case riscv_instr_name_t.MULW: return toubvec!7(0b0000001);
case riscv_instr_name_t.DIVW: return toubvec!7(0b0000001);
case riscv_instr_name_t.DIVUW: return toubvec!7(0b0000001);
case riscv_instr_name_t.REMW: return toubvec!7(0b0000001);
case riscv_instr_name_t.REMUW: return toubvec!7(0b0000001);
case riscv_instr_name_t.ECALL: return toubvec!7(0b0000000);
case riscv_instr_name_t.EBREAK: return toubvec!7(0b0000000);
case riscv_instr_name_t.URET: return toubvec!7(0b0000000);
case riscv_instr_name_t.SRET: return toubvec!7(0b0001000);
case riscv_instr_name_t.MRET: return toubvec!7(0b0011000);
case riscv_instr_name_t.DRET: return toubvec!7(0b0111101);
case riscv_instr_name_t.WFI: return toubvec!7(0b0001000);
case riscv_instr_name_t.SFENCE_VMA: return toubvec!7(0b0001001);
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
// Convert the instruction to assembly code
string convert2bin(string prefix = "") {
import std.conv: to;
ubvec!32 vec;
switch (instr_format) {
case riscv_instr_format_t.J_FORMAT:
vec = cast(ubvec!1) imm[20]
~ cast(ubvec!10) imm[1..11]
~ cast(ubvec!1) imm[11]
~ cast(ubvec!8) imm[12..20]
~ toubvec!5(rd)
~ get_opcode();
break;
case riscv_instr_format_t.U_FORMAT:
vec = cast(ubvec!20) imm[12..32]
~ toubvec!5(rd)
~ get_opcode();
break;
case riscv_instr_format_t.I_FORMAT:
if (canFind( [riscv_instr_name_t.FENCE, riscv_instr_name_t.FENCE_I], instr_name)) {
vec = toubvec!17(0b00000000000000000)
~ get_func3()
~ toubvec!5(0b00000)
~ get_opcode();
} // 17 bit zero and 5 bit zero
else if (category == riscv_instr_category_t.CSR) {
vec = csr // cast(ubvec!11) csr[0..11] SV BUG?
~ cast(ubvec!5) imm[0..5]
~ get_func3()
~ toubvec!5(rd)
~ get_opcode();
}
else if (instr_name == riscv_instr_name_t.ECALL) {
vec = get_func7()
~ toubvec!18(0b000000000000000000)
~ get_opcode();
} // 18 bit zero
else if (canFind([riscv_instr_name_t.URET,
riscv_instr_name_t.SRET,
riscv_instr_name_t.MRET], instr_name )) {
vec = get_func7()
~ toubvec!5(0b00010)
~ toubvec!13(0b0000000000000)
~ get_opcode();
} // 13 bit zero
else if (instr_name == riscv_instr_name_t.DRET) {
vec = get_func7()
~ toubvec!5(0b10010)
~ toubvec!13(0b0000000000000)
~ get_opcode();
} // 13 bit zero
else if (instr_name == riscv_instr_name_t.EBREAK) {
vec = get_func7()
~ toubvec!5(0b00001)
~ toubvec!13(0b0000000000000)
~ get_opcode();
} // 13 bit zero
else if (instr_name == riscv_instr_name_t.WFI) {
vec = get_func7()
~ toubvec!5(0b00101)
~ toubvec!13(0b0000000000000)
~ get_opcode();
}
else {
vec = cast(ubvec!12) imm[0..12]
~ toubvec!5(rs1)
~ get_func3()
~ toubvec!5(rd)
~ get_opcode();
}
break;
case riscv_instr_format_t.S_FORMAT:
vec = cast(ubvec!7) imm[5..12]
~ toubvec!5(rs2)
~ toubvec!5(rs1)
~ get_func3()
~ cast(ubvec!5) imm[0..5]
~ get_opcode();
break;
case riscv_instr_format_t.B_FORMAT:
vec = cast(ubvec!1) imm[12]
~ cast(ubvec!6) imm[5..11]
~ toubvec!5(rs2)
~ toubvec!5(rs1)
~ get_func3()
~ cast(ubvec!4) imm[1..5]
~ cast(ubvec!1) imm[11]
~ get_opcode();
break;
case riscv_instr_format_t.R_FORMAT:
if (category == riscv_instr_category_t.CSR) {
vec = csr // cast(ubvec!11) csr[0..11] -- SV BUG?
~ toubvec!5(rs1)
~ get_func3()
~ toubvec!5(rd)
~ get_opcode();
}
else if (instr_name == riscv_instr_name_t.SFENCE_VMA) {
vec = get_func7()
~ toubvec!18(0b000000000000000000)
~ get_opcode();
} // 18 bits zero
else {
vec = get_func7()
~ toubvec!5(rs2)
~ toubvec!5(rs1)
~ get_func3()
~ toubvec!5(rd)
~ get_opcode();
}
break;
default: uvm_fatal(get_full_name(), format("Unsupported format %0s", instr_format));
assert (false);
}
return prefix ~ format("%8h", vec);
}
string get_instr_name() {
import std.conv: to;
import std.array: replace;
string str_instr_name = instr_name.to!string();
return str_instr_name.replace( '_', '.');
}
// // Get RVC register name for CIW, CL, CS, CB format
ubvec!3 get_c_gpr(riscv_reg_t gpr) {
ubvec!8 c_gpr = toubvec!8(gpr);
return cast(ubvec!3) c_gpr[0..3];
}
// // Default return imm value directly, can be overriden to use labels and symbols
// // Example: %hi(symbol), %pc_rel(label) ...
string get_imm() {
return imm_str;
}
void clear_unused_label() {
if (has_label && !is_branch_target && is_local_numeric_label) {
has_label = false;
}
}
override void do_copy(uvm_object rhs) {
riscv_instr rhs_;
super.copy(rhs);
rhs_ = cast(riscv_instr) rhs;
if ( rhs_ !is null ) { //rhs_ = rhs;
this.group = rhs_.group;
this.instr_format = rhs_.instr_format;
this.category = rhs_.category;
this.instr_name = rhs_.instr_name;
this.rs2 = rhs_.rs2;
this.rs1 = rhs_.rs1;
this.rd = rhs_.rd;
this.imm = rhs_.imm;
this.imm_type = rhs_.imm_type;
this.imm_len = rhs_.imm_len;
this.imm_mask = rhs_.imm_mask;
this.imm_str = rhs_.imm_str;
this.imm_mask = rhs_.imm_mask;
this.is_compressed = rhs_.is_compressed;
this.has_rs2 = rhs_.has_rs2;
this.has_rs1 = rhs_.has_rs1;
this.has_rd = rhs_.has_rd;
this.has_imm = rhs_.has_imm;
}
}
void update_imm_str() {
imm_str = format("%0d", cast(bvec!32) imm);
}
//`include "isa/riscv_instr_cov.svh"
}

View file

@ -0,0 +1,87 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_instr_register;
import riscv.gen.riscv_instr_registry: riscv_instr_registry;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.traits: fullyQualifiedName;
void register(alias MOD, INSTRS...)(riscv_instr_registry registry) {
static if (INSTRS.length == 0) return;
else {
alias INSTR=__traits(getMember, MOD, INSTRS[0]);
static if (is (INSTR == class) && is (INSTR: riscv_instr)) {
// pragma(msg, "register ", fullyQualifiedName!INSTR);
registry.register(INSTR.RISCV_INSTR_NAME_T, fullyQualifiedName!INSTR);
}
register!(MOD, INSTRS[1..$])(registry);
return;
}
}
void register_module(alias MOD)(riscv_instr_registry registry) {
register!(MOD, __traits(allMembers, MOD))(registry);
}
void register_isa(riscv_instr_registry registry) {
import riscv.gen.isa.rv128c_instr;
import riscv.gen.isa.rv32a_instr;
import riscv.gen.isa.rv32b_instr;
import riscv.gen.isa.rv32c_instr;
import riscv.gen.isa.rv32dc_instr;
import riscv.gen.isa.rv32d_instr;
import riscv.gen.isa.rv32fc_instr;
import riscv.gen.isa.rv32f_instr;
import riscv.gen.isa.rv32i_instr;
import riscv.gen.isa.rv32m_instr;
import riscv.gen.isa.rv32v_instr;
import riscv.gen.isa.rv64a_instr;
import riscv.gen.isa.rv64b_instr;
import riscv.gen.isa.rv64c_instr;
import riscv.gen.isa.rv64d_instr;
import riscv.gen.isa.rv64f_instr;
import riscv.gen.isa.rv64i_instr;
import riscv.gen.isa.rv64m_instr;
import riscv.gen.isa.rv64zba_instr;
import riscv.gen.isa.rv64zbb_instr;
import riscv.gen.isa.rv32zba_instr;
import riscv.gen.isa.rv32zbb_instr;
import riscv.gen.isa.rv32zbc_instr;
import riscv.gen.isa.rv32zbs_instr;
register_module!(riscv.gen.isa.rv128c_instr)(registry);
register_module!(riscv.gen.isa.rv32a_instr)(registry);
register_module!(riscv.gen.isa.rv32b_instr)(registry);
register_module!(riscv.gen.isa.rv32c_instr)(registry);
register_module!(riscv.gen.isa.rv32dc_instr)(registry);
register_module!(riscv.gen.isa.rv32d_instr)(registry);
register_module!(riscv.gen.isa.rv32fc_instr)(registry);
register_module!(riscv.gen.isa.rv32f_instr)(registry);
register_module!(riscv.gen.isa.rv32i_instr)(registry);
register_module!(riscv.gen.isa.rv32m_instr)(registry);
register_module!(riscv.gen.isa.rv32v_instr)(registry);
register_module!(riscv.gen.isa.rv64a_instr)(registry);
register_module!(riscv.gen.isa.rv64b_instr)(registry);
register_module!(riscv.gen.isa.rv64c_instr)(registry);
register_module!(riscv.gen.isa.rv64d_instr)(registry);
register_module!(riscv.gen.isa.rv64f_instr)(registry);
register_module!(riscv.gen.isa.rv64i_instr)(registry);
register_module!(riscv.gen.isa.rv64m_instr)(registry);
}

View file

@ -0,0 +1,679 @@
/*
* Copyright 2020 Google LLC
* Copyright 2020 Andes Technology Co., Ltd.
Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Base class for RISC-V vector exenstion ISA, implmented based on spec v0.8
module riscv.gen.isa.riscv_vector_instr;
import riscv.gen.riscv_instr_pkg: riscv_vreg_t, va_variant_t,
riscv_instr_name_t, riscv_instr_format_t, format_string,
MAX_INSTR_STR_LEN, riscv_instr_category_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.isa.riscv_floating_point_instr: riscv_floating_point_instr;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import std.format: format;
import esdl.rand: rand, constraint;
import esdl.data.bvec: ubvec;
import std.algorithm: canFind;
import uvm;
class riscv_vector_instr: riscv_floating_point_instr
{
mixin uvm_object_utils;
@rand riscv_vreg_t vs1;
@rand riscv_vreg_t vs2;
@rand riscv_vreg_t vs3;
@rand riscv_vreg_t vd;
@rand va_variant_t va_variant;
@rand bool vm;
@rand bool wd;
@rand ubvec!11 eew;
bool has_vd = true;
bool has_vs1 = true;
bool has_vs2 = true;
bool has_vs3 = true;
bool has_vm = false;
bool has_va_variant;
bool is_widening_instr;
bool is_narrowing_instr;
bool is_quad_widening_instr;
bool is_convert_instr;
va_variant_t [] allowed_va_variants;
string sub_extension;
@rand ubvec!3 nfields; // Used by segmented load/store
bool rand_nfields;
@rand ubvec!4 emul;
constraint!q{
if (m_cfg.vector_cfg.reserved_vregs.length > 0) {
!(vd inside [m_cfg.vector_cfg.reserved_vregs]);
}
} avoid_reserved_vregs_c;
constraint!q{
if (has_va_variant == true) {
va_variant inside [allowed_va_variants];
}
} va_variant_c;
// Section 3.3.2: Vector Register Grouping (vlmul)
// Instructions specifying a vector operand with an odd-numbered vector register will raisean
// illegal instruction exception.
// TODO: Exclude the instruction that ignore VLMUL
// TODO: Update this constraint for fractional LMUL
constraint!q{
if (m_cfg.vector_cfg.vtype.vlmul > 0) {
vd % m_cfg.vector_cfg.vtype.vlmul == 0;
vs1 % m_cfg.vector_cfg.vtype.vlmul == 0;
vs2 % m_cfg.vector_cfg.vtype.vlmul == 0;
vs3 % m_cfg.vector_cfg.vtype.vlmul == 0;
}
} operand_group_c;
// Section 11.2: Widening Vector Arithmetic Instructions
constraint!q{
if (is_widening_instr == true) {
// The destination vector register group results are arranged as if both
// SEW and LMUL were at twice their current settings.
vd % (m_cfg.vector_cfg.vtype.vlmul * 2) == 0;
// The destination vector register group cannot overlap a source vector
// register group of a different element width (including the mask register if masked)
!(vs1 inside [vd..(vd + m_cfg.vector_cfg.vtype.vlmul * 2)]);
!(vs2 inside [vd..(vd + m_cfg.vector_cfg.vtype.vlmul * 2)]);
(vm == false) -> (vd != 0);
// Double-width result, first source double-width, second source single-width
if (va_variant inside [va_variant_t.WV, va_variant_t.WX]) {
vs2 % (m_cfg.vector_cfg.vtype.vlmul * 2) == 0;
}
}
} widening_instr_c;
// Section 11.3: Narrowing Vector Arithmetic Instructions
constraint!q{
if (is_narrowing_instr == true) {
// The source and destination vector register numbers must be aligned
// appropriately for the vector registergroup size
vs2 % (m_cfg.vector_cfg.vtype.vlmul * 2) == 0;
// The destination vector register group cannot overlap the rst source
// vector register group (specied by vs2)
!(vd inside [vs2..(vs2 + m_cfg.vector_cfg.vtype.vlmul * 2)]);
// The destination vector register group cannot overlap the mask register
// if used, unless LMUL=1 (implemented in vmask_overlap_c)
}
} narrowing_instr_c;
// 12.3. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions
constraint!q{
if (m_cfg.vector_cfg.vtype.vlmul > 1) {
// For vadc and vsbc, an illegal instruction exception is raised if the
// destination vector register is v0 and LMUL> 1
if (instr_name inside [riscv_instr_name_t.VADC,
riscv_instr_name_t.VSBC]) {
vd != 0;
}
// For vmadc and vmsbc, an illegal instruction exception is raised if the
// destination vector register overlaps asource vector register group and LMUL > 1
if (instr_name inside [riscv_instr_name_t.VMADC,
riscv_instr_name_t.VMSBC]) {
vd != vs2;
vd != vs1;
}
}
} add_sub_with_carry_c;
// 12.7. Vector Integer Comparison Instructions
// For all comparison instructions, an illegal instruction exception is raised if the
// destination vector register overlaps a source vector register group and LMUL > 1
constraint!q{
if (category == riscv_instr_category_t.COMPARE) {
vd != vs2;
vd != vs1;
}
} compare_instr_c;
// 16.8. Vector Iota Instruction
// An illegal instruction exception is raised if the destination vector register group
// overlaps the source vector mask register. If the instruction is masked, an illegal
// instruction exception is issued if the destination vector register group overlaps v0.
constraint!q{
if (instr_name == riscv_instr_name_t.VIOTA_M) {
vd != vs2;
(vm == false) -> (vd != 0);
}
} vector_itoa_c;
// 16.9. Vector Element Index Instruction
// The vs2 eld of the instruction must be set to v0, otherwise the encoding is reserved
constraint!q{
if (instr_name == riscv_instr_name_t.VID_V) {
vs2 == 0;
// TODO; Check if this constraint is needed
vd != vs2;
}
} vector_element_index_c;
// Section 17.3 Vector Slide Instructions
// The destination vector register group for vslideup cannot overlap the vector register
// group of the source vector register group or the mask register
constraint!q{
if (instr_name inside [riscv_instr_name_t.VSLIDEUP,
riscv_instr_name_t.VSLIDE1UP,
riscv_instr_name_t.VSLIDEDOWN,
riscv_instr_name_t.VSLIDE1DOWN]) {
vd != vs2;
vd != vs1;
(vm == false) -> (vd != 0);
}
} vector_slide_c;
// Section 17.4: Vector Register Gather Instruction
// For any vrgather instruction, the destination vector register group cannot overlap
// with the source vector register group
constraint!q{
if (instr_name == riscv_instr_name_t.VRGATHER) {
vd != vs2;
vd != vs1;
(vm == false) -> (vd != 0);
}
} vector_gather_c;
// Section 17.5: Vector compress instruction
// The destination vector register group cannot overlap the source vector register
// group or the source vector mask register
constraint!q{
if (instr_name == riscv_instr_name_t.VCOMPRESS) {
vd != vs2;
vd != vs1;
(vm == false) -> (vd != 0);
}
} vector_compress_c;
// Section 7.8. Vector Load/Store Segment Instructions
// The LMUL setting must be such that LMUL * NFIELDS <= 8
// Vector register numbers accessed by the segment load or store would increment
// cannot past 31
constraint!q{
if $(check_sub_extension(sub_extension, "zvlsseg")) {
if (m_cfg.vector_cfg.vtype.vlmul < 8) {
(nfields + 1) * m_cfg.vector_cfg.vtype.vlmul <= 8;
if (category == riscv_instr_category_t.LOAD) {
vd + nfields <= 31;
}
if (category == riscv_instr_category_t.STORE) {
vs3 + nfields <= 31;
}
// TODO: Check gcc compile issue with nfields == 0
nfields > 0;
}
else {
nfields == 0;
}
}
} nfields_c;
constraint!q{
if (instr_name == riscv_instr_name_t.VMV2R_V) {
vs2 % 2 == 0;
vd % 2 == 0;
}
if (instr_name == riscv_instr_name_t.VMV4R_V) {
vs2 % 4 == 0;
vd % 4 == 0;
}
if (instr_name == riscv_instr_name_t.VMV8R_V) {
vs2 % 8 == 0;
vd % 8 == 0;
}
} vmv_alignment_c;
/////////////////// Vector mask constraint ///////////////////
// Section 5.3
// The destination vector register group for a masked vector instruction can only overlap
// the source mask register (v0) when LMUL=1
constraint!q{
(vm == false) && (m_cfg.vector_cfg.vtype.vlmul > 1) -> (vd != 0);
} vmask_overlap_c;
constraint!q{
// Below instruction is always masked
if (instr_name inside [riscv_instr_name_t.VMERGE,
riscv_instr_name_t.VFMERGE,
riscv_instr_name_t.VADC,
riscv_instr_name_t.VSBC]) {
vm == false;
}
} vector_mask_enable_c;
constraint!q{
// (vm=0) is reserved for below ops
if (instr_name inside [riscv_instr_name_t.VMV, riscv_instr_name_t.VFMV,
riscv_instr_name_t.VCOMPRESS, riscv_instr_name_t.VFMV_F_S,
riscv_instr_name_t.VFMV_S_F, riscv_instr_name_t.VMV_X_S,
riscv_instr_name_t.VMV_S_X, riscv_instr_name_t.VMV1R_V,
riscv_instr_name_t.VMV2R_V, riscv_instr_name_t.VMV4R_V,
riscv_instr_name_t.VMV8R_V]) {
vm == true;
}
} vector_mask_disable_c;
// 16.1. Vector Mask-Register Logical Instructions
// No vector mask for these instructions
constraint!q{
if (instr_name inside [riscv_instr_name_t.VMAND_MM : riscv_instr_name_t.VMXNOR_MM]) {
vm == true;
}
} vector_mask_instr_c;
constraint!q{
if (! m_cfg.vector_cfg.vec_fp) {
va_variant != va_variant_t.VF;
}
} disable_floating_point_varaint_c;
constraint!q{
// TODO: Check why this is needed?
if (category == riscv_instr_category_t.STORE) {
(vm == false) -> (vs3 != 0);
vs2 != vs3;
}
// 7.8.3 For vector indexed segment loads, the destination vector register groups
// cannot overlap the source vectorregister group (specied by vs2), nor can they
// overlap the mask register if masked
// AMO instruction uses indexed address mode
if (instr_format inside [riscv_instr_format_t.VLX_FORMAT, riscv_instr_format_t.VAMO_FORMAT]) {
vd != vs2;
}
} vector_load_store_mask_overlap_c;
// load/store EEW/EMUL and corresponding register grouping constraints
constraint!q{
solve eew before emul;
solve emul before vd;
solve emul before vs1;
solve emul before vs2;
solve emul before vs3;
} load_store_solve_order_c;
constraint!q{
if (category inside [riscv_instr_category_t.LOAD, riscv_instr_category_t.STORE,
riscv_instr_category_t.AMO]) {
eew inside [m_cfg.vector_cfg.legal_eew];
if (eew > m_cfg.vector_cfg.vtype.vsew) {
emul == eew / m_cfg.vector_cfg.vtype.vsew;
}
else {
emul == 1;
}
if (emul > 1) {
vd % emul == 0;
vs1 % emul == 0;
vs2 % emul == 0;
vs3 % emul == 0;
}
}
} load_store_eew_emul_c;
// Some temporarily constraint to avoid illegal instruction
// TODO: Review these constraints
constraint!q{
(vm == false) -> (vd != 0);
} temp_c;
this(string name = "riscv_vector_instr") {
super(name);
}
// Filter unsupported instructions based on configuration
override bool is_supported(riscv_instr_gen_config cfg) {
import std.conv: to;
string name = instr_name.to!string();
// 19.2.2. Vector Add with Carry/Subtract with Borrow Reserved under EDIV>1
if ((cfg.vector_cfg.vtype.vediv > 1) &&
(instr_name.inside(riscv_instr_name_t.VADC, riscv_instr_name_t.VSBC,
riscv_instr_name_t.VMADC, riscv_instr_name_t.VMSBC))) {
return false;
}
// Disable widening/narrowing instruction when LMUL == 8
if ((!cfg.vector_cfg.vec_narrowing_widening) &&
(is_widening_instr || is_narrowing_instr)) {
return false;
}
if (!cfg.vector_cfg.vec_quad_widening && is_quad_widening_instr) {
return false;
}
// TODO: Clean up this list, it's causing gcc compile error now
if (instr_name.inside(riscv_instr_name_t.VWMACCSU,
riscv_instr_name_t.VMERGE,
riscv_instr_name_t.VFMERGE,
riscv_instr_name_t.VMADC,
riscv_instr_name_t.VMSBC)) {
return false;
}
// The standard vector floating-point instructions treat 16-bit, 32-bit, 64-bit,
// and 128-bit elements as IEEE-754/2008-compatible values. If the current SEW does
// not correspond to a supported IEEE floating-pointtype, an illegal instruction
// exception is raised
if (!cfg.vector_cfg.vec_fp) {
if ((name[0..2] == "VF") || (name[0..3] == "VMF")) {
return false;
}
}
return true;
}
override string get_instr_name() {
string name = super.get_instr_name();
if (category.inside(riscv_instr_category_t.LOAD, riscv_instr_category_t.STORE)) {
// Add eew before ".v" or "ff.v" suffix
if (instr_name.inside(riscv_instr_name_t.VLEFF_V, riscv_instr_name_t.VLSEGEFF_V)) {
name = name[0..name.length - 4];
name = format("%0s%0dFF.V", name, eew);
}
else {
name = name[0..name.length - 2];
name = format("%0s%0d.V", name, eew);
}
uvm_info(get_full_name(), format("%0s -> %0s", super.get_instr_name(), name), UVM_LOW);
}
return name;
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
import std.string: toLower;
string asm_str;
switch (instr_format) {
case riscv_instr_format_t.VS2_FORMAT:
if (instr_name == riscv_instr_name_t.VID_V) {
asm_str = format("vid.v %s", vd);
}
else if (instr_name.inside(riscv_instr_name_t.VPOPC_M,
riscv_instr_name_t.VFIRST_M)) {
asm_str = format("%0s %0s,%0s", get_instr_name(), rd, vs2);
}
else {
asm_str = format("%0s %0s,%0s", get_instr_name(), vd, vs2);
}
break;
case riscv_instr_format_t.VA_FORMAT:
if (instr_name == riscv_instr_name_t.VMV) {
switch (va_variant) {
case va_variant_t.VV:
asm_str = format("vmv.v.v %s,%s", vd, vs1);
break;
case va_variant_t.VX:
asm_str = format("vmv.v.x %s,%s", vd, rs1);
break;
case va_variant_t.VI:
asm_str = format("vmv.v.i %s,%s", vd, imm_str);
break;
default: uvm_info(get_full_name(), format("Unsupported va_variant %0s", va_variant), UVM_LOW);
}
}
else if (instr_name == riscv_instr_name_t.VFMV) {
asm_str = format("vfmv.v.f %s,%s", vd, fs1);
}
else if (instr_name == riscv_instr_name_t.VMV_X_S) {
asm_str = format("vmv.x.s %s,%s", rd, vs2);
}
else if (instr_name == riscv_instr_name_t.VMV_S_X) {
asm_str = format("vmv.s.x %s,%s", vd, rs1);
}
else if (instr_name == riscv_instr_name_t.VFMV_F_S) {
asm_str = format("vfmv.f.s %s,%s", fd, vs2);
}
else if (instr_name == riscv_instr_name_t.VFMV_S_F) {
asm_str = format("vfmv.s.f %s,%s", vd, fs1);
}
else {
if (!has_va_variant) {
asm_str = format("%0s ", get_instr_name());
asm_str = format_string(asm_str, MAX_INSTR_STR_LEN);
asm_str = asm_str ~ format("%0s,%0s,%0s", vd, vs2, vs1);
}
else {
asm_str = format("%0s.%0s ", get_instr_name(), va_variant);
asm_str = format_string(asm_str, MAX_INSTR_STR_LEN);
switch (va_variant) {
case va_variant_t.WV,
va_variant_t.VV,
va_variant_t.VVM,
va_variant_t.VM:
asm_str = asm_str ~ format("%0s,%0s,%0s", vd, vs2, vs1);
break;
case va_variant_t.WI,
va_variant_t.VI,
va_variant_t.VIM:
asm_str = asm_str ~ format("%0s,%0s,%0s", vd, vs2, imm_str);
break;
case va_variant_t.VF,
va_variant_t.VFM:
if (instr_name.inside(riscv_instr_name_t.VFMADD,
riscv_instr_name_t.VFNMADD,
riscv_instr_name_t.VFMACC,
riscv_instr_name_t.VFNMACC,
riscv_instr_name_t.VFNMSUB,
riscv_instr_name_t.VFWNMSAC,
riscv_instr_name_t.VFWMACC,
riscv_instr_name_t.VFMSUB,
riscv_instr_name_t.VFMSAC,
riscv_instr_name_t.VFNMSAC,
riscv_instr_name_t.VFWNMACC,
riscv_instr_name_t.VFWMSAC)) {
asm_str = asm_str ~ format("%0s,%0s,%0s", vd, fs1, vs2);
}
else {
asm_str = asm_str ~ format("%0s,%0s,%0s", vd, vs2, fs1);
}
break;
case va_variant_t.WX,
va_variant_t.VX,
va_variant_t.VXM:
if (instr_name.inside(riscv_instr_name_t.VMADD,
riscv_instr_name_t.VNMSUB,
riscv_instr_name_t.VMACC,
riscv_instr_name_t.VNMSAC,
riscv_instr_name_t.VWMACCSU,
riscv_instr_name_t.VWMACCU,
riscv_instr_name_t.VWMACCUS,
riscv_instr_name_t.VWMACC)) {
asm_str ~= format("%0s,%0s,%0s", vd, rs1, vs2);
}
else {
asm_str ~= format("%0s,%0s,%0s", vd, vs2, rs1);
}
break;
default: break;
}
}
}
break;
case riscv_instr_format_t.VL_FORMAT:
if (sub_extension == "zvlsseg") {
asm_str = format("%0s %s,(%s)", add_nfields(get_instr_name(), "vlseg"),
vd, rs1);
}
else {
asm_str = format("%0s %s,(%s)", get_instr_name(), vd, rs1);
}
break;
case riscv_instr_format_t.VS_FORMAT:
if (sub_extension == "zvlsseg") {
asm_str = format("%0s %s,(%s)", add_nfields(get_instr_name(), "vsseg"),
vs3, rs1);
}
else {
asm_str = format("%0s %s,(%s)", get_instr_name(), vs3, rs1);
}
break;
case riscv_instr_format_t.VLS_FORMAT:
if (sub_extension == "zvlsseg") {
asm_str = format("%0s %0s,(%0s),%0s", add_nfields(get_instr_name(), "vlsseg"),
vd, rs1, rs2);
}
else {
asm_str = format("%0s %0s,(%0s),%0s", get_instr_name(),
vd, rs1, rs2);
}
break;
case riscv_instr_format_t.VSS_FORMAT:
if (sub_extension == "zvlsseg") {
asm_str = format("%0s %0s,(%0s),%0s", add_nfields(get_instr_name(), "vssseg"),
vs3, rs1, rs2);
}
else {
asm_str = format("%0s %0s,(%0s),%0s", get_instr_name(),
vs3, rs1, rs2);
}
break;
case riscv_instr_format_t.VLX_FORMAT:
if (sub_extension == "zvlsseg") {
asm_str = format("%0s %0s,(%0s),%0s", add_nfields(get_instr_name(), "vlxseg"),
vd, rs1, vs2);
}
else {
asm_str = format("%0s %0s,(%0s),%0s", get_instr_name(),
vd, rs1, vs2);
}
break;
case riscv_instr_format_t.VSX_FORMAT:
if (sub_extension == "zvlsseg") {
asm_str = format("%0s %0s,(%0s),%0s", add_nfields(get_instr_name(), "vsxseg"),
vs3, rs1, vs2);
}
else {
asm_str = format("%0s %0s,(%0s),%0s", get_instr_name(),
vs3, rs1, vs2);
}
break;
case riscv_instr_format_t.VAMO_FORMAT:
if (wd) {
asm_str = format("%0s %0s,(%0s),%0s,%0s", get_instr_name(), vd,
rs1, vs2, vd);
}
else {
asm_str = format("%0s x0,(%0s),%0s,%0s", get_instr_name(),
rs1, vs2, vs3);
}
break;
default:
uvm_fatal(get_full_name(), format("Unsupported format %0s", instr_format));
}
// Add vector mask
asm_str ~= vec_vm_str();
if (comment != "") {
asm_str ~= " #" ~ comment;
}
return asm_str.toLower();
}
override void pre_randomize() {
super.pre_randomize();
rand_mode!q{vs1}(has_vs1);
rand_mode!q{vs2}(has_vs2);
rand_mode!q{vs3}(has_vs3);
rand_mode!q{vd}(has_vd);
rand_mode!q{nfields}(rand_nfields);
if (! (category.inside(riscv_instr_category_t.LOAD,
riscv_instr_category_t.STORE,
riscv_instr_category_t.AMO))) {
load_store_solve_order_c.constraint_mode(false);
}
}
override void set_rand_mode() {
import std.conv: to;
string name = to!string(instr_name);
has_rs1 = true;
has_rs2 = false;
has_rd = false;
has_fs1 = false;
has_fs2 = false;
has_fs3 = false;
has_fd = false;
has_imm = false;
rand_nfields = true;
if (sub_extension != "zvlsseg") {
rand_nfields = false;
}
if ((name[0..2] == "VW") || (name[0..3] == "VFW")) {
is_widening_instr = true;
}
if (name[0..3] == "VQW") {
is_quad_widening_instr = true;
is_widening_instr = true;
}
if ((name[0..2] == "VN") || (name[0..3] == "VFN")) {
is_narrowing_instr = true;
}
if (uvm_is_match("*CVT*", name)) {
is_convert_instr = true;
has_vs1 = false;
}
if (allowed_va_variants.length > 0) {
has_va_variant = true;
}
// Set the rand mode based on the superset of all VA variants
if (instr_format == riscv_instr_format_t.VA_FORMAT) {
has_imm = true;
has_rs1 = true;
has_fs1 = true;
}
}
string vec_vm_str() {
if (vm) {
return "";
}
else {
if (instr_name.inside(riscv_instr_name_t.VMERGE,
riscv_instr_name_t.VFMERGE,
riscv_instr_name_t.VADC,
riscv_instr_name_t.VSBC,
riscv_instr_name_t.VMADC,
riscv_instr_name_t.VMSBC)) {
return ",v0";
}
else {
return ",v0.t";
}
}
}
string add_nfields(string instr_name, string prefix) {
string suffix = instr_name[prefix.length..instr_name.length];
return format("%0s%0d%0s", prefix, nfields + 1, suffix);
}
string add_eew(string instr_name, string prefix) {
string suffix = instr_name[prefix.length..instr_name.length];
return format("%0s%0d%0s", prefix, eew, suffix);
}
bool check_sub_extension(string s, string literal) {
return s == literal;
}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_zba_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t, riscv_instr_name_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.target: XLEN;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.target: supported_isa;
import std.format: format;
import esdl.data.bvec: ubvec, toubvec, clog2;
import uvm;
import std.algorithm: canFind;
class riscv_zba_instr: riscv_instr
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void pre_randomize() {
super.pre_randomize();
}
override void set_imm_len() {
if (instr_name != riscv_instr_name_t.SLLI_UW) {
imm_len = toubvec!5(clog2(XLEN) - 1);
}
else {
imm_len = toubvec!5(clog2(XLEN));
}
imm_mask = imm_mask << imm_len;
}
override ubvec!7 get_opcode() {
switch (instr_name) {
case riscv_instr_name_t.SH1ADD,
riscv_instr_name_t.SH2ADD,
riscv_instr_name_t.SH3ADD: return toubvec!7(0b0110011);
case riscv_instr_name_t.SH1ADD_UW,
riscv_instr_name_t.SH2ADD_UW,
riscv_instr_name_t.SH3ADD_UW: return toubvec!7(0b0111011);
case riscv_instr_name_t.SLLI_UW: return toubvec!7(0b0011011);
default: return super.get_opcode();
}
}
override ubvec!3 get_func3() {
switch (instr_name) {
case riscv_instr_name_t.ADD_UW: return toubvec!3(0b000);
case riscv_instr_name_t.SH1ADD: return toubvec!3(0b010);
case riscv_instr_name_t.SH2ADD: return toubvec!3(0b100);
case riscv_instr_name_t.SH3ADD: return toubvec!3(0b110);
case riscv_instr_name_t.SH1ADD_UW: return toubvec!3(0b010);
case riscv_instr_name_t.SH2ADD_UW: return toubvec!3(0b100);
case riscv_instr_name_t.SH3ADD_UW: return toubvec!3(0b110);
case riscv_instr_name_t.SLLI_UW: return toubvec!3(0b001);
default: return super.get_func3();
}
}
override ubvec!7 get_func7() {
switch (instr_name) {
case riscv_instr_name_t.ADD_UW: return toubvec!7(0b0000100);
case riscv_instr_name_t.SH1ADD: return toubvec!7(0b0010000);
case riscv_instr_name_t.SH2ADD: return toubvec!7(0b0010000);
case riscv_instr_name_t.SH3ADD: return toubvec!7(0b0010000);
case riscv_instr_name_t.SH1ADD_UW: return toubvec!7(0b0010000);
case riscv_instr_name_t.SH2ADD_UW: return toubvec!7(0b0010000);
case riscv_instr_name_t.SH3ADD_UW: return toubvec!7(0b0010000);
case riscv_instr_name_t.SLLI_UW: return toubvec!7(0b0010000);
default: return super.get_func7();
}
}
override string convert2bin(string prefix = "") {
string binary = "";
if (instr_name == riscv_instr_name_t.SLLI_UW) {
binary = format("%8h", toubvec!5(0b0_0001) ~ cast(ubvec!7)(imm[0..6]) ~
rs1 ~ get_func3() ~ rd ~ get_opcode());
}
else {
binary = super.convert2bin(prefix);
}
return binary;
}
override bool is_supported(riscv_instr_gen_config cfg) {
return (cfg.enable_zba_extension &&
(supported_isa.canFind(riscv_instr_group_t.RV32ZBA) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBA)) &&
[riscv_instr_name_t.ADD_UW, riscv_instr_name_t.SH1ADD,
riscv_instr_name_t.SH1ADD_UW, riscv_instr_name_t.SH2ADD,
riscv_instr_name_t.SH2ADD_UW, riscv_instr_name_t.SH3ADD,
riscv_instr_name_t.SH3ADD_UW, riscv_instr_name_t.SLLI_UW].canFind(instr_name));
}
}

View file

@ -0,0 +1,290 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_zbb_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t, riscv_instr_name_t,
riscv_instr_format_t, format_string, MAX_INSTR_STR_LEN;
import riscv.gen.target: XLEN;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.target: supported_isa;
import std.format: format;
import std.string: toLower;
import esdl.data.bvec: ubvec, toubvec, clog2;
import uvm;
import std.algorithm: canFind;
class riscv_zbb_instr: riscv_instr
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void set_rand_mode() {
super.set_rand_mode();
switch (instr_format) {
case riscv_instr_format_t.R_FORMAT:
if (instr_name == riscv_instr_name_t.ZEXT_H) {
has_rs2 = true;
}
break;
case riscv_instr_format_t.I_FORMAT:
if ([riscv_instr_name_t.CLZ, riscv_instr_name_t.CLZW,
riscv_instr_name_t.CTZ, riscv_instr_name_t.CTZW,
riscv_instr_name_t.CPOP, riscv_instr_name_t.CPOPW,
riscv_instr_name_t.ORC_B, riscv_instr_name_t.SEXT_B,
riscv_instr_name_t.SEXT_H, riscv_instr_name_t.REV8].canFind(instr_name)) {
has_imm = false;
}
break;
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
override void pre_randomize() {
super.pre_randomize();
}
final bool is_rv64() {
return group == riscv_instr_group_t.RV64B;
}
override void set_imm_len() {
if (instr_format == riscv_instr_format_t.I_FORMAT) {
if (instr_name == riscv_instr_name_t.RORI) {
imm_len = toubvec!5(clog2(XLEN));
}
else {
imm_len = toubvec!5(5);
}
}
imm_mask = imm_mask << imm_len;
}
override string convert2asm(string prefix = "") {
string asm_str_final;
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
switch (instr_format) {
case riscv_instr_format_t.I_FORMAT: // instr rd rs1
if (! has_imm) {
asm_str_final = format("%0s%0s, %0s", asm_str, rd, rs1);
}
break;
case riscv_instr_format_t.R_FORMAT: // instr rd rs1
if (! has_rs2) {
asm_str_final = format("%0s%0s, %0s", asm_str, rd, rs1);
}
break;
default: uvm_info(get_full_name(),
format("Unsupported format %0s", instr_format),
UVM_LOW);
break;
}
if (asm_str_final == "") {
return super.convert2asm(prefix);
}
if (comment != "") {
asm_str_final = asm_str_final ~ " #" ~ comment;
}
return asm_str_final.toLower();
}
override ubvec!7 get_opcode() {
switch (instr_name) {
case riscv_instr_name_t.ANDN,
riscv_instr_name_t.MAX,
riscv_instr_name_t.MAXU,
riscv_instr_name_t.MIN,
riscv_instr_name_t.MINU,
riscv_instr_name_t.ORN,
riscv_instr_name_t.ROL,
riscv_instr_name_t.ROR,
riscv_instr_name_t.XNOR: return toubvec!7(0b011_0011);
case riscv_instr_name_t.ZEXT_H:
return toubvec!7(0b011_0011 | (toubvec!7(is_rv64()) << 3));
case riscv_instr_name_t.ROLW,
riscv_instr_name_t.RORW: return toubvec!7(0b011_1011);
case riscv_instr_name_t.CLZ,
riscv_instr_name_t.CPOP,
riscv_instr_name_t.CTZ,
riscv_instr_name_t.ORC_B,
riscv_instr_name_t.CLZW,
riscv_instr_name_t.CPOPW,
riscv_instr_name_t.CTZW,
riscv_instr_name_t.RORIW: return toubvec!7(0b001_1011);
case riscv_instr_name_t.REV8,
riscv_instr_name_t.RORI,
riscv_instr_name_t.SEXT_B,
riscv_instr_name_t.SEXT_H: return toubvec!7(0b001_0011);
default: return super.get_opcode();
}
}
override ubvec!3 get_func3() {
switch (instr_name) {
case riscv_instr_name_t.ANDN: return toubvec!3(0b111);
case riscv_instr_name_t.CLZ: return toubvec!3(0b001);
case riscv_instr_name_t.CLZW: return toubvec!3(0b001);
case riscv_instr_name_t.CPOP: return toubvec!3(0b001);
case riscv_instr_name_t.CPOPW: return toubvec!3(0b001);
case riscv_instr_name_t.CTZ: return toubvec!3(0b001);
case riscv_instr_name_t.CTZW: return toubvec!3(0b001);
case riscv_instr_name_t.MAX: return toubvec!3(0b110);
case riscv_instr_name_t.MAXU: return toubvec!3(0b111);
case riscv_instr_name_t.MIN: return toubvec!3(0b100);
case riscv_instr_name_t.MINU: return toubvec!3(0b101);
case riscv_instr_name_t.ORC_B: return toubvec!3(0b101);
case riscv_instr_name_t.ORN: return toubvec!3(0b110);
case riscv_instr_name_t.REV8: return toubvec!3(0b101);
case riscv_instr_name_t.ROL: return toubvec!3(0b001);
case riscv_instr_name_t.ROLW: return toubvec!3(0b001);
case riscv_instr_name_t.ROR: return toubvec!3(0b101);
case riscv_instr_name_t.RORW: return toubvec!3(0b101);
case riscv_instr_name_t.RORI: return toubvec!3(0b101);
case riscv_instr_name_t.RORIW: return toubvec!3(0b101);
case riscv_instr_name_t.SEXT_B: return toubvec!3(0b001);
case riscv_instr_name_t.SEXT_H: return toubvec!3(0b001);
case riscv_instr_name_t.XNOR: return toubvec!3(0b100);
case riscv_instr_name_t.ZEXT_H: return toubvec!3(0b100);
default: return super.get_func3();
}
}
ubvec!5 get_func5() {
switch (instr_name) {
case riscv_instr_name_t.CLZ: return toubvec!5(0b0_0000);
case riscv_instr_name_t.CLZW: return toubvec!5(0b0_0000);
case riscv_instr_name_t.CPOP: return toubvec!5(0b0_0010);
case riscv_instr_name_t.CPOPW: return toubvec!5(0b0_0010);
case riscv_instr_name_t.CTZ: return toubvec!5(0b0_0001);
case riscv_instr_name_t.CTZW: return toubvec!5(0b0_0001);
case riscv_instr_name_t.ORC_B: return toubvec!5(0b0_0111);
case riscv_instr_name_t.REV8: return toubvec!5(0b1_1000);
case riscv_instr_name_t.SEXT_B: return toubvec!5(0b0_0100);
case riscv_instr_name_t.SEXT_H: return toubvec!5(0b0_0101);
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
override ubvec!7 get_func7() {
switch (instr_name) {
case riscv_instr_name_t.ANDN: return toubvec!7(0b010_0000);
case riscv_instr_name_t.CLZ: return toubvec!7(0b011_0000);
case riscv_instr_name_t.CLZW: return toubvec!7(0b011_0000);
case riscv_instr_name_t.CPOP: return toubvec!7(0b011_0000);
case riscv_instr_name_t.CPOPW: return toubvec!7(0b011_0000);
case riscv_instr_name_t.CTZ: return toubvec!7(0b011_0000);
case riscv_instr_name_t.CTZW: return toubvec!7(0b011_0000);
case riscv_instr_name_t.MAX: return toubvec!7(0b000_0101);
case riscv_instr_name_t.MAXU: return toubvec!7(0b000_0101);
case riscv_instr_name_t.MIN: return toubvec!7(0b000_0101);
case riscv_instr_name_t.MINU: return toubvec!7(0b000_0101);
case riscv_instr_name_t.ORC_B: return toubvec!7(0b001_0100);
case riscv_instr_name_t.ORN: return toubvec!7(0b010_0000);
case riscv_instr_name_t.REV8:
return toubvec!7(0b011_0100 | toubvec!7(is_rv64())); // 0110101 64 bit
case riscv_instr_name_t.ROL: return toubvec!7(0b011_0000);
case riscv_instr_name_t.ROLW: return toubvec!7(0b011_0000);
case riscv_instr_name_t.ROR: return toubvec!7(0b011_0000);
case riscv_instr_name_t.RORW: return toubvec!7(0b011_0000);
case riscv_instr_name_t.RORI: return toubvec!7(0b011_0000);
case riscv_instr_name_t.RORIW: return toubvec!7(0b011_0000);
case riscv_instr_name_t.SEXT_B: return toubvec!7(0b011_0000);
case riscv_instr_name_t.SEXT_H: return toubvec!7(0b011_0000);
case riscv_instr_name_t.XNOR: return toubvec!7(0b010_0000);
case riscv_instr_name_t.ZEXT_H: return toubvec!7(0b000_0100);
default: return super.get_func7();
}
}
override string convert2bin(string prefix = "") {
string binary = "";
switch (instr_format) {
case riscv_instr_format_t.R_FORMAT:
if (instr_name == riscv_instr_name_t.ZEXT_H) {
binary = format("%8h", get_func7() ~ get_func5() ~ rs1 ~ get_func3() ~ rd ~ get_opcode());
}
break;
case riscv_instr_format_t.I_FORMAT:
switch (instr_name) {
case riscv_instr_name_t.CLZ,
riscv_instr_name_t.CLZW,
riscv_instr_name_t.CPOP,
riscv_instr_name_t.CPOPW,
riscv_instr_name_t.CTZ,
riscv_instr_name_t.CTZW,
riscv_instr_name_t.ORC_B,
riscv_instr_name_t.REV8,
riscv_instr_name_t.SEXT_B,
riscv_instr_name_t.SEXT_H:
binary = format("%8h", get_func7() ~ get_func5() ~ rs1 ~ get_func3() ~ rd ~
get_opcode());
break;
case riscv_instr_name_t.RORIW:
binary = format("%8h", get_func7() ~ cast (ubvec!6) imm[0..6] ~
rs1 ~ get_func3() ~ rd ~ get_opcode());
break;
case riscv_instr_name_t.RORI:
// set bit 0 of funct7 only if rv64 and shamt[MSB] is set
binary = format("%8h", (get_func7() | cast (ubvec!7) (is_rv64() && imm[5])) ~
cast (ubvec!5) imm[0..5] ~ rs1 ~ get_func3() ~ rd ~ get_opcode());
break;
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
break;
default:
assert (binary == "");
binary = super.convert2bin(prefix);
break;
}
return binary;
}
override bool is_supported(riscv_instr_gen_config cfg) {
return (cfg.enable_zbb_extension &&
(supported_isa.canFind(riscv_instr_group_t.RV32ZBB) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBB)) &&
[riscv_instr_name_t.ANDN, riscv_instr_name_t.CLZ,
riscv_instr_name_t.CLZW, riscv_instr_name_t.CPOP,
riscv_instr_name_t.CPOPW, riscv_instr_name_t.CTZ,
riscv_instr_name_t.CTZW, riscv_instr_name_t.MAX,
riscv_instr_name_t.MAXU, riscv_instr_name_t.MIN,
riscv_instr_name_t.MINU, riscv_instr_name_t.ORC_B,
riscv_instr_name_t.ORN, riscv_instr_name_t.REV8,
riscv_instr_name_t.ROL, riscv_instr_name_t.ROLW,
riscv_instr_name_t.ROR, riscv_instr_name_t.RORW,
riscv_instr_name_t.RORI, riscv_instr_name_t.RORIW,
riscv_instr_name_t.SEXT_B, riscv_instr_name_t.SEXT_H,
riscv_instr_name_t.XNOR, riscv_instr_name_t.ZEXT_H].canFind(instr_name));
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_zbc_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t, riscv_instr_name_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.target: supported_isa;
import std.format: format;
import esdl.data.bvec: ubvec, toubvec, clog2;
import uvm;
import std.algorithm: canFind;
class riscv_zbc_instr: riscv_instr
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void pre_randomize() {
super.pre_randomize();
}
override ubvec!7 get_opcode() {
switch (instr_name) {
case riscv_instr_name_t.CLMUL,
riscv_instr_name_t.CLMULH,
riscv_instr_name_t.CLMULR: return toubvec!7(0b011_0011);
default: return super.get_opcode();
}
}
override ubvec!3 get_func3() {
switch (instr_name) {
case riscv_instr_name_t.CLMUL: return toubvec!3(0b001);
case riscv_instr_name_t.CLMULH: return toubvec!3(0b011);
case riscv_instr_name_t.CLMULR: return toubvec!3(0b010);
default: return super.get_func3();
}
}
override ubvec!7 get_func7() {
switch (instr_name) {
case riscv_instr_name_t.CLMUL: return toubvec!7(0b000_0101);
case riscv_instr_name_t.CLMULH: return toubvec!7(0b000_0101);
case riscv_instr_name_t.CLMULR: return toubvec!7(0b000_0101);
default: return super.get_func7();
}
}
override string convert2bin(string prefix = "") {
string binary = "";
if ([riscv_instr_name_t.CLMUL, riscv_instr_name_t.CLMULH,
riscv_instr_name_t.CLMULR].canFind(instr_name)) {
binary = format("%8h", get_func7() ~ rs2 ~ rs1 ~ get_func3() ~ rd ~ get_opcode());
}
else {
binary = super.convert2bin(prefix);
}
return binary;
}
override bool is_supported(riscv_instr_gen_config cfg) {
return (cfg.enable_zbc_extension &&
(supported_isa.canFind(riscv_instr_group_t.RV32ZBC) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBC)) &&
[riscv_instr_name_t.CLMUL, riscv_instr_name_t.CLMULH,
riscv_instr_name_t.CLMULR].canFind(instr_name));
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.riscv_zbs_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_group_t,
riscv_instr_name_t, riscv_instr_format_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.target: supported_isa, XLEN;
import std.format: format;
import esdl.data.bvec: ubvec, toubvec, clog2;
import uvm;
import std.algorithm: canFind;
class riscv_zbs_instr: riscv_instr
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void pre_randomize() {
super.pre_randomize();
}
final bool is_rv64() {
return (group == riscv_instr_group_t.RV64B);
}
override void set_imm_len() {
if (instr_format == riscv_instr_format_t.I_FORMAT) {
if ([riscv_instr_name_t.BCLRI, riscv_instr_name_t.BEXTI,
riscv_instr_name_t.BINVI, riscv_instr_name_t.BSETI].canFind(instr_name)) {
imm_len = toubvec!5(clog2(XLEN));
}
}
imm_mask = imm_mask << imm_len;
}
override ubvec!7 get_opcode() {
switch (instr_name) {
case riscv_instr_name_t.BCLR,
riscv_instr_name_t.BEXT,
riscv_instr_name_t.BINV,
riscv_instr_name_t.BSET,
riscv_instr_name_t.BCLRI,
riscv_instr_name_t.BEXTI,
riscv_instr_name_t.BINVI,
riscv_instr_name_t.BSETI: return toubvec!7(0b0010011);
default : return super.get_opcode();
}
}
override ubvec!3 get_func3() {
switch (instr_name) {
case riscv_instr_name_t.BCLR: return toubvec!3(0b001);
case riscv_instr_name_t.BCLRI: return toubvec!3(0b001);
case riscv_instr_name_t.BEXT: return toubvec!3(0b101);
case riscv_instr_name_t.BEXTI: return toubvec!3(0b101);
case riscv_instr_name_t.BINV: return toubvec!3(0b001);
case riscv_instr_name_t.BINVI: return toubvec!3(0b001);
case riscv_instr_name_t.BSET: return toubvec!3(0b001);
case riscv_instr_name_t.BSETI: return toubvec!3(0b001);
default: return super.get_func3();
}
}
override ubvec!7 get_func7() {
switch (instr_name) {
case riscv_instr_name_t.BCLR: return toubvec!7(0b0100100);
case riscv_instr_name_t.BCLRI: return toubvec!7(0b0100100);
case riscv_instr_name_t.BEXT: return toubvec!7(0b0100100);
case riscv_instr_name_t.BEXTI: return toubvec!7(0b0100100);
case riscv_instr_name_t.BINV: return toubvec!7(0b0110100);
case riscv_instr_name_t.BINVI: return toubvec!7(0b0110100);
case riscv_instr_name_t.BSET: return toubvec!7(0b0010100);
case riscv_instr_name_t.BSETI: return toubvec!7(0b0010100);
default : return super.get_func7();
}
}
override string convert2bin(string prefix = "") {
string binary = "";
switch (instr_format) {
case riscv_instr_format_t.I_FORMAT:
switch (instr_name) {
case riscv_instr_name_t.BCLRI,
riscv_instr_name_t.BEXTI,
riscv_instr_name_t.BINVI,
riscv_instr_name_t.BSETI:
binary = format("%8h", (get_func7() | (is_rv64() && imm[5])) ~
cast (ubvec!6) (imm[0..5]) ~ rs1 ~
get_func3() ~ rd ~ get_opcode());
break;
default: break;
}
break;
default:
assert (binary == "");
return super.convert2bin(prefix);
}
return binary;
}
override bool is_supported(riscv_instr_gen_config cfg) {
return (cfg.enable_zbs_extension &&
(supported_isa.canFind(riscv_instr_group_t.RV32ZBS) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBS)) &&
[riscv_instr_name_t.BCLR, riscv_instr_name_t.BEXT,
riscv_instr_name_t.BINV, riscv_instr_name_t.BSET,
riscv_instr_name_t.BCLRI, riscv_instr_name_t.BEXTI,
riscv_instr_name_t.BINVI, riscv_instr_name_t.BSETI].canFind(instr_name));
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv128c_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_c_instr_mixin(C_SRLI64, CB_FORMAT, SHIFT, RV128C, NZUIMM));
mixin (riscv_c_instr_mixin(C_SRAI64, CB_FORMAT, SHIFT, RV128C, NZUIMM));
mixin (riscv_c_instr_mixin(C_SLLI64, CI_FORMAT, SHIFT, RV128C, NZUIMM));
mixin (riscv_c_instr_mixin(C_LQ, CL_FORMAT, LOAD, RV32DC, UIMM));
mixin (riscv_c_instr_mixin(C_SQ, CS_FORMAT, STORE, RV32DC, UIMM));
mixin (riscv_c_instr_mixin(C_LQSP, CI_FORMAT, LOAD, RV32DC, UIMM));
mixin (riscv_c_instr_mixin(C_SQSP, CSS_FORMAT, STORE, RV32DC, UIMM));
}
else {
class riscv_C_SRLI64_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SRLI64, CB_FORMAT, SHIFT, RV128C, NZUIMM); }
class riscv_C_SRAI64_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SRAI64, CB_FORMAT, SHIFT, RV128C, NZUIMM); }
class riscv_C_SLLI64_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SLLI64, CI_FORMAT, SHIFT, RV128C, NZUIMM); }
class riscv_C_LQ_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LQ, CL_FORMAT, LOAD, RV32DC, UIMM); }
class riscv_C_SQ_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SQ, CS_FORMAT, STORE, RV32DC, UIMM); }
class riscv_C_LQSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LQSP, CI_FORMAT, LOAD, RV32DC, UIMM); }
class riscv_C_SQSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SQSP, CSS_FORMAT, STORE, RV32DC, UIMM); }
}

View file

@ -0,0 +1,60 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32a_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_amo_instr_mixin(LR_W, R_FORMAT, LOAD, RV32A));
mixin (riscv_amo_instr_mixin(SC_W, R_FORMAT, STORE, RV32A));
mixin (riscv_amo_instr_mixin(AMOSWAP_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOADD_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOAND_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOOR_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOXOR_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOMIN_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOMAX_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOMINU_W, R_FORMAT, AMO, RV32A));
mixin (riscv_amo_instr_mixin(AMOMAXU_W, R_FORMAT, AMO, RV32A));
}
else {
class riscv_LR_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(LR_W, R_FORMAT, LOAD, RV32A); }
class riscv_SC_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(SC_W, R_FORMAT, STORE, RV32A); }
class riscv_AMOSWAP_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOSWAP_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOADD_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOADD_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOAND_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOAND_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOOR_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOOR_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOXOR_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOXOR_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOMIN_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMIN_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOMAX_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMAX_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOMINU_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMINU_W, R_FORMAT, AMO, RV32A); }
class riscv_AMOMAXU_W_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMAXU_W, R_FORMAT, AMO, RV32A); }
}

View file

@ -0,0 +1,132 @@
/*
* Copyright 2019 Google LLC
* Copyright 2019 Mellanox Technologies Ltd
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32b_instr;
import riscv.gen.riscv_defines;
import uvm;
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
version (RISCV_INSTR_STRING_MIXIN) {
// LOGICAL instructions
mixin (riscv_b_instr_mixin(GORC, R_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(GORCI, I_FORMAT, LOGICAL, RV32B, UIMM));
mixin (riscv_b_instr_mixin(CMIX, R4_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(CMOV, R4_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(PACK, R_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(PACKU, R_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(PACKH, R_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(XPERM_N, R_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(XPERM_B, R_FORMAT, LOGICAL, RV32B));
mixin (riscv_b_instr_mixin(XPERM_H, R_FORMAT, LOGICAL, RV32B));
// SHIFT intructions
mixin (riscv_b_instr_mixin(SLO, R_FORMAT, SHIFT, RV32B));
mixin (riscv_b_instr_mixin(SRO, R_FORMAT, SHIFT, RV32B));
mixin (riscv_b_instr_mixin(SLOI, I_FORMAT, SHIFT, RV32B, UIMM));
mixin (riscv_b_instr_mixin(SROI, I_FORMAT, SHIFT, RV32B, UIMM));
mixin (riscv_b_instr_mixin(GREV, R_FORMAT, SHIFT, RV32B));
mixin (riscv_b_instr_mixin(GREVI, I_FORMAT, SHIFT, RV32B, UIMM));
mixin (riscv_b_instr_mixin(FSL, R4_FORMAT, SHIFT, RV32B));
mixin (riscv_b_instr_mixin(FSR, R4_FORMAT, SHIFT, RV32B));
mixin (riscv_b_instr_mixin(FSRI, I_FORMAT, SHIFT, RV32B, UIMM));
// ARITHMETIC intructions
mixin (riscv_b_instr_mixin(CRC32_B, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(CRC32_H, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(CRC32_W, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(CRC32C_B, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(CRC32C_H, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(CRC32C_W, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(SHFL, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(UNSHFL, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(SHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM));
mixin (riscv_b_instr_mixin(UNSHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM));
mixin (riscv_b_instr_mixin(BCOMPRESS, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(BDECOMPRESS, R_FORMAT, ARITHMETIC, RV32B));
mixin (riscv_b_instr_mixin(BFP, R_FORMAT, ARITHMETIC, RV32B));
}
else {
// LOGICAL instructions
class riscv_GORC_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GORC, R_FORMAT, LOGICAL, RV32B); }
class riscv_GORCI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GORCI, I_FORMAT, LOGICAL, RV32B, UIMM); }
class riscv_CMIX_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CMIX, R4_FORMAT, LOGICAL, RV32B); }
class riscv_CMOV_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CMOV, R4_FORMAT, LOGICAL, RV32B); }
class riscv_PACK_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(PACK, R_FORMAT, LOGICAL, RV32B); }
class riscv_PACKU_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(PACKU, R_FORMAT, LOGICAL, RV32B); }
class riscv_PACKH_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(PACKH, R_FORMAT, LOGICAL, RV32B); }
class riscv_XPERM_N_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(XPERM_N, R_FORMAT, LOGICAL, RV32B); }
class riscv_XPERM_B_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(XPERM_B, R_FORMAT, LOGICAL, RV32B); }
class riscv_XPERM_H_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(XPERM_H, R_FORMAT, LOGICAL, RV32B); }
// SHIFT intructions
class riscv_SLO_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SLO, R_FORMAT, SHIFT, RV32B); }
class riscv_SRO_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SRO, R_FORMAT, SHIFT, RV32B); }
class riscv_SLOI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SLOI, I_FORMAT, SHIFT, RV32B, UIMM); }
class riscv_SROI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SROI, I_FORMAT, SHIFT, RV32B, UIMM); }
class riscv_GREV_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GREV, R_FORMAT, SHIFT, RV32B); }
class riscv_GREVI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GREVI, I_FORMAT, SHIFT, RV32B, UIMM); }
class riscv_FSL_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(FSL, R4_FORMAT, SHIFT, RV32B); }
class riscv_FSR_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(FSR, R4_FORMAT, SHIFT, RV32B); }
class riscv_FSRI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(FSRI, I_FORMAT, SHIFT, RV32B, UIMM); }
// ARITHMETIC intructions
class riscv_CRC32_B_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32_B, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_CRC32_H_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32_H, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_CRC32_W_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32_W, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_CRC32C_B_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32C_B, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_CRC32C_H_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32C_H, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_CRC32C_W_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32C_W, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_SHFL_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SHFL, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_UNSHFL_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(UNSHFL, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_SHFLI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM); }
class riscv_UNSHFLI_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(UNSHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM); }
class riscv_BCOMPRESS_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BCOMPRESS, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_BDECOMPRESS_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BDECOMPRESS, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_BFP_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BFP, R_FORMAT, ARITHMETIC, RV32B); }
}

View file

@ -0,0 +1,108 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32c_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_c_instr_mixin(C_LW, CL_FORMAT, LOAD, RV32C, UIMM));
mixin (riscv_c_instr_mixin(C_SW, CS_FORMAT, STORE, RV32C, UIMM));
mixin (riscv_c_instr_mixin(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM));
mixin (riscv_c_instr_mixin(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM));
mixin (riscv_c_instr_mixin(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM));
mixin (riscv_c_instr_mixin(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM));
mixin (riscv_c_instr_mixin(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM));
mixin (riscv_c_instr_mixin(C_LI, CI_FORMAT, ARITHMETIC, RV32C));
mixin (riscv_c_instr_mixin(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM));
mixin (riscv_c_instr_mixin(C_SUB, CA_FORMAT, ARITHMETIC, RV32C));
mixin (riscv_c_instr_mixin(C_ADD, CR_FORMAT, ARITHMETIC, RV32C));
mixin (riscv_c_instr_mixin(C_NOP, CI_FORMAT, ARITHMETIC, RV32C));
mixin (riscv_c_instr_mixin(C_MV, CR_FORMAT, ARITHMETIC, RV32C));
mixin (riscv_c_instr_mixin(C_ANDI, CB_FORMAT, LOGICAL, RV32C));
mixin (riscv_c_instr_mixin(C_XOR, CA_FORMAT, LOGICAL, RV32C));
mixin (riscv_c_instr_mixin(C_OR, CA_FORMAT, LOGICAL, RV32C));
mixin (riscv_c_instr_mixin(C_AND, CA_FORMAT, LOGICAL, RV32C));
mixin (riscv_c_instr_mixin(C_BEQZ, CB_FORMAT, BRANCH, RV32C));
mixin (riscv_c_instr_mixin(C_BNEZ, CB_FORMAT, BRANCH, RV32C));
mixin (riscv_c_instr_mixin(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM));
mixin (riscv_c_instr_mixin(C_SRAI, CB_FORMAT, SHIFT, RV32C, NZUIMM));
mixin (riscv_c_instr_mixin(C_SLLI, CI_FORMAT, SHIFT, RV32C, NZUIMM));
mixin (riscv_c_instr_mixin(C_J, CJ_FORMAT, JUMP, RV32C));
mixin (riscv_c_instr_mixin(C_JAL, CJ_FORMAT, JUMP, RV32C));
mixin (riscv_c_instr_mixin(C_JR, CR_FORMAT, JUMP, RV32C));
mixin (riscv_c_instr_mixin(C_JALR, CR_FORMAT, JUMP, RV32C));
mixin (riscv_c_instr_mixin(C_EBREAK, CI_FORMAT, SYSTEM, RV32C));
}
else {
class riscv_C_LW_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LW, CL_FORMAT, LOAD, RV32C, UIMM); }
class riscv_C_SW_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SW, CS_FORMAT, STORE, RV32C, UIMM); }
class riscv_C_LWSP_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM); }
class riscv_C_SWSP_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM); }
class riscv_C_ADDI4SPN_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM); }
class riscv_C_ADDI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM); }
class riscv_C_ADDI16SP_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM); }
class riscv_C_LI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LI, CI_FORMAT, ARITHMETIC, RV32C); }
class riscv_C_LUI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM); }
class riscv_C_SUB_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SUB, CA_FORMAT, ARITHMETIC, RV32C); }
class riscv_C_ADD_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ADD, CR_FORMAT, ARITHMETIC, RV32C); }
class riscv_C_NOP_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_NOP, CI_FORMAT, ARITHMETIC, RV32C); }
class riscv_C_MV_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_MV, CR_FORMAT, ARITHMETIC, RV32C); }
class riscv_C_ANDI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ANDI, CB_FORMAT, LOGICAL, RV32C); }
class riscv_C_XOR_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_XOR, CA_FORMAT, LOGICAL, RV32C); }
class riscv_C_OR_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_OR, CA_FORMAT, LOGICAL, RV32C); }
class riscv_C_AND_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_AND, CA_FORMAT, LOGICAL, RV32C); }
class riscv_C_BEQZ_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_BEQZ, CB_FORMAT, BRANCH, RV32C); }
class riscv_C_BNEZ_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_BNEZ, CB_FORMAT, BRANCH, RV32C); }
class riscv_C_SRLI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM); }
class riscv_C_SRAI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SRAI, CB_FORMAT, SHIFT, RV32C, NZUIMM); }
class riscv_C_SLLI_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SLLI, CI_FORMAT, SHIFT, RV32C, NZUIMM); }
class riscv_C_J_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_J, CJ_FORMAT, JUMP, RV32C); }
class riscv_C_JAL_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_JAL, CJ_FORMAT, JUMP, RV32C); }
class riscv_C_JR_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_JR, CR_FORMAT, JUMP, RV32C); }
class riscv_C_JALR_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_JALR, CR_FORMAT, JUMP, RV32C); }
class riscv_C_EBREAK_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_EBREAK, CI_FORMAT, SYSTEM, RV32C); }
}

View file

@ -0,0 +1,105 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32d_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_fp_instr_mixin(FLD, I_FORMAT, LOAD, RV32D));
mixin (riscv_fp_instr_mixin(FSD, S_FORMAT, STORE, RV32D));
mixin (riscv_fp_instr_mixin(FMADD_D, R4_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FMSUB_D, R4_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FNMSUB_D, R4_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FNMADD_D, R4_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FADD_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FSUB_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FMUL_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FDIV_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FSQRT_D, I_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FSGNJ_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FSGNJN_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FSGNJX_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FMIN_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FMAX_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FCVT_S_D, I_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FCVT_D_S, I_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FEQ_D, R_FORMAT, COMPARE, RV32D));
mixin (riscv_fp_instr_mixin(FLT_D, R_FORMAT, COMPARE, RV32D));
mixin (riscv_fp_instr_mixin(FLE_D, R_FORMAT, COMPARE, RV32D));
mixin (riscv_fp_instr_mixin(FCLASS_D, R_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FCVT_W_D, I_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FCVT_WU_D, I_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FCVT_D_W, I_FORMAT, ARITHMETIC, RV32D));
mixin (riscv_fp_instr_mixin(FCVT_D_WU, I_FORMAT, ARITHMETIC, RV32D));
}
else {
class riscv_FLD_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FLD, I_FORMAT, LOAD, RV32D); }
class riscv_FSD_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSD, S_FORMAT, STORE, RV32D); }
class riscv_FMADD_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMADD_D, R4_FORMAT, ARITHMETIC, RV32D); }
class riscv_FMSUB_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMSUB_D, R4_FORMAT, ARITHMETIC, RV32D); }
class riscv_FNMSUB_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FNMSUB_D, R4_FORMAT, ARITHMETIC, RV32D); }
class riscv_FNMADD_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FNMADD_D, R4_FORMAT, ARITHMETIC, RV32D); }
class riscv_FADD_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FADD_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FSUB_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSUB_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FMUL_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMUL_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FDIV_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FDIV_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FSQRT_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSQRT_D, I_FORMAT, ARITHMETIC, RV32D); }
class riscv_FSGNJ_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSGNJ_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FSGNJN_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSGNJN_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FSGNJX_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSGNJX_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FMIN_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMIN_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FMAX_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMAX_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FCVT_S_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_S_D, I_FORMAT, ARITHMETIC, RV32D); }
class riscv_FCVT_D_S_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_D_S, I_FORMAT, ARITHMETIC, RV32D); }
class riscv_FEQ_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FEQ_D, R_FORMAT, COMPARE, RV32D); }
class riscv_FLT_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FLT_D, R_FORMAT, COMPARE, RV32D); }
class riscv_FLE_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FLE_D, R_FORMAT, COMPARE, RV32D); }
class riscv_FCLASS_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCLASS_D, R_FORMAT, ARITHMETIC, RV32D); }
class riscv_FCVT_W_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_W_D, I_FORMAT, ARITHMETIC, RV32D); }
class riscv_FCVT_WU_D_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_WU_D, I_FORMAT, ARITHMETIC, RV32D); }
class riscv_FCVT_D_W_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_D_W, I_FORMAT, ARITHMETIC, RV32D); }
class riscv_FCVT_D_WU_INSTR: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_D_WU, I_FORMAT, ARITHMETIC, RV32D); }
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32dc_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_fc_instr_mixin(C_FLD, CL_FORMAT, LOAD, RV32DC, UIMM));
mixin (riscv_fc_instr_mixin(C_FSD, CS_FORMAT, STORE, RV32DC, UIMM));
mixin (riscv_fc_instr_mixin(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM));
mixin (riscv_fc_instr_mixin(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM));
}
else {
class riscv_C_FLD_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FLD, CL_FORMAT, LOAD, RV32DC, UIMM); }
class riscv_C_FSD_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FSD, CS_FORMAT, STORE, RV32DC, UIMM); }
class riscv_C_FLDSP_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM); }
class riscv_C_FSDSP_INSTR: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM); }
}

View file

@ -0,0 +1,105 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32f_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_fp_instr_mixin(FLW, I_FORMAT, LOAD, RV32F));
mixin (riscv_fp_instr_mixin(FSW, S_FORMAT, STORE, RV32F));
mixin (riscv_fp_instr_mixin(FMADD_S, R4_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FMSUB_S, R4_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FNMSUB_S, R4_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FNMADD_S, R4_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FADD_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FSUB_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FMUL_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FDIV_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FSQRT_S, I_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FSGNJ_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FSGNJN_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FSGNJX_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FMIN_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FMAX_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FCVT_W_S, I_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FCVT_WU_S, I_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FMV_X_W, I_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FEQ_S, R_FORMAT, COMPARE, RV32F));
mixin (riscv_fp_instr_mixin(FLT_S, R_FORMAT, COMPARE, RV32F));
mixin (riscv_fp_instr_mixin(FLE_S, R_FORMAT, COMPARE, RV32F));
mixin (riscv_fp_instr_mixin(FCLASS_S, R_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FCVT_S_W, I_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F));
mixin (riscv_fp_instr_mixin(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F));
}
else {
class riscv_FLW_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FLW, I_FORMAT, LOAD, RV32F); }
class riscv_FSW_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSW, S_FORMAT, STORE, RV32F); }
class riscv_FMADD_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMADD_S, R4_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMSUB_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMSUB_S, R4_FORMAT, ARITHMETIC, RV32F); }
class riscv_FNMSUB_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FNMSUB_S, R4_FORMAT, ARITHMETIC, RV32F); }
class riscv_FNMADD_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FNMADD_S, R4_FORMAT, ARITHMETIC, RV32F); }
class riscv_FADD_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FADD_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FSUB_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSUB_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMUL_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMUL_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FDIV_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FDIV_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FSQRT_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSQRT_S, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FSGNJ_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSGNJ_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FSGNJN_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSGNJN_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FSGNJX_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FSGNJX_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMIN_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMIN_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMAX_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMAX_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FCVT_W_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_W_S, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FCVT_WU_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_WU_S, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMV_X_W_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMV_X_W, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FEQ_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FEQ_S, R_FORMAT, COMPARE, RV32F); }
class riscv_FLT_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FLT_S, R_FORMAT, COMPARE, RV32F); }
class riscv_FLE_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FLE_S, R_FORMAT, COMPARE, RV32F); }
class riscv_FCLASS_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCLASS_S, R_FORMAT, ARITHMETIC, RV32F); }
class riscv_FCVT_S_W_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_S_W, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FCVT_S_WU_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMV_W_X_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F); }
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32fc_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_fc_instr_mixin(C_FLW, CL_FORMAT, LOAD, RV32FC, UIMM));
mixin (riscv_fc_instr_mixin(C_FSW, CS_FORMAT, STORE, RV32FC, UIMM));
mixin (riscv_fc_instr_mixin(C_FLWSP, CI_FORMAT, LOAD, RV32FC, UIMM));
mixin (riscv_fc_instr_mixin(C_FSWSP, CSS_FORMAT, STORE, RV32FC, UIMM));
}
else {
class riscv_C_FLW_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FLW, CL_FORMAT, LOAD, RV32FC, UIMM); }
class riscv_C_FSW_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FSW, CS_FORMAT, STORE, RV32FC, UIMM); }
class riscv_C_FLWSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FLWSP, CI_FORMAT, LOAD, RV32FC, UIMM); }
class riscv_C_FSWSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_FSWSP, CSS_FORMAT, STORE, RV32FC, UIMM); }
}

View file

@ -0,0 +1,211 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32i_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
// LOAD instructions
mixin (riscv_instr_mixin(LB, I_FORMAT, LOAD, RV32I));
mixin (riscv_instr_mixin(LH, I_FORMAT, LOAD, RV32I));
mixin (riscv_instr_mixin(LW, I_FORMAT, LOAD, RV32I));
mixin (riscv_instr_mixin(LBU, I_FORMAT, LOAD, RV32I));
mixin (riscv_instr_mixin(LHU, I_FORMAT, LOAD, RV32I));
// STORE instructions
mixin (riscv_instr_mixin(SB, S_FORMAT, STORE, RV32I));
mixin (riscv_instr_mixin(SH, S_FORMAT, STORE, RV32I));
mixin (riscv_instr_mixin(SW, S_FORMAT, STORE, RV32I));
// SHIFT intructions
mixin (riscv_instr_mixin(SLL, R_FORMAT, SHIFT, RV32I));
mixin (riscv_instr_mixin(SLLI, I_FORMAT, SHIFT, RV32I));
mixin (riscv_instr_mixin(SRL, R_FORMAT, SHIFT, RV32I));
mixin (riscv_instr_mixin(SRLI, I_FORMAT, SHIFT, RV32I));
mixin (riscv_instr_mixin(SRA, R_FORMAT, SHIFT, RV32I));
mixin (riscv_instr_mixin(SRAI, I_FORMAT, SHIFT, RV32I));
// ARITHMETIC intructions
mixin (riscv_instr_mixin(ADD, R_FORMAT, ARITHMETIC, RV32I));
mixin (riscv_instr_mixin(ADDI, I_FORMAT, ARITHMETIC, RV32I));
mixin (riscv_instr_mixin(NOP, I_FORMAT, ARITHMETIC, RV32I));
mixin (riscv_instr_mixin(SUB, R_FORMAT, ARITHMETIC, RV32I));
mixin (riscv_instr_mixin(LUI, U_FORMAT, ARITHMETIC, RV32I, UIMM));
mixin (riscv_instr_mixin(AUIPC, U_FORMAT, ARITHMETIC, RV32I, UIMM));
// LOGICAL instructions
mixin (riscv_instr_mixin(XOR, R_FORMAT, LOGICAL, RV32I));
mixin (riscv_instr_mixin(XORI, I_FORMAT, LOGICAL, RV32I));
mixin (riscv_instr_mixin(OR, R_FORMAT, LOGICAL, RV32I));
mixin (riscv_instr_mixin(ORI, I_FORMAT, LOGICAL, RV32I));
mixin (riscv_instr_mixin(AND, R_FORMAT, LOGICAL, RV32I));
mixin (riscv_instr_mixin(ANDI, I_FORMAT, LOGICAL, RV32I));
// COMPARE instructions
mixin (riscv_instr_mixin(SLT, R_FORMAT, COMPARE, RV32I));
mixin (riscv_instr_mixin(SLTI, I_FORMAT, COMPARE, RV32I));
mixin (riscv_instr_mixin(SLTU, R_FORMAT, COMPARE, RV32I));
mixin (riscv_instr_mixin(SLTIU, I_FORMAT, COMPARE, RV32I));
// BRANCH instructions
mixin (riscv_instr_mixin(BEQ, B_FORMAT, BRANCH, RV32I));
mixin (riscv_instr_mixin(BNE, B_FORMAT, BRANCH, RV32I));
mixin (riscv_instr_mixin(BLT, B_FORMAT, BRANCH, RV32I));
mixin (riscv_instr_mixin(BGE, B_FORMAT, BRANCH, RV32I));
mixin (riscv_instr_mixin(BLTU, B_FORMAT, BRANCH, RV32I));
mixin (riscv_instr_mixin(BGEU, B_FORMAT, BRANCH, RV32I));
// JUMP instructions
mixin (riscv_instr_mixin(JAL, J_FORMAT, JUMP, RV32I));
mixin (riscv_instr_mixin(JALR, I_FORMAT, JUMP, RV32I));
// SYNCH instructions
mixin (riscv_instr_mixin(FENCE, I_FORMAT, SYNCH, RV32I));
mixin (riscv_instr_mixin(FENCE_I, I_FORMAT, SYNCH, RV32I));
mixin (riscv_instr_mixin(SFENCE_VMA, R_FORMAT, SYNCH, RV32I));
// SYSTEM instructions
mixin (riscv_instr_mixin(ECALL, I_FORMAT, SYSTEM, RV32I));
mixin (riscv_instr_mixin(EBREAK, I_FORMAT, SYSTEM, RV32I));
mixin (riscv_instr_mixin(URET, I_FORMAT, SYSTEM, RV32I));
mixin (riscv_instr_mixin(SRET, I_FORMAT, SYSTEM, RV32I));
mixin (riscv_instr_mixin(MRET, I_FORMAT, SYSTEM, RV32I));
mixin (riscv_instr_mixin(DRET, I_FORMAT, SYSTEM, RV32I));
mixin (riscv_instr_mixin(WFI, I_FORMAT, INTERRUPT, RV32I));
// CSR instructions
mixin (riscv_instr_mixin(CSRRW, R_FORMAT, CSR, RV32I, UIMM));
mixin (riscv_instr_mixin(CSRRS, R_FORMAT, CSR, RV32I, UIMM));
mixin (riscv_instr_mixin(CSRRC, R_FORMAT, CSR, RV32I, UIMM));
mixin (riscv_instr_mixin(CSRRWI, I_FORMAT, CSR, RV32I, UIMM));
mixin (riscv_instr_mixin(CSRRSI, I_FORMAT, CSR, RV32I, UIMM));
mixin (riscv_instr_mixin(CSRRCI, I_FORMAT, CSR, RV32I, UIMM));
}
else {
// LOAD instructions
class riscv_LB_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LB, I_FORMAT, LOAD, RV32I); }
class riscv_LH_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LH, I_FORMAT, LOAD, RV32I); }
class riscv_LW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LW, I_FORMAT, LOAD, RV32I); }
class riscv_LBU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LBU, I_FORMAT, LOAD, RV32I); }
class riscv_LHU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LHU, I_FORMAT, LOAD, RV32I); }
// STORE instructions
class riscv_SB_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SB, S_FORMAT, STORE, RV32I); }
class riscv_SH_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SH, S_FORMAT, STORE, RV32I); }
class riscv_SW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SW, S_FORMAT, STORE, RV32I); }
// SHIFT intructions
class riscv_SLL_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLL, R_FORMAT, SHIFT, RV32I); }
class riscv_SLLI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLLI, I_FORMAT, SHIFT, RV32I); }
class riscv_SRL_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRL, R_FORMAT, SHIFT, RV32I); }
class riscv_SRLI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRLI, I_FORMAT, SHIFT, RV32I); }
class riscv_SRA_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRA, R_FORMAT, SHIFT, RV32I); }
class riscv_SRAI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRAI, I_FORMAT, SHIFT, RV32I); }
// ARITHMETIC intructions
class riscv_ADD_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ADD, R_FORMAT, ARITHMETIC, RV32I); }
class riscv_ADDI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ADDI, I_FORMAT, ARITHMETIC, RV32I); }
class riscv_NOP_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(NOP, I_FORMAT, ARITHMETIC, RV32I); }
class riscv_SUB_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SUB, R_FORMAT, ARITHMETIC, RV32I); }
class riscv_LUI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LUI, U_FORMAT, ARITHMETIC, RV32I, UIMM); }
class riscv_AUIPC_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(AUIPC, U_FORMAT, ARITHMETIC, RV32I, UIMM); }
// LOGICAL instructions
class riscv_XOR_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(XOR, R_FORMAT, LOGICAL, RV32I); }
class riscv_XORI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(XORI, I_FORMAT, LOGICAL, RV32I); }
class riscv_OR_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(OR, R_FORMAT, LOGICAL, RV32I); }
class riscv_ORI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ORI, I_FORMAT, LOGICAL, RV32I); }
class riscv_AND_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(AND, R_FORMAT, LOGICAL, RV32I); }
class riscv_ANDI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ANDI, I_FORMAT, LOGICAL, RV32I); }
// COMPARE instructions
class riscv_SLT_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLT, R_FORMAT, COMPARE, RV32I); }
class riscv_SLTI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLTI, I_FORMAT, COMPARE, RV32I); }
class riscv_SLTU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLTU, R_FORMAT, COMPARE, RV32I); }
class riscv_SLTIU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLTIU, I_FORMAT, COMPARE, RV32I); }
// BRANCH instructions
class riscv_BEQ_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(BEQ, B_FORMAT, BRANCH, RV32I); }
class riscv_BNE_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(BNE, B_FORMAT, BRANCH, RV32I); }
class riscv_BLT_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(BLT, B_FORMAT, BRANCH, RV32I); }
class riscv_BGE_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(BGE, B_FORMAT, BRANCH, RV32I); }
class riscv_BLTU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(BLTU, B_FORMAT, BRANCH, RV32I); }
class riscv_BGEU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(BGEU, B_FORMAT, BRANCH, RV32I); }
// JUMP instructions
class riscv_JAL_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(JAL, J_FORMAT, JUMP, RV32I); }
class riscv_JALR_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(JALR, I_FORMAT, JUMP, RV32I); }
// SYNCH instructions
class riscv_FENCE_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(FENCE, I_FORMAT, SYNCH, RV32I); }
class riscv_FENCE_I_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(FENCE_I, I_FORMAT, SYNCH, RV32I); }
class riscv_SFENCE_VMA_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SFENCE_VMA, R_FORMAT, SYNCH, RV32I); }
// SYSTEM instructions
class riscv_ECALL_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ECALL, I_FORMAT, SYSTEM, RV32I); }
class riscv_EBREAK_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(EBREAK, I_FORMAT, SYSTEM, RV32I); }
class riscv_URET_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(URET, I_FORMAT, SYSTEM, RV32I); }
class riscv_SRET_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRET, I_FORMAT, SYSTEM, RV32I); }
class riscv_MRET_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(MRET, I_FORMAT, SYSTEM, RV32I); }
class riscv_DRET_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(DRET, I_FORMAT, SYSTEM, RV32I); }
class riscv_WFI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(WFI, I_FORMAT, INTERRUPT, RV32I); }
// CSR instructions
class riscv_CSRRW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(CSRRW, R_FORMAT, CSR, RV32I, UIMM); }
class riscv_CSRRS_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(CSRRS, R_FORMAT, CSR, RV32I, UIMM); }
class riscv_CSRRC_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(CSRRC, R_FORMAT, CSR, RV32I, UIMM); }
class riscv_CSRRWI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(CSRRWI, I_FORMAT, CSR, RV32I, UIMM); }
class riscv_CSRRSI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(CSRRSI, I_FORMAT, CSR, RV32I, UIMM); }
class riscv_CSRRCI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(CSRRCI, I_FORMAT, CSR, RV32I, UIMM); }
}

View file

@ -0,0 +1,54 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32m_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
//////////// RV32M instructions //////////////
mixin (riscv_instr_mixin(MUL, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(MULH, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(MULHSU, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(MULHU, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(DIV, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(DIVU, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(REM, R_FORMAT, ARITHMETIC, RV32M));
mixin (riscv_instr_mixin(REMU, R_FORMAT, ARITHMETIC, RV32M));
}
else {
//////////// RV32M instructions //////////////
class riscv_MUL_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(MUL, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_MULH_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(MULH, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_MULHSU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(MULHSU, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_MULHU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(MULHU, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_DIV_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(DIV, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_DIVU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(DIVU, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_REM_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(REM, R_FORMAT, ARITHMETIC, RV32M); }
class riscv_REMU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(REMU, R_FORMAT, ARITHMETIC, RV32M); }
}

View file

@ -0,0 +1,666 @@
/*
* Copyright 2020 Google LLC
* Copyright 2020 Andes Technology Co., Ltd.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32v_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
// Vector CSR access instruction
mixin (riscv_instr_mixin(VSETVLI, VSET_FORMAT, CSR, RVV));
mixin (riscv_instr_mixin(VSETVL, VSET_FORMAT, CSR, RVV));
// Vector integer arithmetic instruction
mixin (riscv_va_instr_mixin(VADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VRSUB, VA_FORMAT, ARITHMETIC, RVV, [VX, VI]));
mixin (riscv_va_instr_mixin(VWADDU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, WV, WX]));
mixin (riscv_va_instr_mixin(VWSUBU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, WV, WX]));
mixin (riscv_va_instr_mixin(VWADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, WV, WX]));
mixin (riscv_va_instr_mixin(VWSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, WV, WX]));
mixin (riscv_va_instr_mixin(VADC, VA_FORMAT, ARITHMETIC, RVV, [VVM, VXM, VIM]));
mixin (riscv_va_instr_mixin(VMADC, VA_FORMAT, ARITHMETIC, RVV, [VVM, VXM, VIM, VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSBC, VA_FORMAT, ARITHMETIC, RVV, [VVM, VXM]));
mixin (riscv_va_instr_mixin(VMSBC, VA_FORMAT, ARITHMETIC, RVV, [VVM, VXM, VV, VX]));
mixin (riscv_va_instr_mixin(VAND, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VOR, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VXOR, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSLL, VA_FORMAT, SHIFT, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSRL, VA_FORMAT, SHIFT, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSRA, VA_FORMAT, SHIFT, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VNSRL, VA_FORMAT, SHIFT, RVV, [WV, WX, WI]));
mixin (riscv_va_instr_mixin(VNSRA, VA_FORMAT, SHIFT, RVV, [WV, WX, WI]));
mixin (riscv_va_instr_mixin(VMSEQ, VA_FORMAT, COMPARE, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VMSNE, VA_FORMAT, COMPARE, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VMSLTU, VA_FORMAT, COMPARE, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMSLT, VA_FORMAT, COMPARE, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMSLEU, VA_FORMAT, COMPARE, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VMSLE, VA_FORMAT, COMPARE, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VMSGTU, VA_FORMAT, COMPARE, RVV, [VX, VI]));
mixin (riscv_va_instr_mixin(VMSGT, VA_FORMAT, COMPARE, RVV, [VX, VI]));
mixin (riscv_va_instr_mixin(VMINU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMIN, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMAXU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMAX, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMUL, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMULH, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMULHU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMULHSU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VDIVU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VDIV, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VREMU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VREM, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMUL, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMULU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMULSU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VNMSAC, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VMADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VNMSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMACCU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMACCSU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VWMACCUS, VA_FORMAT, ARITHMETIC, RVV, [VX]));
/* Quad widening is not yet supported
mixin (riscv_va_instr_mixin(VQMACCU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VQMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VQMACCSU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VQMACCUS, VA_FORMAT, ARITHMETIC, RVV, [VX]));
*/
mixin (riscv_va_instr_mixin(VMERGE, VA_FORMAT, ARITHMETIC, RVV, [VVM, VXM, VIM]));
mixin (riscv_va_instr_mixin(VMV, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
// Vector Fixed-Point Arithmetic Instructions
mixin (riscv_va_instr_mixin(VSADDU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSSUBU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VSSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VAADDU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VAADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VASUBU, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VASUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VX]));
mixin (riscv_va_instr_mixin(VSSRL, VA_FORMAT, SHIFT, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VSSRA, VA_FORMAT, SHIFT, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VNCLIPU, VA_FORMAT, ARITHMETIC, RVV, [WV, WX, WI]));
mixin (riscv_va_instr_mixin(VNCLIP, VA_FORMAT, ARITHMETIC, RVV, [WV, WX, WI]));
// Vector Floating-Point Instructions
mixin (riscv_va_instr_mixin(VFADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFRSUB, VA_FORMAT, ARITHMETIC, RVV, [VF]));
mixin (riscv_va_instr_mixin(VFMUL, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFDIV, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFRDIV, VA_FORMAT, ARITHMETIC, RVV, [VF]));
mixin (riscv_va_instr_mixin(VFWMUL, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFNMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFMSAC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFNMSAC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFMADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFNMADD, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFMSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFNMSUB, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFWMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFWNMACC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFWMSAC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFWNMSAC, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFSQRT_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFMIN, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFMAX, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFSGNJ, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFSGNJN, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VFSGNJX, VA_FORMAT, ARITHMETIC, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VMFEQ, VA_FORMAT, COMPARE, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VMFNE, VA_FORMAT, COMPARE, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VMFLT, VA_FORMAT, COMPARE, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VMFLE, VA_FORMAT, COMPARE, RVV, [VV, VF]));
mixin (riscv_va_instr_mixin(VMFGT, VA_FORMAT, COMPARE, RVV, [VF]));
mixin (riscv_va_instr_mixin(VMFGE, VA_FORMAT, COMPARE, RVV, [VF]));
mixin (riscv_va_instr_mixin(VFCLASS_V,VS2_FORMAT, COMPARE, RVV));
mixin (riscv_va_instr_mixin(VFMERGE, VA_FORMAT, ARITHMETIC, RVV, [VFM]));
mixin (riscv_va_instr_mixin(VFMV, VA_FORMAT, ARITHMETIC, RVV, [VF]));
// Vector conversion instructions
mixin (riscv_va_instr_mixin(VFCVT_XU_F_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFCVT_X_F_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFCVT_F_XU_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFCVT_F_X_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWCVT_XU_F_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWCVT_X_F_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWCVT_F_XU_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWCVT_F_X_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWCVT_F_F_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFNCVT_XU_F_W, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFNCVT_X_F_W, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFNCVT_F_XU_W, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFNCVT_F_X_W, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFNCVT_F_F_W, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFNCVT_ROD_F_F_W, VS2_FORMAT, ARITHMETIC, RVV));
// Vector reduction instruction
mixin (riscv_va_instr_mixin(VREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDMAXU_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDMAX_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDMINU_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDMIN_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDAND_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDOR_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VREDXOR_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VWREDSUMU_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VWREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFREDOSUM_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFREDMAX_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWREDOSUM_VS, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFWREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV));
// Vector mask instruction
mixin (riscv_va_instr_mixin(VMAND_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMNAND_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMANDNOT_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMXOR_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMOR_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMNOR_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMORNOT_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMXNOR_MM, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VPOPC_M, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFIRST_M, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMSBF_M, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMSIF_M, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMSOF_M, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VIOTA_M, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VID_V, VS2_FORMAT, ARITHMETIC, RVV));
// Vector permutation instruction
mixin (riscv_va_instr_mixin(VMV_X_S, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMV_S_X, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFMV_F_S, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VFMV_S_F, VA_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VSLIDEUP, VA_FORMAT, ARITHMETIC, RVV, [VI, VX]));
mixin (riscv_va_instr_mixin(VSLIDEDOWN, VA_FORMAT, ARITHMETIC, RVV, [VI, VX]));
mixin (riscv_va_instr_mixin(VSLIDE1UP, VA_FORMAT, ARITHMETIC, RVV, [VX]));
mixin (riscv_va_instr_mixin(VSLIDE1DOWN, VA_FORMAT, ARITHMETIC, RVV, [VX]));
mixin (riscv_va_instr_mixin(VRGATHER, VA_FORMAT, ARITHMETIC, RVV, [VV, VX, VI]));
mixin (riscv_va_instr_mixin(VCOMPRESS, VA_FORMAT, ARITHMETIC, RVV, [VM]));
mixin (riscv_va_instr_mixin(VMV1R_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMV2R_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMV4R_V, VS2_FORMAT, ARITHMETIC, RVV));
mixin (riscv_va_instr_mixin(VMV8R_V, VS2_FORMAT, ARITHMETIC, RVV));
// -------------------------------------------------------------------------
// Section 7. Vector Loads and Stores
// -------------------------------------------------------------------------
// Section 7.4 - Vector Unit-Stride Instructions
mixin (riscv_va_instr_mixin(VLE_V, VL_FORMAT, LOAD, RVV));
mixin (riscv_va_instr_mixin(VSE_V, VS_FORMAT, STORE, RVV));
// Section 7.5 - Vector Strided Instructions
mixin (riscv_va_instr_mixin(VLSE_V, VLS_FORMAT, LOAD, RVV));
mixin (riscv_va_instr_mixin(VSSE_V, VSS_FORMAT, STORE, RVV));
// Section 7.6 - Vector Indexed Instructions
mixin (riscv_va_instr_mixin(VLXEI_V, VLX_FORMAT, LOAD, RVV));
mixin (riscv_va_instr_mixin(VSXEI_V, VSX_FORMAT, STORE, RVV));
mixin (riscv_va_instr_mixin(VSUXEI_V, VSX_FORMAT, STORE, RVV));
// Section 7.7 - Vector Unit-Stride Fault-Only-First Loads
mixin (riscv_va_instr_mixin(VLEFF_V, VL_FORMAT, LOAD, RVV));
// Section 7.8 - Vector Load/Store Segment Instructions (Zvlsseg)
// 7.8.1. Vector Unit Strided Segment Loads and Stores
mixin (riscv_va_instr_mixin(VLSEGE_V, VL_FORMAT, LOAD, RVV, [], "zvlsseg"));
mixin (riscv_va_instr_mixin(VSSEGE_V, VS_FORMAT, STORE, RVV, [], "zvlsseg"));
mixin (riscv_va_instr_mixin(VLSEGEFF_V, VL_FORMAT, LOAD, RVV, [], "zvlsseg"));
// 7.8.2. Vector Strided Segment Loads and Stores
mixin (riscv_va_instr_mixin(VLSSEGE_V, VLS_FORMAT, LOAD, RVV, [], "zvlsseg"));
mixin (riscv_va_instr_mixin(VSSSEGE_V, VSS_FORMAT, STORE, RVV, [], "zvlsseg"));
// 7.8.3. Vector Indexed Segment Loads and Stores
mixin (riscv_va_instr_mixin(VLXSEGEI_V, VLX_FORMAT, LOAD, RVV, [], "zvlsseg"));
mixin (riscv_va_instr_mixin(VSXSEGEI_V, VSX_FORMAT, STORE, RVV, [], "zvlsseg"));
mixin (riscv_va_instr_mixin(VSUXSEGEI_V, VSX_FORMAT, STORE, RVV, [], "zvlsseg"));
// -------------------------------------------------------------------------
// Section 8. Vector AMO Operations (Zvamo)
// -------------------------------------------------------------------------
// EEW vector AMOs
mixin (riscv_va_instr_mixin(VAMOSWAPE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOADDE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOXORE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOANDE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOORE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOMINE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOMAXE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOMINUE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
mixin (riscv_va_instr_mixin(VAMOMAXUE_V, VAMO_FORMAT, AMO, RVV, [], "zvamo"));
}
else {
// Vector CSR access instruction
class riscv_VSETVLI_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(VSETVLI, VSET_FORMAT, CSR, RVV); }
class riscv_VSETVL_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(VSETVL, VSET_FORMAT, CSR, RVV); }
// Vector integer arithmetic instruction
class riscv_VADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VADD, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VRSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VRSUB, VA_FORMAT, ARITHMETIC, RVV, VX, VI); }
class riscv_VWADDU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWADDU, VA_FORMAT, ARITHMETIC, RVV, VV, VX, WV, WX); }
class riscv_VWSUBU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWSUBU, VA_FORMAT, ARITHMETIC, RVV, VV, VX, WV, WX); }
class riscv_VWADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWADD, VA_FORMAT, ARITHMETIC, RVV, VV, VX, WV, WX); }
class riscv_VWSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VX, WV, WX); }
class riscv_VADC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VADC, VA_FORMAT, ARITHMETIC, RVV, VVM, VXM, VIM); }
class riscv_VMADC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMADC, VA_FORMAT, ARITHMETIC, RVV, VVM, VXM, VIM, VV, VX, VI); }
class riscv_VSBC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSBC, VA_FORMAT, ARITHMETIC, RVV, VVM, VXM); }
class riscv_VMSBC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSBC, VA_FORMAT, ARITHMETIC, RVV, VVM, VXM, VV, VX); }
class riscv_VAND_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VAND, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VOR_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VOR, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VXOR_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VXOR, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VSLL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSLL, VA_FORMAT, SHIFT, RVV, VV, VX, VI); }
class riscv_VSRL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSRL, VA_FORMAT, SHIFT, RVV, VV, VX, VI); }
class riscv_VSRA_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSRA, VA_FORMAT, SHIFT, RVV, VV, VX, VI); }
class riscv_VNSRL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VNSRL, VA_FORMAT, SHIFT, RVV, WV, WX, WI); }
class riscv_VNSRA_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VNSRA, VA_FORMAT, SHIFT, RVV, WV, WX, WI); }
class riscv_VMSEQ_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSEQ, VA_FORMAT, COMPARE, RVV, VV, VX, VI); }
class riscv_VMSNE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSNE, VA_FORMAT, COMPARE, RVV, VV, VX, VI); }
class riscv_VMSLTU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSLTU, VA_FORMAT, COMPARE, RVV, VV, VX); }
class riscv_VMSLT_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSLT, VA_FORMAT, COMPARE, RVV, VV, VX); }
class riscv_VMSLEU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSLEU, VA_FORMAT, COMPARE, RVV, VV, VX, VI); }
class riscv_VMSLE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSLE, VA_FORMAT, COMPARE, RVV, VV, VX, VI); }
class riscv_VMSGTU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSGTU, VA_FORMAT, COMPARE, RVV, VX, VI); }
class riscv_VMSGT_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSGT, VA_FORMAT, COMPARE, RVV, VX, VI); }
class riscv_VMINU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMINU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMIN_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMIN, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMAXU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMAXU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMAX_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMAX, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMUL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMUL, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMULH_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMULH, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMULHU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMULHU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMULHSU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMULHSU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VDIVU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VDIVU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VDIV_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VDIV, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VREMU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREMU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VREM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREM, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMUL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMUL, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMULU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMULU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMULSU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMULSU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VNMSAC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VNMSAC, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VMADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMADD, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VNMSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VNMSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMACCU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMACCU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMACCSU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMACCSU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VWMACCUS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWMACCUS, VA_FORMAT, ARITHMETIC, RVV, VX); }
/* Quad widening is not yet supported
class riscv_VQMACCU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VQMACCU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VQMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VQMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VQMACCSU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VQMACCSU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VQMACCUS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VQMACCUS, VA_FORMAT, ARITHMETIC, RVV, VX); }
*/
class riscv_VMERGE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMERGE, VA_FORMAT, ARITHMETIC, RVV, VVM, VXM, VIM); }
class riscv_VMV_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
// Vector Fixed-Point Arithmetic Instructions
class riscv_VSADDU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSADDU, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VSADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSADD, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VSSUBU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSSUBU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VSSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VAADDU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VAADDU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VAADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VAADD, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VASUBU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VASUBU, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VASUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VASUB, VA_FORMAT, ARITHMETIC, RVV, VV, VX); }
class riscv_VSSRL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSSRL, VA_FORMAT, SHIFT, RVV, VV, VX, VI); }
class riscv_VSSRA_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSSRA, VA_FORMAT, SHIFT, RVV, VV, VX, VI); }
class riscv_VNCLIPU_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VNCLIPU, VA_FORMAT, ARITHMETIC, RVV, WV, WX, WI); }
class riscv_VNCLIP_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VNCLIP, VA_FORMAT, ARITHMETIC, RVV, WV, WX, WI); }
// Vector Floating-Point Instructions
class riscv_VFADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFADD, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFRSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFRSUB, VA_FORMAT, ARITHMETIC, RVV, VF); }
class riscv_VFMUL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMUL, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFDIV_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFDIV, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFRDIV_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFRDIV, VA_FORMAT, ARITHMETIC, RVV, VF); }
class riscv_VFWMUL_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWMUL, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFNMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFMSAC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMSAC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFNMSAC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNMSAC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFMADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMADD, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFNMADD_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNMADD, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFMSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFNMSUB_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNMSUB, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFWMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFWNMACC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWNMACC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFWMSAC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWMSAC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFWNMSAC_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWNMSAC, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFSQRT_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFSQRT_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFMIN_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMIN, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFMAX_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMAX, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFSGNJ_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFSGNJ, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFSGNJN_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFSGNJN, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VFSGNJX_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFSGNJX, VA_FORMAT, ARITHMETIC, RVV, VV, VF); }
class riscv_VMFEQ_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMFEQ, VA_FORMAT, COMPARE, RVV, VV, VF); }
class riscv_VMFNE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMFNE, VA_FORMAT, COMPARE, RVV, VV, VF); }
class riscv_VMFLT_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMFLT, VA_FORMAT, COMPARE, RVV, VV, VF); }
class riscv_VMFLE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMFLE, VA_FORMAT, COMPARE, RVV, VV, VF); }
class riscv_VMFGT_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMFGT, VA_FORMAT, COMPARE, RVV, VF); }
class riscv_VMFGE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMFGE, VA_FORMAT, COMPARE, RVV, VF); }
class riscv_VFCLASS_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFCLASS_V,VS2_FORMAT, COMPARE, RVV); }
class riscv_VFMERGE_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMERGE, VA_FORMAT, ARITHMETIC, RVV, VFM); }
class riscv_VFMV_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMV, VA_FORMAT, ARITHMETIC, RVV, VF); }
// Vector conversion instructions
class riscv_VFCVT_XU_F_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFCVT_XU_F_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFCVT_X_F_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFCVT_X_F_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFCVT_F_XU_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFCVT_F_XU_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFCVT_F_X_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFCVT_F_X_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWCVT_XU_F_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWCVT_XU_F_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWCVT_X_F_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWCVT_X_F_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWCVT_F_XU_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWCVT_F_XU_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWCVT_F_X_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWCVT_F_X_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWCVT_F_F_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWCVT_F_F_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFNCVT_XU_F_W_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNCVT_XU_F_W, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFNCVT_X_F_W_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNCVT_X_F_W, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFNCVT_F_XU_W_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNCVT_F_XU_W, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFNCVT_F_X_W_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNCVT_F_X_W, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFNCVT_F_F_W_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNCVT_F_F_W, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFNCVT_ROD_F_F_W_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFNCVT_ROD_F_F_W, VS2_FORMAT, ARITHMETIC, RVV); }
// Vector reduction instruction
class riscv_VREDSUM_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDMAXU_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDMAXU_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDMAX_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDMAX_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDMINU_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDMINU_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDMIN_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDMIN_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDAND_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDAND_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDOR_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDOR_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VREDXOR_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VREDXOR_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VWREDSUMU_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWREDSUMU_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VWREDSUM_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VWREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFREDOSUM_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFREDOSUM_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFREDSUM_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFREDMAX_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFREDMAX_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWREDOSUM_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWREDOSUM_VS, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFWREDSUM_VS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFWREDSUM_VS, VA_FORMAT, ARITHMETIC, RVV); }
// Vector mask instruction
class riscv_VMAND_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMAND_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMNAND_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMNAND_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMANDNOT_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMANDNOT_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMXOR_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMXOR_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMOR_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMOR_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMNOR_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMNOR_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMORNOT_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMORNOT_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMXNOR_MM_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMXNOR_MM, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VPOPC_M_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VPOPC_M, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VFIRST_M_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFIRST_M, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VMSBF_M_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSBF_M, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VMSIF_M_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSIF_M, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VMSOF_M_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMSOF_M, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VIOTA_M_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VIOTA_M, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VID_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VID_V, VS2_FORMAT, ARITHMETIC, RVV); }
// Vector permutation instruction
class riscv_VMV_X_S_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV_X_S, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VMV_S_X_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV_S_X, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFMV_F_S_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMV_F_S, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VFMV_S_F_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VFMV_S_F, VA_FORMAT, ARITHMETIC, RVV); }
class riscv_VSLIDEUP_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSLIDEUP, VA_FORMAT, ARITHMETIC, RVV, VI, VX); }
class riscv_VSLIDEDOWN_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSLIDEDOWN, VA_FORMAT, ARITHMETIC, RVV, VI, VX); }
class riscv_VSLIDE1UP_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSLIDE1UP, VA_FORMAT, ARITHMETIC, RVV, VX); }
class riscv_VSLIDE1DOWN_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSLIDE1DOWN, VA_FORMAT, ARITHMETIC, RVV, VX); }
class riscv_VRGATHER_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VRGATHER, VA_FORMAT, ARITHMETIC, RVV, VV, VX, VI); }
class riscv_VCOMPRESS_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VCOMPRESS, VA_FORMAT, ARITHMETIC, RVV, VM); }
class riscv_VMV1R_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV1R_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VMV2R_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV2R_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VMV4R_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV4R_V, VS2_FORMAT, ARITHMETIC, RVV); }
class riscv_VMV8R_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VMV8R_V, VS2_FORMAT, ARITHMETIC, RVV); }
// -------------------------------------------------------------------------
// Section 7. Vector Loads and Stores
// -------------------------------------------------------------------------
// Section 7.4 - Vector Unit-Stride Instructions
class riscv_VLE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VLE_V, VL_FORMAT, LOAD, RVV); }
class riscv_VSE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSE_V, VS_FORMAT, STORE, RVV); }
// Section 7.5 - Vector Strided Instructions
class riscv_VLSE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VLSE_V, VLS_FORMAT, LOAD, RVV); }
class riscv_VSSE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSSE_V, VSS_FORMAT, STORE, RVV); }
// Section 7.6 - Vector Indexed Instructions
class riscv_VLXEI_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VLXEI_V, VLX_FORMAT, LOAD, RVV); }
class riscv_VSXEI_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSXEI_V, VSX_FORMAT, STORE, RVV); }
class riscv_VSUXEI_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VSUXEI_V, VSX_FORMAT, STORE, RVV); }
// Section 7.7 - Vector Unit-Stride Fault-Only-First Loads
class riscv_VLEFF_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!(VLEFF_V, VL_FORMAT, LOAD, RVV); }
// Section 7.8 - Vector Load/Store Segment Instructions (Zvlsseg)
// 7.8.1. Vector Unit Strided Segment Loads and Stores
class riscv_VLSEGE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VLSEGE_V, VL_FORMAT, LOAD, RVV); }
class riscv_VSSEGE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VSSEGE_V, VS_FORMAT, STORE, RVV); }
class riscv_VLSEGEFF_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VLSEGEFF_V, VL_FORMAT, LOAD, RVV); }
// 7.8.2. Vector Strided Segment Loads and Stores
class riscv_VLSSEGE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VLSSEGE_V, VLS_FORMAT, LOAD, RVV); }
class riscv_VSSSEGE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VSSSEGE_V, VSS_FORMAT, STORE, RVV); }
// 7.8.3. Vector Indexed Segment Loads and Stores
class riscv_VLXSEGEI_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VLXSEGEI_V, VLX_FORMAT, LOAD, RVV); }
class riscv_VSXSEGEI_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VSXSEGEI_V, VSX_FORMAT, STORE, RVV); }
class riscv_VSUXSEGEI_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvlsseg", VSUXSEGEI_V, VSX_FORMAT, STORE, RVV); }
// -------------------------------------------------------------------------
// Section 8. Vector AMO Operations (Zvamo)
// -------------------------------------------------------------------------
// EEW vector AMOs
class riscv_VAMOSWAPE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOSWAPE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOADDE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOADDE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOXORE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOXORE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOANDE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOANDE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOORE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOORE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOMINE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOMINE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOMAXE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOMAXE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOMINUE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOMINUE_V, VAMO_FORMAT, AMO, RVV); }
class riscv_VAMOMAXUE_V_instr: riscv_vector_instr
{ mixin RISCV_VA_INSTR_MIXIN!("zvamo", VAMOMAXUE_V, VAMO_FORMAT, AMO, RVV); }
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32zba_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_zba_instr_mixin(SH1ADD, R_FORMAT, ARITHMETIC, RV32ZBA));
mixin (riscv_zba_instr_mixin(SH2ADD, R_FORMAT, ARITHMETIC, RV32ZBA));
mixin (riscv_zba_instr_mixin(SH3ADD, R_FORMAT, ARITHMETIC, RV32ZBA));
}
else {
class riscv_SH1ADD_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SH1ADD, R_FORMAT, ARITHMETIC, RV32ZBA); }
class riscv_SH2ADD_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SH2ADD, R_FORMAT, ARITHMETIC, RV32ZBA); }
class riscv_SH3ADD_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SH3ADD, R_FORMAT, ARITHMETIC, RV32ZBA); }
}

View file

@ -0,0 +1,82 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32zbb_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_zbb_instr_mixin(ANDN, R_FORMAT, LOGICAL, RV32ZBB));
mixin (riscv_zbb_instr_mixin(CLZ, I_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(CPOP, I_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(CTZ, I_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(MAX, R_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(MAXU, R_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(MIN, R_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(MINU, R_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(ORC_B, I_FORMAT, LOGICAL, RV32ZBB));
mixin (riscv_zbb_instr_mixin(ORN, R_FORMAT, LOGICAL, RV32ZBB));
mixin (riscv_zbb_instr_mixin(REV8, I_FORMAT, SHIFT, RV32ZBB));
mixin (riscv_zbb_instr_mixin(ROL, R_FORMAT, SHIFT, RV32ZBB));
mixin (riscv_zbb_instr_mixin(ROR, R_FORMAT, SHIFT, RV32ZBB));
mixin (riscv_zbb_instr_mixin(RORI, I_FORMAT, SHIFT, RV32ZBB, UIMM));
mixin (riscv_zbb_instr_mixin(SEXT_B, I_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(SEXT_H, I_FORMAT, ARITHMETIC, RV32ZBB));
mixin (riscv_zbb_instr_mixin(XNOR, R_FORMAT, LOGICAL, RV32ZBB));
mixin (riscv_zbb_instr_mixin(ZEXT_H, R_FORMAT, ARITHMETIC, RV32ZBB));
}
else {
class riscv_ANDN_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ANDN, R_FORMAT, LOGICAL, RV32ZBB); }
class riscv_CLZ_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(CLZ, I_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_CPOP_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(CPOP, I_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_CTZ_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(CTZ, I_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_MAX_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(MAX, R_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_MAXU_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(MAXU, R_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_MIN_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(MIN, R_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_MINU_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(MINU, R_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_ORC_B_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ORC_B, I_FORMAT, LOGICAL, RV32ZBB); }
class riscv_ORN_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ORN, R_FORMAT, LOGICAL, RV32ZBB); }
class riscv_REV8_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(REV8, I_FORMAT, SHIFT, RV32ZBB); }
class riscv_ROL_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ROL, R_FORMAT, SHIFT, RV32ZBB); }
class riscv_ROR_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ROR, R_FORMAT, SHIFT, RV32ZBB); }
class riscv_RORI_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(RORI, I_FORMAT, SHIFT, RV32ZBB, UIMM); }
class riscv_SEXT_B_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(SEXT_B, I_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_SEXT_H_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(SEXT_H, I_FORMAT, ARITHMETIC, RV32ZBB); }
class riscv_XNOR_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(XNOR, R_FORMAT, LOGICAL, RV32ZBB); }
class riscv_ZEXT_H_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ZEXT_H, R_FORMAT, ARITHMETIC, RV32ZBB); }
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32zbc_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_zbc_instr_mixin(CLMUL, R_FORMAT, ARITHMETIC, RV32ZBC));
mixin (riscv_zbc_instr_mixin(CLMULH, R_FORMAT, ARITHMETIC, RV32ZBC));
mixin (riscv_zbc_instr_mixin(CLMULR, R_FORMAT, ARITHMETIC, RV32ZBC));
}
else {
class riscv_CLMUL_instr: riscv_zbc_instr
{ mixin RISCV_INSTR_MIXIN!(CLMUL, R_FORMAT, ARITHMETIC, RV32ZBC); }
class riscv_CLMULH_instr: riscv_zbc_instr
{ mixin RISCV_INSTR_MIXIN!(CLMULH, R_FORMAT, ARITHMETIC, RV32ZBC); }
class riscv_CLMULR_instr: riscv_zbc_instr
{ mixin RISCV_INSTR_MIXIN!(CLMULR, R_FORMAT, ARITHMETIC, RV32ZBC); }
}

View file

@ -0,0 +1,52 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv32zbs_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_zbs_instr_mixin(BCLR, R_FORMAT, SHIFT, RV32ZBS));
mixin (riscv_zbs_instr_mixin(BCLRI, I_FORMAT, SHIFT, RV32ZBS, UIMM));
mixin (riscv_zbs_instr_mixin(BEXT, R_FORMAT, SHIFT, RV32ZBS));
mixin (riscv_zbs_instr_mixin(BEXTI, I_FORMAT, SHIFT, RV32ZBS, UIMM));
mixin (riscv_zbs_instr_mixin(BINV, R_FORMAT, SHIFT, RV32ZBS));
mixin (riscv_zbs_instr_mixin(BINVI, I_FORMAT, SHIFT, RV32ZBS, UIMM));
mixin (riscv_zbs_instr_mixin(BSET, R_FORMAT, SHIFT, RV32ZBS));
mixin (riscv_zbs_instr_mixin(BSETI, I_FORMAT, SHIFT, RV32ZBS, UIMM));
}
else {
class riscv_BCLR_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BCLR, R_FORMAT, SHIFT, RV32ZBS); }
class riscv_BCLRI_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BCLRI, I_FORMAT, SHIFT, RV32ZBS, UIMM); }
class riscv_BEXT_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BEXT, R_FORMAT, SHIFT, RV32ZBS); }
class riscv_BEXTI_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BEXTI, I_FORMAT, SHIFT, RV32ZBS, UIMM); }
class riscv_BINV_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BINV, R_FORMAT, SHIFT, RV32ZBS); }
class riscv_BINVI_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BINVI, I_FORMAT, SHIFT, RV32ZBS, UIMM); }
class riscv_BSET_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BSET, R_FORMAT, SHIFT, RV32ZBS); }
class riscv_BSETI_instr: riscv_zbs_instr
{ mixin RISCV_INSTR_MIXIN!(BSETI, I_FORMAT, SHIFT, RV32ZBS, UIMM); }
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64a_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_amo_instr_mixin(LR_D, R_FORMAT, LOAD, RV64A));
mixin (riscv_amo_instr_mixin(SC_D, R_FORMAT, STORE, RV64A));
mixin (riscv_amo_instr_mixin(AMOSWAP_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOADD_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOAND_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOOR_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOXOR_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOMIN_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOMAX_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOMINU_D, R_FORMAT, AMO, RV64A));
mixin (riscv_amo_instr_mixin(AMOMAXU_D, R_FORMAT, AMO, RV64A));
}
else {
class riscv_LR_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(LR_D, R_FORMAT, LOAD, RV64A); }
class riscv_SC_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(SC_D, R_FORMAT, STORE, RV64A); }
class riscv_AMOSWAP_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOSWAP_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOADD_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOADD_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOAND_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOAND_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOOR_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOOR_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOXOR_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOXOR_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOMIN_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMIN_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOMAX_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMAX_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOMINU_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMINU_D, R_FORMAT, AMO, RV64A); }
class riscv_AMOMAXU_D_instr: riscv_amo_instr
{ mixin RISCV_INSTR_MIXIN!(AMOMAXU_D, R_FORMAT, AMO, RV64A); }
}

View file

@ -0,0 +1,108 @@
/*
* Copyright 2019 Google LLC
* Copyright 2019 Mellanox Technologies Ltd
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64b_instr;
import riscv.gen.riscv_defines;
import uvm;
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
version (RISCV_INSTR_STRING_MIXIN) {
// ARITHMETIC intructions
mixin (riscv_b_instr_mixin(BMATOR, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(BMATXOR, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(BMATFLIP, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(CRC32_D, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(CRC32C_D, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(SHFLW, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(UNSHFLW, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(BCOMPRESSW, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(BDECOMPRESSW, R_FORMAT, ARITHMETIC, RV64B));
mixin (riscv_b_instr_mixin(BFPW, R_FORMAT, ARITHMETIC, RV64B));
// SHIFT intructions
mixin (riscv_b_instr_mixin(SLOW, R_FORMAT, SHIFT, RV64B));
mixin (riscv_b_instr_mixin(SROW, R_FORMAT, SHIFT, RV64B));
mixin (riscv_b_instr_mixin(SLOIW, I_FORMAT, SHIFT, RV64B, UIMM));
mixin (riscv_b_instr_mixin(SROIW, I_FORMAT, SHIFT, RV64B, UIMM));
mixin (riscv_b_instr_mixin(GREVW, R_FORMAT, SHIFT, RV64B));
mixin (riscv_b_instr_mixin(GREVIW, I_FORMAT, SHIFT, RV64B, UIMM));
mixin (riscv_b_instr_mixin(FSLW, R4_FORMAT, SHIFT, RV64B));
mixin (riscv_b_instr_mixin(FSRW, R4_FORMAT, SHIFT, RV64B));
mixin (riscv_b_instr_mixin(FSRIW, I_FORMAT, SHIFT, RV64B, UIMM));
// LOGICAL instructions
mixin (riscv_b_instr_mixin(GORCW, R_FORMAT, LOGICAL, RV64B));
mixin (riscv_b_instr_mixin(GORCIW, I_FORMAT, LOGICAL, RV64B, UIMM));
mixin (riscv_b_instr_mixin(PACKW, R_FORMAT, LOGICAL, RV64B));
mixin (riscv_b_instr_mixin(PACKUW, R_FORMAT, LOGICAL, RV64B));
mixin (riscv_b_instr_mixin(XPERM_W, R_FORMAT, LOGICAL, RV64B));
}
else {
// ARITHMETIC intructions
class riscv_BMATOR_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BMATOR, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_BMATXOR_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BMATXOR, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_BMATFLIP_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BMATFLIP, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_CRC32_D_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32_D, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_CRC32C_D_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(CRC32C_D, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_SHFLW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SHFLW, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_UNSHFLW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(UNSHFLW, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_BCOMPRESSW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BCOMPRESSW, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_BDECOMPRESSW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BDECOMPRESSW, R_FORMAT, ARITHMETIC, RV64B); }
class riscv_BFPW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BFPW, R_FORMAT, ARITHMETIC, RV64B); }
// SHIFT intructions
class riscv_SLOW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SLOW, R_FORMAT, SHIFT, RV64B); }
class riscv_SROW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SROW, R_FORMAT, SHIFT, RV64B); }
class riscv_SLOIW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SLOIW, I_FORMAT, SHIFT, RV64B, UIMM); }
class riscv_SROIW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(SROIW, I_FORMAT, SHIFT, RV64B, UIMM); }
class riscv_GREVW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GREVW, R_FORMAT, SHIFT, RV64B); }
class riscv_GREVIW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GREVIW, I_FORMAT, SHIFT, RV64B, UIMM); }
class riscv_FSLW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(FSLW, R4_FORMAT, SHIFT, RV64B); }
class riscv_FSRW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(FSRW, R4_FORMAT, SHIFT, RV64B); }
class riscv_FSRIW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(FSRIW, I_FORMAT, SHIFT, RV64B, UIMM); }
// LOGICAL instructions
class riscv_GORCW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GORCW, R_FORMAT, LOGICAL, RV64B); }
class riscv_GORCIW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(GORCIW, I_FORMAT, LOGICAL, RV64B, UIMM); }
class riscv_PACKW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(PACKW, R_FORMAT, LOGICAL, RV64B); }
class riscv_PACKUW_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(PACKUW, R_FORMAT, LOGICAL, RV64B); }
class riscv_XPERM_W_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(XPERM_W, R_FORMAT, LOGICAL, RV64B); }
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64c_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_c_instr_mixin(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C));
mixin (riscv_c_instr_mixin(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C));
mixin (riscv_c_instr_mixin(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C));
mixin (riscv_c_instr_mixin(C_LD, CL_FORMAT, LOAD, RV64C, UIMM));
mixin (riscv_c_instr_mixin(C_SD, CS_FORMAT, STORE, RV64C, UIMM));
mixin (riscv_c_instr_mixin(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM));
mixin (riscv_c_instr_mixin(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM));
}
else {
class riscv_C_ADDIW_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C); }
class riscv_C_SUBW_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C); }
class riscv_C_ADDW_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C); }
class riscv_C_LD_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LD, CL_FORMAT, LOAD, RV64C, UIMM); }
class riscv_C_SD_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SD, CS_FORMAT, STORE, RV64C, UIMM); }
class riscv_C_LDSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM); }
class riscv_C_SDSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM); }
}

View file

@ -0,0 +1,45 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64d_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_fp_instr_mixin(FMV_X_D, I_FORMAT, ARITHMETIC, RV64D));
mixin (riscv_fp_instr_mixin(FMV_D_X, I_FORMAT, ARITHMETIC, RV64D));
mixin (riscv_fp_instr_mixin(FCVT_L_D, I_FORMAT, ARITHMETIC, RV64D));
mixin (riscv_fp_instr_mixin(FCVT_LU_D, I_FORMAT, ARITHMETIC, RV64D));
mixin (riscv_fp_instr_mixin(FCVT_D_L, I_FORMAT, ARITHMETIC, RV64D));
mixin (riscv_fp_instr_mixin(FCVT_D_LU, I_FORMAT, ARITHMETIC, RV64D));
}
else {
class riscv_FMV_X_D_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMV_X_D, I_FORMAT, ARITHMETIC, RV64D); }
class riscv_FMV_D_X_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMV_D_X, I_FORMAT, ARITHMETIC, RV64D); }
class riscv_FCVT_L_D_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_L_D, I_FORMAT, ARITHMETIC, RV64D); }
class riscv_FCVT_LU_D_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_LU_D, I_FORMAT, ARITHMETIC, RV64D); }
class riscv_FCVT_D_L_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_D_L, I_FORMAT, ARITHMETIC, RV64D); }
class riscv_FCVT_D_LU_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_D_LU, I_FORMAT, ARITHMETIC, RV64D); }
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64f_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_fp_instr_mixin(FCVT_L_S, I_FORMAT, ARITHMETIC, RV64F));
mixin (riscv_fp_instr_mixin(FCVT_LU_S, I_FORMAT, ARITHMETIC, RV64F));
mixin (riscv_fp_instr_mixin(FCVT_S_L, I_FORMAT, ARITHMETIC, RV64F));
mixin (riscv_fp_instr_mixin(FCVT_S_LU, I_FORMAT, ARITHMETIC, RV64F));
}
else {
class riscv_FCVT_L_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_L_S, I_FORMAT, ARITHMETIC, RV64F); }
class riscv_FCVT_LU_S_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_LU_S, I_FORMAT, ARITHMETIC, RV64F); }
class riscv_FCVT_S_L_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_S_L, I_FORMAT, ARITHMETIC, RV64F); }
class riscv_FCVT_S_LU_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FCVT_S_LU, I_FORMAT, ARITHMETIC, RV64F); }
}

View file

@ -0,0 +1,67 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64i_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_instr_mixin(LWU, I_FORMAT, LOAD, RV64I));
mixin (riscv_instr_mixin(LD, I_FORMAT, LOAD, RV64I));
mixin (riscv_instr_mixin(SD, S_FORMAT, STORE, RV64I));
// SHIFT intructions
mixin (riscv_instr_mixin(SLLW, R_FORMAT, SHIFT, RV64I));
mixin (riscv_instr_mixin(SLLIW, I_FORMAT, SHIFT, RV64I));
mixin (riscv_instr_mixin(SRLW, R_FORMAT, SHIFT, RV64I));
mixin (riscv_instr_mixin(SRLIW, I_FORMAT, SHIFT, RV64I));
mixin (riscv_instr_mixin(SRAW, R_FORMAT, SHIFT, RV64I));
mixin (riscv_instr_mixin(SRAIW, I_FORMAT, SHIFT, RV64I));
// ARITHMETIC intructions
mixin (riscv_instr_mixin(ADDW, R_FORMAT, ARITHMETIC, RV64I));
mixin (riscv_instr_mixin(ADDIW, I_FORMAT, ARITHMETIC, RV64I));
mixin (riscv_instr_mixin(SUBW, R_FORMAT, ARITHMETIC, RV64I));
}
else {
class riscv_LWU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LWU, I_FORMAT, LOAD, RV64I); }
class riscv_LD_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(LD, I_FORMAT, LOAD, RV64I); }
class riscv_SD_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SD, S_FORMAT, STORE, RV64I); }
// SHIFT intructions
class riscv_SLLW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLLW, R_FORMAT, SHIFT, RV64I); }
class riscv_SLLIW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SLLIW, I_FORMAT, SHIFT, RV64I); }
class riscv_SRLW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRLW, R_FORMAT, SHIFT, RV64I); }
class riscv_SRLIW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRLIW, I_FORMAT, SHIFT, RV64I); }
class riscv_SRAW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRAW, R_FORMAT, SHIFT, RV64I); }
class riscv_SRAIW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SRAIW, I_FORMAT, SHIFT, RV64I); }
// ARITHMETIC intructions
class riscv_ADDW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ADDW, R_FORMAT, ARITHMETIC, RV64I); }
class riscv_ADDIW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(ADDIW, I_FORMAT, ARITHMETIC, RV64I); }
class riscv_SUBW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(SUBW, R_FORMAT, ARITHMETIC, RV64I); }
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64m_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_instr_mixin(MULW, R_FORMAT, ARITHMETIC, RV64M));
mixin (riscv_instr_mixin(DIVW, R_FORMAT, ARITHMETIC, RV64M));
mixin (riscv_instr_mixin(DIVUW, R_FORMAT, ARITHMETIC, RV64M));
mixin (riscv_instr_mixin(REMW, R_FORMAT, ARITHMETIC, RV64M));
mixin (riscv_instr_mixin(REMUW, R_FORMAT, ARITHMETIC, RV64M));
}
else {
class riscv_MULW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(MULW, R_FORMAT, ARITHMETIC, RV64M); }
class riscv_DIVW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(DIVW, R_FORMAT, ARITHMETIC, RV64M); }
class riscv_DIVUW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(DIVUW, R_FORMAT, ARITHMETIC, RV64M); }
class riscv_REMW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(REMW, R_FORMAT, ARITHMETIC, RV64M); }
class riscv_REMUW_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(REMUW, R_FORMAT, ARITHMETIC, RV64M); }
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64zba_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_zba_instr_mixin(ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA));
mixin (riscv_zba_instr_mixin(SH1ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA));
mixin (riscv_zba_instr_mixin(SH2ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA));
mixin (riscv_zba_instr_mixin(SH3ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA));
mixin (riscv_zba_instr_mixin(SLLI_UW, I_FORMAT, SHIFT, RV64ZBA, UIMM));
}
else {
class riscv_ADD_UW_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA); }
class riscv_SH1ADD_UW_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SH1ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA); }
class riscv_SH2ADD_UW_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SH2ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA); }
class riscv_SH3ADD_UW_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SH3ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA); }
class riscv_SLLI_UW_instr: riscv_zba_instr
{ mixin RISCV_INSTR_MIXIN!(SLLI_UW, I_FORMAT, SHIFT, RV64ZBA, UIMM); }
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, Inc.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.isa.rv64zbb_instr;
import riscv.gen.riscv_defines;
import uvm;
version (RISCV_INSTR_STRING_MIXIN) {
mixin (riscv_zbb_instr_mixin(CLZW, I_FORMAT, ARITHMETIC, RV64ZBB));
mixin (riscv_zbb_instr_mixin(CPOPW, I_FORMAT, ARITHMETIC, RV64ZBB));
mixin (riscv_zbb_instr_mixin(CTZW, I_FORMAT, ARITHMETIC, RV64ZBB));
mixin (riscv_zbb_instr_mixin(ROLW, R_FORMAT, SHIFT, RV64ZBB));
mixin (riscv_zbb_instr_mixin(RORW, R_FORMAT, SHIFT, RV64ZBB));
mixin (riscv_zbb_instr_mixin(RORIW, I_FORMAT, SHIFT, RV64ZBB, UIMM));
}
else {
class riscv_CLZW_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(CLZW, I_FORMAT, ARITHMETIC, RV64ZBB); }
class riscv_CPOPW_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(CPOPW, I_FORMAT, ARITHMETIC, RV64ZBB); }
class riscv_CTZW_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(CTZW, I_FORMAT, ARITHMETIC, RV64ZBB); }
class riscv_ROLW_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(ROLW, R_FORMAT, SHIFT, RV64ZBB); }
class riscv_RORW_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(RORW, R_FORMAT, SHIFT, RV64ZBB); }
class riscv_RORIW_instr: riscv_zbb_instr
{ mixin RISCV_INSTR_MIXIN!(RORIW, I_FORMAT, SHIFT, RV64ZBB, UIMM); }
}

View file

@ -0,0 +1,32 @@
module riscv.gen;
public import riscv.gen.isa;
public import riscv.gen.target;
public import riscv.gen.riscv_amo_instr_lib;
public import riscv.gen.riscv_asm_program_gen;
public import riscv.gen.riscv_callstack_gen;
public import riscv.gen.riscv_custom_instr_enum;
public import riscv.gen.riscv_data_page_gen;
public import riscv.gen.riscv_debug_rom_gen;
public import riscv.gen.riscv_directed_instr_lib;
public import riscv.gen.riscv_illegal_instr;
public import riscv.gen.riscv_instr_gen_config;
public import riscv.gen.riscv_instr_pkg;
public import riscv.gen.riscv_instr_registry;
public import riscv.gen.riscv_instr_sequence;
public import riscv.gen.riscv_instr_stream;
public import riscv.gen.riscv_load_store_instr_lib;
public import riscv.gen.riscv_loop_instr;
public import riscv.gen.riscv_page_table;
public import riscv.gen.riscv_page_table_entry;
public import riscv.gen.riscv_page_table_exception_cfg;
public import riscv.gen.riscv_page_table_list;
public import riscv.gen.riscv_pmp_cfg;
public import riscv.gen.riscv_privileged_common_seq;
public import riscv.gen.riscv_privil_reg;
public import riscv.gen.riscv_pseudo_instr;
public import riscv.gen.riscv_reg;
public import riscv.gen.riscv_signature_pkg;
public import riscv.gen.riscv_vector_cfg;
public import riscv.gen.riscv_defines;

View file

@ -0,0 +1,268 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.riscv_amo_instr_lib;
import riscv.gen.riscv_instr_pkg: riscv_reg_t, riscv_pseudo_instr_name_t,
riscv_instr_name_t, riscv_instr_group_t, riscv_instr_category_t;
import riscv.gen.target: supported_isa, XLEN;
import riscv.gen.riscv_directed_instr_lib: riscv_mem_access_stream;
import riscv.gen.riscv_load_store_instr_lib: riscv_vector_load_store_instr_stream;
import riscv.gen.riscv_pseudo_instr: riscv_pseudo_instr;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import std.algorithm: canFind;
import esdl.rand: constraint, rand, randomize_with;
import esdl.base.rand: urandom;
import uvm;
class riscv_amo_base_instr_stream : riscv_mem_access_stream
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
@rand uint num_amo;
@rand uint num_mixed_instr;
@rand int[] offset;
@rand riscv_reg_t[] rs1_reg;
@rand int num_of_rs1_reg;
uint data_page_id;
uint max_offset;
// User can specify a small group of available registers to generate various hazard condition
@rand riscv_reg_t[] avail_regs;
constraint! q{
num_of_rs1_reg == 1;
} num_of_rs1_reg_c;
constraint! q{
// solve num_of_rs1_reg before rs1_reg;
rs1_reg.length == num_of_rs1_reg;
offset.length == num_of_rs1_reg;
foreach (rreg; rs1_reg) {
rreg !inside [cfg.reserved_regs, reserved_rd, riscv_reg_t.ZERO];
}
unique [rs1_reg];
} rs1_c;
constraint! q{
foreach (offs; offset) {
offs inside [0..max_offset];
}
} addr_range_c;
constraint! q{
foreach (offs; offset) {
if (XLEN == 32) {
offs % 4 == 0;
} else {
offs % 8 == 0;
}
}
} aligned_amo_c;
// `uvm_object_utils(riscv_amo_base_instr_stream)
// `uvm_object_new
override void pre_randomize() {
data_page = cfg.amo_region;
max_data_page_id = cast(int)data_page.length;
assert (max_data_page_id != 0);
data_page_id = urandom(0, max_data_page_id);
max_offset = data_page[data_page_id].size_in_bytes;
}
// Use "la" instruction to initialize the offset regiseter
void init_offset_reg() {
import std.conv: to;
foreach (i, rreg; rs1_reg) {
riscv_pseudo_instr la_instr;
la_instr = riscv_pseudo_instr.type_id.create("la_instr");
la_instr.pseudo_instr_name = riscv_pseudo_instr_name_t.LA;
la_instr.rd = rreg;
la_instr.imm_str = format("%0s+%0d", cfg.amo_region[data_page_id], offset[i]);
append_instr(la_instr);
}
}
override void post_randomize() {
gen_amo_instr();
reserved_rd ~= rs1_reg;
add_mixed_instr(num_mixed_instr);
init_offset_reg();
super.post_randomize();
}
// AMO instruction generation
void gen_amo_instr() { }
}
// A pair of LR/SC instruction
class riscv_lr_sc_instr_stream : riscv_amo_base_instr_stream
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
riscv_instr lr_instr;
riscv_instr sc_instr;
constraint! q{
num_amo == 1;
num_mixed_instr inside [0..16]; // [0:15]
} legal_c ;
override void gen_amo_instr() {
riscv_instr_name_t[] allowed_lr_instr;
riscv_instr_name_t[] allowed_sc_instr;
if (canFind (supported_isa , riscv_instr_group_t.RV32A)) {
allowed_lr_instr = [riscv_instr_name_t.LR_W];
allowed_sc_instr = [riscv_instr_name_t.SC_W];
}
if (canFind (supported_isa, riscv_instr_group_t.RV64A)) {
allowed_lr_instr ~= riscv_instr_name_t.LR_D;
allowed_sc_instr ~= riscv_instr_name_t.SC_D;
}
lr_instr = cfg.instr_registry.get_rand_instr(allowed_lr_instr);
sc_instr = cfg.instr_registry.get_rand_instr(allowed_sc_instr);
lr_instr.randomize_with! q{
rs1 == $0;
if ($1.length > 0) {
rd !inside [$1];
}
if ($2.length > 0) {
rd !inside [$2];
}
rd != $0;
} (rs1_reg[0], reserved_rd, cfg.reserved_regs);
sc_instr.randomize_with! q{
rs1 == $0;
if ($1.length > 0) {
rd !inside [$1];
}
if ($2.length > 0) {
rd !inside [$2];
}
rd != $0;
} (rs1_reg[0], reserved_rd, cfg.reserved_regs);
append_instr(lr_instr);
append_instr(sc_instr);
}
// section 8.3 Eventual Success of Store-Conditional Instructions
// An LR/SC sequence begins with an LR instruction and ends with an SC instruction.
// The dynamic code executed between the LR and SC instructions can only contain
// instructions from the base “I” instruction set, excluding loads, stores, backward
// jumps, taken backward branches, JALR, FENCE, and SYSTEM instructions. If the “C”
// extension is supported, then compressed forms of the aforementioned “I” instructions
// are also permitted.
override void add_mixed_instr(int instr_cnt) {
riscv_instr instr;
int i;
setup_allowed_instr(true, true);
//setup_allowed_instr(.no_branch(1), .no_load_store(1));
while (i < instr_cnt) {
instr = riscv_instr.type_id.create("instr");
randomize_instr(instr, false, false, [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32C]);
if (! instr.category.inside(riscv_instr_category_t.SYNCH,
riscv_instr_category_t.SYSTEM)) {
insert_instr(instr);
i++;
}
}
}
}
class riscv_amo_instr_stream: riscv_amo_base_instr_stream
{
riscv_instr[] amo_instr;
constraint! q{
solve num_amo before num_mixed_instr;
num_amo inside [1..11];
num_mixed_instr inside [0..num_amo+1];
} reasonable_c;
constraint! q{
solve num_amo before num_of_rs1_reg;
num_of_rs1_reg inside [1..num_amo+1];
num_of_rs1_reg < 5;
} num_of_rs1_reg_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void gen_amo_instr() {
amo_instr.length = num_amo;
foreach (i, ref instr; amo_instr) {
instr = cfg.instr_registry.get_rand_instr([riscv_instr_category_t.AMO]);
amo_instr[i].randomize_with! q{
if ($0.length > 0) {
rd !inside [$0];
}
if ($1.length > 0) {
rd !inside [$1];
}
rs1 inside [$2];
rd !inside [$2];
} (reserved_rd, cfg.reserved_regs, rs1_reg);
append_instr(instr);
}
}
}
class riscv_vector_amo_instr_stream: riscv_vector_load_store_instr_stream
{
constraint! q{
// AMO operation uses indexed address mode
address_mode == address_mode_e.INDEXED;
} amo_address_mode_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
void add_element_vec_load_stores() {
allowed_instr = [riscv_instr_name_t.VAMOSWAPE_V, riscv_instr_name_t.VAMOADDE_V,
riscv_instr_name_t.VAMOXORE_V, riscv_instr_name_t.VAMOANDE_V,
riscv_instr_name_t.VAMOORE_V, riscv_instr_name_t.VAMOMINE_V,
riscv_instr_name_t.VAMOMAXE_V, riscv_instr_name_t.VAMOMINUE_V,
riscv_instr_name_t.VAMOMAXUE_V] ~ allowed_instr;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,206 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------------------
// RISC-V abstract program class
//
// This class is used to model a node in a callstack tree, no actual instruction is included
// in this class.
//-----------------------------------------------------------------------------------------
module riscv.gen.riscv_callstack_gen;
import riscv.gen.riscv_instr_pkg: program_id_t;
import esdl.rand: constraint, rand, randomize;
import esdl.data.bvec: ubvec, toubvec;
import esdl.base.rand: urandom, shuffle;
import uvm;
import std.format: format;
class riscv_program: uvm_object
{
mixin uvm_object_utils;
// ID of the current program
@rand program_id_t program_id;
// The level of current program in the call stack tree
@rand uint call_stack_level;
// The list of all sub-programs of the current program
@rand program_id_t[] sub_program_id;
constraint! q{
unique [sub_program_id];
foreach (id; sub_program_id) {
// Cannot call itself, recursive function call is not supported
id != program_id;
}
} legal_c;
this(string name = "") {
super(name);
}
override string convert2string() {
string str = format("PID[%0d] Lv[%0d] :", program_id, call_stack_level);
foreach (id; sub_program_id) {
str = format("%0s %0d", str, id);
}
return str;
}
}
//-----------------------------------------------------------------------------------------
// RISC-V assembly program call stack generator
//
// The call stack is generated as a tree structure to avoid dead call loop.
// Level 0: P0
// / | \
// Level 1: P1 P2 P3
// | \/ \
// Level 2: P4 P5 P6
// |
// Level 3: P7
//
// Rules: A program can only call the program in the next level.
// A program can be called many times by other upper level programs.
// A program can call the same lower level programs multiple times.
//-----------------------------------------------------------------------------------------
class riscv_callstack_gen : uvm_object
{
mixin uvm_object_utils;
// Number of programs in the call stack
int program_cnt = 10;
// Handles of all programs
riscv_program[] program_h;
// Maximum call stack level
int max_stack_level = 50;
@rand ubvec!11[] stack_level;
constraint! q{
// The stack level is assigned in ascending order to avoid call loop
stack_level.length == program_cnt;
stack_level[0] == 0;
foreach (i, slevel; stack_level) {
if (i > 0) {
slevel inside [1..program_cnt];
slevel >= stack_level[i-1];
slevel <= stack_level[i-1]+1;
slevel <= max_stack_level;
}
}
} program_stack_level_c;
//`endif
this(string name = "") {
super(name);
}
// Init all program instances before randomization
void init(int program_cnt) {
this.program_cnt = program_cnt;
program_h.length = program_cnt;
foreach(i, ref prog; program_h) {
prog = riscv_program.type_id.create(format("program_%0d", i));
}
}
// In the randomiation stage, only the stack level of each program is specified. The call stack
// generation process is to build the call relationship between different programs. This is
// implemented with post randomize rather than constraints for performance considerations.
// Solving a complex call stack with SV constraint could take considerable time for the solver.
void post_randomize() {
int last_level;
last_level = stack_level[program_cnt-1];
foreach(i, prog; program_h) {
prog.program_id = toubvec!16(i);
prog.call_stack_level = stack_level[i];
}
// Top-down generate the entire call stack.
// A program can only call the programs in the next level.
for(int i = 0; i < last_level; i ++) {
int total_sub_program_cnt;
int[] program_list;
int[] next_program_list;
int[] sub_program_id_pool;
int[] sub_program_cnt;
int idx;
for (int j=0; j<program_cnt; j++) {
if (stack_level[j] == i) {
program_list ~= j;
}
if (stack_level[j] == i+1) {
next_program_list ~=j;
}
}
// Randmly duplicate some sub programs in the pool to create a case that
// one sub program is called by multiple caller. Also it's possible to call
// the same sub program in one program multiple times.
int len = cast(int) next_program_list.length;
total_sub_program_cnt = urandom(len, (len + 2));
sub_program_id_pool.length = total_sub_program_cnt;
foreach (j, ref spid; sub_program_id_pool) {
if (j < next_program_list.length)
spid = next_program_list[j];
else {
int nextid = urandom(0, cast(int) next_program_list.length);
spid = next_program_list[nextid];
}
}
sub_program_id_pool.shuffle();
sub_program_cnt.length = program_list.length;
uvm_info(get_full_name(), format("%0d programs @Lv%0d-> %0d programs at next level",
program_list.length, i, sub_program_id_pool.length), UVM_LOW);
// Distribute the programs of the next level among the programs of current level
// Make sure all program has a caller so that no program is obsolete.
foreach (spid; sub_program_id_pool) {
int caller_id = urandom(0, cast(int) sub_program_cnt.length);
sub_program_cnt[caller_id]++;
}
foreach (j, id; program_list) {
program_h[id].sub_program_id.length = sub_program_cnt[j];
uvm_info(get_full_name(), format("%0d sub programs are assigned to program[%0d]",
sub_program_cnt[j], id), UVM_LOW);
foreach (ref spid; program_h[id].sub_program_id) {
spid = toubvec!16(sub_program_id_pool[idx]);
idx++;
}
}
}
}
void print_call_stack(program_id_t i, string str) {
if (program_h[i].sub_program_id.length == 0)
uvm_info(get_full_name(), str, UVM_LOW);
else {
foreach (spid; program_h[i].sub_program_id) {
print_call_stack(spid, format("%0s -> %0d", str, spid));
}
}
}
}

View file

@ -0,0 +1,3 @@
//TODO custom instruction added
// CUSTOM_i,
module riscv.gen.riscv_custom_instr_enum;

View file

@ -0,0 +1,131 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------------------
// RISC-V assmebly program data section generator
// There can be user mode and supervisor(kernel) mode data pages
//-----------------------------------------------------------------------------------------
module riscv.gen.riscv_data_page_gen;
import riscv.gen.riscv_instr_pkg: mem_region_t, data_pattern_t, hart_prefix, format_string,
format_data, LABEL_STR_LEN;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import std.format: format;
import esdl.data.bvec: ubvec, toubvec;
import esdl.base.rand: urandom;
import uvm;
class riscv_data_page_gen: uvm_object
{
import std.conv: to;
riscv_instr_gen_config cfg;
string[] data_page_str;
mem_region_t[] mem_region_setting;
mixin uvm_object_utils;
this(string name = "cls_avail_regs") {
super(name);
}
// The data section can be initialized with different data pattern:
// - Random value, incremental value, all zeros
void gen_data(in int idx,
in data_pattern_t pattern,
in uint num_of_bytes,
out ubyte[] data) {
ubyte temp_data;
data.length = num_of_bytes;
foreach (i, ref dd; data) {
if (pattern == data_pattern_t.RAND_DATA) {
temp_data = toubvec!8(urandom!ubyte());
dd = temp_data;
}
else if (pattern == data_pattern_t.INCR_VAL) {
dd = cast(ubyte) ((idx + (cast(int) i)) % 256);
}
}
}
// Generate data pages for all memory regions
void gen_data_page(int hart_id,
data_pattern_t pattern,
bool is_kernel = false,
bool amo = false) {
string tmp_str;
ubyte[] tmp_data;
int page_cnt;
int page_size;
data_page_str.length = 0;
if (is_kernel) {
mem_region_setting = cfg.s_mem_region;
}
else if (amo) {
mem_region_setting = cfg.amo_region;
}
else {
mem_region_setting = cfg.mem_region;
}
foreach (setting; mem_region_setting) {
uvm_info(get_full_name, format("Generate data section: %0s size:0x%0x xwr:0x%0x]",
setting.name, setting.size_in_bytes, setting.xwr), UVM_LOW);
if (amo) {
if (cfg.use_push_data_section) {
data_page_str ~= format(".pushsection .%0s,\"aw\",@progbits;",
setting.name);
}
else {
data_page_str ~= format(".section .%0s,\"aw\",@progbits;",
setting.name);
}
data_page_str ~= format("%0s:", setting.name);
}
else {
if (cfg.use_push_data_section) {
data_page_str ~= format(".pushsection .%0s,\"aw\",@progbits;",
(hart_prefix(hart_id) ~ setting.name));
}
else {
data_page_str ~= format(".section .%0s,\"aw\",@progbits;",
(hart_prefix(hart_id) ~ setting.name));
}
data_page_str ~= format("%0s:",
(hart_prefix(hart_id) ~ setting.name));
}
page_size = setting.size_in_bytes;
for (int i = 0; i < page_size; i+= 32) {
if (page_size-i >= 32) {
gen_data(i, pattern, 32, tmp_data);
}
else {
gen_data(i, pattern, page_size-i, tmp_data);
}
tmp_str = format_string(format(".word %0s", format_data(tmp_data)), LABEL_STR_LEN);
data_page_str ~= tmp_str;
}
if (cfg.use_push_data_section) {
data_page_str ~= ".popsection;";
}
}
}
}

View file

@ -0,0 +1,274 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//---------------------------------------------------------------------------------------
// RISC-V debug ROM class
//
// This is the main class to generate a test debug ROM, which includes control knobs to
// toggle various configuration fields of DCSR.
//---------------------------------------------------------------------------------------
module riscv.gen.riscv_debug_rom_gen;
import riscv.gen.riscv_instr_pkg: privileged_reg_t, hart_prefix, push_gpr_to_kernel_stack,
indent, pop_gpr_from_kernel_stack, privileged_mode_t;
import riscv.gen.target: supported_privileged_mode;
import riscv.gen.riscv_instr_sequence: riscv_instr_sequence;
import riscv.gen.riscv_asm_program_gen: riscv_asm_program_gen;
import riscv.gen.riscv_signature_pkg: core_status_t, signature_type_t, test_result_t;
import std.format: format;
import std.algorithm.searching: canFind;
import esdl.rand: randomize;
import uvm;
class riscv_debug_rom_gen : riscv_asm_program_gen
{
string[] debug_main;
string[] debug_end;
// string[] str; // This should actually be a local variable inside the methods/functions
string dret;
int hart;
mixin uvm_object_utils;
this(string name = "") {
super(name);
dret = "dret";
}
//-------------------------------------------------------------------------------------
// Main function to generate whole debug ROM
//-------------------------------------------------------------------------------------
override void gen_program() {
string[] sub_program_name;
if (! cfg.gen_debug_section) {
// If the debug section should not be generated, we just populate it
// with a dret instruction.
debug_main ~= dret;
gen_section(format("%0sdebug_rom", hart_prefix(hart)), debug_main);
}
else {
if (cfg.enable_ebreak_in_debug_rom) {
gen_ebreak_header();
}
// Need to save off GPRs to avoid modifying program flow
push_gpr_to_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH,
cfg.mstatus_mprv, cfg.sp, cfg.tp, debug_main);
// Signal that the core entered debug rom only if the rom is actually
// being filled with random instructions to prevent stress tests from
// having to execute unnecessary push/pop of GPRs on the stack ever
// time a debug request is sent
gen_signature_handshake(debug_main, signature_type_t.CORE_STATUS, core_status_t.IN_DEBUG_MODE);
if (cfg.enable_ebreak_in_debug_rom) {
// send dpc and dcsr to testbench, as this handshake will be
// executed twice due to the ebreak loop, there should be no change
// in their values as by the Debug Mode Spec Ch. 4.1.8
gen_signature_handshake(debug_main, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DCSR);
gen_signature_handshake(debug_main, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DPC);
}
if (cfg.set_dcsr_ebreak) {
// We want to set dcsr.ebreak(m/s/u) to 1'b1, depending on what modes
// are available.
// TODO(udinator) - randomize the dcsr.ebreak setup
gen_dcsr_ebreak();
}
if (cfg.enable_debug_single_step) {
gen_single_step_logic();
}
gen_dpc_update();
// write DCSR to the testbench for any analysis
gen_signature_handshake(debug_main, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DCSR);
if (cfg.enable_ebreak_in_debug_rom || cfg.set_dcsr_ebreak) {
gen_increment_ebreak_counter();
}
format_section(debug_main);
gen_sub_program(hart, sub_program[hart], sub_program_name,cfg.num_debug_sub_program,
true, "debug_sub");
main_program[hart] = riscv_instr_sequence.type_id.create("debug_program");
main_program[hart].instr_cnt = cfg.debug_program_instr_cnt;
main_program[hart].is_debug_program = 1;
main_program[hart].cfg = cfg;
main_program[hart].randomize();
// `DV_CHECK_RANDOMIZE_FATAL(main_program[hart])
main_program[hart].gen_instr(true, cfg.no_branch_jump);
gen_callstack(main_program[hart], sub_program[hart], sub_program_name,
cfg.num_debug_sub_program);
main_program[hart].post_process_instr();
main_program[hart].generate_instr_stream(true);
debug_main ~= main_program[hart].instr_string_list.toArray ~
format("%sla x%0d, debug_end", indent, cfg.scratch_reg) ~
format("%sjalr x0, x%0d, 0", indent, cfg.scratch_reg);
insert_sub_program(sub_program[hart], debug_main);
gen_section(format("%0sdebug_rom", hart_prefix(hart)), debug_main);
if (cfg.enable_ebreak_in_debug_rom) {
gen_ebreak_footer();
}
pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH,
cfg.mstatus_mprv, cfg.sp, cfg.tp, debug_end);
if (cfg.enable_ebreak_in_debug_rom) {
gen_restore_ebreak_scratch_reg();
}
//format_section(debug_end);
debug_end ~= dret;
gen_section(format("%0sdebug_end", hart_prefix(hart)), debug_end);
}
gen_debug_exception_handler();
}
// Generate exception handling routine for debug ROM
// TODO(udinator) - remains empty for now, only a DRET
void gen_debug_exception_handler() {
string[] str = ["dret"];
gen_section(format("%0sdebug_exception", hart_prefix(hart)), str);
}
//-------------------------------------------------------------------------------------
// Helper functions to generate smaller sections of code
//-------------------------------------------------------------------------------------
// As execution of ebreak in D mode causes core to re-enter D mode, this directed
// sequence will be a loop that ensures the ebreak instruction will only be executed
// once to prevent infinitely looping back to the beginning of the debug rom.
// Write dscratch to random GPR and branch to debug_end if greater than 0, for ebreak loops.
// Use dscratch1 to store original GPR value.
void gen_ebreak_header() {
string[] str = [format("csrw 0x%0x, x%0d", privileged_reg_t.DSCRATCH1, cfg.scratch_reg),
format("csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH0),
format("beq x%0d, x0, 1f", cfg.scratch_reg),
format("j %0sdebug_end", hart_prefix(hart)),
format("1: csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH1)];
debug_main ~= str;
}
// Set dscratch0 back to 0x0 to prepare for the next entry into debug
// mode, and write dscratch0 and dcsr to the testbench for any
// analysis
void gen_ebreak_footer() {
// send dpc and dcsr to testbench, as this handshake will be
// executed twice due to the ebreak loop, there should be no change
// in their values as by the Debug Mode Spec Ch. 4.1.8
gen_signature_handshake(debug_end, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DCSR);
gen_signature_handshake(debug_end, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DPC);
string str = format("csrwi 0x%0x, 0x0", privileged_reg_t.DSCRATCH0);
debug_end ~= str;
}
// Increment dscratch0 by 1 to update the loop counter for all ebreak tests
void gen_increment_ebreak_counter() {
// Add 1 to dscratch0
increment_csr(privileged_reg_t.DSCRATCH0, 1, debug_main);
string str = format("csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH1);
debug_main ~= str;
}
// We have been using dscratch1 to store the
// value of our given scratch register for use in ebreak loop, so we
// need to restore its value before returning from D mode
void gen_restore_ebreak_scratch_reg() {
string str = format("csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH1);
debug_end ~= str;
}
// To enable debug single stepping, we must set dcsr.step to 1.
// We will repeat the debug single stepping process a random number of times,
// using a dscratch CSR as the counter, and decrement this counter by 1 every time we
// enter debug mode, until this counter reaches 0, at which point we set
// dcsr.step to 0 until the next debug stimulus is asserted.
// Store our designated scratch_reg to dscratch1
void gen_single_step_logic() {
string[] str = [format("csrw 0x%0x, x%0d", privileged_reg_t.DSCRATCH1, cfg.scratch_reg),
// Only un-set dcsr.step if it is 1 and the iterations counter
// is at 0 (has finished iterating)
format("csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DCSR),
format("andi x%0d, x%0d, 4", cfg.scratch_reg, cfg.scratch_reg),
// If dcsr.step is 0, set to 1 and set the counter
format("beqz x%0d, 1f", cfg.scratch_reg),
format("csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH0),
// if the counter is greater than 0, decrement and continue single stepping
format("bgtz x%0d, 2f", cfg.scratch_reg),
format("csrc 0x%0x, 0x4", privileged_reg_t.DCSR),
format("beqz x0, 3f"),
// Set dcsr.step and the num_iterations counter
format("1: csrs 0x%0x, 0x4", privileged_reg_t.DCSR),
format("li x%0d, %0d", cfg.scratch_reg, cfg.single_step_iterations),
format("csrw 0x%0x, x%0d", privileged_reg_t.DSCRATCH0, cfg.scratch_reg),
format("beqz x0, 3f"),
// Decrement dscratch counter
format("2: csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH0),
format("addi x%0d, x%0d, -1", cfg.scratch_reg, cfg.scratch_reg),
format("csrw 0x%0x, x%0d", privileged_reg_t.DSCRATCH0, cfg.scratch_reg),
// Restore scratch_reg value from dscratch1
format("3: csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DSCRATCH1)];
debug_main ~= str;
// write dpc to testbench
gen_signature_handshake(debug_main, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DPC);
// write out the counter to the testbench
gen_signature_handshake(debug_main, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.DSCRATCH0);
}
// Check dcsr.cause, and update dpc by 0x4 if the cause is ebreak, as
// ebreak will set set dpc to its own address, which will cause an
// infinite loop.
void gen_dpc_update() {
string[] str = [format("csrr x%0d, 0x%0x", cfg.scratch_reg, privileged_reg_t.DCSR),
format("slli x%0d, x%0d, 0x17", cfg.scratch_reg, cfg.scratch_reg),
format("srli x%0d, x%0d, 0x1d", cfg.scratch_reg, cfg.scratch_reg),
format("li x%0d, 0x1", cfg.gpr[0]),
format("bne x%0d, x%0d, 4f", cfg.scratch_reg, cfg.gpr[0])];
debug_main ~= str;
increment_csr(privileged_reg_t.DPC, 4, debug_main);
str = ["4: nop"];
debug_main ~= str;
}
// Set dcsr.ebreak(m/s/u)
// TODO(udinator) - randomize the setup for these fields
void gen_dcsr_ebreak() {
if (canFind (supported_privileged_mode, privileged_mode_t.MACHINE_MODE)) {
string[] str = [format("li x%0d, 0x8000", cfg.scratch_reg),
format("csrs 0x%0x, x%0d", privileged_reg_t.DCSR, cfg.scratch_reg)];
debug_main ~= str;
}
if ( canFind (supported_privileged_mode , privileged_mode_t.SUPERVISOR_MODE)) {
string[] str = [format("li x%0d, 0x2000", cfg.scratch_reg),
format("csrs 0x%0x, x%0d", privileged_reg_t.DCSR, cfg.scratch_reg)];
debug_main ~= str;
}
if (canFind (supported_privileged_mode, privileged_mode_t.USER_MODE)) {
string[] str = [format("li x%0d, 0x1000", cfg.scratch_reg),
format("csrs 0x%0x, x%0d", privileged_reg_t.DCSR, cfg.scratch_reg)];
debug_main ~= str;
}
}
void increment_csr(privileged_reg_t csr, int val, ref string [] instr) {
string[] str = [format("csrr x%0d, 0x%0x", cfg.scratch_reg, csr),
format("addi x%0d, x%0d, 0x%0x", cfg.scratch_reg, cfg.scratch_reg, val),
format("csrw 0x%0x, x%0d", csr, cfg.scratch_reg)];
instr ~= str;
}
}

View file

@ -0,0 +1,330 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.riscv_defines;
public import riscv.gen.riscv_instr_pkg: riscv_instr_name_t, riscv_instr_group_t,
riscv_instr_category_t, riscv_instr_format_t, va_variant_t, imm_t;
mixin(declareEnums!riscv_instr_name_t());
mixin(declareEnums!riscv_instr_group_t());
mixin(declareEnums!riscv_instr_category_t());
mixin(declareEnums!riscv_instr_format_t());
mixin(declareEnums!va_variant_t());
mixin(declareEnums!imm_t());
public import riscv.gen.isa.riscv_instr: riscv_instr;
public import riscv.gen.isa.riscv_floating_point_instr: riscv_floating_point_instr;
public import riscv.gen.isa.riscv_compressed_instr: riscv_compressed_instr;
public import riscv.gen.isa.riscv_amo_instr: riscv_amo_instr;
public import riscv.gen.isa.riscv_b_instr: riscv_b_instr;
public import riscv.gen.isa.riscv_vector_instr: riscv_vector_instr;
public import riscv.gen.isa.custom.riscv_custom_instr: riscv_custom_instr;
public import riscv.gen.isa.riscv_zba_instr: riscv_zba_instr;
public import riscv.gen.isa.riscv_zbb_instr: riscv_zbb_instr;
public import riscv.gen.isa.riscv_zbc_instr: riscv_zbc_instr;
public import riscv.gen.isa.riscv_zbs_instr: riscv_zbs_instr;
// enum aliases
static string declareEnums (alias E)()
{
import std.traits;
import std.conv;
string res;
foreach(e; __traits(allMembers, E))
{
res ~= "enum " ~ E.stringof ~ " " ~ e ~ " = " ~
E.stringof ~ "." ~ e ~ ";\n";
}
return res;
}
string riscv_instr_mixin_tmpl(BASE_TYPE)(riscv_instr_name_t instr_name,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) {
import std.conv: to;
string class_str = "class riscv_" ~ instr_name.to!string() ~ "_instr: " ~ BASE_TYPE.stringof;
class_str ~= "\n{\n";
class_str ~= " enum riscv_instr_name_t RISCV_INSTR_NAME_T = \n";
class_str ~= " riscv_instr_name_t." ~ instr_name.to!string() ~ ";\n";
class_str ~= " mixin uvm_object_utils;\n";
class_str ~= " this(string name = \"\") {\n";
class_str ~= " super(name);\n";
class_str ~= " this.instr_name = riscv_instr_name_t." ~ instr_name.to!string() ~ ";\n";
class_str ~= " this.instr_format = riscv_instr_format_t." ~ instr_format.to!string() ~ ";\n";
class_str ~= " this.group = riscv_instr_group_t." ~ instr_group.to!string() ~ ";\n";
class_str ~= " this.category = riscv_instr_category_t." ~ instr_category.to!string() ~ ";\n";
class_str ~= " this.imm_type = imm_t." ~ imm_tp.to!string() ~ ";\n";
class_str ~= " set_imm_len();\n";
class_str ~= " set_rand_mode();\n";
class_str ~= " }\n";
class_str ~= "}\n";
return class_str;
}
string riscv_va_instr_mixin_tmpl(BASE_TYPE)(riscv_instr_name_t instr_name,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
va_variant_t[] vavs = [],
string ext = "") {
import std.conv: to;
string class_str = "class riscv_" ~ instr_name.to!string() ~ "_instr: " ~ BASE_TYPE.stringof;
class_str ~= "\n{\n";
class_str ~= " enum riscv_instr_name_t RISCV_INSTR_NAME_T = \n";
class_str ~= " riscv_instr_name_t." ~ instr_name.to!string() ~ ";\n";
class_str ~= " mixin uvm_object_utils;\n";
class_str ~= " this(string name = \"\") {\n";
class_str ~= " super(name);\n";
class_str ~= " this.instr_name = riscv_instr_name_t." ~ instr_name.to!string() ~ ";\n";
class_str ~= " this.instr_format = riscv_instr_format_t." ~ instr_format.to!string() ~ ";\n";
class_str ~= " this.group = riscv_instr_group_t." ~ instr_group.to!string() ~ ";\n";
class_str ~= " this.category = riscv_instr_category_t." ~ instr_category.to!string() ~ ";\n";
class_str ~= " this.imm_type = imm_t.IMM;\n";
class_str ~= " this.allowed_va_variants = [";
foreach (vav; vavs) {
class_str ~= " va_variant_t." ~ vav.to!string() ~ ",\n";
}
class_str ~= " ];\n";
class_str ~= " this.sub_extension = \"" ~ ext ~ "\";\n";
class_str ~= " set_imm_len();\n";
class_str ~= " set_rand_mode();\n";
class_str ~= " }\n";
class_str ~= "}\n";
return class_str;
}
class RISCV_INSTR_TMPL(riscv_instr_name_t instr_n,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
imm_t imm_tp,
BASE_TYPE): BASE_TYPE
{
enum riscv_instr_name_t RISCV_INSTR_NAME_T = instr_n;
mixin uvm_object_utils;
this(string name="") {
super(name);
this.instr_name = instr_n;
this.instr_format = instr_format;
this.group = instr_group;
this.category = instr_category;
this.imm_type = imm_tp;
set_imm_len();
set_rand_mode();
}
}
mixin template RISCV_INSTR_MIXIN(riscv_instr_name_t instr_n,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
imm_t imm_tp=imm_t.IMM)
{
enum riscv_instr_name_t RISCV_INSTR_NAME_T = instr_n;
mixin uvm_object_utils;
this(string name="") {
super(name);
this.instr_name = instr_n;
this.instr_format = instr_format;
this.group = instr_group;
this.category = instr_category;
this.imm_type = imm_tp;
set_imm_len();
set_rand_mode();
}
}
class RISCV_VA_INSTR_TMPL(string ext, riscv_instr_name_t instr_n,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
imm_t imm_tp,
BASE_TYPE,
vav...): BASE_TYPE
{
enum riscv_instr_name_t RISCV_INSTR_NAME_T = instr_n;
mixin uvm_object_utils;
this(string name="") {
super(name);
this.instr_name = instr_n;
this.instr_format = instr_format;
this.group = instr_group;
this.category = instr_category;
this.imm_type = imm_tp;
this.allowed_va_variants = [vav];
this.sub_extension = ext;
set_imm_len();
set_rand_mode();
}
}
mixin template RISCV_VA_INSTR_MIXIN(string ext, riscv_instr_name_t instr_n,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
vav...)
{
enum riscv_instr_name_t RISCV_INSTR_NAME_T = instr_n;
mixin uvm_object_utils;
this(string name="") {
super(name);
this.instr_name = instr_n;
this.instr_format = instr_format;
this.group = instr_group;
this.category = instr_category;
this.imm_type = imm_t.IMM;
this.allowed_va_variants = [vav];
this.sub_extension = ext;
set_imm_len();
set_rand_mode();
}
}
mixin template RISCV_VA_INSTR_MIXIN(riscv_instr_name_t instr_n,
riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category,
riscv_instr_group_t instr_group,
vav...)
{
enum riscv_instr_name_t RISCV_INSTR_NAME_T = instr_n;
mixin uvm_object_utils;
this(string name="") {
super(name);
this.instr_name = instr_n;
this.instr_format = instr_format;
this.group = instr_group;
this.category = instr_category;
this.imm_type = imm_t.IMM;
this.allowed_va_variants = [vav];
this.sub_extension = "";
set_imm_len();
set_rand_mode();
}
}
alias riscv_instr_mixin = riscv_instr_mixin_tmpl!riscv_instr;
alias RISCV_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_instr);
alias riscv_fp_instr_mixin = riscv_instr_mixin_tmpl!riscv_floating_point_instr;
alias RISCV_FP_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_floating_point_instr);
alias riscv_amo_instr_mixin = riscv_instr_mixin_tmpl!riscv_amo_instr;
alias RISCV_AMO_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_amo_instr);
alias riscv_c_instr_mixin = riscv_instr_mixin_tmpl!riscv_compressed_instr;
alias RISCV_C_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_compressed_instr);
alias riscv_fc_instr_mixin = riscv_instr_mixin_tmpl!riscv_compressed_instr;
alias RISCV_FC_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_compressed_instr);
alias riscv_va_instr_mixin = riscv_va_instr_mixin_tmpl!riscv_vector_instr;
alias RISCV_VA_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
vav...) =
RISCV_VA_INSTR_TMPL!("", instr_n, instr_format, instr_category, instr_group, imm_t.IMM,
riscv_vector_instr, vav);
alias RISCV_VA_INSTR(string ext, riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
vav...) =
RISCV_VA_INSTR_TMPL!(ext, instr_n, instr_format, instr_category, instr_group, imm_t.IMM,
riscv_vector_instr, vav);
alias riscv_custom_instr_mixin = riscv_instr_mixin_tmpl!riscv_custom_instr;
alias RISCV_CUSTOM_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_custom_instr);
alias riscv_b_instr_mixin = riscv_instr_mixin_tmpl!riscv_b_instr;
alias RISCV_B_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_b_instr);
//Zba-extension instruction
alias riscv_zba_instr_mixin = riscv_instr_mixin_tmpl!riscv_zba_instr;
alias RISCV_ZBA_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_zba_instr);
//Zbb-extension instruction
alias riscv_zbb_instr_mixin = riscv_instr_mixin_tmpl!riscv_zbb_instr;
alias RISCV_ZBB_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_zbb_instr);
//Zbc-extension instruction
alias riscv_zbc_instr_mixin = riscv_instr_mixin_tmpl!riscv_zbc_instr;
alias RISCV_ZBC_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_zbc_instr);
//Zbs-extension instruction
alias riscv_zbs_instr_mixin = riscv_instr_mixin_tmpl!riscv_zbs_instr;
alias RISCV_ZBS_INSTR(riscv_instr_name_t instr_n, riscv_instr_format_t instr_format,
riscv_instr_category_t instr_category, riscv_instr_group_t instr_group,
imm_t imm_tp = imm_t.IMM) =
RISCV_INSTR_TMPL!(instr_n, instr_format, instr_category, instr_group, imm_tp,
riscv_zbs_instr);

View file

@ -0,0 +1,557 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Base class for directed instruction stream
module riscv.gen.riscv_directed_instr_lib;
import riscv.gen.riscv_instr_pkg: mem_region_t, riscv_reg_t, riscv_instr_name_t,
riscv_pseudo_instr_name_t, hart_prefix, riscv_instr_category_t, riscv_instr_group_t;
import riscv.gen.target: XLEN;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_pseudo_instr: riscv_pseudo_instr;
import riscv.gen.riscv_instr_stream: riscv_rand_instr_stream;
import std.format: format;
import std.algorithm: canFind;
import esdl.rand: rand, constraint, randomize_with, randomize;
import esdl.base.rand: urandom, shuffle;
import esdl.data.bvec: ubvec, toubvec;
import uvm;
class riscv_directed_instr_stream: riscv_rand_instr_stream
{
mixin uvm_object_utils;
//`uvm_object_utils(riscv_directed_instr_stream)
string label;
this(string name = "") {
super(name);
}
void post_randomize() {
foreach (instr; instr_list) {
instr.has_label = false;
instr.atomic = true;
}
instr_list[0].comment = format("Start %0s", get_name());
instr_list[$-1].comment = format("End %0s", get_name());
if(label!= "") {
instr_list[0].label = label;
instr_list[0].has_label = true;
}
}
}
// Base class for memory access stream
class riscv_mem_access_stream : riscv_directed_instr_stream
{
mixin uvm_object_utils;
int max_data_page_id;
bool load_store_shared_memory;
mem_region_t[] data_page;
this(string name = "") {
super(name);
}
void pre_randomize() {
if (load_store_shared_memory) {
data_page = cfg.amo_region;
}
else if(kernel_mode) {
data_page = cfg.s_mem_region;
}
else {
data_page = cfg.mem_region;
}
max_data_page_id = cast(int) data_page.length;
}
// Use "la" instruction to initialize the base regiseter
void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0) {
riscv_pseudo_instr la_instr;
la_instr = riscv_pseudo_instr.type_id.create("la_instr");
la_instr.pseudo_instr_name = riscv_pseudo_instr_name_t.LA;
la_instr.rd = gpr;
if (load_store_shared_memory) {
la_instr.imm_str = format("%0s+%0d", cfg.amo_region[id].name, base);
}
else if(kernel_mode) {
la_instr.imm_str = format("%0s%0s+%0d",
hart_prefix(hart), cfg.s_mem_region[id].name, base);
}
else {
la_instr.imm_str = format("%0s%0s+%0d",
hart_prefix(hart), cfg.mem_region[id].name, base);
}
prepend_instr(la_instr);
}
// Insert some other instructions to mix with mem_access instruction
void add_mixed_instr(int instr_cnt) {
riscv_instr instr;
setup_allowed_instr(1, 1);
for (int i = 0; i < instr_cnt; i ++) {
instr = riscv_instr.type_id.create("instr");
randomize_instr(instr);
insert_instr(instr);
}
}
}
// Jump instruction (JAL, JALR)
// la rd0, jump_tagert_label
// addi rd1, offset, rd0
// jalr rd, offset, rd1
// For JAL, restore the stack before doing the jump
class riscv_jump_instr: riscv_directed_instr_stream
{
riscv_instr jump;
riscv_instr addi;
riscv_pseudo_instr la;
riscv_instr branch;
@rand riscv_reg_t gpr;
@rand int imm;
@rand bool enable_branch;
@rand int mixed_instr_cnt;
riscv_instr[] stack_exit_instr;
string target_program_label;
int idx;
bool use_jalr;
constraint! q{
gpr !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
imm inside [-1023:1023];
mixed_instr_cnt inside [5:10];
if (jump.instr_name inside [ riscv_instr_name_t.C_JR, riscv_instr_name_t.C_JALR]) {
imm == 0;
}
} instr_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
la = riscv_pseudo_instr.type_id.create("la");
}
void pre_randomize() {
if (use_jalr) {
jump = cfg.instr_registry.get_instr(riscv_instr_name_t.JALR);
}
else if (cfg.disable_compressed_instr || (cfg.ra != riscv_reg_t.RA)) {
jump = cfg.instr_registry.get_rand_instr([riscv_instr_name_t.JAL, riscv_instr_name_t.JALR]);
}
else {
jump = cfg.instr_registry.get_rand_instr([riscv_instr_name_t.JAL, riscv_instr_name_t.JALR,
riscv_instr_name_t.C_JALR]);
}
addi = cfg.instr_registry.get_instr(riscv_instr_name_t.ADDI);
branch = cfg.instr_registry.get_rand_instr([riscv_instr_name_t.BEQ, riscv_instr_name_t.BNE,
riscv_instr_name_t.BLT, riscv_instr_name_t.BGE,
riscv_instr_name_t.BLTU, riscv_instr_name_t.BGEU]);
}
override void post_randomize() {
riscv_instr[] instr;
jump.randomize_with! q{
if (has_rd == true) {
rd == $0;
}
if (has_rs1 == true) {
rs1 == $1;
}
} (cfg.ra, gpr);
//DV_CHECK_RANDOMIZE_WITH_FATAL(addi, rs1 == gpr; rd == gpr;)
addi.randomize_with! q{ rs1 == $0; rd == $0; } (gpr);
//DV_CHECK_RANDOMIZE_FATAL(branch)
branch.randomize();
la.pseudo_instr_name = riscv_pseudo_instr_name_t.LA;
la.imm_str = target_program_label;
la.rd = gpr;
// Generate some random instructions to mix with jump instructions
reserved_rd = [gpr];
initialize_instr_list(mixed_instr_cnt);
gen_instr(true);
if (jump.instr_name.inside(riscv_instr_name_t.JALR, riscv_instr_name_t.C_JALR)) {
// JALR is expected to set lsb to 0
int offset = urandom!q{[]}(0, 1);
addi.imm_str = format("%0d", imm + offset);
}
else {
addi.imm_str = format("%0d", imm);
}
if (cfg.enable_misaligned_instr) {
// Jump to a misaligned address
jump.imm_str = format("%0d", -imm + 2);
}
else {
jump.imm_str = format("%0d", -imm);
}
// The branch instruction is always inserted right before the jump instruction to avoid
// skipping other required instructions like restore stack, load jump base etc.
// The purse of adding the branch instruction here is to cover branch -> jump scenario.
if (enable_branch) instr = [branch];
// Restore stack before unconditional jump
if ((jump.rd == riscv_reg_t.ZERO) || (jump.instr_name == riscv_instr_name_t.C_JR)) {
instr = stack_exit_instr ~ instr;
}
if (jump.instr_name == riscv_instr_name_t.JAL) {
jump.imm_str = target_program_label;
}
else {
instr = [la, addi] ~ instr;
}
mix_instr_stream(instr);
append_instr(jump);
foreach (linstr; instr_list) {
linstr.has_label = false;
linstr.atomic = true;
}
jump.has_label = true;
jump.label = format("%0s_j%0d", label, idx);
jump.comment = format("jump %0s -> %0s", label, target_program_label);
branch.imm_str = jump.label;
branch.comment = "branch to jump instr";
branch.branch_assigned = true;
}
}
// Stress back to back jump instruction
class riscv_jal_instr : riscv_rand_instr_stream
{
riscv_instr[] jump;
riscv_instr jump_start;
riscv_instr jump_end;
@rand uint num_of_jump_instr;
riscv_instr_name_t[] jal;
constraint! q{
num_of_jump_instr inside [10:30];
} instr_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
void post_randomize() {
int[] order;
order.length = num_of_jump_instr;
jump.length = num_of_jump_instr;
foreach (i, ref ord; order) {
ord = cast(int) i;
}
order.shuffle();
setup_allowed_instr(1, 1);
jal = [riscv_instr_name_t.JAL];
if (!cfg.disable_compressed_instr) {
jal ~= riscv_instr_name_t.C_J;
if (XLEN == 32) {
jal ~= riscv_instr_name_t.C_JAL;
}
}
// First instruction
jump_start = cfg.instr_registry.get_instr(riscv_instr_name_t.JAL);
//`DV_CHECK_RANDOMIZE_WITH_FATAL(jump_start, rd == cfg.ra;)
jump_start.randomize_with! q{rd == $0;} (cfg.ra);
jump_start.imm_str = format("%0df", order[0]);
jump_start.label = label;
// Last instruction
randomize_instr(jump_end);
jump_end.label = format("%0d", num_of_jump_instr);
foreach (i, ref jj ; jump) {
jj = cfg.instr_registry.get_rand_instr(jal);
//DV_CHECK_RANDOMIZE_WITH_FATAL(jump[i],
// Giving randomization error
jj.randomize_with! q{
if (has_rd == true ) {
rd dist [riscv_reg_t.RA := 5, riscv_reg_t.T1 := 2, riscv_reg_t.SP..riscv_reg_t.T0 :/ 1, riscv_reg_t.T2..riscv_reg_t.T6 :/ 2];
rd !inside [$0];
}
} (cfg.reserved_regs);
jj.label = format("%0d", i);
}
foreach (i, rr; order) {
if (i == num_of_jump_instr - 1) {
jump[rr].imm_str = format("%0df", num_of_jump_instr);
}
else {
if (order[i+1] > rr) {
jump[rr].imm_str = format("%0df", order[i+1]);
}
else {
jump[rr].imm_str = format("%0db", order[i+1]);
}
}
}
instr_list = jump_start ~ jump ~ jump_end;
foreach (instr; instr_list) {
instr.has_label = true;
instr.atomic = true;
}
}
}
// Push stack instruction stream
class riscv_push_stack_instr : riscv_rand_instr_stream
{
int stack_len;
int num_of_reg_to_save;
int num_of_redudant_instr;
riscv_instr[] push_stack_instr;
riscv_reg_t[] saved_regs;
riscv_instr branch_instr;
@rand bool enable_branch;
string push_start_label;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
void init() {
// Save RA, T0
reserved_rd = [cfg.ra];
saved_regs = [cfg.ra];
num_of_reg_to_save = cast(int) saved_regs.length;
if(num_of_reg_to_save * (XLEN/8) > stack_len) {
uvm_fatal(get_full_name(), format("stack len [%0d] is not enough to store %d regs",
stack_len, num_of_reg_to_save));
}
num_of_redudant_instr = urandom!q{[]}(3,10);
initialize_instr_list(num_of_redudant_instr);
}
void gen_push_stack_instr(int stack_len, bool allow_branch = true) {
this.stack_len = stack_len;
init();
gen_instr(true);
push_stack_instr.length = num_of_reg_to_save+1;
foreach( i, ref sinstr; push_stack_instr) {
sinstr = riscv_instr.type_id.create(format("push_stack_instr_%0d", i));
}
// addi sp,sp,-imm
push_stack_instr[0] = cfg.instr_registry.get_instr(riscv_instr_name_t.ADDI);
//DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[0],
push_stack_instr[0].randomize_with! q{ rd == $0; rs1 == $0;
imm == $1;} (cfg.sp, ~stack_len + 1);
push_stack_instr[0].imm_str = format("-%0d", stack_len);
foreach (i, sreg; saved_regs) {
if (XLEN == 32) {
push_stack_instr[i+1] = cfg.instr_registry.get_instr(riscv_instr_name_t.SW);
// `DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
push_stack_instr[i+1].randomize_with! q{
rs2 == $0 ; rs1 == $1 ; imm == 4 * ($2+1);
} (sreg, cfg.sp, i);
}
else {
push_stack_instr[i+1] = cfg.instr_registry.get_instr(riscv_instr_name_t.SD);
// `DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
push_stack_instr[i+1].randomize_with! q{
instr_name == riscv_instr_name_t.SD; rs2 == $0 ; rs1 == $1 ; imm == 8 * ($2+1);
} (sreg, cfg.sp, i);
}
push_stack_instr[i+1].process_load_store = false;
}
if (allow_branch) {
//DV_CHECK_STD_RANDOMIZE_FATAL(enable_branch)
enable_branch = urandom!bool();
}
else {
enable_branch = false;
}
if (enable_branch) {
branch_instr = cfg.instr_registry.get_rand_instr([riscv_instr_category_t.BRANCH]);
// `DV_CHECK_RANDOMIZE_FATAL(branch_instr)
branch_instr.randomize();
branch_instr.imm_str = push_start_label;
branch_instr.branch_assigned = true;
push_stack_instr[0].label = push_start_label;
push_stack_instr[0].has_label = true;
push_stack_instr = [branch_instr] ~ push_stack_instr;
}
mix_instr_stream(push_stack_instr);
foreach (i, ref instr; instr_list) {
instr.atomic = true;
if (instr.label == "")
instr.has_label =false;
}
}
}
// Pop stack instruction stream
class riscv_pop_stack_instr: riscv_rand_instr_stream
{
int stack_len;
int num_of_reg_to_save;
int num_of_redudant_instr;
riscv_instr[] pop_stack_instr;
riscv_reg_t[] saved_regs;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
//uvm_object_utils(riscv_pop_stack_instr)
void init() {
reserved_rd = [cfg.ra];
num_of_reg_to_save = cast(int) saved_regs.length;
if(num_of_reg_to_save * 4 > stack_len) {
uvm_fatal(get_full_name(), format("stack len [%0d] is not enough to store %d regs",
stack_len, num_of_reg_to_save));
}
num_of_redudant_instr = urandom!q{[]}(3,10);
initialize_instr_list(num_of_redudant_instr);
}
void gen_pop_stack_instr(int stack_len, riscv_reg_t[] saved_regs) {
this.stack_len = stack_len;
this.saved_regs = saved_regs;
init();
gen_instr(true);
pop_stack_instr.length = num_of_reg_to_save+1;
foreach (i, ref psinstr; pop_stack_instr) {
psinstr = riscv_instr.type_id.create(format("pop_stack_instr_%0d", i));
}
foreach (i, ref sreg; saved_regs) {
if (XLEN == 32) {
pop_stack_instr[i] = cfg.instr_registry.get_instr(riscv_instr_name_t.LW);
//DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
pop_stack_instr[i].randomize_with! q{
rd == $0; rs1 == $1; imm == 4 * ($2+1);
} (sreg, cfg.sp, i);
}
else {
pop_stack_instr[i] = cfg.instr_registry.get_instr(riscv_instr_name_t.LD);
//DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
pop_stack_instr[i].randomize_with! q{
rd == $0; rs1 == $1; imm == 8 * ($2+1);
} (sreg, cfg.sp, i);
}
pop_stack_instr[i].process_load_store = false;
}
// addi sp,sp,imm
pop_stack_instr[num_of_reg_to_save] = cfg.instr_registry.get_instr(riscv_instr_name_t.ADDI);
//DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[num_of_reg_to_save],
pop_stack_instr[num_of_reg_to_save].randomize_with! q{
rd == $0; rs1 == $0; imm == $1;
} ( cfg.sp, stack_len);
pop_stack_instr[num_of_reg_to_save].imm_str = format("%0d", stack_len);
mix_instr_stream(pop_stack_instr);
foreach (instr; instr_list) {
instr.atomic = true;
instr.has_label = false;
}
}
}
// Strees the numeric corner cases of integer arithmetic operations
class riscv_int_numeric_corner_stream: riscv_directed_instr_stream
{
enum int_numeric_e {
NormalValue,
Zero,
AllOne,
NegativeMax
}
uint num_of_avail_regs = 10;
@rand uint num_of_instr;
@rand ubvec!XLEN[] init_val; // becasue of compile error it has been commented.
@rand int_numeric_e[] init_val_type;
riscv_pseudo_instr[] init_instr;
constraint! q{
//solve init_val_type before init_val;
init_val_type.length == num_of_avail_regs;
init_val.length == num_of_avail_regs;
num_of_instr inside [15..31];
} init_val_c ;
constraint! q{
unique [avail_regs];
foreach (areg; avail_regs) {
areg !inside [cfg.reserved_regs];
areg != riscv_reg_t.ZERO;
}
} avail_regs_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
void pre_randomize() {
avail_regs.length = num_of_avail_regs;
// super.pre_randomize();
}
override void post_randomize() {
init_instr.length = num_of_avail_regs;
foreach (i, ref ivtype; init_val_type) {
if (ivtype == int_numeric_e.Zero) {
init_val[i] = toubvec!XLEN(0);
}
else if (ivtype == int_numeric_e.AllOne) {
init_val[i] = toubvec!XLEN(-1);
}
else if (ivtype == int_numeric_e.NegativeMax) {
init_val[i] = toubvec!XLEN(1UL << (XLEN-1));
}
init_instr[i] = new riscv_pseudo_instr;
init_instr[i].rd = avail_regs[i];
init_instr[i].pseudo_instr_name = riscv_pseudo_instr_name_t.LI;
init_instr[i].imm_str = format("0x%0x", init_val[i]);
append_instr(init_instr[i]);
}
for (int i = 0; i < num_of_instr; i++) {
riscv_instr instr =
cfg.instr_registry.get_rand_instr([riscv_instr_category_t.ARITHMETIC],
[riscv_instr_group_t.RV32C, riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV32F , riscv_instr_group_t.RV64F,
riscv_instr_group_t.RV32D, riscv_instr_group_t.RV64D]);
randomize_gpr(instr);
append_instr(instr);
}
super.post_randomize();
}
}

View file

@ -0,0 +1,488 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ---------------------------------------------------------------------------------------------
// This class is used to generate illegal or HINT instructions.
// The illegal instruction will be generated in binary format and mixed with other valid instr.
// The mixed instruction stream will be stored in data section and loaded to instruction pages
// at run time.
// ---------------------------------------------------------------------------------------------
module riscv.gen.riscv_illegal_instr;
import riscv.gen.riscv_instr_pkg: privileged_reg_t, riscv_instr_group_t;
import riscv.gen.target: supported_isa, XLEN, custom_csr;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import std.traits: EnumMembers;
import std.format: format;
import std.algorithm: canFind;
import esdl.data.bvec: ubvec, toubvec;
import esdl.rand: rand, constraint;
import uvm;
class riscv_illegal_instr: uvm_object
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
string comment;
enum illegal_instr_type_e: ubyte {
kIllegalOpcode,
kIllegalCompressedOpcode,
kIllegalFunc3,
kIllegalFunc7,
kReservedCompressedInstr,
kHintInstr,
kIllegalSystemInstr
}
enum reserved_c_instr_e: ubyte {
kIllegalCompressed,
kReservedAddispn,
kReservedAddiw,
kReservedAddi16sp,
kReservedLui,
kReservedLwsp,
kReservedLdsp,
kReservedLqsp,
kReservedJr,
kReservedC0,
kReservedC1,
kReservedC2
}
// Default legal opcode for RV32I instructions
ubvec!7[] legal_opcode = [0b0000011.toubvec!7,
0b0001111.toubvec!7,
0b0010011.toubvec!7,
0b0010111.toubvec!7,
0b0100011.toubvec!7,
0b0110111.toubvec!7,
0b1100011.toubvec!7,
0b0110011.toubvec!7,
0b1100111.toubvec!7,
0b1110011.toubvec!7,
0b1101111.toubvec!7];
// Default legal opcode for RV32C instructions
ubvec!3[] legal_c00_opcode = [0b000.toubvec!3,
0b010.toubvec!3,
0b110.toubvec!3];
ubvec!3[] legal_c10_opcode = [0b000.toubvec!3,
0b010.toubvec!3,
0b100.toubvec!3,
0b110.toubvec!3];
@rand illegal_instr_type_e exception;
@rand reserved_c_instr_e reserved_c;
@rand ubvec!32 instr_bin;
@rand ubvec!7 opcode;
@rand bool compressed;
@rand ubvec!3 func3;
@rand ubvec!7 func7;
@rand bool has_func3;
@rand bool has_func7;
@rand ubvec!2 c_op;
@rand ubvec!3 c_msb;
riscv_instr_gen_config cfg;
privileged_reg_t[] csrs;
constraint! q{
exception dist [
illegal_instr_type_e.kIllegalOpcode := 3,
illegal_instr_type_e.kIllegalCompressedOpcode := 1,
illegal_instr_type_e.kIllegalFunc3 := 1,
illegal_instr_type_e.kIllegalFunc7 := 1,
illegal_instr_type_e.kReservedCompressedInstr := 1,
illegal_instr_type_e.kHintInstr := 3,
illegal_instr_type_e.kIllegalSystemInstr := 3
];
if (riscv_instr_group_t.RV32C !inside [supported_isa]) {
exception != illegal_instr_type_e.kHintInstr;
compressed == false;
}
} exception_dist_c;
constraint! q{
solve opcode before instr_bin;
solve func3 before instr_bin;
solve func7 before instr_bin;
solve c_msb before instr_bin;
solve c_op before instr_bin;
if (compressed == true) {
instr_bin[0..2] == c_op;
instr_bin[13..16] == c_msb;
}
else {
instr_bin[0..7] == opcode;
if (has_func7 == true) {
instr_bin[25..32] == func7;
}
if (has_func3 == true) {
instr_bin[12..15] == func3;
}
}
} instr_bit_assignment_c;
// Invalid SYSTEM instructions
constraint! q{
if (exception == illegal_instr_type_e.kIllegalSystemInstr) {
opcode == 0b1110011;
// ECALL/EBREAK/xRET/WFI
if (func3 == 0b000) {
// Constrain RS1 and RD to be non-zero
instr_bin[15..20] != 0;
instr_bin[7..12] != 0;
// Valid SYSTEM instructions considered by this
// Constrain the upper 12 bits to be invalid
instr_bin[20..32] !inside [0x0, 0x1, 0x2, 0x102, 0x302, 0x7b2, 0x105];
}
else {
// Invalid CSR instructions
instr_bin[20..32] !inside [csrs];
instr_bin[20..32] !inside [custom_csr];
}
}
} system_instr_c;
constraint! q{
if ((c_msb == 0b000) && (c_op == 0b10) && (XLEN == 32)) {
if (exception == illegal_instr_type_e.kReservedCompressedInstr) {
instr_bin[12] == 1;
}
else {
instr_bin[12] == 0;
}
}
} legal_rv32_c_slli;
constraint! q{
if (compressed == true ) {
exception inside [illegal_instr_type_e.kReservedCompressedInstr,
illegal_instr_type_e.kIllegalCompressedOpcode,
illegal_instr_type_e.kHintInstr];
}
else {
exception inside [illegal_instr_type_e.kIllegalOpcode,
illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7,
illegal_instr_type_e.kIllegalSystemInstr];
}
if (!has_func7) {
exception != illegal_instr_type_e.kIllegalFunc7;
}
if (!has_func3) {
exception != illegal_instr_type_e.kIllegalFunc3;
}
} exception_type_c;
constraint! q{
c_op != 0b11;
} compressed_instr_op_c;
// Avoid generating illegal func3/func7 errors for opcode used by B-extension for now
//
// TODO(udi): add support for generating illegal B-extension instructions
constraint! q{
if (riscv_instr_group_t.RV32B inside [supported_isa]) {
if (exception inside [illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7]) {
opcode !inside [0b0110011, 0b0010011, 0b0111011];
}
}
} b_extension_c;
constraint! q{
if (riscv_instr_group_t.RV32ZBA inside [supported_isa]) {
if (exception inside [illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7]) {
opcode !inside [0b0110011, 0b0111011, 0b0011011];
}
}
} zba_extension_c;
constraint! q{
if (riscv_instr_group_t.RV32ZBB inside [supported_isa]) {
if (exception inside [illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7]) {
opcode !inside [0b0110011, 0b0010011, 0b0111011, 0b0011011];
}
}
} zbb_extension_c;
constraint! q{
if (riscv_instr_group_t.RV32ZBB inside [supported_isa]) {
if (exception inside [illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7]) {
opcode !inside [0b0110011];
}
}
} zbc_extension_c;
constraint! q{
if (riscv_instr_group_t.RV32ZBS inside [supported_isa]) {
if (exception inside [illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7]) {
opcode !inside [0b0110011, 0b0010011];
}
}
} zbs_extension_c;
constraint! q{
if (exception == illegal_instr_type_e.kIllegalCompressedOpcode) {
c_op != 0b01;
if (legal_c00_opcode.length == 8) {
c_op != 0b00;
}
else {
c_msb !inside [legal_c00_opcode];
}
if (legal_c10_opcode.length == 8) {
c_op != 0b10;
}
else {
c_msb !inside [legal_c10_opcode];
}
}
} illegal_compressed_op_c;
constraint! q{
solve exception before reserved_c;
solve exception before opcode;
solve reserved_c before instr_bin;
solve reserved_c before c_msb;
solve reserved_c before c_op;
if (XLEN == 32) {
//c.addiw is RV64/RV128 only instruction, the encoding is used for C.JAL for RV32C
reserved_c != reserved_c_instr_e.kReservedAddiw;
}
if (exception == illegal_instr_type_e.kReservedCompressedInstr) {
(reserved_c == reserved_c_instr_e.kIllegalCompressed) ->
(instr_bin[0..16] == 0);
(reserved_c == reserved_c_instr_e.kReservedAddispn) ->
((instr_bin[5..16] == 0) && (c_op == 0b00));
(reserved_c == reserved_c_instr_e.kReservedAddiw) ->
(c_msb == 0b001 && c_op == 0b01 && instr_bin[7..12] == 0b0);
(reserved_c == reserved_c_instr_e.kReservedC0) ->
(instr_bin[10..16] == 0b100111 && instr_bin[5..7] == 0b10 && c_op == 0b01);
(reserved_c == reserved_c_instr_e.kReservedC1) ->
(instr_bin[10..16] == 0b100111 && instr_bin[5..7] == 0b11 && c_op == 0b01);
(reserved_c == reserved_c_instr_e.kReservedC2) ->
(c_msb == 0b100 && c_op == 0b00);
(reserved_c == reserved_c_instr_e.kReservedAddi16sp) ->
(c_msb == 0b011 && c_op == 0b01 && instr_bin[7..12] == 2 &&
instr_bin[12] == 0 && instr_bin[2..7] == 0);
(reserved_c == reserved_c_instr_e.kReservedLui) ->
(c_msb == 0b011 && c_op == 0b01 && instr_bin[12] == 0 && instr_bin[2..7] ==0);
(reserved_c == reserved_c_instr_e.kReservedJr) ->
(instr_bin == 0b1000_0000_0000_0010);
(reserved_c == reserved_c_instr_e.kReservedLqsp) ->
(c_msb == 0b001 && c_op == 0b10 && instr_bin[7..12] == 0);
(reserved_c == reserved_c_instr_e.kReservedLwsp) ->
(c_msb == 0b010 && c_op == 0b10 && instr_bin[7..12] == 0);
(reserved_c == reserved_c_instr_e.kReservedLdsp) ->
(c_msb == 0b011 && c_op == 0b10 && instr_bin[7..12] == 0b0);
}
} reserved_compressed_instr_c;
constraint! q{
if (exception == illegal_instr_type_e.kHintInstr) {
// C.ADDI
(c_msb == 0b000 && c_op == 0b01 && instr_bin[12] == 0 && instr_bin[2..7] == 0b00000) ||
// C.LI
(c_msb == 0b010 && c_op == 0b01 && instr_bin[7..12] == 0b0) ||
// C.SRAI64, C.SRLI64
(c_msb == 0b100 && c_op == 0b01 && instr_bin[11..13] == 0b00 &&
instr_bin[2..7] == 0b00000) ||
// C.MV
(c_msb == 0b100 && c_op == 0b10 && instr_bin[7..12] == 0b00000 &&
instr_bin[2..7] != 0b00000) ||
// C.LUI
(c_msb == 0b011 && c_op == 0b01 && instr_bin[7..12] == 0b00000 &&
(instr_bin[12] != 0 || instr_bin[2..7] != 0b00000)) ||
// C.SLLI
(c_msb == 0b000 && c_op == 0b10 && instr_bin[7..12] == 0b00000) ||
// C.SLLI64
(c_msb == 0b000 && c_op == 0b10 && instr_bin[7..12] != 0b00000 && instr_bin[12] == 0b0 &&
instr_bin[2..7] == 0b00000) ||
// C.ADD
(c_msb == 0b100 && c_op == 0b10 && instr_bin[7..12] == 0b00000 && instr_bin[12] == 0b1 &&
instr_bin[2..7] != 0b00000);
}
} hint_instr_c;
constraint! q{
solve opcode before instr_bin;
if (exception == illegal_instr_type_e.kIllegalOpcode) {
!(opcode inside [legal_opcode]);
opcode[0..2] == 0b11;
}
else {
opcode inside [legal_opcode];
}
} illegal_opcode_c;
// TODO: Enable atomic instruction
constraint! q{
if (exception != illegal_instr_type_e.kIllegalOpcode) {
opcode != 0b0101111;
}
} no_atomic_c;
constraint! q{
solve opcode before func3;
if (compressed == false) {
if (exception == illegal_instr_type_e.kIllegalFunc3) {
(opcode == 0b1100111) -> (func3 != 0b000);
(opcode == 0b1100011) -> (func3 inside [0b010, 0b011]);
if (XLEN == 32) {
(opcode == 0b0100011) -> (func3 >= 0b011);
(opcode == 0b0000011) -> (func3 inside [0b011, 0b111]);
} else {
(opcode == 0b0100011) -> (func3 > 0b011);
(opcode == 0b0000011) -> (func3 == 0b111);
}
(opcode == 0b0001111) -> (func3 !inside [0b000, 0b001]);
(opcode == 0b1110011) -> (func3 == 0b100);
(opcode == 0b0011011) -> (func3 !inside [0b000, 0b001, 0b101]);
(opcode == 0b0111011) -> (func3 inside [0b010, 0b011]);
opcode inside [0b1100111, 0b1100011, 0b0000011, 0b0100011,
0b0001111, 0b1110011, 0b0011011, 0b0111011];
}
else {
(opcode == 0b1100111) -> (func3 == 0b000);
(opcode == 0b1100011) -> (func3 !inside [0b010, 0b011]);
if (XLEN == 32) {
(opcode == 0b0100011) -> (func3 < 0b011);
(opcode == 0b0000011) -> (func3 !inside [0b011, 0b111]);
}
else {
(opcode == 0b0100011) -> (func3 <= 0b011);
(opcode == 0b0000011) -> (func3 != 0b111);
}
(opcode == 0b0001111) -> (func3 inside [0b000, 0b001]);
(opcode == 0b1110011) -> (func3 != 0b100);
(opcode == 0b0011011) -> (func3 inside [0b000, 0b001, 0b101]);
(opcode == 0b0111011) -> (func3 !inside [0b010, 0b011]);
}
}
} illegal_func3_c;
constraint! q{
solve opcode before func7;
if ((opcode == 0b0010011) && (func3 == 0b001) || (func3 == 0b101) ||
(opcode == 0b0110011) || (opcode == 0b0111011)) {
has_func7 == true;
}
else {
has_func7 == false;
}
} has_func7_c;
constraint! q{
solve opcode before func7;
if (opcode inside [0b0110111, 0b1101111, 0b0010111]) {
has_func3 == false;
}
else {
has_func3 == true;
}
} has_func3_c;
constraint! q{
if (compressed == false) {
if (exception == illegal_instr_type_e.kIllegalFunc7) {
!(func7 inside [0, 0b0100000, 1]);
if (opcode == 0b0001001) { // SLLI, SRLI, SRAI
!(func7[6:1] inside [0, 0b010000]);
}
} else {
func7 inside [0, 0b0100000, 1];
}
}
} illegal_func7_c;
// `uvm_object_utils(riscv_illegal_instr)
// `uvm_object_new
void init(riscv_instr_gen_config cfg) {
privileged_reg_t csr;
this.cfg = cfg;
if ((canFind(supported_isa, riscv_instr_group_t.RV32F) ||
canFind(supported_isa, riscv_instr_group_t.RV32D))) {
legal_opcode ~= [0b0000111.toubvec!7, 0b0100111.toubvec!7, 0b1000011.toubvec!7,
0b1000111.toubvec!7, 0b1001011.toubvec!7, 0b1001111.toubvec!7,
0b1010011.toubvec!7] ;
}
if (canFind(supported_isa, riscv_instr_group_t.RV64I)) {
legal_opcode ~= [0b0011011.toubvec!7];
}
if (canFind(supported_isa, riscv_instr_group_t.RV32A)) {
legal_opcode ~= [0b0101111.toubvec!7];
}
if (canFind(supported_isa, riscv_instr_group_t.RV64I) ||
canFind(supported_isa, riscv_instr_group_t.RV64M )) {
legal_opcode ~= [0b0111011.toubvec!7];
}
if (canFind(supported_isa, riscv_instr_group_t.RV64I)) {
legal_c00_opcode ~= [0b011.toubvec!3, 0b111.toubvec!3];
legal_c10_opcode ~= [0b011.toubvec!3, 0b111.toubvec!3];
}
// csr = csr.first();
// for (int i = 0; i < csr.num(); i = i + 1) begin
// csrs.push_back(csr);
// csr = csr.next();
// end
csrs = [EnumMembers!privileged_reg_t];
}
string get_bin_str() {
import std.conv: to;
string str;
if (compressed) {
str = format("%4h", (cast(ubvec!16) instr_bin[0..16]));
}
else {
str = format("%8h", (cast(ubvec!32) instr_bin[0..31]));
}
uvm_info(get_full_name(), format("Illegal instruction type: %0s, illegal instruction: 0x%0x",
exception, instr_bin), UVM_HIGH);
return str;
}
void post_randomize() {
import std.conv: to;
comment = to!string(exception);
if (exception == illegal_instr_type_e.kReservedCompressedInstr) {
comment ~= " " ~ to!string(reserved_c);
}
else if (exception == illegal_instr_type_e.kIllegalOpcode) {
comment ~= " " ~ format("%7b", opcode);
}
}
}

View file

@ -0,0 +1,821 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// RISC-V assembly program generator configuration class
//-----------------------------------------------------------------------------
module riscv.gen.riscv_instr_gen_config;
import riscv.gen.riscv_instr_pkg: data_pattern_t, vreg_init_method_t, exception_cause_t,
interrupt_cause_t, privileged_mode_t, mtvec_mode_t, f_rounding_mode_t, riscv_reg_t,
mem_region_t, privileged_reg_t, riscv_instr_category_t, b_ext_group_t,
riscv_instr_group_t, get_int_arg_value, get_bool_arg_value, get_hex_arg_value,
cmdline_enum_processor, satp_mode_t;
import riscv.gen.riscv_instr_registry: riscv_instr_registry;
import riscv.gen.isa.riscv_instr_register: register_isa;
import riscv.gen.target: NUM_HARTS, XLEN, supported_privileged_mode, supported_isa,
SATP_MODE, implemented_csr, support_sfence, support_debug_mode, supported_interrupt_mode;
import riscv.gen.riscv_pmp_cfg: riscv_pmp_cfg;
import riscv.gen.riscv_vector_cfg: riscv_vector_cfg;
import std.traits: EnumMembers;
import std.algorithm: canFind;
import std.string: format, toUpper, toLower, strip;
import std.conv: to;
import esdl.base.cmdl: CommandLine;
import esdl.data.bvec: ubvec, toBit, toubvec, clog2;
import esdl.rand: constraint, rand;
import uvm;
class riscv_instr_gen_config: uvm_object
{
mixin uvm_object_utils;
//-----------------------------------------------------------------------------
// Random instruction generation settings
//-----------------------------------------------------------------------------
// Instruction count of the main program
@rand @UVM_DEFAULT int main_program_instr_cnt;
// Instruction count of each sub-program
@rand @UVM_DEFAULT int[] sub_program_instr_cnt;
// Instruction count of the debug rom
@rand @UVM_DEFAULT int debug_program_instr_cnt;
// Instruction count of debug sub-programs
@rand int[] debug_sub_program_instr_cnt;
// Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
@rand @UVM_DEFAULT data_pattern_t data_page_pattern;
// Initialization of the vregs
// SAME_VALUES_ALL_ELEMS - Using vmv.v.x to fill all the elements of the vreg with the same value as the one in the GPR selected
// RANDOM_VALUES_VMV - Using vmv.v.x + vslide1up.vx to randomize the contents of each vector element
// RANDOM_VALUES_LOAD - Using vle.v, same approach as RANDOM_VALUES_VMV but more efficient for big VLEN
vreg_init_method_t vreg_init_method = vreg_init_method_t.RANDOM_VALUES_VMV;
// Associate array for delegation configuration for each exception and interrupt
// When the bit is 1, the corresponding delegation is enabled.
@rand bool[exception_cause_t] m_mode_exception_delegation;
@rand bool[exception_cause_t] s_mode_exception_delegation;
@rand bool[interrupt_cause_t] m_mode_interrupt_delegation;
@rand bool[interrupt_cause_t] s_mode_interrupt_delegation;
// Priviledged mode after boot
@rand @UVM_DEFAULT privileged_mode_t init_privileged_mode;
@rand ubvec!(XLEN) mstatus;
@rand ubvec!(XLEN) mie;
@rand ubvec!(XLEN) sstatus;
@rand ubvec!(XLEN) sie;
@rand ubvec!(XLEN) ustatus;
@rand ubvec!(XLEN) uie;
// Key fields in xSTATUS
// Memory protection bits
@rand bool mstatus_mprv;
@rand bool mstatus_mxr;
@rand bool mstatus_sum;
@rand bool mstatus_tvm;
@rand ubvec!2 mstatus_fs;
@rand ubvec!2 mstatus_vs;
@rand mtvec_mode_t mtvec_mode;
// TVEC alignment
// This value is the log_2 of the byte-alignment of TVEC.BASE field
// As per RISC-V privileged spec, default will be set to 2 (4-byte aligned)
@rand @UVM_DEFAULT int tvec_alignment = 2;
// Floating point rounding mode
@rand f_rounding_mode_t fcsr_rm;
// Enable sfence.vma instruction
@rand bool enable_sfence;
// Reserved register
// Reserved for various hardcoded routines
@rand riscv_reg_t[4] gpr;
// Used by any DCSR operations inside of the debug rom
// Also used by the PMP generation.
@rand riscv_reg_t scratch_reg;
// Reg used exclusively by the PMP exception handling routine.
// Can overlap with the other GPRs used in the random generation,
// as PMP exception handler is hardcoded and does not include any
// random instructions.
@rand riscv_reg_t pmp_reg;
// Use a random register for stack pointer/thread pointer
@rand @UVM_DEFAULT riscv_reg_t sp;
@rand @UVM_DEFAULT riscv_reg_t tp;
@rand @UVM_DEFAULT riscv_reg_t ra;
// Options for privileged mode CSR checking
// Below checking can be made optional as the ISS implementation could be different with the
// processor.
bool check_misa_init_val = false;
bool check_xstatus = true;
// Virtual address translation is on for this test
@rand bool virtual_addr_translation_on;
// Vector extension setting
@rand riscv_vector_cfg vector_cfg;
// PMP configuration settings
@rand riscv_pmp_cfg pmp_cfg;
//-----------------------------------------------------------------------------
// User space memory region and stack setting
//-----------------------------------------------------------------------------
mem_region_t[] mem_region = [{"region_0", 4096, toBit!0b111},
{"region_1", 4096*16, toBit!0b111}];
// Dedicated shared memory region for multi-harts atomic operations
mem_region_t[] amo_region = [{"amo_0", 64, toBit!0b111}];
// Stack section word length
int stack_len = 5000;
//-----------------------------------------------------------------------------
// Kernel section setting, used by supervisor mode programs
//-----------------------------------------------------------------------------
mem_region_t[] s_mem_region =[{"s_region_0", 4096, toBit!0b111},
{"s_region_1", 4096, toBit!0b111}];
// Kernel Stack section word length
int kernel_stack_len = 4000;
// Number of instructions for each kernel program
int kernel_program_instr_cnt = 400;
// Queue of all the main implemented CSRs that the boot privilege mode cannot access
// e.g. these CSRs are in higher privilege modes - access should raise an exception
privileged_reg_t[] invalid_priv_mode_csrs;
//-----------------------------------------------------------------------------
// Command line options or control knobs
//-----------------------------------------------------------------------------
// Main options for RISC-V assembly program generation
// Number of sub-programs per test
int num_of_sub_program = 5;
int instr_cnt = 200;
int num_of_tests = 1;
// For tests doesn't involve load/store, the data section generation could be skipped
@UVM_DEFAULT bool no_data_page;
// Options to turn off some specific types of instructions
@UVM_DEFAULT bool no_branch_jump; // No branch/jump instruction
@UVM_DEFAULT bool no_load_store; // No load/store instruction
@UVM_DEFAULT bool no_csr_instr; // No csr instruction
@UVM_DEFAULT bool no_ebreak = true; // No ebreak instruction
@UVM_DEFAULT bool no_dret = true; // No dret instruction
@UVM_DEFAULT bool no_fence; // No fence instruction
@UVM_DEFAULT bool no_wfi = true; // No WFI instruction
@UVM_DEFAULT bool enable_unaligned_load_store;
@UVM_DEFAULT int illegal_instr_ratio;
@UVM_DEFAULT int hint_instr_ratio;
// Number of harts to be simulated, must be <= NUM_HARTS
@UVM_DEFAULT int num_of_harts = NUM_HARTS;
// Use SP as stack pointer
@UVM_DEFAULT bool fix_sp;
// Use push/pop section for data pages
@UVM_DEFAULT bool use_push_data_section = false;
// Directed boot privileged mode, u, m, s
@UVM_DEFAULT string boot_mode_opts;
@UVM_DEFAULT bool enable_page_table_exception; // int in SV version
@UVM_DEFAULT bool no_directed_instr;
// A name suffix for the generated assembly program
string asm_test_suffix;
// Enable interrupt bit in MSTATUS (MIE, SIE, UIE)
@UVM_DEFAULT bool enable_interrupt;
bool enable_nested_interrupt;
// We need a separate control knob for enabling timer interrupts, as Spike
// throws an exception if xIE.xTIE is enabled
@UVM_DEFAULT bool enable_timer_irq;
// Generate a bare program without any init/exit/error handling/page table routines
// The generated program can be integrated with a larger program.
// Note that the bare mode program is not expected to run in standalone mode
@UVM_DEFAULT bool bare_program_mode;
// Enable accessing illegal CSR instruction
// - Accessing non-existence CSR
// - Accessing CSR with wrong privileged mode
@UVM_DEFAULT bool enable_illegal_csr_instruction;
// Enable accessing CSRs at an invalid privilege level
@UVM_DEFAULT bool enable_access_invalid_csr_level;
// Enable misaligned instruction (caused by JALR instruction)
@UVM_DEFAULT bool enable_misaligned_instr;
// Enable some dummy writes to main system CSRs (xSTATUS/xIE) at beginning of test
// to check repeated writes
@UVM_DEFAULT bool enable_dummy_csr_write;
@UVM_DEFAULT bool randomize_csr = false;
// sfence support
@UVM_DEFAULT bool allow_sfence_exception = false;
// Interrupt/Exception Delegation
@UVM_DEFAULT bool no_delegation = true;
@UVM_DEFAULT bool force_m_delegation = false;
@UVM_DEFAULT bool force_s_delegation = false;
@UVM_DEFAULT bool support_supervisor_mode;
@UVM_DEFAULT bool disable_compressed_instr;
// "Memory mapped" address that when written to will indicate some event to
// the testbench - testbench will take action based on the value written
@UVM_DEFAULT ubvec!XLEN signature_addr = 0xdead_beef;
@UVM_DEFAULT bool require_signature_addr = false;
// Enable a full or empty debug_rom section.
// Full debug_rom will contain random instruction streams.
// Empty debug_rom will contain just dret instruction and will return immediately.
// Will be empty by default.
@UVM_DEFAULT bool gen_debug_section = false;
// Enable generation of a directed sequence of instructions containing
// ebreak inside the debug_rom.
// Disabled by default.
@UVM_DEFAULT bool enable_ebreak_in_debug_rom = false;
// Enable setting dcsr.ebreak(m/s/u)
@UVM_DEFAULT bool set_dcsr_ebreak = false;
// Number of sub programs in the debug rom
@UVM_DEFAULT int num_debug_sub_program = 0;
// Enable debug single stepping
@UVM_DEFAULT bool enable_debug_single_step = false;
// Number of single stepping iterations
@UVM_DEFAULT @rand int single_step_iterations;
// Enable mstatus.tw bit - causes u-mode WFI to raise illegal instruction exceptions
@UVM_DEFAULT bool set_mstatus_tw;
// Enable users to set mstatus.mprv to enable privilege checks on memory accesses.
@UVM_DEFAULT bool set_mstatus_mprv;
// Stack space allocated to each program, need to be enough to store necessary context
// Example: RA, SP, T0
uint min_stack_len_per_program = 10 * (XLEN/8);
uint max_stack_len_per_program = 16 * (XLEN/8);
// Maximum branch distance, avoid skipping large portion of the code
@UVM_DEFAULT uint max_branch_step = 20;
// Maximum directed instruction stream sequence count
@UVM_DEFAULT uint max_directed_instr_stream_seq = 20;
// Reserved registers
@UVM_DEFAULT riscv_reg_t[] reserved_regs;
// Floating point support
@UVM_DEFAULT bool enable_floating_point;
// Vector extension support
@UVM_DEFAULT bool enable_vector_extension;
// Only generate vector instructions
@UVM_DEFAULT bool vector_instr_only;
// Bit manipulation extension support
@UVM_DEFAULT bool enable_b_extension;
@UVM_DEFAULT bool enable_zba_extension;
@UVM_DEFAULT bool enable_zbb_extension;
@UVM_DEFAULT bool enable_zbc_extension;
@UVM_DEFAULT bool enable_zbs_extension;
@UVM_DEFAULT b_ext_group_t[] enable_bitmanip_groups =
[b_ext_group_t.ZBB, b_ext_group_t.ZBS, b_ext_group_t.ZBP, b_ext_group_t.ZBE,
b_ext_group_t.ZBF, b_ext_group_t.ZBC, b_ext_group_t.ZBR, b_ext_group_t.ZBM,
b_ext_group_t.ZBT, b_ext_group_t.ZB_TMP];
//-----------------------------------------------------------------------------
// Command line options for instruction distribution control
//-----------------------------------------------------------------------------
int dist_control_mode;
uint[riscv_instr_category_t] category_dist;
riscv_instr_registry instr_registry;
CommandLine cmdl;
constraint! q{
sub_program_instr_cnt.length == num_of_sub_program;
debug_sub_program_instr_cnt.length == num_debug_sub_program;
main_program_instr_cnt inside [10:instr_cnt];
foreach (cnt; sub_program_instr_cnt) {
cnt inside [10:instr_cnt];
}
// Disable sfence if the program is not boot to supervisor mode
// If sfence exception is allowed, we can enable sfence instruction in any priviledged mode.
// When MSTATUS.TVM is set, executing sfence.vma will be treate as illegal instruction
if (allow_sfence_exception) {
enable_sfence == true;
(init_privileged_mode != privileged_mode_t.SUPERVISOR_MODE) || mstatus_tvm == true;
}
else {
(init_privileged_mode != privileged_mode_t.SUPERVISOR_MODE || !support_sfence || mstatus_tvm
|| no_fence) -> (enable_sfence == false);
}
} default_c;
constraint! q{
if (support_debug_mode) {
debug_program_instr_cnt inside [100:300];
foreach (cnt; debug_sub_program_instr_cnt) {
cnt inside [100:300];
}
}
main_program_instr_cnt + sub_program_instr_cnt.sum == instr_cnt;
} debug_mode_c;
// Keep the number of single step iterations relatively small
constraint! q{
if (enable_debug_single_step) {
single_step_iterations inside [10 : 50];
}
} debug_single_step_c;
// Boot privileged mode distribution
constraint! q{
// Boot to higher privileged mode more often
if (supported_privileged_mode.length == 2) {
init_privileged_mode dist [supported_privileged_mode[0] := 6,
supported_privileged_mode[1] := 4];
}
else if (supported_privileged_mode.length == 3) {
init_privileged_mode dist [supported_privileged_mode[0] := 4,
supported_privileged_mode[1] := 3,
supported_privileged_mode[2] := 3];
}
else {
init_privileged_mode == supported_privileged_mode[0];
}
} boot_privileged_mode_dist_c;
immutable int tvec_align = clog2((XLEN*4)/8);
constraint! q{
mtvec_mode inside [supported_interrupt_mode];
if (mtvec_mode == mtvec_mode_t.DIRECT) {
@soft tvec_alignment == 2;
} else {
// Setting MODE = Vectored may impose an additional alignmentconstraint on BASE,
// requiring up to 4×XLEN-byte alignment
@soft tvec_alignment == tvec_align;
}
} mtvec_c;
constraint! q{
// This is default disabled at setup phase. It can be enabled in the exception and interrupt
// handling routine
if (set_mstatus_mprv == true) {
mstatus_mprv == true;
} else {
mstatus_mprv == false;
}
if (SATP_MODE == satp_mode_t.BARE) {
mstatus_mxr == false;
mstatus_sum == false;
mstatus_tvm == false;
}
} mstatus_c;
// Exception delegation setting
constraint! q{
// Do not delegate instructino page fault to supervisor/user mode because this may introduce
// dead loop. All the subsequent instruction fetches may fail and program cannot recover.
m_mode_exception_delegation[exception_cause_t.INSTRUCTION_PAGE_FAULT] == false;
if (force_m_delegation) {
foreach (del, enbl; m_mode_exception_delegation) {
@soft enbl == true;
}
foreach (del, enbl; m_mode_interrupt_delegation) {
@soft enbl == true;
}
}
if (force_s_delegation) {
foreach (del, enbl; s_mode_exception_delegation) {
@soft enbl == true;
}
foreach (del, enbl; s_mode_interrupt_delegation) {
@soft enbl == true;
}
}
} exception_delegation_c;
// Spike only supports a subset of exception and interrupt delegation
// You can modify this constraint if your ISS support different set of delegations
constraint! q{
foreach (del, enbl; m_mode_exception_delegation) {
if (!support_supervisor_mode || no_delegation) {
enbl == false;
}
if (del !inside [exception_cause_t.INSTRUCTION_ADDRESS_MISALIGNED,
exception_cause_t.BREAKPOINT,
exception_cause_t.ECALL_UMODE,
exception_cause_t.INSTRUCTION_PAGE_FAULT,
exception_cause_t.LOAD_PAGE_FAULT,
exception_cause_t.STORE_AMO_PAGE_FAULT]) {
enbl == false;
}
}
foreach (del, enbl; m_mode_interrupt_delegation) {
if (!support_supervisor_mode || no_delegation) {
enbl == false;
}
if (del !inside [interrupt_cause_t.S_SOFTWARE_INTR,
interrupt_cause_t.S_TIMER_INTR,
interrupt_cause_t.S_EXTERNAL_INTR]) {
enbl == false;
}
}
} delegation_c;
constraint! q{
ra dist [riscv_reg_t.RA := 3, riscv_reg_t.T1 := 2,
riscv_reg_t.SP:riscv_reg_t.T0 :/ 1,
riscv_reg_t.T2:riscv_reg_t.T6 :/ 4];
ra != sp;
ra != tp;
ra != riscv_reg_t.ZERO;
} ra_c;
constraint! q{
if (fix_sp) {
sp == riscv_reg_t.SP;
}
sp != tp;
sp !inside [riscv_reg_t.GP, riscv_reg_t.RA, riscv_reg_t.ZERO];
tp !inside [riscv_reg_t.GP, riscv_reg_t.RA, riscv_reg_t.ZERO];
} sp_tp_c;
constraint! q{
scratch_reg !inside [riscv_reg_t.ZERO, sp, tp, ra, riscv_reg_t.GP];
} reserve_scratch_reg_c;
// This reg is only used inside PMP exception routine,
// so we can be a bit looser with constraints.
constraint! q{
pmp_reg !inside [riscv_reg_t.ZERO, sp, tp];
} reserve_pmp_reg_c;
constraint! q{
foreach (r; gpr) {
r !inside [sp, tp, scratch_reg, pmp_reg, riscv_reg_t.ZERO,
riscv_reg_t.RA, riscv_reg_t.GP];
}
unique [gpr];
} gpr_c;
constraint! q{
solve init_privileged_mode before virtual_addr_translation_on;
} addr_translation_rnd_order_c;
constraint! q{
if ((init_privileged_mode != privileged_mode_t.MACHINE_MODE) &&
(SATP_MODE != satp_mode_t.BARE)) {
virtual_addr_translation_on == true;
}
else {
virtual_addr_translation_on == false;
}
} addr_translation_c;
constraint! q{
if (enable_floating_point) {
mstatus_fs == 1;
}
else {
mstatus_fs == 0;
}
} floating_point_c;
constraint! q{
if (enable_vector_extension) {
mstatus_vs == 1;
}
else {
mstatus_vs == 0;
}
} mstatus_vs_c;
// `uvm_object_utils_begin(riscv_instr_gen_config)
// `uvm_field_int(main_program_instr_cnt, UVM_DEFAULT)
// `uvm_field_sarray_int(sub_program_instr_cnt, UVM_DEFAULT)
// `uvm_field_int(debug_program_instr_cnt, UVM_DEFAULT)
// `uvm_field_enum(data_pattern_t, data_page_pattern, UVM_DEFAULT)
// `uvm_field_enum(privileged_mode_t, init_privileged_mode, UVM_DEFAULT)
// `uvm_field_array_enum(riscv_reg_t, reserved_regs, UVM_DEFAULT)
// `uvm_field_enum(riscv_reg_t, ra, UVM_DEFAULT)
// `uvm_field_enum(riscv_reg_t, sp, UVM_DEFAULT)
// `uvm_field_enum(riscv_reg_t, tp, UVM_DEFAULT)
// `uvm_field_int(tvec_alignment, UVM_DEFAULT)
// `uvm_field_int(no_data_page, UVM_DEFAULT)
// `uvm_field_int(no_branch_jump, UVM_DEFAULT)
// `uvm_field_int(no_load_store, UVM_DEFAULT)
// `uvm_field_int(no_csr_instr, UVM_DEFAULT)
// `uvm_field_int(no_ebreak, UVM_DEFAULT)
// `uvm_field_int(no_dret, UVM_DEFAULT)
// `uvm_field_int(no_fence, UVM_DEFAULT)
// `uvm_field_int(no_wfi, UVM_DEFAULT)
// `uvm_field_int(fix_sp, UVM_DEFAULT)
// `uvm_field_int(enable_unaligned_load_store, UVM_DEFAULT)
// `uvm_field_int(illegal_instr_ratio, UVM_DEFAULT)
// `uvm_field_int(hint_instr_ratio, UVM_DEFAULT)
// `uvm_field_string(boot_mode_opts, UVM_DEFAULT)
// `uvm_field_int(enable_page_table_exception, UVM_DEFAULT)
// `uvm_field_int(no_directed_instr, UVM_DEFAULT)
// `uvm_field_int(enable_interrupt, UVM_DEFAULT)
// `uvm_field_int(enable_timer_irq, UVM_DEFAULT)
// `uvm_field_int(bare_program_mode, UVM_DEFAULT)
// `uvm_field_int(enable_illegal_csr_instruction, UVM_DEFAULT)
// `uvm_field_int(enable_access_invalid_csr_level, UVM_DEFAULT)
// `uvm_field_int(enable_misaligned_instr, UVM_DEFAULT)
// `uvm_field_int(enable_dummy_csr_write, UVM_DEFAULT)
// `uvm_field_int(randomize_csr, UVM_DEFAULT)
// `uvm_field_int(allow_sfence_exception, UVM_DEFAULT)
// `uvm_field_int(no_delegation, UVM_DEFAULT)
// `uvm_field_int(force_m_delegation, UVM_DEFAULT)
// `uvm_field_int(force_s_delegation, UVM_DEFAULT)
// `uvm_field_int(support_supervisor_mode, UVM_DEFAULT)
// `uvm_field_int(disable_compressed_instr, UVM_DEFAULT)
// `uvm_field_int(signature_addr, UVM_DEFAULT)
// `uvm_field_int(num_of_harts, UVM_DEFAULT)
// `uvm_field_int(require_signature_addr, UVM_DEFAULT)
// `uvm_field_int(gen_debug_section, UVM_DEFAULT)
// `uvm_field_int(enable_ebreak_in_debug_rom, UVM_DEFAULT)
// `uvm_field_int(set_dcsr_ebreak, UVM_DEFAULT)
// `uvm_field_int(num_debug_sub_program, UVM_DEFAULT)
// `uvm_field_int(enable_debug_single_step, UVM_DEFAULT)
// `uvm_field_int(single_step_iterations, UVM_DEFAULT)
// `uvm_field_int(set_mstatus_tw, UVM_DEFAULT)
// `uvm_field_int(set_mstatus_mprv, UVM_DEFAULT)
// `uvm_field_int(max_branch_step, UVM_DEFAULT)
// `uvm_field_int(max_directed_instr_stream_seq, UVM_DEFAULT)
// `uvm_field_int(enable_floating_point, UVM_DEFAULT)
// `uvm_field_int(enable_vector_extension, UVM_DEFAULT)
// `uvm_field_int(vector_instr_only, UVM_DEFAULT)
// `uvm_field_int(enable_b_extension, UVM_DEFAULT)
// `uvm_field_array_enum(b_ext_group_t, enable_bitmanip_groups, UVM_DEFAULT)
// `uvm_field_int(use_push_data_section, UVM_DEFAULT)
// `uvm_object_utils_end
this(string name = "") {
// string s;
instr_registry = riscv_instr_registry.type_id.create("registry");
register_isa(instr_registry);
instr_registry.set_cfg(this);
riscv_instr_group_t[] march_isa;
super(name);
init_delegation();
// inst = uvm_cmdline_processor::get_inst(); // call uvm_cmdline_proc() directly instead
cmdl = new CommandLine();
get_int_arg_value("+num_of_tests=", num_of_tests);
get_bool_arg_value("+enable_page_table_exception=", enable_page_table_exception);
get_bool_arg_value("+enable_interrupt=", enable_interrupt);
get_bool_arg_value("+enable_nested_interrupt=", enable_nested_interrupt);
get_bool_arg_value("+enable_timer_irq=", enable_timer_irq);
get_int_arg_value("+num_of_sub_program=", num_of_sub_program);
get_int_arg_value("+instr_cnt=", instr_cnt);
get_bool_arg_value("+no_ebreak=", no_ebreak);
get_bool_arg_value("+no_dret=", no_dret);
get_bool_arg_value("+no_wfi=", no_wfi);
get_bool_arg_value("+no_branch_jump=", no_branch_jump);
get_bool_arg_value("+no_load_store=", no_load_store);
get_bool_arg_value("+no_csr_instr=", no_csr_instr);
get_bool_arg_value("+fix_sp=", fix_sp);
get_bool_arg_value("+use_push_data_section=", use_push_data_section);
get_bool_arg_value("+enable_illegal_csr_instruction=", enable_illegal_csr_instruction);
get_bool_arg_value("+enable_access_invalid_csr_level=", enable_access_invalid_csr_level);
get_bool_arg_value("+enable_misaligned_instr=", enable_misaligned_instr);
get_bool_arg_value("+enable_dummy_csr_write=", enable_dummy_csr_write);
get_bool_arg_value("+allow_sfence_exception=", allow_sfence_exception);
get_bool_arg_value("+no_data_page=", no_data_page);
get_bool_arg_value("+no_directed_instr=", no_directed_instr);
get_bool_arg_value("+no_fence=", no_fence);
get_bool_arg_value("+no_delegation=", no_delegation);
get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio);
get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio);
get_int_arg_value("+num_of_harts=", num_of_harts);
get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
get_bool_arg_value("+force_s_delegation=", force_s_delegation);
get_bool_arg_value("+require_signature_addr=", require_signature_addr);
get_bool_arg_value("+disable_compressed_instr=", disable_compressed_instr);
get_bool_arg_value("+randomize_csr=", randomize_csr);
if (require_signature_addr) {
int signature_addr_int;
get_hex_arg_value("+signature_addr=", signature_addr_int);
signature_addr = toubvec!XLEN(signature_addr_int);
}
if (cmdl.plusArgs("tvec_alignment=%d", tvec_alignment)) {
rand_mode!q{tvec_alignment}(false);
}
get_bool_arg_value("+gen_debug_section=", gen_debug_section);
get_bool_arg_value("+bare_program_mode=", bare_program_mode);
get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program);
get_bool_arg_value("+enable_ebreak_in_debug_rom=", enable_ebreak_in_debug_rom);
get_bool_arg_value("+set_dcsr_ebreak=", set_dcsr_ebreak);
get_bool_arg_value("+enable_debug_single_step=", enable_debug_single_step);
get_bool_arg_value("+set_mstatus_tw=", set_mstatus_tw);
get_bool_arg_value("+set_mstatus_mprv=", set_mstatus_mprv);
get_bool_arg_value("+enable_floating_point=", enable_floating_point);
get_bool_arg_value("+enable_vector_extension=", enable_vector_extension);
get_bool_arg_value("+enable_b_extension=", enable_b_extension);
get_bool_arg_value("+enable_zba_extension=", enable_zba_extension);
get_bool_arg_value("+enable_zbb_extension=", enable_zbb_extension);
get_bool_arg_value("+enable_zbc_extension=", enable_zbc_extension);
get_bool_arg_value("+enable_zbs_extension=", enable_zbs_extension);
cmdline_enum_processor!(b_ext_group_t).get_array_values("+enable_bitmanip_groups=",
enable_bitmanip_groups);
if (uvm_cmdline_processor.get_inst().get_arg_value("+boot_mode=", boot_mode_opts)) {
uvm_info(get_full_name(), format("Got boot mode option - %0s", boot_mode_opts), UVM_LOW);
switch(boot_mode_opts) {
case "m": init_privileged_mode = privileged_mode_t.MACHINE_MODE;
break;
case "s": init_privileged_mode = privileged_mode_t.SUPERVISOR_MODE;
break;
case "u": init_privileged_mode = privileged_mode_t.USER_MODE;
break;
default: uvm_fatal(get_full_name(),
format("Illegal boot mode option - %0s", boot_mode_opts));
break;
}
rand_mode!q{init_privileged_mode}(false); //
addr_translation_rnd_order_c.constraint_mode(false);
}
uvm_info(get_full_name(), format("riscv_instr_pkg.supported_privileged_mode = %0d",
supported_privileged_mode.length), UVM_LOW);
uvm_cmdline_processor.get_inst().get_arg_value("+asm_test_suffix=", asm_test_suffix);
// Directed march list from the runtime options, ex. RV32I, RV32M etc.
cmdline_enum_processor !(riscv_instr_group_t).get_array_values("+march=", march_isa);
if (march_isa.length != 0) supported_isa = march_isa;
if (!(canFind(supported_isa, riscv_instr_group_t.RV32C))) {
disable_compressed_instr = true;
}
if (! (supported_isa.canFind(riscv_instr_group_t.RV32ZBA) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBA))) {
enable_zba_extension = false;
}
if (! (supported_isa.canFind(riscv_instr_group_t.RV32ZBB) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBB))) {
enable_zbb_extension = false;
}
if (! (supported_isa.canFind(riscv_instr_group_t.RV32ZBC) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBC))) {
enable_zbc_extension = false;
}
if (! (supported_isa.canFind(riscv_instr_group_t.RV32ZBS) ||
supported_isa.canFind(riscv_instr_group_t.RV64ZBS))) {
enable_zbs_extension = false;
}
vector_cfg = riscv_vector_cfg.type_id.create("vector_cfg");
pmp_cfg = riscv_pmp_cfg.type_id.create("pmp_cfg");
rand_mode!q{pmp_cfg}(pmp_cfg.pmp_randomize);
pmp_cfg.initialize(require_signature_addr);
setup_instr_distribution();
get_invalid_priv_lvl_csr();
}
void setup_instr_distribution() {
int val;
get_int_arg_value("+dist_control_mode=", dist_control_mode);
if (dist_control_mode == 1) {
foreach (category; [EnumMembers!riscv_instr_category_t]) {
string opts = format("dist_%0s=", category) ~ "%d";
opts = opts.toLower();
if (cmdl.plusArgs(opts, val)) { // $value$plusargs(opts, val)
category_dist[category] = val;
}
else {
category_dist[category] = 10; // Default ratio
}
uvm_info(get_full_name(), format("Set dist[%0s] = %0d",
category, category_dist[category]), UVM_LOW);
}
}
}
// Initialize the exception/interrupt delegation associate array, set all delegation default to 0
void init_delegation() {
foreach (cause; [EnumMembers!exception_cause_t]) {
m_mode_exception_delegation[cause] = false;
s_mode_exception_delegation[cause] = false;
}
foreach (cause; [EnumMembers!interrupt_cause_t]) {
m_mode_interrupt_delegation[cause] = false;
s_mode_interrupt_delegation[cause] = false;
}
}
void pre_randomize() {
foreach (mode; supported_privileged_mode) {
if (mode == privileged_mode_t.SUPERVISOR_MODE) {
support_supervisor_mode = true;
}
}
}
void get_non_reserved_gpr() { }
void post_randomize() {
// Setup the list all reserved registers
reserved_regs = [tp, sp, scratch_reg];
// Need to save all loop registers, and RA/T0
min_stack_len_per_program = 2 * (XLEN/8);
// Check if the setting is legal
check_setting();
// WFI is not supported in umode
if (init_privileged_mode == privileged_mode_t.USER_MODE) {
no_wfi = true;
}
instr_registry.create_instr_list(this);
}
void check_setting() {
bool support_64b = false;
bool support_128b = false;
foreach (isa; supported_isa) {
if (canFind([riscv_instr_group_t.RV64I,
riscv_instr_group_t.RV64M,
riscv_instr_group_t.RV64A,
riscv_instr_group_t.RV64F,
riscv_instr_group_t.RV64D,
riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV64B], isa)) {
support_64b = true;
}
else if (canFind([riscv_instr_group_t.RV128I,
riscv_instr_group_t.RV128C], isa)) {
support_128b = true;
}
}
if (support_128b && XLEN != 128) {
uvm_fatal(get_full_name(),
"XLEN should be set to 128 based on riscv_instr_pkg.supported_isa setting");
}
if (!support_128b && support_64b && XLEN != 64) {
uvm_fatal(get_full_name(),
"XLEN should be set to 64 based on riscv_instr_pkg.supported_isa setting");
}
if (!(support_128b || support_64b) && XLEN != 32) {
uvm_fatal(get_full_name(),
"XLEN should be set to 32 based on riscv_instr_pkg.supported_isa setting");
}
if (!(support_128b || support_64b) &&
!(canFind([satp_mode_t.SV32,
satp_mode_t.BARE], SATP_MODE))) {
uvm_fatal(get_full_name(),
format("SATP mode %0s is not supported for RV32G ISA", SATP_MODE));
}
}
// Populate invalid_priv_mode_csrs with the main implemented CSRs for each supported privilege
// mode
// TODO(udi) - include performance/pmp/trigger CSRs?
void get_invalid_priv_lvl_csr() {
char[] invalid_lvl;
// Debug CSRs are inaccessible from all but Debug Mode, and we cannot boot into Debug Mode
invalid_lvl ~= 'D';
switch (init_privileged_mode) {
case privileged_mode_t.MACHINE_MODE:
break;
case privileged_mode_t.SUPERVISOR_MODE:
invalid_lvl ~= 'M';
break;
case privileged_mode_t.USER_MODE:
invalid_lvl ~= 'S';
invalid_lvl ~= 'M';
break;
default:
uvm_fatal(get_full_name(), "Unsupported initialization privilege mode");
break;
}
foreach (csr; implemented_csr) {
string csr_name = csr.to!string();
if (canFind(invalid_lvl, csr)) {
invalid_priv_mode_csrs ~= csr;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,330 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// RISC-V assembly program generator configuration class
//-----------------------------------------------------------------------------
module riscv.gen.riscv_instr_registry;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_instr_pkg: riscv_instr_name_t, riscv_instr_group_t,
riscv_instr_category_t, privileged_reg_t, riscv_reg_t, privileged_mode_t;
import riscv.gen.target: unsupported_instr, supported_isa,
implemented_csr, XLEN;
import std.format: format;
import std.algorithm: canFind, remove;
import std.traits: EnumMembers;
import esdl.base.rand: urandom;
import uvm;
class riscv_instr_registry: uvm_object
{
mixin uvm_object_utils;
// All derived instructions
string[riscv_instr_name_t] instr_registry;
// Instruction list
riscv_instr_name_t[] instr_names;
// Categorized instruction list
riscv_instr_name_t[][riscv_instr_group_t] instr_group;
riscv_instr_name_t[][riscv_instr_category_t] instr_category;
riscv_instr_name_t[] basic_instr;
riscv_instr[riscv_instr_name_t] instr_template;
// Privileged CSR filter
privileged_reg_t[] exclude_reg;
privileged_reg_t[] include_reg;
riscv_instr_gen_config cfg;
this (string name="") {
super(name);
}
void set_cfg(riscv_instr_gen_config cfg) {
this.cfg = cfg;
}
bool register(riscv_instr_name_t instr_name, string qualified_name) {
uvm_info("riscv_instr", format("Registering %0s", instr_name), UVM_LOW);
instr_registry[instr_name] = qualified_name;
return true;
}
// Create the list of instructions based on the supported ISA extensions and configuration of the
// generator.
void create_instr_list(riscv_instr_gen_config cfg) {
assert (cfg !is null);
instr_names.length = 0;
// instr_group.clear();
foreach (group; [EnumMembers!riscv_instr_group_t]) instr_group[group] = [];
// instr_category.clear();
foreach (category; [EnumMembers!riscv_instr_category_t]) instr_category[category] = [];
foreach (instr_name, instr_class_name; instr_registry) {
riscv_instr instr_inst;
if (canFind(unsupported_instr, instr_name)) continue;
instr_inst = create_instr(instr_name, instr_class_name);
instr_inst.m_cfg = cfg;
instr_template[instr_name] = instr_inst;
if (!instr_inst.is_supported(cfg)) continue;
// C_JAL is RV32C only instruction
if ((XLEN != 32) && (instr_name == riscv_instr_name_t.C_JAL)) continue;
if (canFind(cfg.reserved_regs, riscv_reg_t.SP ) &&
(instr_name == riscv_instr_name_t.C_ADDI16SP)) {
continue;
}
if (!cfg.enable_sfence && instr_name == riscv_instr_name_t.SFENCE_VMA) continue;
if (cfg.no_fence && (instr_name.inside(riscv_instr_name_t.FENCE,
riscv_instr_name_t.FENCE_I,
riscv_instr_name_t.SFENCE_VMA))) continue;
if (canFind(supported_isa, instr_inst.group) &&
!(cfg.disable_compressed_instr &&
(instr_inst.group.inside(riscv_instr_group_t.RV32C, riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV32DC, riscv_instr_group_t.RV32FC,
riscv_instr_group_t.RV128C))) &&
!(!cfg.enable_floating_point &&
(instr_inst.group.inside(riscv_instr_group_t.RV32F, riscv_instr_group_t.RV64F,
riscv_instr_group_t.RV32D, riscv_instr_group_t.RV64D))) &&
!(!cfg.enable_vector_extension &&
(instr_inst.group == riscv_instr_group_t.RVV)) &&
!(cfg.vector_instr_only &&
(instr_inst.group != riscv_instr_group_t.RVV))) {
instr_category[instr_inst.category] ~= instr_name;
instr_group[instr_inst.group] ~= instr_name;
instr_names ~= instr_name;
}
}
build_basic_instruction_list(cfg);
create_csr_filter(cfg);
}
void create_csr_filter(riscv_instr_gen_config cfg) {
include_reg.length = 0;
exclude_reg.length = 0;
if (cfg.enable_illegal_csr_instruction) {
exclude_reg = implemented_csr;
}
else if (cfg.enable_access_invalid_csr_level) {
include_reg = cfg.invalid_priv_mode_csrs;
}
else {
// Use scratch register to avoid the side effect of modifying other privileged mode CSR.
if (cfg.init_privileged_mode == privileged_mode_t.MACHINE_MODE) {
include_reg = [privileged_reg_t.MSCRATCH];
}
else if (cfg.init_privileged_mode == privileged_mode_t.SUPERVISOR_MODE) {
include_reg = [privileged_reg_t.SSCRATCH];
}
else {
include_reg = [privileged_reg_t.USCRATCH];
}
}
}
riscv_instr create_instr(riscv_instr_name_t instr_name, string instr_class_name) {
import std.conv: to;
uvm_coreservice_t coreservice = uvm_coreservice_t.get();
uvm_factory factory = coreservice.get_factory();
uvm_object obj =
factory.create_object_by_name(instr_class_name, "riscv_instr", instr_class_name);
if (obj is null) {
uvm_fatal("riscv_instr", format("Failed to create instr: %0s", instr_class_name));
}
riscv_instr instr = cast(riscv_instr) obj;
if (instr is null) {
uvm_fatal("riscv_instr", format("Failed to cast instr: %0s", instr_class_name));
}
return instr;
}
void build_basic_instruction_list(riscv_instr_gen_config cfg) {
basic_instr =
instr_category[riscv_instr_category_t.SHIFT] ~
instr_category[riscv_instr_category_t.ARITHMETIC] ~
instr_category[riscv_instr_category_t.LOGICAL] ~
instr_category[riscv_instr_category_t.COMPARE];
if (!cfg.no_ebreak) {
basic_instr ~= riscv_instr_name_t.EBREAK;
foreach (sup_isa; supported_isa) {
if ((sup_isa == riscv_instr_group_t.RV32C) &&
!(cfg.disable_compressed_instr)) {
basic_instr ~= riscv_instr_name_t.C_EBREAK;
break;
}
}
}
if (cfg.no_dret == 0) {
basic_instr ~= riscv_instr_name_t.DRET;
}
if (cfg.no_fence == 0) {
basic_instr ~= instr_category[riscv_instr_category_t.SYNCH];
}
if ((cfg.no_csr_instr == 0) && (cfg.init_privileged_mode == privileged_mode_t.MACHINE_MODE)) {
basic_instr ~= instr_category[riscv_instr_category_t.CSR];
}
if (cfg.no_wfi == 0) {
basic_instr ~= riscv_instr_name_t.WFI;
}
}
riscv_instr get_rand_instr(riscv_instr_name_t[] exclude_instr,
riscv_instr_category_t[] include_category) {
return get_rand_instr(null, exclude_instr, include_category, null, null, null);
}
riscv_instr get_rand_instr(riscv_instr_category_t[] include_category,
riscv_instr_group_t[] exclude_group) {
return get_rand_instr(null, null, include_category, null, null, exclude_group);
}
riscv_instr get_rand_instr(riscv_instr_category_t[] include_category) {
return get_rand_instr(null, null, include_category, null, null, null);
}
riscv_instr get_rand_instr(riscv_instr_name_t[] include_instr) {
return get_rand_instr(include_instr, null, null, null, null, null);
}
riscv_instr get_rand_instr(riscv_instr_name_t[] include_instr,
riscv_instr_name_t[] exclude_instr,
riscv_instr_group_t[] exclude_group) {
return get_rand_instr(include_instr, exclude_instr, null, null, null, exclude_group);
}
riscv_instr get_rand_instr(riscv_instr_name_t[] include_instr = null,
riscv_instr_name_t[] exclude_instr = null,
riscv_instr_category_t[] include_category = null,
riscv_instr_category_t[] exclude_category = null,
riscv_instr_group_t[] include_group = null,
riscv_instr_group_t[] exclude_group = null) {
ulong idx;
riscv_instr_name_t name;
// riscv_instr_name_t name;
riscv_instr_name_t[] allowed_instr;
riscv_instr_name_t[] disallowed_instr;
riscv_instr_category_t[] allowed_categories;
foreach (icatg; include_category) {
allowed_instr ~= instr_category[icatg];
}
foreach (ecatg; exclude_category) {
disallowed_instr ~= instr_category[ecatg];
}
foreach (igrp; include_group) {
allowed_instr ~= instr_group[igrp];
}
foreach (egrp; exclude_group) {
if (egrp in instr_group) {
disallowed_instr ~= instr_group[egrp];
}
}
disallowed_instr ~= exclude_instr;
if (disallowed_instr.length == 0) {
if (include_instr.length > 0) {
idx = urandom(0, include_instr.length);
name = include_instr[idx];
}
else if (allowed_instr.length > 0) {
idx = urandom(0, allowed_instr.length);
name = allowed_instr[idx];
}
else {
idx = urandom(0, instr_names.length);
name = instr_names[idx];
}
}
else {
import std.algorithm.sorting: sort;
import std.algorithm.setops: setIntersection, setDifference;
import std.array: array;
riscv_instr_name_t[] instr_set = instr_names.dup;
instr_set.sort();
riscv_instr_name_t[] include_set = instr_set;
riscv_instr_name_t[] allowed_set = instr_set;
if (include_instr.length > 0) {
include_set = include_instr;
include_set.sort();
}
if (allowed_instr.length > 0) {
allowed_set = allowed_instr;
allowed_set.sort();
}
riscv_instr_name_t[] inter_set =
setDifference(setIntersection(instr_set, include_set, allowed_set),
disallowed_instr.sort()).array();
idx = urandom(0, inter_set.length);
name = inter_set[idx];
}
// Shallow copy for all relevant fields, avoid using create() to improve performance
auto instr = instr_template[name].dup;
instr.m_cfg = cfg;
return instr;
}
riscv_instr get_load_store_instr(riscv_instr_name_t[] load_store_instr = null) {
if (load_store_instr.length == 0) {
load_store_instr = instr_category[riscv_instr_category_t.LOAD] ~
instr_category[riscv_instr_category_t.STORE];
}
// Filter out unsupported load/store instruction
if (unsupported_instr.length > 0) {
uint i = 0;
while (i < load_store_instr.length) {
if (canFind(unsupported_instr, load_store_instr[i])) {
remove(load_store_instr, load_store_instr[i]);
}
else {
i += 1;
}
}
}
if (load_store_instr.length == 0) {
assert (false, "Cannot generate random instruction");
}
ulong idx = urandom( 0, load_store_instr.length);
riscv_instr_name_t name = load_store_instr[idx];
// Shallow copy for all relevant fields, avoid using create() to improve performance
auto instr = instr_template[name].dup;
instr.m_cfg = cfg;
return instr;
}
riscv_instr get_instr(riscv_instr_name_t name) {
if (name !in instr_template) {
uvm_fatal("riscv_instr", format("Cannot get instr %0s", name));
}
// Shallow copy for all relevant fields, avoid using create() to improve performance
auto instr = instr_template[name].dup;
instr.m_cfg = cfg;
return instr;
}
}

View file

@ -0,0 +1,396 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------------------
// RISC-V instruction sequence
//
// This class is used to generate a single instruction sequence for a RISC-V assembly program.
// It's used by riscv_asm_program_gen to generate the main program and all sub-programs. The
// flow is explained below:
// For main program:
// - Generate instruction sequence body.
// - Post-process the load/store/branch instructions.
// - Insert the jump instructions to its sub-programs (done by riscv_asm_program_gen).
// For sub program:
// - Generate the stack push instructions which are executed when entering this program.
// - Generate instruction sequence body.
// - Generate the stack pop instructions which are executed before exiting this program.
// - Post-process the load/store/branch instructions.
// - Insert the jump instructions to its sub-programs (done by riscv_asm_program_gen).
// - Generate a return instruction at the end of the program.
//-----------------------------------------------------------------------------------------
module riscv.gen.riscv_instr_sequence;
import riscv.gen.riscv_instr_pkg: riscv_instr_category_t, riscv_instr_name_t,
format_string, riscv_reg_t, indent, LABEL_STR_LEN;
import riscv.gen.target: support_pmp, XLEN;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.riscv_directed_instr_lib: riscv_push_stack_instr, riscv_pop_stack_instr,
riscv_jump_instr;
import riscv.gen.riscv_instr_stream: riscv_instr_stream, riscv_prog_instr_stream;
import riscv.gen.riscv_illegal_instr: riscv_illegal_instr;
import std.format: format;
import std.algorithm.searching: canFind;
import esdl.data.queue: Queue;
import esdl.rand: randomize, randomize_with;
import esdl.base.rand: urandom, shuffle;
import uvm;
class riscv_instr_sequence: uvm_sequence!(uvm_sequence_item,uvm_sequence_item)
{
uint instr_cnt; // Instruction count of this sequence
riscv_push_stack_instr instr_stack_enter; // Stack push instructions for sub-programs
riscv_pop_stack_instr instr_stack_exit; // Stack pop instructions for sub-programs
riscv_prog_instr_stream instr_stream; // Main instruction streams
bool is_main_program; // Type of this sequence (main or sub program)
bool is_debug_program; // Indicates whether sequence is debug program
string label_name; // Label of the sequence (program name)
riscv_instr_gen_config cfg; // Configuration class handle
Queue!string instr_string_list; // Save the instruction list in string format
int program_stack_len; // Stack space allocated for this program
riscv_instr_stream[] directed_instr; // List of all directed instruction stream
riscv_illegal_instr illegal_instr; // Illegal instruction generator
int illegal_instr_pct; // Percentage of illegal instruction
int hint_instr_pct; // Percentage of HINT instruction
mixin uvm_object_utils;
this(string name = "") {
super(name);
if(!uvm_config_db!(riscv_instr_gen_config).get(null, "*", "instr_cfg", cfg))
uvm_fatal(get_full_name(), "Cannot get instr_gen_cfg");
instr_stream = riscv_prog_instr_stream.type_id.create("instr_stream");
instr_stack_enter = riscv_push_stack_instr.type_id.create("instr_stack_enter");
instr_stack_exit = riscv_pop_stack_instr.type_id.create("instr_stack_exit");
illegal_instr = riscv_illegal_instr.type_id.create("illegal_instr");
}
// Main function to generate the instruction stream
// The main random instruction stream is generated by instr_stream.gen_instr(), which generates
// each instruction one by one with a separate randomization call. It's not done by a single
// randomization call for the entire instruction stream because this solution won't scale if
// we have hundreds of thousands of instructions to generate. The constraint solver slows down
// considerably as the instruction stream becomes longer. The downside is we cannot specify
// constraints between instructions. The way to solve it is to have a dedicated directed
// instruction stream for such scenarios, like hazard sequence.
void gen_instr(bool is_main_program, bool no_branch = false) {
this.is_main_program = is_main_program;
instr_stream.cfg = cfg;
instr_stream.initialize_instr_list(instr_cnt);
uvm_info(get_full_name(), format("Start generating %0d instruction",
instr_stream.instr_list.length), UVM_LOW);
// Do not generate load/store instruction here
// The load/store instruction will be inserted as directed instruction stream
instr_stream.gen_instr(no_branch, true,
is_debug_program);
if(!is_main_program) {
gen_stack_enter_instr();
gen_stack_exit_instr();
}
uvm_info(get_full_name(), "Finishing instruction generation", UVM_LOW);
}
// Generate the stack push operations for this program
// It pushes the necessary context to the stack like RA, T0,loop registers etc. The stack
// pointer(SP) is reduced by the amount the stack space allocated to this program.
void gen_stack_enter_instr() {
bool allow_branch = ((illegal_instr_pct > 0) || (hint_instr_pct > 0)) ? false : true;
allow_branch &= !cfg.no_branch_jump;
// DV_CHECK_STD_RANDOMIZE_WITH_FATAL(program_stack_len,
// Keep stack len word aligned to avoid unaligned load/store
// program_stack_len % (XLEN/8) == 0;,
// "Cannot randomize program_stack_len")
program_stack_len =
(XLEN/8) * (cast(int) urandom(cfg.min_stack_len_per_program/(XLEN/8),
cfg.max_stack_len_per_program/(XLEN/8) + 1));
instr_stack_enter.cfg = cfg;
instr_stack_enter.push_start_label = label_name ~ "_stack_p";
instr_stack_enter.gen_push_stack_instr(program_stack_len, allow_branch);
instr_stream.prepend_instr_list(instr_stack_enter.instr_list);
}
// Recover the saved GPR from the stack
// Advance the stack pointer(SP) to release the allocated stack space.
void gen_stack_exit_instr() {
instr_stack_exit.cfg = cfg;
instr_stack_exit.gen_pop_stack_instr(program_stack_len, instr_stack_enter.saved_regs);
instr_stream.append_instr_list(instr_stack_exit.instr_list);
}
//----------------------------------------------------------------------------------------------
// Instruction post-process
//
// Post-process is required for branch instructions:
//
// - Need to assign a valid branch target. This is done by picking a random instruction label in
// this sequence and assigning to the branch instruction. All the non-atomic instructions
// will have a unique numeric label as the local branch target identifier.
// - The atomic instruction streams don't have labels except for the first instruction. This is
// to avoid branching into an atomic instruction stream which breaks its atomicy. The
// definition of an atomic instruction stream here is a sequence of instructions which must be
// executed in-order.
// - In this sequence, only forward branch is handled. The backward branch target is implemented
// in a dedicated loop instruction sequence. Randomly choosing a backward branch target could
// lead to dead loops in the absence of proper loop exiting conditions.
//
//----------------------------------------------------------------------------------------------
void post_process_instr() {
// int i;
int label_idx;
int branch_cnt;
uint[] branch_idx;
int[int] branch_target; // '{default: 0};
// Insert directed instructions, it's randomly mixed with the random instruction stream.
// foreach (instr; directed_instr) {
// instr_stream.insert_instr_stream(instr.instr_list);
// }
instr_stream.mixin_directed_instr_list(directed_instr);
// Assign an index for all instructions, these indexes won't change even a new instruction
// is injected in the post process.
foreach (i, instr; instr_stream.instr_list) {
instr.idx = label_idx;
if (instr.has_label && !instr_stream.instr_list[i].atomic) {
if ((illegal_instr_pct > 0) && (instr.is_illegal_instr == false)) {
// The illegal instruction generator always increase PC by 4 when resume execution, need
// to make sure PC + 4 is at the correct instruction boundary.
if (instr.is_compressed) {
if (i < instr_stream.instr_list.length-1) {
if (instr_stream.instr_list[i+1].is_compressed) {
instr.is_illegal_instr = (urandom(0, 100) < illegal_instr_pct);
}
}
}
else {
instr.is_illegal_instr = (urandom(0, 100) < illegal_instr_pct);
}
}
if ((hint_instr_pct > 0) && (instr.is_illegal_instr == 0)) {
if (instr.is_compressed) {
instr.is_hint_instr = (urandom(0, 100) < hint_instr_pct);
}
}
instr.label = format("%0d", label_idx);
instr.is_local_numeric_label = true;
label_idx++;
}
}
// Generate branch target
branch_idx.length = 30;
// `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(,
foreach (ref idx; branch_idx) {
idx = urandom(1, cfg.max_branch_step+1);
}
foreach (i, instr; instr_stream.instr_list) {
if ((instr.category == riscv_instr_category_t.BRANCH) &&
(!instr.branch_assigned) &&
(!instr.is_illegal_instr)) {
// Post process the branch instructions to give a valid local label
// Here we only allow forward branch to avoid unexpected infinite loop
// The loop structure will be inserted with a separate routine using
// reserved loop registers
int branch_target_label;
int branch_byte_offset;
branch_target_label = instr.idx + branch_idx[branch_cnt];
if (branch_target_label >= label_idx) {
branch_target_label = label_idx-1;
}
branch_cnt++;
if (branch_cnt == branch_idx.length) {
branch_cnt = 0;
branch_idx.shuffle();
}
uvm_info(get_full_name(),
format("Processing branch instruction[%0d]:%0s # %0d -> %0d",
i, instr.convert2asm(),
instr.idx, branch_target_label), UVM_HIGH);
instr.imm_str = format("%0df", branch_target_label);
// Below calculation is only needed for generating the instruction stream in binary format
for (size_t j = i + 1; j < instr_stream.instr_list.length; j++) {
branch_byte_offset = (instr_stream.instr_list[j-1].is_compressed) ?
branch_byte_offset + 2 : branch_byte_offset + 4;
if (instr_stream.instr_list[j].label == format("%0d", branch_target_label)) {
instr.imm = branch_byte_offset;
break;
}
else if (j == instr_stream.instr_list.length - 1) {
uvm_fatal(get_full_name(), format("Cannot find target label : %0d", branch_target_label));
}
}
instr.branch_assigned = true;
branch_target[branch_target_label] = 1;
}
// Remove the local label which is not used as branch target
if (instr.has_label &&
instr.is_local_numeric_label) {
import std.conv: to;
int idx = instr.label.to!int();
if (idx !in branch_target || ! branch_target[idx]) { // emulate SV {default: 0}
instr.has_label = false;
}
}
// i++;
}
uvm_info(get_full_name(), "Finished post-processing instructions", UVM_HIGH);
}
// Inject a jump instruction stream
// This function is called by riscv_asm_program_gen with the target program label
// The jump routine is implmented with an atomic instruction stream(riscv_jump_instr). Similar
// to load/store instructions, JALR/JAL instructions also need a proper base address and offset
// as the jump target.
void insert_jump_instr(string target_label, int idx) {
riscv_jump_instr jump_instr;
jump_instr = riscv_jump_instr.type_id.create("jump_instr");
jump_instr.target_program_label = target_label;
if (!is_main_program)
jump_instr.stack_exit_instr = instr_stack_exit.pop_stack_instr;
jump_instr.cfg = cfg;
jump_instr.label = label_name;
jump_instr.idx = idx;
jump_instr.use_jalr = is_main_program;
jump_instr.randomize();
instr_stream.insert_instr_stream(jump_instr.instr_list);
uvm_info(get_full_name(), format("%0s -> %0s...done",
jump_instr.jump.instr_name, target_label), UVM_LOW);
}
// Convert the instruction stream to the string format.
// Label is attached to the instruction if available, otherwise attach proper space to make
// the code indent consistent.
void generate_instr_stream(bool no_label = false) {
string prefix, str;
int i;
instr_string_list = [];
for (i = 0; i < instr_stream.instr_list.length; i++) {
if (i == 0) {
if (no_label) {
prefix = format_string(" ", LABEL_STR_LEN);
}
else {
prefix = format_string(format("%0s:", label_name), LABEL_STR_LEN);
}
instr_stream.instr_list[i].has_label = true;
}
else {
if(instr_stream.instr_list[i].has_label) {
prefix = format_string(format("%0s:", instr_stream.instr_list[i].label),
LABEL_STR_LEN);
}
else {
prefix = format_string(" ", LABEL_STR_LEN);
}
}
str = prefix ~ instr_stream.instr_list[i].convert2asm();
instr_string_list ~= str;
}
// If PMP is supported, need to align <main> to a 4-byte boundary.
// TODO(udi) - this might interfere with multi-hart programs,
// may need to specifically match hart0.
if (support_pmp && !uvm_re_match(uvm_glob_to_re("*main*"), label_name)) {
instr_string_list.pushFront(".align 2");
}
insert_illegal_hint_instr();
prefix = format_string(format("%0d:", i), LABEL_STR_LEN);
if(!is_main_program) {
generate_return_routine(prefix);
}
}
void generate_return_routine(string prefix) {
import std.algorithm: countUntil;
string str;
int i;
Queue!riscv_instr_name_t jump_instr = [riscv_instr_name_t.JALR];
bool rand_lsb = urandom!bool();
riscv_reg_t ra;
uint ra_idx;
auto zero_idx = cfg.reserved_regs.countUntil(riscv_reg_t.ZERO);
// if (zero_idx >= 0) {
ra_idx = urandom (0, cast(uint) cfg.reserved_regs.length);
if (ra_idx <= zero_idx) ra_idx += 1;
ra = cfg.reserved_regs[ra_idx];
// }
// else {
// ra_idx = urandom (0, cast(uint) cfg.reserved_regs.length);
// ra = cfg.reserved_regs[ra_idx];
// }
// Randomly set lsb of the return address, JALR should zero out lsb automatically
str = prefix ~ format("addi x%0d, x%0d, %0d", ra, cfg.ra, rand_lsb);
instr_string_list ~= str;
if (!cfg.disable_compressed_instr) {
jump_instr ~= riscv_instr_name_t.C_JR;
if (!(canFind(cfg.reserved_regs, riscv_reg_t.RA))) {
jump_instr ~= riscv_instr_name_t.C_JALR;
}
}
assert (jump_instr.length != 0);
i = urandom(0, cast(uint) jump_instr.length);
switch (jump_instr[i]) {
case riscv_instr_name_t.C_JALR : str = prefix ~ format("c.jalr x%0d", ra); break;
case riscv_instr_name_t.C_JR : str = prefix ~ format("c.jr x%0d", ra); break;
case riscv_instr_name_t.JALR : str = prefix ~ format("jalr x%0d, x%0d, 0", ra, ra); break;
default: uvm_fatal(get_full_name(), format("Unsupported jump_instr %0s", jump_instr[i]));
}
instr_string_list ~= str;
}
void insert_illegal_hint_instr() {
int bin_instr_cnt;
int idx;
string str;
illegal_instr.init(cfg);
bin_instr_cnt = instr_cnt * cfg.illegal_instr_ratio / 1000;
if (bin_instr_cnt >= 0) {
uvm_info(get_full_name(), format("Injecting %0d illegal instructions, ratio %0d/100",
bin_instr_cnt, cfg.illegal_instr_ratio), UVM_LOW);
for(int i = 0; i != bin_instr_cnt; ++i) {
// DV_CHECK_RANDOMIZE_WITH_FATAL(,
illegal_instr.randomize_with! q{ exception != illegal_instr_type_e.kHintInstr;} ();
str = indent ~ format(".4byte 0x%s # %0s",
illegal_instr.get_bin_str(), illegal_instr.comment);
idx = urandom(0, cast(uint) instr_string_list.length+1);
instr_string_list.insert(idx, str);
}
}
bin_instr_cnt = instr_cnt * cfg.hint_instr_ratio / 1000;
if (bin_instr_cnt >= 0) {
uvm_info(get_full_name(), format("Injecting %0d HINT instructions, ratio %0d/100",
bin_instr_cnt, cfg.illegal_instr_ratio), UVM_LOW);
for(int i = 0; i != bin_instr_cnt; ++i) {
//DV_CHECK_RANDOMIZE_WITH_FATAL(illegal_instr,
illegal_instr.randomize_with! q{exception == illegal_instr_type_e.kHintInstr;}();
str = indent ~ format(".2byte 0x%s # %0s",
illegal_instr.get_bin_str(), illegal_instr.comment);
idx = urandom(0, cast(uint) instr_string_list.length+1);
instr_string_list.insert(idx, str);
}
}
}
}

View file

@ -0,0 +1,634 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Base class for RISC-V instruction stream
// A instruction stream here is a queue of RISC-V basic instructions.
// This class also provides some functions to manipulate the instruction stream, like insert a new
// instruction, mix two instruction streams etc.
module riscv.gen.riscv_instr_stream;
import riscv.gen.riscv_instr_pkg: riscv_instr_name_t, riscv_reg_t,
riscv_instr_category_t, riscv_instr_group_t, riscv_vreg_t,
riscv_pseudo_instr_name_t, va_variant_t;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_pseudo_instr: riscv_pseudo_instr;
// import riscv.gen.riscv_instr_registry: riscv_instr_registry;
import riscv.gen.isa.riscv_vector_instr: riscv_vector_instr;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.target: XLEN;
import std.format: format;
import std.algorithm: canFind, sort;
import esdl.rand: rand, constraint, randomize, randomize_with;
import esdl.base.rand: urandom;
import esdl.data.queue: Queue;
import esdl.data.bvec: ubvec;
import uvm;
class riscv_instr_stream: uvm_object
{
mixin uvm_object_utils;
Queue!riscv_instr instr_list;
uint instr_cnt;
string label = "";
// User can specify a small group of available registers to generate various hazard condition
@rand riscv_reg_t[] avail_regs;
// Some additional reserved registers that should not be used as rd register
// by this instruction stream
riscv_reg_t[] reserved_rd;
int hart;
// used when we mixin directed instructions into the prog instr_list
uint next_stream;
// riscv_instr_registry registry;
this(string name = "riscv_instr_stream") {
super(name);
}
// Initialize the instruction stream, create each instruction instance
void initialize_instr_list(uint instr_cnt) {
instr_list.length = 0;
this.instr_cnt = instr_cnt;
create_instr_instance();
}
void create_instr_instance() {
riscv_instr instr;
for (int i = 0; i < instr_cnt; i++) {
instr = riscv_instr.type_id.create(format("instr_%0d", i));
append_instr(instr);
}
}
// Insert an instruction to the existing instruction stream at the given index
// When index is -1, the instruction is injected at a random location
void insert_instr(riscv_instr instr, int idx = -1) {
int current_instr_cnt = cast(int) instr_list.length;
if (current_instr_cnt == 0) {
idx = 0;
}
else if (idx == -1) {
idx = cast(int) urandom(0, current_instr_cnt);
while (instr_list[idx].atomic) {
idx += 1;
if (idx == current_instr_cnt - 1) {
instr_list ~= instr;
return;
}
}
}
else if ((idx > current_instr_cnt) || (idx < 0)) {
uvm_error(get_full_name() ,
format("Cannot insert instr:%0s at idx %0d",
instr.convert2asm(), idx));
}
instr_list.insert(idx, instr);
}
void insert_instr_map(Queue!riscv_instr new_instr, int idx = -1, bool replace = false) {
assert (replace == false);
}
// Insert an instruction to the existing instruction stream at the given index
// When index is -1, the instruction is injected at a random location
// When replace is 1, the original instruction at the inserted position will be replaced
void insert_instr_stream(Queue!riscv_instr new_instr, int idx = -1, bool replace = false) {
int current_instr_cnt = cast(int) instr_list.length;
int new_instr_cnt = cast(int) new_instr.length;
if (current_instr_cnt == 0) {
instr_list ~= new_instr;
return;
}
if (idx == -1) {
idx = cast(int) urandom(0, current_instr_cnt);
for (int i=0; i < 10 ; i++) {
if (instr_list[idx].atomic) break;
idx = cast(int) urandom(0, current_instr_cnt);
}
if (instr_list[idx].atomic) {
foreach (k, instr; instr_list) {
if (! instr.atomic) {
idx = cast(int) k;
break;
}
}
if (instr_list[idx].atomic) {
uvm_fatal(get_full_name, format("Cannot inject the instruction"));
}
}
}
else if((idx > current_instr_cnt) || (idx < 0)) {
uvm_error(get_full_name(), format("Cannot insert instr stream at idx %0d", idx));
}
//When replace is 1, the original instruction at this index will be removed. The label of the
//original instruction will be copied to the head of inserted instruction stream.
if (replace) {
new_instr[0].label = instr_list[idx].label;
new_instr[0].has_label = instr_list[idx].has_label;
foreach (i, instr; new_instr) {
instr_list[i+idx] = instr;
}
}
else {
if (idx == 0) {
instr_list.pushFront(new_instr[]);
}
else {
instr_list.insert(idx, new_instr[]);
}
}
}
void insert_instr_stream(riscv_instr[] new_instr, int idx = -1, bool replace = false) {
int current_instr_cnt = cast(int) instr_list.length;
int new_instr_cnt = cast(int) new_instr.length;
if (current_instr_cnt == 0) {
instr_list ~= new_instr;
return;
}
if (idx == -1) {
idx = cast(int) urandom(0, current_instr_cnt);
for (int i=0; i < 10 ; i++) {
if (instr_list[idx].atomic) break;
idx = cast(int) urandom(0, current_instr_cnt);
}
if (instr_list[idx].atomic) {
foreach (k, instr; instr_list) {
if (! instr.atomic) {
idx = cast(int) k;
break;
}
}
if (instr_list[idx].atomic) {
uvm_fatal(get_full_name, format("Cannot inject the instruction"));
}
}
}
else if((idx > current_instr_cnt) || (idx < 0)) {
uvm_error(get_full_name(), format("Cannot insert instr stream at idx %0d", idx));
}
//When replace is 1, the original instruction at this index will be removed. The label of the
//original instruction will be copied to the head of inserted instruction stream.
if (replace) {
new_instr[0].label = instr_list[idx].label;
new_instr[0].has_label = instr_list[idx].has_label;
if (idx == 0) {
instr_list.removeFront();
instr_list.pushFront(new_instr);
}
else {
instr_list.remove(idx);
instr_list.insert(idx, new_instr);
}
}
else {
if (idx == 0) {
instr_list.pushFront(new_instr);
}
else {
instr_list.insert(idx, new_instr);
}
}
}
void append_instr(riscv_instr instr) {
instr_list ~= instr;
}
void prepend_instr(riscv_instr instr) {
instr_list.pushFront(instr);
}
void append_instr_list(Queue!riscv_instr instr) {
instr_list ~= instr[];
}
void prepend_instr_list(Queue!riscv_instr instr) {
instr_list.pushFront(instr[]);
}
// Mix the input instruction stream with the original instruction, the instruction order is
// preserved. When 'contained' is set, the original instruction stream will be inside the
// new instruction stream with the first and last instruction from the input instruction stream.
void mix_instr_stream(riscv_instr[] new_instr, bool contained = false) {
int current_instr_cnt = cast(int) instr_list.length;
int[] insert_instr_position;
int new_instr_cnt = cast(int) new_instr.length;
insert_instr_position.length = new_instr_cnt;
foreach (ref position; insert_instr_position) {
position = urandom(0, current_instr_cnt);
}
if (insert_instr_position.length > 0) {
insert_instr_position.sort();
}
if (contained) {
insert_instr_position[0] = 0;
if (new_instr_cnt > 1) {
insert_instr_position[new_instr_cnt-1] = current_instr_cnt-1;
}
}
foreach (k, instr; new_instr) {
insert_instr(instr, insert_instr_position[k] + cast(int) k);
}
}
void mix_instr_stream(Queue!riscv_instr new_instr, bool contained = false) {
import std.range: enumerate;
int current_instr_cnt = cast(int) instr_list.length;
int[] insert_instr_position;
int new_instr_cnt = cast(int) new_instr.length;
insert_instr_position.length = new_instr_cnt;
foreach (ref position; insert_instr_position) {
position = urandom(0, current_instr_cnt+1);
}
if (insert_instr_position.length > 0) {
insert_instr_position.sort();
}
if (contained) {
insert_instr_position[0] = 0;
if (new_instr_cnt > 1) {
insert_instr_position[new_instr_cnt-1] = current_instr_cnt-1;
}
}
foreach (k, instr; new_instr[].enumerate) {
insert_instr(instr, insert_instr_position[k] + cast(int) k);
}
}
override string convert2string() {
string str;
foreach (instr; instr_list)
str ~= instr.convert2asm() ~ "\n";
return str;
}
}
// Generate a random instruction stream based on the configuration
// There are two ways to use this class to generate instruction stream
// 1. For short instruction stream, you can call randomize() directly.
// 2. For long instruction stream (>1K), randomize() all instructions together might take a long
// time for the constraint solver. In this case, you can call gen_instr to generate instructions
// one by one. The time only grows linearly with the instruction count
class riscv_rand_instr_stream: riscv_instr_stream
{
mixin uvm_object_utils;
riscv_instr_gen_config cfg;
bool kernel_mode;
riscv_instr_name_t[] allowed_instr;
uint[riscv_instr_category_t] category_dist;
this(string name = "riscv_rand_instr_stream") {
super(name);
}
override void create_instr_instance() {
instr_list.length = instr_cnt;
}
void setup_allowed_instr(bool no_branch = false, bool no_load_store = true) {
allowed_instr = cfg.instr_registry.basic_instr;
if (no_branch == false) {
allowed_instr ~= cfg.instr_registry.instr_category[riscv_instr_category_t.BRANCH];
}
if (no_load_store == false) {
allowed_instr ~= cfg.instr_registry.instr_category[riscv_instr_category_t.LOAD];
allowed_instr ~= cfg.instr_registry.instr_category[riscv_instr_category_t.STORE];
}
setup_instruction_dist(no_branch, no_load_store);
}
void randomize_avail_regs() {
import std.traits: EnumMembers;
import std.algorithm.mutation: remove;
import std.algorithm.searching: countUntil;
if (avail_regs.length > 0) {
riscv_reg_t[(EnumMembers!riscv_reg_t).length] allowed_regs = [EnumMembers!riscv_reg_t];
riscv_reg_t[] allowed_regs_range = allowed_regs;
// remove cfg.reserved_regs and reserved_rd
foreach (rreg; cfg.reserved_regs) {
ptrdiff_t loc = allowed_regs_range.countUntil(rreg);
if (loc >= 0) allowed_regs_range.remove(loc);
}
foreach (rreg; reserved_rd) {
ptrdiff_t loc = allowed_regs_range.countUntil(rreg);
if (loc >= 0) allowed_regs_range.remove(loc);
}
// avail_regs[0] has to be between S0 and A5
auto start0 = allowed_regs_range.countUntil!((a) => a >= riscv_reg_t.S0);
auto end0 = allowed_regs_range.countUntil!((a) => a > riscv_reg_t.A5);
if (end0 < 0) end0 = allowed_regs_range.length;
if (start0 < 0 || start0 == end0) assert(false, "Cannot randomize avail_regs");
auto loc0 = urandom(start0, end0);
avail_regs[0] = allowed_regs_range[loc0];
allowed_regs_range.remove(loc0);
// avail_regs elements have to be unique
for (size_t n=1; n != avail_regs.length; ++n) {
if (allowed_regs_range.length == 0) assert (false, "Cannot randomize avail_regs");
assert(allowed_regs_range.length != 0);
auto loc = urandom(0, allowed_regs_range.length);
avail_regs[n] = allowed_regs_range[loc];
allowed_regs_range.remove(loc);
}
}
}
void setup_instruction_dist(bool no_branch = false, bool no_load_store = true) {
if (cfg.dist_control_mode) {
category_dist = cfg.category_dist;
if (no_branch) {
category_dist[riscv_instr_category_t.BRANCH] = 0;
}
if (no_load_store) {
category_dist[riscv_instr_category_t.LOAD] = 0;
category_dist[riscv_instr_category_t.STORE] = 0;
}
uvm_info(get_full_name(), format("setup_instruction_dist: %0d", category_dist.length), UVM_LOW);
}
}
void gen_instr(bool no_branch = false, bool no_load_store = true,
bool is_debug_program = false) {
setup_allowed_instr(no_branch, no_load_store);
assert (instr_list.length != 0);
foreach (ref instr; instr_list) {
randomize_instr(instr, is_debug_program);
}
// Do not allow branch instruction as the last instruction because there's no
// forward branch target
while (instr_list[$-1].category == riscv_instr_category_t.BRANCH) {
instr_list.length = instr_list.length - 1;
if (instr_list.length == 0) break;
}
}
void randomize_instr(out riscv_instr instr,
bool is_in_debug = false,
bool disable_dist = false,
riscv_instr_group_t[] include_group = []) {
riscv_instr_name_t[] exclude_instr;
if (reserved_rd.canFind(riscv_reg_t.SP) || cfg.reserved_regs.canFind(riscv_reg_t.SP) ||
(avail_regs.length > 0 && ! avail_regs.canFind(riscv_reg_t.SP))) {
exclude_instr = [riscv_instr_name_t.C_ADDI4SPN, riscv_instr_name_t.C_ADDI16SP,
riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_LDSP];
}
// Post-process the allowed_instr and exclude_instr lists to handle
// adding ebreak instructions to the debug rom.
if (is_in_debug) {
if (cfg.no_ebreak && cfg.enable_ebreak_in_debug_rom) {
allowed_instr ~= [riscv_instr_name_t.EBREAK, riscv_instr_name_t.C_EBREAK];
}
else if (! cfg.no_ebreak && ! cfg.enable_ebreak_in_debug_rom) {
exclude_instr ~= [riscv_instr_name_t.EBREAK, riscv_instr_name_t.C_EBREAK];
}
}
instr = cfg.instr_registry.get_rand_instr(allowed_instr, exclude_instr, include_group);
randomize_gpr(instr);
}
void randomize_gpr(riscv_instr instr) {
assert (cfg !is null);
instr.m_cfg = cfg;
instr.randomize_with! q{
if ($0.length > 0) {
if (has_rs1) {
rs1 inside [$0];
}
if (has_rs2) {
rs2 inside [$0];
}
if (has_rd) {
rd inside [$0];
}
}
foreach (rrd; $1) {
if (has_rd) {
rd != rrd;
}
if (instr_format == riscv_instr_format_t.CB_FORMAT) {
rs1 != rrd;
}
}
foreach (rreg; $2) {
if (has_rd) {
rd != rreg;
}
if (instr_format == riscv_instr_format_t.CB_FORMAT) {
rs1 != rreg;
}
}
} (avail_regs, reserved_rd, cfg.reserved_regs);
// TODO: Add constraint for CSR, floating point register
}
riscv_instr get_init_gpr_instr(riscv_reg_t gpr, ubvec!XLEN val) {
riscv_pseudo_instr li_instr;
li_instr = riscv_pseudo_instr.type_id.create("li_instr");
li_instr.randomize_with! q{
pseudo_instr_name == riscv_pseudo_instr_name_t.LI;
rd == $0;
} (gpr);
li_instr.imm_str = format("0x%0x", val);
return li_instr;
}
void add_init_vector_gpr_instr(riscv_vreg_t gpr, ubvec!XLEN val) {
riscv_vector_instr instr
= cast(riscv_vector_instr) cfg.instr_registry.get_instr(riscv_instr_name_t.VMV);
instr.m_cfg = cfg;
instr.avoid_reserved_vregs_c.constraint_mode(false);
instr.randomize_with! q{
va_variant == va_variant_t.VX;
vd == $0;
rs1 == $1;
} (gpr, cfg.gpr[0]);
prepend_instr(instr);
prepend_instr(get_init_gpr_instr(cfg.gpr[0], val));
}
}
class riscv_prog_instr_stream: riscv_rand_instr_stream
{
mixin uvm_object_utils;
riscv_instr_stream[] dir_instr_list;
// used in mixin_directed_instr_list
uint[] dir_n;
this(string name = "riscv_prog_instr_stream") {
super(name);
}
// Insert an instruction to the existing instruction stream at the given index
// When index is -1, the instruction is injected at a random location
// When replace is 1, the original instruction at the inserted position will be replaced
override void insert_instr_stream(Queue!riscv_instr new_instr, int idx = -1, bool replace = false) {
int current_instr_cnt = cast(int) instr_list.length;
int new_instr_cnt = cast(int) new_instr.length;
if (current_instr_cnt == 0) {
instr_list = new_instr;
return;
}
if (idx == -1) {
idx = cast(int) urandom(0, current_instr_cnt);
for (int i=0; i < 10 ; i++) {
if (instr_list[idx].atomic) break;
idx = cast(int) urandom(0, current_instr_cnt);
}
if (instr_list[idx].atomic) {
foreach (k, instr; instr_list) {
if (! instr.atomic) {
idx = cast(int) k;
break;
}
}
if (instr_list[idx].atomic) {
uvm_fatal(get_full_name, format("Cannot inject the instruction"));
}
}
}
else if((idx > current_instr_cnt) || (idx < 0)) {
uvm_error(get_full_name(), format("Cannot insert instr stream at idx %0d", idx));
}
//When replace is 1, the original instruction at this index will be removed. The label of the
//original instruction will be copied to the head of inserted instruction stream.
if (replace) {
new_instr[0].label = instr_list[idx].label;
new_instr[0].has_label = instr_list[idx].has_label;
foreach (i, instr; new_instr) {
instr_list[i+idx] = instr;
}
}
else {
if (idx == 0) {
instr_list.pushFront(new_instr[]);
}
else {
instr_list.insert(idx, new_instr[]);
}
}
}
override void insert_instr_stream(riscv_instr[] new_instr, int idx = -1, bool replace = false) {
int current_instr_cnt = cast(int) instr_list.length;
int new_instr_cnt = cast(int) new_instr.length;
if (current_instr_cnt == 0) {
instr_list ~= new_instr;
return;
}
if (idx == -1) {
idx = cast(int) urandom(0, current_instr_cnt);
for (int i=0; i < 10 ; i++) {
if (instr_list[idx].atomic) break;
idx = cast(int) urandom(0, current_instr_cnt);
}
if (instr_list[idx].atomic) {
foreach (k, instr; instr_list) {
if (! instr.atomic) {
idx = cast(int) k;
break;
}
}
if (instr_list[idx].atomic) {
uvm_fatal(get_full_name, format("Cannot inject the instruction"));
}
}
}
else if((idx > current_instr_cnt) || (idx < 0)) {
uvm_error(get_full_name(), format("Cannot insert instr stream at idx %0d", idx));
}
//When replace is 1, the original instruction at this index will be removed. The label of the
//original instruction will be copied to the head of inserted instruction stream.
if (replace) {
new_instr[0].label = instr_list[idx].label;
new_instr[0].has_label = instr_list[idx].has_label;
foreach (i, instr; new_instr) {
instr_list[i+idx] = instr;
}
}
else {
if (idx == 0) {
instr_list.pushFront(new_instr);
}
else {
instr_list.insert(idx, new_instr);
}
}
}
void mixin_directed_instr_list(riscv_instr_stream[] dir_list) {
riscv_instr[] mixed_list;
uint instr_count = cast(uint) instr_list.length;
uint mixed_count = instr_count;
dir_n.length = instr_count;
this.dir_instr_list = dir_list;
foreach (size_t dir_idx, dir_instr; dir_instr_list) {
mixed_count += dir_instr.instr_list.length;
uint rnd_idx = urandom(0, instr_count);
uint next_dir = dir_n[rnd_idx];
if (next_dir == 0)
dir_n[rnd_idx] = cast(uint) (dir_idx + 1);
else {
uint insert_idx = cast(uint) (dir_idx + 1);
riscv_instr_stream instr = dir_instr_list[next_dir-1];
while (instr.next_stream != 0) {
if (rnd_idx % 2 == 0) { // insert at the end of linked list
uint next_idx = instr.next_stream;
instr.next_stream = insert_idx;
insert_idx = next_idx;
}
instr = dir_instr_list[instr.next_stream-1];
}
instr.next_stream = cast(uint) (insert_idx);
}
}
mixed_list.length = mixed_count;
uint n = 0;
foreach (i, instr; instr_list) {
uint next_dir = dir_n[i];
while (next_dir != 0) {
uint next = dir_instr_list[next_dir-1].next_stream;
foreach (dinstr; dir_instr_list[next_dir-1].instr_list) {
mixed_list[n++] = dinstr;
}
next_dir = next;
}
mixed_list[n++] = instr;
}
assert (mixed_count == n);
instr_list = mixed_list;
}
}

View file

@ -0,0 +1,785 @@
/*
* Copyright 2018 Google LLC
* Copyright 2020 Andes Technology Co., Ltd.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Base class for all load/store instruction stream
module riscv.gen.riscv_load_store_instr_lib;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.riscv_instr_pkg: riscv_reg_t, riscv_vreg_t, riscv_instr_name_t,
riscv_instr_group_t, riscv_instr_category_t;
import riscv.gen.target: XLEN, VLEN, supported_isa;
import riscv.gen.riscv_pseudo_instr: riscv_pseudo_instr;
import riscv.gen.isa.riscv_vector_instr: riscv_vector_instr;
import riscv.gen.riscv_directed_instr_lib: riscv_mem_access_stream;
import std.format: format;
import std.algorithm.searching: canFind, minElement, maxElement;
import esdl.rand: rand, constraint, randomize_with;
import esdl.base.rand: urandom;
import esdl.data.queue: Queue;
import esdl.data.bvec: ubvec, toubvec;
import uvm;
class riscv_load_store_base_instr_stream : riscv_mem_access_stream
{
enum locality_e : ubyte {
NARROW,
HIGH,
MEDIUM,
SPARSE
}
@rand uint num_load_store;
@rand uint num_mixed_instr;
@rand int base;
int[] offset;
int[] addr;
riscv_instr[] load_store_instr;
@rand uint data_page_id;
@rand riscv_reg_t rs1_reg;
@rand locality_e locality;
@rand uint max_load_store_offset;
@rand bool use_sp_as_rs1;
mixin uvm_object_utils;
constraint! q{
solve use_sp_as_rs1 before rs1_reg;
} sp_rnd_order_c;
constraint! q{
use_sp_as_rs1 dist [true := 1, false := 2];
if (use_sp_as_rs1 == true) {
rs1_reg == riscv_reg_t.SP;
}
} sp_c;
constraint! q{
rs1_reg !inside [cfg.reserved_regs, reserved_rd, riscv_reg_t.ZERO];
} rs1_c ;
constraint! q{
solve data_page_id before max_load_store_offset;
solve max_load_store_offset before base;
data_page_id < max_data_page_id;
foreach (i, page; data_page) {
if (i == data_page_id) {
max_load_store_offset == page.size_in_bytes;
}
}
base inside [0..max_load_store_offset];
} addr_c;
this(string name = "") {
super(name);
}
void randomize_offset() {
import std.algorithm: min, max;
int offset_, addr_;
offset.length = num_load_store;
addr.length = num_load_store;
if (base < 0 || base >= max_load_store_offset)
assert (false);
for (int i=0; i!=num_load_store; ++i) {
if (locality == locality_e.NARROW) {
offset_ = urandom!q{[]}(max(-16, 0-base), min(16, max_load_store_offset - 1 - base));
}
else if (locality == locality_e.HIGH) {
offset_ = urandom!q{[]}(max(-64, 0-base), min(64, max_load_store_offset - 1 - base));
}
else if (locality == locality_e.MEDIUM) {
offset_ = urandom!q{[]}(max(-256, 0-base), min(256, max_load_store_offset - 1 - base));
}
else if (locality == locality_e.SPARSE) {
offset_ = urandom!q{[]}(max(-2048, 0-base), min(2047, max_load_store_offset - 1 - base));
}
addr_ = base + offset_;
if (addr_ < 0 || addr_ >= max_load_store_offset) assert (false);
offset[i] = offset_;
addr[i] = addr_;
}
}
override void pre_randomize() {
super.pre_randomize();
if (canFind(cfg.reserved_regs, riscv_reg_t.SP) ||
canFind(reserved_rd, riscv_reg_t.SP)) {
use_sp_as_rs1 = false;
rand_mode!q{use_sp_as_rs1}(false);
sp_rnd_order_c.constraint_mode(false);
}
}
override void post_randomize() {
randomize_offset();
// rs1 cannot be modified by other instructions
if (!canFind(reserved_rd, rs1_reg )) {
reserved_rd ~= rs1_reg;
}
gen_load_store_instr();
add_mixed_instr(num_mixed_instr);
add_rs1_init_la_instr(rs1_reg, data_page_id, base);
super.post_randomize();
}
// Generate each load/store instruction
void gen_load_store_instr() {
bool enable_compressed_load_store;
riscv_instr instr;
randomize_avail_regs();
if (((rs1_reg >= riscv_reg_t.S0 && rs1_reg <= riscv_reg_t.A5) ||
rs1_reg == riscv_reg_t.SP) && !cfg.disable_compressed_instr) {
enable_compressed_load_store = true;
}
foreach (i, a; addr) {
// Assign the allowed load/store instructions based on address alignment
// This is done separately rather than a constraint to improve the randomization performance
allowed_instr = [riscv_instr_name_t.LB, riscv_instr_name_t.LBU, riscv_instr_name_t.SB];
if (!cfg.enable_unaligned_load_store) {
if (a % 2 == 0) {
allowed_instr = [riscv_instr_name_t.LH, riscv_instr_name_t.LHU, riscv_instr_name_t.SH] ~
allowed_instr;
}
if (a % 4 == 0) {
allowed_instr = [riscv_instr_name_t.LW, riscv_instr_name_t.SW] ~ allowed_instr;
if (cfg.enable_floating_point) {
allowed_instr = [riscv_instr_name_t.FLW, riscv_instr_name_t.FSW] ~ allowed_instr;
}
if ((offset[i] >= 0 && offset[i] <= 127) && (offset[i] % 4 == 0) &&
(canFind(supported_isa ,riscv_instr_group_t.RV32C)) &&
enable_compressed_load_store) {
if (rs1_reg == riscv_reg_t.SP) {
uvm_info(get_full_name(), "Add LWSP/SWSP to allowed instr", UVM_LOW);
allowed_instr = [riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_SWSP];
}
else {
allowed_instr = [riscv_instr_name_t.C_LW, riscv_instr_name_t.C_SW] ~ allowed_instr;
if (cfg.enable_floating_point && (canFind(supported_isa, riscv_instr_group_t.RV32FC ))) {
allowed_instr = [riscv_instr_name_t.C_FLW, riscv_instr_name_t.C_FSW] ~ allowed_instr;
}
}
}
}
if ((XLEN >= 64) && (a % 8 == 0)) {
allowed_instr = [riscv_instr_name_t.LWU, riscv_instr_name_t.LD, riscv_instr_name_t.SD] ~
allowed_instr;
if (cfg.enable_floating_point && (canFind(supported_isa, riscv_instr_group_t.RV32D ))) {
allowed_instr = [riscv_instr_name_t.FLD, riscv_instr_name_t.FSD] ~ allowed_instr;
}
if ((offset[i] >= 0 && offset[i] <= 255) && (offset[i] % 8 == 0) &&
(canFind(supported_isa, riscv_instr_group_t.RV64C) &&
enable_compressed_load_store)) {
if (rs1_reg == riscv_reg_t.SP) {
allowed_instr = [riscv_instr_name_t.C_LDSP, riscv_instr_name_t.C_SDSP];
}
else {
allowed_instr = [riscv_instr_name_t.C_LD, riscv_instr_name_t.C_SD] ~ allowed_instr;
if (cfg.enable_floating_point && (canFind(supported_isa, riscv_instr_group_t.RV32DC))) {
allowed_instr = [riscv_instr_name_t.C_FLD, riscv_instr_name_t.C_FSD] ~ allowed_instr;
}
}
}
}
}
else { // unaligned load/store
allowed_instr = [riscv_instr_name_t.LW, riscv_instr_name_t.SW, riscv_instr_name_t.LH,
riscv_instr_name_t.LHU, riscv_instr_name_t.SH] ~ allowed_instr;
// Compressed load/store still needs to be aligned
if ((offset[i] >= 0 && offset[i] <= 127) && (offset[i] % 4 == 0) &&
(canFind(supported_isa, riscv_instr_group_t.RV32C )) &&
enable_compressed_load_store) {
if (rs1_reg == riscv_reg_t.SP) {
allowed_instr = [riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_SWSP];
}
else {
allowed_instr = [riscv_instr_name_t.C_LW, riscv_instr_name_t.C_SW] ~ allowed_instr;
}
}
if (XLEN >= 64) {
allowed_instr = [riscv_instr_name_t.LWU, riscv_instr_name_t.LD, riscv_instr_name_t.SD] ~
allowed_instr;
if ((offset[i] >= 0 && offset[i] <= 255) && (offset[i] % 8 == 0) &&
(canFind(supported_isa, riscv_instr_group_t.RV64C)) &&
enable_compressed_load_store) {
if (rs1_reg == riscv_reg_t.SP) {
allowed_instr = [riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_SWSP];
}
else {
allowed_instr = [riscv_instr_name_t.C_LD, riscv_instr_name_t.C_SD] ~ allowed_instr;
}
}
}
}
instr = cfg.instr_registry.get_load_store_instr(allowed_instr);
instr.has_rs1 = false;
instr.has_imm = false;
randomize_gpr(instr);
instr.rs1 = rs1_reg;
instr.imm_str = format("%0d", offset[i]); // $signed(offset[i]));
instr.process_load_store = 0;
append_instr(instr);
load_store_instr ~= instr;
}
}
}
// A single load/store instruction
class riscv_single_load_store_instr_stream : riscv_load_store_base_instr_stream
{
constraint! q{
num_load_store == 1;
num_mixed_instr < 5;
} legal_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
}
// Back to back load/store instructions
class riscv_load_store_stress_instr_stream : riscv_load_store_base_instr_stream
{
uint max_instr_cnt = 30;
uint min_instr_cnt = 10;
constraint! q{
num_load_store inside [min_instr_cnt:max_instr_cnt];
num_mixed_instr == 0;
} legal_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
}
// Back to back load/store instructions
class riscv_load_store_shared_mem_stream : riscv_load_store_stress_instr_stream
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void pre_randomize() {
load_store_shared_memory = 1;
super.pre_randomize();
}
}
// Random load/store sequence
// A random mix of load/store instructions and other instructions
class riscv_load_store_rand_instr_stream : riscv_load_store_base_instr_stream
{
constraint! q{
num_load_store inside [10:30];
num_mixed_instr inside [10:30];
} legal_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
}
// Use a small set of GPR to create various WAW, RAW, WAR hazard scenario
class riscv_hazard_instr_stream : riscv_load_store_base_instr_stream
{
uint num_of_avail_regs = 6;
constraint! q{
num_load_store inside [10:30];
num_mixed_instr inside [10:30];
} legal_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void pre_randomize() {
avail_regs.length = num_of_avail_regs;
super.pre_randomize();
}
}
// Use a small set of address to create various load/store hazard sequence
// This instruction stream focus more on hazard handling of load store unit.
class riscv_load_store_hazard_instr_stream : riscv_load_store_base_instr_stream
{
@rand int hazard_ratio;
constraint! q{
hazard_ratio inside [20:100];
} hazard_ratio_c;
constraint! q{
num_load_store inside [10:20];
num_mixed_instr inside [1:7];
} legal_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void randomize_offset() {
import std.algorithm: min, max;
int offset_, addr_;
offset.length = num_load_store;
addr.length = num_load_store;
if (base < 0 || base > max_load_store_offset)
assert (false);
for (int i=0; i!=num_load_store; ++i) {
if ((i > 0) && (urandom(0, 100) < hazard_ratio)) {
offset[i] = offset[i-1];
addr[i] = addr[i-1];
}
else {
if (locality == locality_e.NARROW) {
offset_ = urandom!q{[]}(max(-16, 0-base), min(16, max_load_store_offset - 1 - base));
}
else if (locality == locality_e.HIGH) {
offset_ = urandom!q{[]}(max(-64, 0-base), min(64, max_load_store_offset - 1 - base));
}
else if (locality == locality_e.MEDIUM) {
offset_ = urandom!q{[]}(max(-256, 0-base), min(256, max_load_store_offset - 1 - base));
}
else if (locality == locality_e.SPARSE) {
offset_ = urandom!q{[]}(max(-2048, 0-base), min(2047, max_load_store_offset - 1 - base));
}
addr_ = base + offset_;
if (addr_ < 0 || addr_ >= max_load_store_offset) assert (false);
offset[i] = offset_;
addr[i] = addr_;
}
}
}
}
// Back to back access to multiple data pages
// This is useful to test data TLB switch and replacement
class riscv_multi_page_load_store_instr_stream: riscv_mem_access_stream
{
mixin uvm_object_utils;
riscv_load_store_stress_instr_stream[] load_store_instr_stream;
@rand uint num_of_instr_stream;
@rand uint[] data_page_id;
@rand riscv_reg_t[] rs1_reg;
constraint! q{
foreach (id; data_page_id) {
id < max_data_page_id;
}
data_page_id.length == num_of_instr_stream;
rs1_reg.length == num_of_instr_stream;
unique [rs1_reg];
foreach(id; rs1_reg) {
id !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
}
} default_c;
constraint! q{
// solve num_of_instr_stream before data_page_id;
num_of_instr_stream inside [1 : max_data_page_id];
unique [data_page_id];
} page_c;
// Avoid accessing a large number of pages because we may run out of registers for rs1
// Each page access needs a reserved register as the base address of load/store instruction
constraint! q{
num_of_instr_stream inside [2:8];
} reasonable_c;
this(string name = "") {
super(name);
}
// Generate each load/store seq, and mix them together
override void post_randomize() {
load_store_instr_stream.length = num_of_instr_stream;
foreach(i, ref instr; load_store_instr_stream) {
instr = riscv_load_store_stress_instr_stream.type_id.
create(format("load_store_instr_stream_%0d", i));
instr.min_instr_cnt = 5;
instr.max_instr_cnt = 10;
instr.cfg = cfg;
instr.hart = hart;
instr.sp_c.constraint_mode(false);
// Make sure each load/store sequence doesn't override the rs1 of other sequences.
foreach(j , ref l; rs1_reg) {
if(i != j) {
instr.reserved_rd =
(instr.reserved_rd ~ l);
}
}
instr.randomize_with! q{
rs1_reg == $0;
data_page_id == $1;
} (rs1_reg[i], data_page_id[i]);
if (i == 0) {
instr_list = instr.instr_list;
}
else {
mix_instr_stream(instr.instr_list);
}
}
}
}
// Access the different locations of the same memory regions
class riscv_mem_region_stress_test: riscv_multi_page_load_store_instr_stream
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
constraint! q{
num_of_instr_stream inside [2..5];
foreach (i, id; data_page_id) {
if (i > 0) {
data_page_id[i] == data_page_id[i-1];
}
}
} page_c;
}
// Random load/store sequence to full address range
// The address range is not preloaded with data pages, use store instruction to initialize first
class riscv_load_store_rand_addr_instr_stream : riscv_load_store_base_instr_stream
{
@rand ubvec!XLEN addr_offset;
// Find an unused 4K page from address 1M onward
constraint! q{
addr_offset[XLEN-1:20] != 0;
// TODO(taliu) Support larger address range
addr_offset[XLEN-1:31] == 0;
addr_offset[11:0] == 0;
} addr_offset_c;
constraint! q{
num_load_store inside [5:10];
num_mixed_instr inside [5:10];
} legal_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void randomize_offset() {
// import std.conv: to;
offset.length = num_load_store;
addr.length = num_load_store;
for (int i=0; i<num_load_store; i++) {
offset[i] = urandom(-2048, 2048);
addr[i] = cast(int) addr_offset + offset[i];
}
}
override void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0) {
Queue!riscv_instr instr;
riscv_pseudo_instr li_instr;
riscv_instr store_instr;
riscv_instr add_instr;
int[] min_offset;
int[] max_offset;
min_offset ~= offset.minElement;
max_offset ~= offset.maxElement;
// Use LI to initialize the address offset
li_instr = riscv_pseudo_instr.type_id.create("li_instr");
//DV_CHECK_RANDOMIZE_WITH_FATAL(li_instr,
li_instr.randomize_with! q{
pseudo_instr_name == riscv_pseudo_instr_name_t.LI;
rd inside [$0];
rd != $1;
} (cfg.gpr, gpr);
li_instr.imm_str = format("0x%0x", addr_offset);
// Add offset to the base address
add_instr = cfg.instr_registry.get_instr(riscv_instr_name_t.ADD);
//`DV_CHECK_RANDOMIZE_WITH_FATAL(add_instr,
add_instr.randomize_with! q{
rs1 == $0;
rs2 == $1;
rd == $0;
}(gpr, li_instr.rd);
instr ~= li_instr;
instr ~= add_instr;
// Create SW instruction template
store_instr = cfg.instr_registry.get_instr(riscv_instr_name_t.SB);
//`DV_CHECK_RANDOMIZE_WITH_FATAL(store_instr,
store_instr.randomize_with! q{
instr_name == riscv_instr_name_t.SB;
rs1 == $0;
}(gpr);
// Initialize the location which used by load instruction later
foreach (i, lsinstr; load_store_instr) {
if (lsinstr.category == riscv_instr_category_t.LOAD) {
riscv_instr store;
store = riscv_instr.type_id.create("store");
store.copy(store_instr);
store.rs2 = cast(riscv_reg_t) ((cast(int) i) % 32);
store.imm_str = lsinstr.imm_str;
// TODO: C_FLDSP is in both rv32 and rv64 ISA
switch (lsinstr.instr_name) {
case riscv_instr_name_t.LB,
riscv_instr_name_t.LBU:
store.instr_name = riscv_instr_name_t.SB;
break;
case riscv_instr_name_t.LH,
riscv_instr_name_t.LHU :
store.instr_name = riscv_instr_name_t.SH;
break;
case riscv_instr_name_t.LW,
riscv_instr_name_t.C_LW,
riscv_instr_name_t.C_LWSP,
riscv_instr_name_t.FLW,
riscv_instr_name_t.C_FLW,
riscv_instr_name_t.C_FLWSP:
store.instr_name = riscv_instr_name_t.SW;
break;
case riscv_instr_name_t.LD,
riscv_instr_name_t.C_LD,
riscv_instr_name_t.C_LDSP,
riscv_instr_name_t.FLD,
riscv_instr_name_t.C_FLD,
riscv_instr_name_t.LWU:
store.instr_name = riscv_instr_name_t.SD;
break;
default: uvm_fatal(get_full_name(), format("Unexpected op: %0s",
lsinstr.convert2asm()));
break;
}
instr ~= store;
}
}
prepend_instr_list(instr);
super.add_rs1_init_la_instr(gpr, id, 0);
}
}
class riscv_vector_load_store_instr_stream : riscv_mem_access_stream
{
enum address_mode_e {UNIT_STRIDED, STRIDED, INDEXED}
@rand ubvec!11 eew;
@rand uint data_page_id;
@rand uint num_mixed_instr;
@rand uint stride_byte_offset;
@rand uint index_addr;
@rand address_mode_e address_mode;
@rand riscv_reg_t rs1_reg; // Base address
@rand riscv_reg_t rs2_reg; // Stride offset
riscv_vreg_t vs2_reg; // Index address
constraint! q{
num_mixed_instr inside [0:10];
} vec_mixed_instr_c;
constraint! q{
solve eew before stride_byte_offset;
// Keep a reasonable byte offset range to avoid vector memory address overflow
stride_byte_offset inside [1 : 128];
stride_byte_offset % (eew / 8) == 1;
} stride_byte_offset_c;
constraint! q{
solve eew before index_addr;
// Keep a reasonable index address range to avoid vector memory address overflow
index_addr inside [1 : 128];
index_addr % (eew / 8) == 1;
} index_addr_c;
constraint! q{
rs1_reg !inside [cfg.reserved_regs, reserved_rd, riscv_reg_t.ZERO];
rs2_reg !inside [cfg.reserved_regs, reserved_rd, riscv_reg_t.ZERO];
rs1_reg != rs2_reg;
} vec_rs_c;
constraint! q{
data_page_id < max_data_page_id;
} vec_data_page_id_c;
int base;
int max_load_store_addr;
riscv_vector_instr load_store_instr;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void post_randomize() {
reserved_rd ~= rs1_reg;
reserved_rd ~= rs2_reg;
randomize_avail_regs();
gen_load_store_instr();
randomize_addr();
add_mixed_instr(num_mixed_instr);
add_rs1_init_la_instr(rs1_reg, data_page_id, base);
if (address_mode == address_mode_e.STRIDED) {
this.append_instr(get_init_gpr_instr(rs2_reg, toubvec!64(stride_byte_offset)));
}
else if (address_mode == address_mode_e.INDEXED) {
// TODO: Support different index address for each element
add_init_vector_gpr_instr(vs2_reg, toubvec!64(index_addr));
}
super.post_randomize();
}
void randomize_addr() {
int ss = address_span();
bool success;
for (int i=0; i<10; ++i) {
max_load_store_addr = data_page[data_page_id].size_in_bytes - ss;
if (max_load_store_addr >= 0) {
success = true;
break;
}
//DV_CHECK_STD_RANDOMIZE_WITH_FATAL(data_page_id, data_page_id < max_data_page_id;)
assert (max_data_page_id != 0);
data_page_id = urandom(0, max_data_page_id);
}
if (success != true) {
uvm_fatal(get_full_name(), format(("Expected positive value for max_load_store_addr, got %0d." ~
" Perhaps more memory needs to be allocated in the data pages for vector loads and stores." ~
"\ndata_page_id:%0d\ndata_page[data_page_id].size_in_bytes:%0d\naddress_span:%0d" ~
"\nstride_bytes:%0d\nVLEN:%0d\nLMUL:%0d\ncfg.vector_cfg.vtype.vsew:%0d\n\n"),
max_load_store_addr, data_page_id, data_page[data_page_id].size_in_bytes, ss,
stride_bytes(), VLEN,
cfg.vector_cfg.vtype.vlmul, cfg.vector_cfg.vtype.vsew));
}
// `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(base, base >= 0; base <= max_load_store_addr;)
base = urandom!q{[]}(0, max_load_store_addr);
base = (cast(int) eew) * base/(cast(int) eew);
}
int address_span() {
int num_elements = VLEN * cfg.vector_cfg.vtype.vlmul / cfg.vector_cfg.vtype.vsew;
switch (address_mode) {
case (address_mode_e.UNIT_STRIDED) : return num_elements * stride_bytes();
case (address_mode_e.STRIDED) : return num_elements * stride_byte_offset;
case (address_mode_e.INDEXED) : return index_addr + num_elements * stride_bytes();
default : return 0 ;
}
}
int stride_bytes() {
return cast(int) eew / 8;
}
// Generate each load/store instruction
void gen_load_store_instr() {
build_allowed_instr();
randomize_vec_load_store_instr();
this.append_instr(load_store_instr);
}
void build_allowed_instr() {
switch (address_mode) {
case address_mode_e.UNIT_STRIDED:
allowed_instr = [riscv_instr_name_t.VLE_V, riscv_instr_name_t.VSE_V] ~ allowed_instr;
if (cfg.vector_cfg.enable_fault_only_first_load) {
allowed_instr = [riscv_instr_name_t.VLEFF_V] ~ allowed_instr;
}
if (cfg.vector_cfg.enable_zvlsseg) {
allowed_instr = [riscv_instr_name_t.VLSEGE_V, riscv_instr_name_t.VSSEGE_V] ~ allowed_instr;
if (cfg.vector_cfg.enable_fault_only_first_load) {
allowed_instr = [riscv_instr_name_t.VLSEGEFF_V] ~ allowed_instr;
}
}
break;
case address_mode_e.STRIDED:
allowed_instr = [riscv_instr_name_t.VLSE_V, riscv_instr_name_t.VSSE_V] ~ allowed_instr;
if (cfg.vector_cfg.enable_zvlsseg) {
allowed_instr = [riscv_instr_name_t.VLSSEGE_V, riscv_instr_name_t.VSSSEGE_V] ~ allowed_instr;
}
break;
case address_mode_e.INDEXED:
allowed_instr = [riscv_instr_name_t.VLXEI_V, riscv_instr_name_t.VSXEI_V,
riscv_instr_name_t.VSUXEI_V] ~ allowed_instr;
if (cfg.vector_cfg.enable_zvlsseg) {
allowed_instr = [riscv_instr_name_t.VLXSEGEI_V, riscv_instr_name_t.VSXSEGEI_V,
riscv_instr_name_t.VSUXSEGEI_V] ~ allowed_instr;
}
break;
default: break;
}
}
void randomize_vec_load_store_instr() {
load_store_instr =
cast(riscv_vector_instr) cfg.instr_registry.get_load_store_instr(allowed_instr);
load_store_instr.m_cfg = cfg;
load_store_instr.has_rs1 = false;
load_store_instr.has_vs2 = true;
load_store_instr.has_imm = false;
randomize_gpr(load_store_instr);
load_store_instr.rs1 = rs1_reg;
load_store_instr.rs2 = rs2_reg;
load_store_instr.vs2 = vs2_reg;
if (address_mode == address_mode_e.INDEXED) {
cfg.vector_cfg.reserved_vregs = [load_store_instr.vs2];
vs2_reg = load_store_instr.vs2;
uvm_info(get_full_name(), format("vs2_reg = v%0d", vs2_reg), UVM_LOW);
}
load_store_instr.process_load_store = 0;
}
}

View file

@ -0,0 +1,257 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// TODO: Support other loop counter update instruction other than ADDI
// TODO: Support forward branch inside the loop
module riscv.gen.riscv_loop_instr;
import riscv.gen.riscv_instr_pkg: riscv_reg_t, riscv_instr_name_t,
riscv_instr_category_t, compressed_gpr;
import riscv.gen.riscv_instr_stream: riscv_rand_instr_stream;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import esdl.rand: rand, constraint, randomize_with;
import esdl.data.bvec: ubvec;
import uvm;
class riscv_loop_instr: riscv_rand_instr_stream
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
@rand riscv_reg_t[] loop_cnt_reg;
@rand riscv_reg_t[] loop_limit_reg;
@rand int[] loop_init_val;
@rand int[] loop_step_val;
@rand int[] loop_limit_val;
@rand ubvec!3 num_of_nested_loop;
@rand int num_of_instr_in_loop;
@rand riscv_instr_name_t[] branch_type;
riscv_instr[] loop_init_instr;
riscv_instr[] loop_update_instr;
riscv_instr[] loop_branch_instr;
riscv_instr[] loop_branch_target_instr;
// Aggregated loop instruction stream
riscv_instr[] loop_instr;
constraint! q{
solve num_of_nested_loop before loop_cnt_reg;
solve num_of_nested_loop before loop_limit_reg;
foreach (lcnt; loop_cnt_reg) {
lcnt != riscv_reg_t.ZERO;
foreach (resr; cfg.reserved_regs) {
lcnt != resr;
}
}
foreach (llimit; loop_limit_reg) {
foreach (resr; cfg.reserved_regs) {
llimit != resr;
}
}
unique [loop_cnt_reg, loop_limit_reg];
loop_cnt_reg.length == num_of_nested_loop;
loop_limit_reg.length == num_of_nested_loop;
} legal_loop_regs_c;
constraint! q{
solve num_of_nested_loop before loop_init_val;
solve num_of_nested_loop before loop_step_val;
solve num_of_nested_loop before loop_limit_val;
solve loop_limit_val before loop_limit_reg;
solve branch_type before loop_init_val;
solve branch_type before loop_step_val;
solve branch_type before loop_limit_val;
num_of_instr_in_loop inside [1:25];
num_of_nested_loop inside [1:2];
loop_init_val.length == num_of_nested_loop;
loop_step_val.length == num_of_nested_loop;
loop_limit_val.length == num_of_nested_loop;
branch_type.length == num_of_nested_loop;
foreach (btype; branch_type) {
if (!cfg.disable_compressed_instr) {
btype inside [riscv_instr_name_t.C_BNEZ, riscv_instr_name_t.C_BEQZ,
riscv_instr_name_t.BEQ, riscv_instr_name_t.BNE,
riscv_instr_name_t.BLTU, riscv_instr_name_t.BLT,
riscv_instr_name_t.BGEU, riscv_instr_name_t.BGE];
}
else {
btype inside [riscv_instr_name_t.BEQ, riscv_instr_name_t.BNE,
riscv_instr_name_t.BLTU, riscv_instr_name_t.BLT,
riscv_instr_name_t.BGEU, riscv_instr_name_t.BGE];
}
}
foreach (i, linit; loop_init_val) {
if (branch_type[i] inside [riscv_instr_name_t.C_BNEZ, riscv_instr_name_t.C_BEQZ]) {
loop_limit_val[i] == 0;
// loop_limit_reg[i] == riscv_reg_t.ZERO; // handled in post_randomize
loop_cnt_reg[i] inside [compressed_gpr]; // TBD -- FIXME -- EUVM
}
else {
loop_limit_val[i] inside [-20..20];
loop_limit_reg[i] != riscv_reg_t.ZERO;
}
if (branch_type[i] inside [riscv_instr_name_t.C_BNEZ, riscv_instr_name_t.C_BEQZ,
riscv_instr_name_t.BEQ, riscv_instr_name_t.BNE]) {
((loop_limit_val[i] - linit) % loop_step_val[i] == 0) &&
(loop_limit_val[i] != linit);
}
else if (branch_type[i] == riscv_instr_name_t.BGE) {
loop_step_val[i] < 0;
}
else if (branch_type[i] == riscv_instr_name_t.BGEU) {
loop_step_val[i] < 0;
linit > 0;
// Avoid count to negative
loop_step_val[i] + loop_limit_val[i] > 0;
}
else if (branch_type[i] == riscv_instr_name_t.BLT) {
loop_step_val[i] > 0;
}
else if (branch_type[i] == riscv_instr_name_t.BLTU) {
loop_step_val[i] > 0;
loop_limit_val[i] > 0;
}
linit inside [-10..10];
loop_step_val[i] inside [-10..10];
if (linit < loop_limit_val[i]) {
loop_step_val[i] > 0;
}
else {
loop_step_val[i] < 0;
}
}
} loop_c;
void post_randomize() {
reserved_rd = loop_cnt_reg ~ loop_limit_reg;
// Generate instructions that mixed with the loop instructions
initialize_instr_list(num_of_instr_in_loop);
gen_instr(true);
// Randomize the key loop instructions
loop_init_instr.length = num_of_nested_loop*2;
loop_update_instr.length = num_of_nested_loop;
loop_branch_instr.length = num_of_nested_loop;
loop_branch_target_instr.length = num_of_nested_loop;
for (int i = 0; i < num_of_nested_loop; i++) {
if (branch_type[i] == riscv_instr_name_t.C_BNEZ ||
branch_type[i] == riscv_instr_name_t.C_BEQZ) {
loop_limit_reg[i] = riscv_reg_t.ZERO;
}
// Instruction to init the loop counter
loop_init_instr[2*i] =
cfg.instr_registry.get_rand_instr([riscv_instr_name_t.ADDI]);
// `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i],
loop_init_instr[2*i].randomize_with!q{
rd == $0;
rs1 == riscv_reg_t.ZERO;
imm == $1;
} (loop_cnt_reg[i], loop_init_val[i]);
loop_init_instr[2*i].comment = format("init loop %0d counter", i);
// Instruction to init loop limit
loop_init_instr[2*i+1] =
cfg.instr_registry.get_rand_instr([riscv_instr_name_t.ADDI]);
// `DV_CHECK_RANDOMIZE_WITH_FATAL(l,
loop_init_instr[2*i+1].randomize_with! q{
rd == $0;
rs1 == riscv_reg_t.ZERO;
imm == $1;
} (loop_limit_reg[i], loop_limit_val[i]);
loop_init_instr[2*i+1].comment = format("init loop %0d limit", i);
// Branch target instruction, can be anything
loop_branch_target_instr[i] =
cfg.instr_registry.get_rand_instr(null, [riscv_instr_name_t.C_ADDI16SP],
[riscv_instr_category_t.ARITHMETIC,
riscv_instr_category_t.LOGICAL,
riscv_instr_category_t.COMPARE]);
//DV_CHECK_RANDOMIZE_WITH_FATAL(,
loop_branch_target_instr[i].randomize_with! q{
if (instr_format == riscv_instr_format_t.CB_FORMAT) {
rs1 !inside [$0, $1];
}
if (has_rd) {
rd !inside [$0, $1];
}
} (reserved_rd, cfg.reserved_regs);
loop_branch_target_instr[i].label = format("%0s_%0d_t", label, i);
// Instruction to update loop counter
loop_update_instr[i] =
cfg.instr_registry.get_rand_instr([riscv_instr_name_t.ADDI]);
//DV_CHECK_RANDOMIZE_WITH_FATAL(],
loop_update_instr[i].randomize_with! q{
rd == $0;
rs1 == $0;
imm == $1;
} (loop_cnt_reg[i], loop_step_val[i]);
loop_update_instr[i].comment = format("update loop %0d counter", i);
// Backward branch instruction
loop_branch_instr[i] = cfg.instr_registry.get_rand_instr([branch_type[i]]);
// `DV_CHECK_RANDOMIZE_WITH_FATAL(,
loop_branch_instr[i].randomize_with! q{
rs1 == $0;
if ($1 !inside [riscv_instr_name_t.C_BEQZ,
riscv_instr_name_t.C_BNEZ]) {
rs2 == $2;
}
} (loop_cnt_reg[i], branch_type[i], loop_limit_reg[i]);
loop_branch_instr[i].comment = format("branch for loop %0d", i);
loop_branch_instr[i].imm_str = loop_branch_target_instr[i].label;
loop_branch_instr[i].branch_assigned = true;
}
// Randomly distribute the loop instruction in the existing instruction stream
build_loop_instr_stream();
mix_instr_stream(loop_instr, true);
foreach (instr; instr_list) {
if (instr.label != "")
instr.has_label = true;
else
instr.has_label = false;
instr.atomic = true;
}
}
// Build the whole loop structure from innermost loop to the outermost loop
void build_loop_instr_stream() {
loop_instr.length = 0;
for (int i = 0; i < num_of_nested_loop; i++) {
loop_instr = [loop_init_instr[2*i],
loop_init_instr[2*i+1],
loop_branch_target_instr[i],
loop_update_instr[i]] ~
loop_instr ~
loop_branch_instr[i];
}
uvm_info(get_full_name(), format("Totally %0d instructions have been added",
loop_instr.length), UVM_HIGH);
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// RISC-V page table class
// This class is defined based on RISC-V privileged spec 1.10, three page table structure is
// supported: SV32, SV39, SV48
// This class is used by riscv_page_table_list to generate all page tables the program
module riscv.gen.riscv_page_table;
import riscv.gen.riscv_instr_pkg: satp_mode_t;
import riscv.gen.riscv_page_table_entry: riscv_page_table_entry;
import riscv.gen.target: XLEN;
import std.string: format;
import esdl.data.bvec: ubvec;
import esdl.rand: rand;
import uvm;
version(CHECK_COMPILE) alias riscv_page_table_SV39 = riscv_page_table!(satp_mode_t.SV39);
class riscv_page_table(satp_mode_t MODE): uvm_object
{
uint num_of_pte; // Number of page table entry
uint table_id; // Page table ID
ubvec!2 level; // Page table level
ubvec!XLEN [] pte_binary; // Page table entry in binary format
@rand riscv_page_table_entry!(MODE)[] pte; // List of all page table// entries
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
// `uvm_object_param_utils(riscv_page_table#(MODE))
// `uvm_object_new
// Init page table
void init_page_table(uint num_of_pte = 1) {
this.num_of_pte = num_of_pte;
pte.length = num_of_pte;
pte_binary.length = num_of_pte;
}
// Generate the page table binary
void gen_page_table_binary() {
foreach (i, p; pte) {
pte_binary[i] = p.bits;
}
}
// Generate the page table section in the output assembly program
// Basically it's like a data section with all PTE binaries.
void gen_page_table_section(out string [] instr) {
string str;
this.gen_page_table_binary();
// Align the page table to 4K boundary
instr = instr ~ ".align 12" ~ format("%0s:", get_name());
foreach (i, pte; pte_binary) {
if (i % 8 == 0) {
if (XLEN == 64) {
str = format(".dword 0x%0x", pte);
}
else {
str = format(".word 0x%0x", pte);
}
}
else {
str = str ~ format(", 0x%0x", pte);
}
if (((i + 1) % 8 == 0) || (i == pte_binary.length - 1)) {
instr ~= str;
}
}
}
}

View file

@ -0,0 +1,251 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//--------------------------------------------------------------------------------------------
// RISC-V Page Table Entry(PTE)
//
// Support SV32, SV39, SV48 PTE format defined in RISC-V privileged spec 1.10.
// -------------------------------------------------------------------------------------------
module riscv.gen.riscv_page_table_entry;
import riscv.gen.riscv_instr_pkg: pte_permission_t, satp_mode_t;
import riscv.gen.target: XLEN;
import std.format: format;
import esdl.data.bvec: ubvec;
import esdl.rand: constraint, rand;
import uvm;
version(CHECK_COMPILE) alias riscv_page_table_entry_SV39 = riscv_page_table_entry!(satp_mode_t.SV39);
class riscv_page_table_entry(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
{
enum int PPN0_WIDTH = (MODE == satp_mode_t.SV32) ? 10 : 9;
enum int PPN1_WIDTH = (MODE == satp_mode_t.SV32) ? 12 : 9;
enum int PPN2_WIDTH = (MODE == satp_mode_t.SV39) ? 26 : ((MODE == satp_mode_t.SV48) ? 9 : 1);
enum int PPN3_WIDTH = (MODE == satp_mode_t.SV48) ? 9 : 1;
enum int RSVD_WIDTH = (MODE == satp_mode_t.SV32) ? 1 : 10;
enum int VPN_WIDTH = (MODE == satp_mode_t.SV32) ? 10 : 9;
// Spare bits in virtual address = XLEN - used virtual address bits
enum int VADDR_SPARE = (MODE == satp_mode_t.SV32) ? 0 : (MODE == satp_mode_t.SV39) ? 25 : 16;
// Virtual address bit width
enum int VADDR_WIDTH = (MODE == satp_mode_t.SV32) ? 31 : (MODE == satp_mode_t.SV39) ? 38 : 48;
mixin uvm_object_utils;
//`uvm_object_param_utils(riscv_page_table_entry#(MODE))
//`uvm_object_new
this(string name = "") {
super(name);
}
@rand bool v; // PTE is valid
@rand pte_permission_t xwr; // PTE execute-write-read permission
@rand bool u; // Accessible in User Mode
@rand bool g; // Gloabal mapping
@rand bool a; // Accessed flag
@rand bool d; // Dirty flag
@rand ubvec!2 rsw; // Reserved for future use
@rand ubvec!PPN0_WIDTH ppn0;
@rand ubvec!PPN1_WIDTH ppn1;
@rand ubvec!PPN2_WIDTH ppn2;
@rand ubvec!PPN3_WIDTH ppn3;
@rand ubvec!XLEN bits;
@rand ubvec!RSVD_WIDTH rsvd;
int child_table_id;
ubvec!XLEN starting_pa; // Starting physical address
ubvec!XLEN starting_va; // Starting virtual address offset
// This two bits are implementation specific, set them to 1 to avoid mismatching
constraint! q{
@soft a == true;
@soft d == true;
} access_dirty_bit_c;
// Set reserved fields to 0
constraint! q{
@soft rsw == 0;
@soft rsvd == 0;
} reserved_bits_c;
// PPN is assigned in the post-process
constraint! q{
@soft ppn0 == 0;
@soft ppn1 == 0;
@soft ppn2 == 0;
@soft ppn3 == 0;
} ppn_zero_c;
constraint! q{
// If the PTE is not a leaf page, U,A,D must be cleared by SW for future compatibility
if (xwr == pte_permission_t.NEXT_LEVEL_PAGE) {
u == false;
a == false;
d == false;
}
} sw_legal_c;
void turn_off_default_constraint() {
access_dirty_bit_c.constraint_mode(false);
reserved_bits_c.constraint_mode(false);
ppn_zero_c.constraint_mode(false);
sw_legal_c.constraint_mode(false);
}
void post_randomize() {
pack_entry();
}
override void do_copy(uvm_object rhs) {
super.do_copy(rhs);
riscv_page_table_entry!(MODE) rhs_ =
cast(riscv_page_table_entry!MODE) rhs;
//`DV_CHECK_FATAL($cast(rhs_, rhs), "Cast to page_table_entry failed!")
this.v = rhs_.v;
this.xwr = rhs_.xwr;
this.u = rhs_.u;
this.g = rhs_.g;
this.a = rhs_.a;
this.d = rhs_.d;
this.rsw = rhs_.rsw;
this.ppn0 = rhs_.ppn0;
this.ppn1 = rhs_.ppn1;
this.ppn2 = rhs_.ppn2;
this.ppn3 = rhs_.ppn3;
this.bits = rhs_.bits;
this.rsvd = rhs_.rsvd;
this.starting_pa = rhs_.starting_pa;
this.starting_va = rhs_.starting_va;
this.child_table_id = rhs_.child_table_id;
}
override string convert2string() {
string str = format("xwr: %0s, (v)alid:%0d, u: %0d, pa:0x%0x, va:0x%0x",
xwr, v, u, starting_pa, starting_va);
switch (MODE) {
case satp_mode_t.SV32:
str = str ~ format(", ppn[1:0] = %0d/%0d", ppn1, ppn0);
break;
case satp_mode_t.SV39:
str = str ~ format(", ppn[2:0] = %0d/%0d/%0d", ppn2, ppn1, ppn0);
break;
case satp_mode_t.SV48 :
str = str ~ format(", ppn[3:0] = %0d/%0d/%0d/%0d", ppn3, ppn2, ppn1, ppn0);
break;
default:
uvm_fatal(get_full_name(), format("Unsupported mode %0x", MODE));
break;
}
return str;
}
// Pack the PTE to bit stream
void pack_entry() {
switch (MODE) {
case satp_mode_t.SV32:
bits = ppn1 ~ ppn0 ~ rsw ~ d ~ a ~ g ~ u ~ xwr ~ v;
break;
case satp_mode_t.SV39:
bits = cast(ubvec!XLEN) (rsvd ~ ppn2 ~ ppn1 ~ ppn0 ~ rsw ~ d ~ a ~ g ~ u ~ xwr ~ v);
break;
case satp_mode_t.SV48:
bits = cast(ubvec!XLEN) (rsvd ~ ppn3 ~ ppn2 ~ ppn1 ~ ppn0 ~ rsw ~ d ~ a ~ g ~ u ~ xwr ~ v);
break;
default:
uvm_fatal(get_full_name(), format("Unsupported mode %0x", MODE));
break;
}
}
// Return the PPN field offset based on the page level
int get_ppn_offset(ubvec!2 page_level) {
switch (page_level) {
case 0:
return 0;
case 1:
return PPN0_WIDTH;
case 2:
return PPN0_WIDTH + PPN1_WIDTH;
case 3:
return PPN0_WIDTH + PPN1_WIDTH + PPN2_WIDTH;
default: uvm_fatal(get_full_name(),
format("Unsupported page_level %0x", page_level));
assert (false);
}
}
// Assign each PPN field based on the input physical address. This function //is used to setup the
// leaf PTE to map to the target physical address.
// start_pa : Start phyical address.
// pte_index : The PTE index of the input page level.
// page_level : The page level that this PTE belongs to.
void set_ppn(ubvec!XLEN base_pa, int pte_index, ubvec!2 page_level) {
int[4] pte_incr;
int pte_per_table = 4096 / (XLEN/8);
ppn0 = cast(ubvec!PPN0_WIDTH) (base_pa[12 .. 12 + PPN0_WIDTH]);
ppn1 = cast(ubvec!PPN1_WIDTH) (base_pa[12 + PPN0_WIDTH ..12 + PPN0_WIDTH + PPN1_WIDTH]);
if (MODE == satp_mode_t.SV39) {
ppn2 = cast(ubvec!PPN2_WIDTH) (base_pa[12 + PPN0_WIDTH + PPN1_WIDTH ..12 + PPN0_WIDTH + PPN1_WIDTH+ PPN2_WIDTH]);
}
else if (MODE == satp_mode_t.SV48) {
ppn2 = cast(ubvec!PPN2_WIDTH) (base_pa[12 + PPN0_WIDTH + PPN1_WIDTH .. 12 + PPN0_WIDTH + PPN1_WIDTH + PPN2_WIDTH]);
ppn3 = cast(ubvec!PPN3_WIDTH) (base_pa[12 + PPN0_WIDTH + PPN1_WIDTH + PPN2_WIDTH ..12 + PPN0_WIDTH + PPN1_WIDTH + PPN2_WIDTH+ PPN3_WIDTH]);
}
foreach (i; pte_incr) {
if (i >= page_level) {
pte_incr[i] = pte_index % pte_per_table;
pte_index = pte_index / pte_per_table;
}
}
ppn0 += pte_incr[0];
ppn1 += pte_incr[1];
ppn2 += pte_incr[2];
ppn3 += pte_incr[3];
starting_pa = get_starting_pa();
starting_va = starting_pa - base_pa;
}
// Get the starting physical address covered by this PTE
ubvec!XLEN get_starting_pa() {
ubvec!XLEN retval;
switch(MODE) {
case satp_mode_t.SV32:
retval = ppn1 ~ ppn0;
break;
case satp_mode_t.SV39:
retval = ppn2 ~ ppn1 ~ ppn0;
break;
case satp_mode_t.SV48:
retval = ppn3 ~ ppn2 ~ ppn1 ~ ppn0;
break;
default:
uvm_fatal(get_full_name(),
format("Unsupported mode %0x", MODE));
break;
}
retval <<= 12;
return retval;
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.riscv_page_table_exception_cfg;
import esdl.rand: constraint, rand;
import uvm;
class riscv_page_table_exception_cfg : uvm_object
{
mixin uvm_object_utils ;
this(string name = "") {
super(name);
}
bool enable_exception;
// Knobs for each type of exception
@rand bool allow_page_access_control_exception;
@rand bool allow_superpage_misaligned_exception;
@rand bool allow_leaf_link_page_exception;
@rand bool allow_invalid_page_exception;
@rand bool allow_privileged_mode_exception;
@rand bool allow_zero_access_bit_exception;
@rand bool allow_zero_dirty_bit_exception;
// Exception ratio control
uint page_access_fault_ratio = 10;
uint misaligned_superpage_ratio = 10;
uint leaf_link_page_ratio = 10;
uint invalid_page_ratio = 10;
uint privl_mode_fault_ratio = 10;
uint zero_access_fault_ratio = 5;
uint zero_dirty_fault_ratio = 5;
constraint! q{
if (enable_exception == true) {
allow_page_access_control_exception dist
[ true := page_access_fault_ratio,
false := 100 - page_access_fault_ratio ];
allow_superpage_misaligned_exception dist
[ true := misaligned_superpage_ratio,
false := 100 - misaligned_superpage_ratio ];
allow_leaf_link_page_exception dist
[ true := leaf_link_page_ratio,
false := 100 - leaf_link_page_ratio ];
allow_invalid_page_exception dist
[ true := invalid_page_ratio,
false := 100 - invalid_page_ratio ];
allow_privileged_mode_exception dist
[ true := privl_mode_fault_ratio,
false := 100 - privl_mode_fault_ratio ];
allow_zero_access_bit_exception dist
[ true := zero_access_fault_ratio,
false := 100 - zero_access_fault_ratio ];
allow_zero_dirty_bit_exception dist
[ true := zero_dirty_fault_ratio,
false := 100 - zero_dirty_fault_ratio ];
}
else {
allow_page_access_control_exception == false;
allow_superpage_misaligned_exception == false;
allow_leaf_link_page_exception == false;
allow_invalid_page_exception == false;
allow_privileged_mode_exception == false;
allow_zero_access_bit_exception == false;
allow_zero_dirty_bit_exception == false;
}
} exception_ratio_c;
}

View file

@ -0,0 +1,584 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//----------------------------------------------------------------------------------------------
// Complete RISC-V page table generator
//
// This class is used to generate all the page tables and link them together.
// Below features are supported:
// - Multiple PTEs for each page table
// - Multiple tables at each level(except for root table)
// - Mixed leaf entry and non-leaf entry at any level
// - Allow injecting page table exceptions for any PTE
//----------------------------------------------------------------------------------------------
module riscv.gen.riscv_page_table_list;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t, riscv_reg_t,
privileged_reg_t, pte_permission_t, pop_gpr_from_kernel_stack,
MAX_USED_VADDR_BITS, MPRV_BIT_MASK;
import riscv.gen.target: XLEN, SATP_MODE;
import riscv.gen.riscv_page_table_exception_cfg: riscv_page_table_exception_cfg;
import riscv.gen.riscv_page_table_entry: riscv_page_table_entry;
import riscv.gen.riscv_page_table: riscv_page_table;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import std.string: format;
import esdl.data.bvec: ubvec, clog2;
import esdl.rand: constraint, rand, randomize_with, randomize;
import uvm;
version(CHECK_COMPILE) alias riscv_page_table_list_SV39 = riscv_page_table_list!(satp_mode_t.SV39);
class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
{
mixin uvm_object_utils;
enum int PteSize = XLEN / 8;
enum int PteCnt = 4096 / PteSize;
enum int PageLevel = (MODE == satp_mode_t.SV32) ? 2 : ((MODE == satp_mode_t.SV39) ? 3 : 4);
enum int LinkPtePerTable = 2;
enum int SuperLeafPtePerTable = 2;
satp_mode_t mode = MODE;
// Privileged mode of the program
privileged_mode_t privileged_mode = privileged_mode_t.USER_MODE;
// Starting physical address of the program.
ubvec!XLEN start_pa = 0x80000000;
// Num of page table per level
uint[] num_of_page_table;
// Page table list, from highest level to the lowest level
riscv_page_table!(MODE)[] page_table;
// Root page table PTE idx for the init code entry
uint root_init_pte_idx;
// Instruction generator configuration
riscv_instr_gen_config cfg;
// Allow exception or not
bool enable_exception;
riscv_page_table_exception_cfg exception_cfg;
// Valid PTE entry for exception recovery
riscv_page_table_entry!(MODE) valid_leaf_pte;
riscv_page_table_entry!(MODE) valid_link_pte;
riscv_page_table_entry!(MODE) valid_data_leaf_pte;
riscv_page_table_entry!(MODE) illegal_pte;
// Registers used for page table exception handling
@rand riscv_reg_t level_reg;
@rand riscv_reg_t fault_vaddr_reg;
@rand riscv_reg_t pte_addr_reg;
@rand riscv_reg_t pte_reg;
@rand riscv_reg_t tmp_reg;
@rand riscv_reg_t mask_reg;
@rand riscv_reg_t mpp_reg;
constraint! q{
unique [level_reg, fault_vaddr_reg, pte_addr_reg,
pte_reg, tmp_reg, mask_reg, mpp_reg];
level_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
fault_vaddr_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
pte_addr_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
pte_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
mask_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
mpp_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
tmp_reg !inside [cfg.reserved_regs, riscv_reg_t.ZERO];
} page_table_exception_handling_reg_c ;
this(string name = "") {
super(name);
default_page_table_setting();
exception_cfg = riscv_page_table_exception_cfg.type_id.create("exception_cfg");
valid_leaf_pte = riscv_page_table_entry!(MODE).type_id.create("valid_leaf_pte");
valid_link_pte = riscv_page_table_entry!(MODE).type_id.create("valid_link_pte");
valid_data_leaf_pte = riscv_page_table_entry!(MODE).type_id.create("valid_data_leaf_pte");
illegal_pte = riscv_page_table_entry!(MODE).type_id.create("illegal_pte");
}
// To avoid large numbers of page tables, by default we limit the number of non-leaf PTE
// at higher level. To be more specific, all PTEs of level 0 page table is leaf PTE. For
// higher level page table, only PTE[0] and PTE[1] is non-leaf PTE, all other PTEs are leaf
// PTE. All leaf PTE should have PPN map to the real physical address of the instruction
// or data. For non-leaf PTE, the PPN should map to the physical address of the next PTE.
// Take SV39 for example: (PteSize = 8B)
// Table size is 4KB, PteSize=8B, entry count = 4K/8 = 512
// Level 2: Root table, 2 entries, PTE[0] and PTE[1] is non-leaf PTE, PTE[2] is leaf PTE, all
// other PTEs are invalid, totalling 1 page table with 3 PTEs at this level.
// Level 1: Two page tables, map to PTE[0] and PTE[1] of the root table.
// Each table has 512 entries, PTE[0], PTE[1] are non-leaf PTE, cover 4MB memory
// space. PTE[2:511] are leaf PTE, cover 510 * 2MB memory space.
// Level 0: 4 page tables at this level(map to PTE[0] and PTE[1] of the previous level),
// each table has 512 leaf PTE.
// In summary, 7(1+2+4) tables are needed for SV39.
// Similarly, 3 (1+2) page tables for SV32, 15 (1 + 2 + 4 + 8) page tables for SV48.
// Note:
// - The number of randomization call is optimized to improve performance
// - PPN assignment is done at program run time
void randomize_page_table() {
int pte_index;
exception_cfg.enable_exception = enable_exception;
create_valid_pte();
foreach (i, ptbl; page_table) {
uvm_info(get_full_name(), format("Randomizing page table %0d, num of PTE: %0d",
i, ptbl.pte.length), UVM_LOW);
if (i == 0) {
pte_index = 0;
}
else if(ptbl.level != page_table[i-1].level) {
pte_index = 0;
}
foreach (j, ref entry; ptbl.pte) {
if (ptbl.level > 0) {
// Superpage
if (j < LinkPtePerTable) {
entry = cast(riscv_page_table_entry!MODE) valid_link_pte.clone();
// First few super pages are link PTE to the next level
// $cast(page_table[i].pte[j], valid_link_pte.clone());
}
else if (j < SuperLeafPtePerTable + LinkPtePerTable) {
entry = cast(riscv_page_table_entry!MODE) valid_leaf_pte.clone();
// Non-link superpage table entry
// $cast(page_table[i].pte[j], valid_leaf_pte.clone());
}
else {
// Invalid unused PTEs
entry = riscv_page_table_entry!(MODE).type_id.
create(format("pte_%0d_%0d",i, j));
entry.v = false;
}
}
else {
entry = cast(riscv_page_table_entry!MODE) valid_leaf_pte.clone();
// Lowest level leaf pages
// $cast(page_table[i].pte[j], valid_leaf_pte.clone());
}
if (entry.xwr != pte_permission_t.NEXT_LEVEL_PAGE) {
entry.set_ppn(start_pa, pte_index, ptbl.level);
}
pte_index++;
if(enable_exception) {
inject_page_table_exception(entry, ptbl.level);
}
entry.pack_entry();
uvm_info(get_full_name(), format("%0s PT_%0d_%0d: %0s", privileged_mode,
i, j, entry.convert2string()), UVM_HIGH);
}
}
}
// Create the basic legal page table entries
void create_valid_pte() {
valid_leaf_pte.randomize_with! q{
if ($0 == $1) {
u == true;
}
else {
// Accessing user mode page from supervisor mode is only allowed when MSTATUS.SUM and
// MSTATUS.MPRV are both 1
if(!($2 && $3)) {
u == false;
}
}
// Set a,d bit to 1 avoid page/access fault exceptions
a == true;
d == true;
// Default: Readable, writable, executable page
@soft xwr == $4;
// Page is valid
v == true;
} (privileged_mode, privileged_mode_t.USER_MODE,
cfg.mstatus_sum, cfg.mstatus_mprv, pte_permission_t.R_W_EXECUTE_PAGE);
valid_link_pte = cast(riscv_page_table_entry!(MODE)) valid_leaf_pte.clone;
valid_data_leaf_pte = cast (riscv_page_table_entry!(MODE)) valid_leaf_pte.clone;
illegal_pte.turn_off_default_constraint();
valid_link_pte.xwr = pte_permission_t.NEXT_LEVEL_PAGE;
valid_link_pte.pack_entry();
// Set data page to read/write, but not executable
valid_data_leaf_pte.xwr = pte_permission_t.READ_WRITE_PAGE;
valid_data_leaf_pte.pack_entry();
}
void inject_page_table_exception(riscv_page_table_entry!(MODE) pte, int level) {
exception_cfg.randomize();
illegal_pte.randomize_with! q{ xwr !inside [$0, $1]; } (pte_permission_t.NEXT_LEVEL_PAGE,
pte_permission_t.R_W_EXECUTE_PAGE);
// `DV_CHECK_RANDOMIZE_FATAL(exception_cfg)
// `DV_CHECK_RANDOMIZE_WITH_FATAL(illegal_pte,
// !(xwr inside {NEXT_LEVEL_PAGE, R_W_EXECUTE_PAGE});)
// Wrong privilege mode setting
if (exception_cfg.allow_privileged_mode_exception) {
pte.u = ! pte.u;
}
// Random access control
// The link PTE is unchanged to avoid changing page table mappings
if (exception_cfg.allow_page_access_control_exception &&
(pte.xwr != pte_permission_t.NEXT_LEVEL_PAGE)) {
pte.xwr = illegal_pte.xwr;
}
// Invalid page exception
if (exception_cfg.allow_invalid_page_exception) {
pte.v = 0;
}
// Set "access" bit to zero
if (exception_cfg.allow_zero_access_bit_exception) {
pte.a = 0;
}
// Set "dirty" bit to zero
if (exception_cfg.allow_zero_dirty_bit_exception) {
pte.d = 0;
}
// Unaligned super leaf PTE
if (exception_cfg.allow_superpage_misaligned_exception &&
(level > 0) && (pte.xwr != pte_permission_t.NEXT_LEVEL_PAGE)) {
ubvec!(riscv_page_table_entry!(MODE).VPN_WIDTH) fault_ppn;
fault_ppn.randomize();
// `DV_CHECK_STD_RANDOMIZE_FATAL(fault_ppn)
if (level == 3) {
pte.ppn2.assign(fault_ppn);
}
else if (level == 2) {
pte.ppn1 = fault_ppn;
}
else {
pte.ppn0 = fault_ppn;
}
}
// Illegal link PTE for the lowest level page table
if (exception_cfg.allow_leaf_link_page_exception && (level == 0)) {
pte.xwr = pte_permission_t.NEXT_LEVEL_PAGE;
}
}
// Page fault handling routine
// There are two types of page fault handling routine.
// 1. For page table error injection test, fix all PTE related to the virtual address by walking
// through the page table with the fault address.
// 2. For normal test, a page table fault typically means the program is accessing a large
// virtual address which currently not mapped a valid physical address. Need to do a
// memcpy to move data from lower physical address to the place the virtual address map to.
// TODO: Refactor this part with new reserved GPR
void gen_page_fault_handling_routine(ref string[] instr) {
uint level;
string load_store_unit;
ubvec!XLEN bit_mask = 1;
if (MODE == satp_mode_t.SV48) {
load_store_unit = "d";
level = 3;
bit_mask = bit_mask >> (riscv_page_table_entry!(MODE).RSVD_WIDTH +
riscv_page_table_entry!(MODE).PPN3_WIDTH);
}
else if (MODE == satp_mode_t.SV39) {
load_store_unit = "d";
level = 2;
bit_mask = bit_mask >> (riscv_page_table_entry!(MODE).RSVD_WIDTH +
riscv_page_table_entry!(MODE).PPN2_WIDTH);
}
else if (MODE == satp_mode_t.SV32) {
load_store_unit = "w";
level = 1;
bit_mask = bit_mask >> (riscv_page_table_entry!(MODE).PPN1_WIDTH);
}
else {
uvm_fatal(get_full_name(), "Unsupported MODE");
}
if (cfg.mstatus_mprv && (SATP_MODE != satp_mode_t.BARE)) {
// Check if mstatus.mpp equals to machine mode(0x11)
// If MPP != Machine_mode and MSTATUS.MPRV = 1, load/store address translation is the same as
// the mode indicated by MPP
instr ~= format("csrr x%0d, 0x%0x // MSTATUS", mpp_reg, privileged_reg_t.MSTATUS);
instr ~= format("srli x%0d, x%0d, 11", mpp_reg, mpp_reg);
instr ~= format("andi x%0d, x%0d, 0x3", mpp_reg, mpp_reg);
instr ~= format("xori x%0d, x%0d, 0x3", mpp_reg, mpp_reg);
}
// Flush TLB to force synchronization
instr ~= "sfence.vma x0, x0";
// Start from root level, top-down fix all related PTEs
instr ~= format("li x%0d, %0d", level_reg, level);
instr ~= format("li x%0d, 0x%0x", mask_reg, bit_mask);
// Get the address that causes the page fault
instr ~= format("csrr x%0d, 0x%0x # MTVAL", fault_vaddr_reg, privileged_reg_t.MTVAL);
// Remove lower 4KB offset
instr ~= format("srli x%0d, x%0d, 12", fault_vaddr_reg, fault_vaddr_reg);
// Remove the virtual address spare bits, align the VPN to the msb
instr ~= format("slli x%0d, x%0d, %0d", fault_vaddr_reg, fault_vaddr_reg,
riscv_page_table_entry!(MODE).VADDR_SPARE + 12);
// Starting from the root table
instr ~= format("la x%0d, page_table_0", pte_addr_reg);
instr ~= "fix_pte:";
// Get the VPN of the current level
// Note the VPN under process is on the msb, right shift XLEN - VPN_WIDTH to get the VPN value
instr ~= format("srli x%0d, x%0d, %0d",
tmp_reg, fault_vaddr_reg,
XLEN - riscv_page_table_entry!(MODE).VPN_WIDTH);
// Get the actual address offset within the page table
instr ~= format("slli x%0d, x%0d, %0d",
tmp_reg, tmp_reg, clog2(XLEN/8));
// Add page table starting address and PTE offset to get PTE physical address
instr ~= format("add x%0d, x%0d, x%0d",
pte_addr_reg, pte_addr_reg, tmp_reg);
// Load the PTE from the memory
instr ~= format("l%0s x%0d, 0(x%0d)",
load_store_unit, pte_reg, pte_addr_reg);
// Check if the it's a link PTE (PTE[4:1] == 0)
instr ~= format("slli x%0d, x%0d, %0d",
tmp_reg, pte_reg, XLEN - 4);
instr ~= format("srli x%0d, x%0d, %0d",
tmp_reg, tmp_reg, XLEN - 3);
instr ~= format("bne zero, x%0d, fix_leaf_pte", tmp_reg);
// Handle link PTE exceptions
// - If level == 0, change the link PTE to leaf PTE, and finish exception handling
instr ~= format("beq zero, x%0d, fix_leaf_pte", level_reg);
// - If level != 0, fix the link PTE, and move to the PTE it points to
// - Override the low 10 bits with the correct link PTE setting
instr ~= format("srli x%0d, x%0d, 10", pte_reg, pte_reg);
instr ~= format("slli x%0d, x%0d, 10", pte_reg, pte_reg);
instr ~= format("li x%0d, 0x%0x", tmp_reg, valid_link_pte.bits);
instr ~= format("or x%0d, x%0d, x%0d", pte_reg, pte_reg, tmp_reg);
instr ~= format("s%0s x%0d, 0(x%0d)", load_store_unit, pte_reg, pte_addr_reg);
// - Zero out 10 lower access control bits
instr ~= format("srli x%0d, x%0d, 10", pte_addr_reg, pte_reg);
// - Left shift 12 bits to create the physical address
instr ~= format("slli x%0d, x%0d, 12", pte_addr_reg, pte_addr_reg);
// - Remove the VPN of the current level
instr ~= format("slli x%0d, x%0d, %0d", fault_vaddr_reg, fault_vaddr_reg,
riscv_page_table_entry!(MODE).VPN_WIDTH);
// - Decrement the level, update the bit mask
instr ~= format("addi x%0d, x%0d, -1", level_reg, level_reg);
instr ~= format("srli x%0d, x%0d, %0d",
mask_reg, mask_reg, riscv_page_table_entry!(MODE).VPN_WIDTH);
// - Jump to fix the PTE of the next level
instr ~= "j fix_pte";
// fix_leaf_pte: Override the low 10 bits with the correct leaf PTE setting
instr ~= "fix_leaf_pte:";
// Use mask to zero out lower 10 bits and unaligned VPN
instr ~= format("not x%0d, x%0d", mask_reg, mask_reg);
instr ~= format("and x%0d, x%0d, x%0d", pte_reg, pte_reg, mask_reg);
instr ~= format("li x%0d, 0x%0x", tmp_reg, valid_leaf_pte.bits);
instr ~= format("or x%0d, x%0d, x%0d", pte_reg, pte_reg, tmp_reg);
instr ~= format("s%0s x%0d, 0(x%0d)", load_store_unit, pte_reg, pte_addr_reg);
instr ~= "j fix_kernel_leaf_pte";
// Fix kernel leaf PTE
instr ~= "fix_kernel_leaf_pte:";
// - Load the starting virtual address of the kernel space
instr ~= format("la x%0d, kernel_instr_start", tmp_reg);
// TODO: Fix kernel instruction/data pages separatedly
instr ~= format("slli x%0d, x%0d, %0d", tmp_reg, tmp_reg,
XLEN - MAX_USED_VADDR_BITS);
instr ~= format("srli x%0d, x%0d, %0d", tmp_reg, tmp_reg,
XLEN - MAX_USED_VADDR_BITS);
instr ~= format("csrr x%0d, 0x%0x # MTVAL", fault_vaddr_reg, privileged_reg_t.MTVAL);
// - Check if the fault virtual address is in the kernel space
instr ~= format("bgeu x%0d, x%0d, fix_pte_done", tmp_reg, fault_vaddr_reg);
// - Set the PTE.u bit to 0 for kernel space PTE
instr ~= format("li x%0d, 0x%0x", tmp_reg, 0x10); //`h10
instr ~= format("not x%0d, x%0d", tmp_reg, tmp_reg);
instr ~= format("and x%0d, x%0d, x%0d", pte_reg, tmp_reg, pte_reg);
instr ~= format("s%0s x%0d, 0(x%0d)", load_store_unit, pte_reg, pte_addr_reg);
// End of page table fault handling
instr ~= "fix_pte_done:";
// Make sure all outstanding memory access is completed
instr ~= "sfence.vma";
// Randomly decide if run some kernel program before exiting from exception handling
// Use the low 2 bits of x30 to determine whether to skip it or not.
instr ~= format("slli x30, x30, %0d", XLEN - 2);
instr ~= "beqz x30, fix_pte_ret";
// Randomly decide if set MPRV to 1
instr ~= format("slli x31, x31, %0d", XLEN - 2);
instr ~= "beqz x30, check_mprv";
instr ~= format("csrr x%0d, 0x%0x", tmp_reg, privileged_reg_t.MSTATUS);
instr ~= format("li x%0d, 0x%0x", mask_reg, MPRV_BIT_MASK);
instr ~= format("not x%0d, x%0d", mask_reg, mask_reg);
instr ~= format("or x%0d, x%0d, 0x%0x", tmp_reg, tmp_reg, mask_reg);
instr ~= format("csrrw x%0d, 0x%0x, x%0d", tmp_reg, privileged_reg_t.MSTATUS, tmp_reg);
// Run some kernel mode program before returning from exception handling
// If MPRV = 0, jump to regular kernel mode program
// If MPRV = 1, jump to kernel program with U mode mem load/store
instr ~= format("check_mprv: li x%0d, 0x%0x", mask_reg, MPRV_BIT_MASK);
instr ~= format("csrr x%0d, 0x%0x", tmp_reg, privileged_reg_t.MSTATUS);
instr ~= format("and x%0d, x%0d, x%0d", tmp_reg, tmp_reg, mask_reg);
instr ~= format("beqz x%0d, j_smode", tmp_reg);
instr ~= "jal ra, smode_lsu_program";
instr ~= "j fix_pte_ret";
instr ~= "j_smode: jal ra, smode_program";
instr ~= "fix_pte_ret:";
// Recover the user mode GPR from kernal stack
pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH,
cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
instr ~= "mret";
foreach (ref s; instr) {
import std.uni: toLower;
s = s.toLower();
}
}
void default_page_table_setting() {
num_of_page_table.length = PageLevel;
foreach(i, num; num_of_page_table) {
num = cast(int) (LinkPtePerTable ^^ (PageLevel - i - 1));
}
}
void create_page_table_list() {
import std.algorithm.iteration: sum;
page_table.length = sum(num_of_page_table);
foreach(i, ref page; page_table) {
page = riscv_page_table!(MODE).type_id.create(format("page_table_%0d", cast(uint) i));
page.init_page_table(PteCnt);
page.table_id = cast(uint) i;
page.level.assign(get_level(cast(uint) i));
}
}
int get_1st_4k_table_id() {
foreach (i, page; page_table) {
if (page.level == 0) { return cast(int) i; }
}
return -1;
}
// Link page table
void process_page_table(out string[] instr) {
string load_store_unit;
int pte_addr_offset;
ubvec!XLEN ubit_mask = 1;
ubit_mask[4] = 0; // U bit of PTE
load_store_unit = (XLEN == 32) ? "w" : "d";
// Assign the PPN of link PTE to link the page tables together
foreach (i, ptbl; page_table) {
if (ptbl.level == 0) break;
instr ~= format("la x%0d, page_table_%0d+2048 # Process PT_%0d",
cfg.gpr[1], i, i);
foreach (j, entry; ptbl.pte) {
if(j >= SuperLeafPtePerTable) continue;
pte_addr_offset = cast(uint) ((j * PteSize) - 2048);
uvm_info(get_full_name(), format("Processing PT_%0d_PTE_%0d, v = %0d, level = %0d",
i, j, entry.v, ptbl.level), UVM_LOW);
if (entry.xwr == pte_permission_t.NEXT_LEVEL_PAGE)
{ instr ~=
format("l%0s x%0d, %0d(x%0d)",
load_store_unit, cfg.gpr[2], pte_addr_offset, cfg.gpr[1])
// Load the target page table physical address, PPN should be 0
~ format("la x%0d, page_table_%0d # Link PT_%0d_PTE_%0d -> PT_%0d", cfg.gpr[0],
get_child_table_id(cast(int) i, cast(int) j), cast(int) i, cast(int) j,
get_child_table_id(cast(int) i, cast(int) j))
// Right shift the address for 2 bits to the correct PPN position in PTE
~ format("srli x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0])
// Assign PPN
~ format("or x%0d, x%0d, x%0d", cfg.gpr[2], cfg.gpr[0], cfg.gpr[2])
// Store the new PTE value
~ format("s%0s x%0d, %0d(x%0d)",
load_store_unit, cfg.gpr[2], pte_addr_offset, cfg.gpr[1]);
}
}
}
// ---------------------------------------------------------------------------
// Set the kernel page u bit to 0 for supervisor mode instruction/data pages
// ---------------------------------------------------------------------------
if (cfg.support_supervisor_mode) {
instr ~=
// Process kernel instruction pages
format("la x%0d, kernel_instr_start", cfg.gpr[0])
~ format("la x%0d, kernel_instr_end", cfg.gpr[1])
// Get the VPN of the physical address
~ format("slli x%0d, x%0d, %0d",
cfg.gpr[0], cfg.gpr[0], XLEN - MAX_USED_VADDR_BITS)
~ format("srli x%0d, x%0d, %0d",
cfg.gpr[0], cfg.gpr[0], XLEN - MAX_USED_VADDR_BITS + 12)
~ format("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], clog2(XLEN))
~ format("slli x%0d, x%0d, %0d", cfg.gpr[1], cfg.gpr[1],
XLEN - MAX_USED_VADDR_BITS)
~ format("srli x%0d, x%0d, %0d", cfg.gpr[1], cfg.gpr[1],
XLEN - MAX_USED_VADDR_BITS + 12)
~ format("slli x%0d, x%0d, %0d", cfg.gpr[1], cfg.gpr[1], clog2(XLEN))
// Starting from the first 4KB leaf page table
~ format("la x%0d, page_table_%0d", cfg.gpr[2], get_1st_4k_table_id())
~ format("add x%0d, x%0d, x%0d", cfg.gpr[0], cfg.gpr[2], cfg.gpr[0])
~ format("add x%0d, x%0d, x%0d", cfg.gpr[1], cfg.gpr[2], cfg.gpr[1])
~ format("li x%0d, 0x%0x", cfg.gpr[2], ubit_mask)
~ "1:"
// Load the PTE from the memory
~ format("l%0s x%0d, 0(x%0d)", load_store_unit, cfg.gpr[3], cfg.gpr[0])
// Unset U bit
~ format("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2])
// Save PTE back to memory
~ format("s%0s x%0d, 0(x%0d)", load_store_unit, cfg.gpr[3], cfg.gpr[0])
// Move to the next PTE
~ format("addi x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN/8)
// If not the end of the kernel space, process the next PTE
~ format("ble x%0d, x%0d, 1b", cfg.gpr[0], cfg.gpr[1])
// Process kernel data pages
~ format("la x%0d, kernel_data_start", cfg.gpr[0])
// Get the VPN of the physical address
~ format("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0],
XLEN - MAX_USED_VADDR_BITS)
~ format("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0],
XLEN - MAX_USED_VADDR_BITS + 12)
~ format("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], clog2(XLEN))
// Starting from the first 4KB leaf page table
~ format("la x%0d, page_table_%0d", cfg.gpr[2], get_1st_4k_table_id())
~ format("add x%0d, x%0d, x%0d", cfg.gpr[0], cfg.gpr[2], cfg.gpr[0])
~ format("li x%0d, 0x%0x", cfg.gpr[2], ubit_mask)
// Assume 20 PTEs for kernel data pages
~ format("addi x%0d, x%0d, %0d", cfg.gpr[1], cfg.gpr[1], 20 * XLEN/8)
~ "2:"
// Load the PTE from the memory
~ format("l%0s x%0d, 0(x%0d)", load_store_unit, cfg.gpr[3], cfg.gpr[0])
// Unset U bit
~ format("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2])
// Save PTE back to memory
~ format("s%0s x%0d, 0(x%0d)", load_store_unit, cfg.gpr[3], cfg.gpr[0])
// Move to the next PTE
~ format("addi x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN/8)
// If not the end of the kernel space, process the next PTE
~ format("ble x%0d, x%0d, 2b", cfg.gpr[0], cfg.gpr[1]);
}
instr ~= "sfence.vma";
}
// If you want to create custom page table topology, override the below tasks to specify the
// level and parent of each table.
int get_level(int table_id) {
for (int level = PageLevel - 1; level >= 0; level--) {
if (table_id < num_of_page_table[level])
return level;
table_id -= num_of_page_table[level];
}
assert (false);
}
int get_child_table_id(int table_id, int pte_id) {
return (table_id * LinkPtePerTable + pte_id + 1);
}
}

View file

@ -0,0 +1,755 @@
/*
* Copyright 2020 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.riscv_pmp_cfg;
import riscv.gen.riscv_instr_pkg: pmp_cfg_reg_t, pmp_addr_mode_t,
privileged_reg_t, riscv_reg_t, exception_cause_t, get_int_arg_value,
get_bool_arg_value, get_hex_arg_value;
import riscv.gen.target: XLEN;
import std.format: format;
import esdl.data.bvec: ubvec, toubvec, tobvec, clog2;
import esdl.rand: rand, constraint;
import uvm;
class riscv_pmp_cfg: uvm_object {
mixin uvm_object_utils;
// default to a single PMP region
@rand @UVM_DEFAULT int pmp_num_regions = 1;
// default to granularity of 0 (4 bytes grain)
@UVM_DEFAULT int pmp_granularity = 0;
// number of configuration bytes per pmpcfg CSR
int cfg_per_csr;
// enable bit for pmp randomization
bool pmp_randomize = false;
// allow pmp randomization to cause address range overlap
@rand bool pmp_allow_addr_overlap = false;
// By default, after returning from a PMP exception, we return to the exact same instruction that
// resulted in a PMP exception to begin with, creating an infinite loop of taking an exception.
// To avoid this situation, this configuration knob will enable the relevant PMP exception
// handlers to find the pmpcfg CSR that controls the address region resulting in the exception and
// change the relevant access bit to 1'b1, allowing forward progress in the code, while also
// allowing all access restrictions to be enforced.
bool enable_pmp_exception_handler = true;
// Setting this bit to 1'b1 enables generation of the directed stream of instructions to test
// write accesses to all supported pmpaddr[i] CSRs.
bool enable_write_pmp_csr;
// pmp CSR configurations
@rand pmp_cfg_reg_t[] pmp_cfg;
// This value is the address offset between the minimum and maximum pmpaddr
// CSR values.
// As pmpaddr0 will be set to the address of the <main> label, the address stored
// in pmpaddr0 added to this pmp_max_offset value will give the upper bound of the
// address range covered by the PMP address range.
// Can be manually configured from the command line.
@UVM_DEFAULT ubvec!(XLEN) pmp_max_offset = ubvec!(XLEN).max();
// used to parse addr_mode configuration from cmdline
alias addr_mode_wrapper = uvm_enum_wrapper!(pmp_addr_mode_t);
pmp_addr_mode_t addr_mode;
// Store the base addresses of pmpaddr0 and pmpcfg0
privileged_reg_t base_pmp_addr = privileged_reg_t.PMPADDR0;
privileged_reg_t base_pmpcfg_addr = privileged_reg_t.PMPCFG0;
/////////////////////////////////////////////////
// constraints - apply when pmp_randomize is 1 //
/////////////////////////////////////////////////
constraint! q{
pmp_num_regions inside [1 : 16];
pmp_granularity inside [0 : XLEN + 3];
} sanity_c;
constraint! q{
foreach (cfg; pmp_cfg) {
!(cfg.w && !cfg.r);
}
} xwr_c;
constraint! q{
foreach (cfg; pmp_cfg) {
(pmp_granularity == 0) -> (cfg.a != pmp_addr_mode_t.NAPOT);
(pmp_granularity >= 1) -> (cfg.a != pmp_addr_mode_t.NA4);
}
} grain_addr_mode_c;
constraint! q{
foreach (i, cfg; pmp_cfg) {
// Offset of pmp_cfg[0] does not matter, since it will be set to <main>,
// so we do not constrain it here, as it will be overridden during generation
if (i != 0) {
cfg.offset inside [1 : pmp_max_offset];
}
else {
cfg.offset == 0;
}
}
} addr_range_c;
constraint! q{
foreach (i, cfg; pmp_cfg) {
if (!pmp_allow_addr_overlap && i > 0) {
cfg.offset > pmp_cfg[i-1].offset;
}
}
} addr_overlapping_c;
// Privileged spec states that in TOR mode, offset[i-1] < offset[i]
constraint! q{
foreach (cfg; pmp_cfg) {
if (cfg.a == pmp_addr_mode_t.TOR) {
pmp_allow_addr_overlap == false;
}
}
} tor_addr_overlap_c;
this(string name = "") {
string s;
super(name);
int pmp_max_offset_int;
cfg_per_csr = XLEN / 8;
if (uvm_cmdline_processor.get_inst().get_arg_value("+pmp_num_regions=", s)) {
import std.conv: to;
pmp_num_regions = s.to!int;
rand_mode!q{pmp_num_regions}(false);
}
get_int_arg_value("+pmp_granularity=", pmp_granularity);
get_bool_arg_value("+pmp_randomize=", pmp_randomize);
get_bool_arg_value("+pmp_allow_addr_overlap=", pmp_allow_addr_overlap);
get_bool_arg_value("+enable_write_pmp_csr=", enable_write_pmp_csr);
get_hex_arg_value("+pmp_max_offset=", pmp_max_offset_int);
pmp_max_offset = toubvec!XLEN(pmp_max_offset_int);
uvm_info(get_full_name(), format("pmp max offset: 0x%0x", pmp_max_offset), UVM_LOW);
pmp_cfg.length = pmp_num_regions;
}
void initialize(bool require_signature_addr) {
if (!pmp_randomize) {
set_defaults();
setup_pmp();
}
}
// This will only get called if pmp_randomize is set, in which case we apply command line
// arguments after randomization
void post_randomize() {
// `ifdef _VCP //GRK958
// foreach(pmp_cfg[i]) pmp_cfg[i].zero = 2'b00;
// `endif
setup_pmp();
}
void set_defaults() {
uvm_info(get_full_name(), format("MAX OFFSET: 0x%0x", pmp_max_offset), UVM_LOW);
foreach (i, cfg; pmp_cfg) {
cfg.l = false;
cfg.a = pmp_addr_mode_t.TOR;
cfg.x = true;
cfg.w = true;
cfg.r = true;
cfg.offset = assign_default_addr_offset(pmp_num_regions, cast(int) i);
}
}
ubvec!XLEN assign_default_addr_offset(int num_regions, int index) {
ubvec!XLEN offset;
if (num_regions == 1) {
assert (index == 0);
offset = 0;
}
else {
offset = pmp_max_offset / (num_regions - 1);
offset = offset * index;
}
return offset;
}
void setup_pmp() {
string arg_name;
string pmp_region;
foreach (i, ref cfg; pmp_cfg) {
arg_name = format("+pmp_region_%0d=", i);
if (uvm_cmdline_processor.get_inst().get_arg_value(arg_name, pmp_region)) {
cfg = parse_pmp_config(pmp_region, cfg);
uvm_info(get_full_name(), format("Configured pmp_cfg[%0d] from command line: %p",
i , cfg), UVM_LOW);
}
}
}
pmp_cfg_reg_t parse_pmp_config(string pmp_region, pmp_cfg_reg_t ref_pmp_cfg) {
string [] fields;
string [] field_vals;
string field_type;
string field_val;
pmp_cfg_reg_t pmp_cfg_reg = ref_pmp_cfg;
uvm_string_split(pmp_region, ',', fields);
foreach (i, ref field; fields) {
import std.conv: to;
uvm_string_split(field, ':', field_vals);
field_type = field_vals[0];
field_val = field_vals[1];
field_vals.length = 0;
switch (field_type) {
case "L" :
pmp_cfg_reg.l = field_val.to!bool;
break;
case "A":
bool ch_mode = addr_mode_wrapper.from_name(field_val, addr_mode);
if(!ch_mode) uvm_error(get_full_name(), format("Check failed : %s", field_val));
pmp_cfg_reg.a = addr_mode;
break;
case "X":
pmp_cfg_reg.x = field_val.to!bool;
break;
case "W":
pmp_cfg_reg.w = field_val.to!bool;
break;
case "R":
pmp_cfg_reg.r = field_val.to!bool;
break;
case "ADDR":
// Don't have to convert address to "PMP format" here,
// since it must be masked off in hardware
static if (XLEN == 32) {
pmp_cfg_reg.addr = format_addr(toubvec!XLEN(field_val.to!uint(16)));
}
else static if (XLEN == 64) {
pmp_cfg_reg.addr = format_addr(toubvec!XLEN(field_val.to!ulong(16)));
}
else {
uvm_fatal(get_full_name(), format("Unsupported XLEN %0s", XLEN));
}
break;
default:
uvm_fatal(get_full_name(), format("%s, Invalid PMP configuration field name!", field_val));
}
}
return pmp_cfg_reg;
}
ubvec!XLEN format_addr(ubvec!XLEN addr) {
// For all ISAs, pmpaddr CSRs do not include the bottom two bits of the input address
ubvec!XLEN shifted_addr;
shifted_addr = addr >> 2;
switch (XLEN) {
// RV32 - pmpaddr is bits [33:2] of the whole 34 bit address
// Return the input address right-shifted by 2 bits
case 32:
return shifted_addr;
// RV64 - pmpaddr is bits [55:2] of the whole 56 bit address, prepended by 10'b0
// Return {10'b0, shifted_addr[53:0]}
case 64:
shifted_addr[53..64] = 0;
return shifted_addr;
default:
uvm_fatal(get_full_name(), format("Unsupported XLEN %0s", XLEN));
assert (false);
}
}
// TODO(udinator) - implement function to return hardware masked pmpaddr "representation"
ubvec!XLEN convert_addr2pmp(ubvec!XLEN addr) {
uvm_info(get_full_name(), "Placeholder function, need to implement", UVM_LOW);
return addr;
}
ubvec!1 booltobit( bool x) {
if ( x == true)
return 0b1.toubvec!1;
else
return 0b0.toubvec!1;
}
// This function parses the pmp_cfg[] array to generate the actual instructions to set up
// the PMP CSR registers.
// Since either 4 (in rv32) or 8 (in rv64) PMP configuration registers fit into one physical
// CSR, this function waits until it has reached this maximum to write to the physical CSR to
// save some extraneous instructions from being performed.
void gen_pmp_instr(riscv_reg_t[2] scratch_reg, ref string[] instr) {
ubvec!XLEN pmp_word;
ubvec!XLEN cfg_bitmask;
ubvec!8 cfg_byte;
int pmp_id;
foreach (i, ref cfg; pmp_cfg) {
// TODO(udinator) condense this calculations if possible
pmp_id = cast(int) (i/cfg_per_csr);
if (i == 0) {
cfg_byte = tobvec!0b0 ~ cfg.zero ~ tobvec!2(pmp_addr_mode_t.TOR) ~ tobvec!3(0b111);
}
else {
bool l, w, r, x;
l = cfg.l;
//a = cfg.a;
x = cfg.x;
w = cfg.w;
r = cfg.r;
cfg_byte = booltobit(l) ~ cfg.zero ~ tobvec!2(cfg.a)
~ booltobit(x) ~ booltobit(w) ~ booltobit(r);
}
uvm_info(get_full_name(), format("cfg_byte: 0x%0x", cfg_byte), UVM_DEBUG);
// First write to the appropriate pmpaddr CSR
cfg_bitmask = cfg_byte << ((i % cfg_per_csr) * 8);
uvm_info(get_full_name(), format("cfg_bitmask: 0x%0x", cfg_bitmask), UVM_DEBUG);
pmp_word = pmp_word | cfg_bitmask;
uvm_info(get_full_name(), format("pmp_word: 0x%0x", pmp_word), UVM_DEBUG);
cfg_bitmask = 0;
if (i == 0) {
// load the address of the <main> section into pmpaddr0
instr ~= format("la x%0d, main", scratch_reg[0]);
instr ~= format("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]);
instr ~= format("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg[0]);
uvm_info(get_full_name(), "Loaded the address of <main> section into pmpaddr0", UVM_LOW);
}
else {
// If an actual address has been set from the command line, use this address,
// otherwise use the default offset+<main> address
//
// TODO(udinator) - The practice of passing in a max offset from the command line
// is somewhat unintuitive, and is just an initial step. Eventually a max address
// should be passed in from the command line and this routine do all of the
// calculations to split the address range formed by [<main> : pmp_max_addr].
// This will likely require a complex assembly routine - the code below is a very simple
// first step towards this goal, allowing users to specify a PMP memory address
// from the command line instead of having to calculate an offset themselves.
if (cfg.addr != 0) {
instr ~= format("li x%0d, 0x%0x", scratch_reg[0], cfg.addr);
instr ~= format("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg[0]);
uvm_info(get_full_name(),
format("Address 0x%0x loaded into pmpaddr[%d] CSR", base_pmp_addr + i, i),
UVM_LOW);
}
else {
// Add the offset to the base address to get the other pmpaddr values
instr ~= format("la x%0d, main", scratch_reg[0]);
instr ~= format("li x%0d, 0x%0x", scratch_reg[1], cfg.offset);
instr ~= format("add x%0d, x%0d, x%0d",
scratch_reg[0], scratch_reg[0], scratch_reg[1]);
instr ~= format("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]);
instr ~= format("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg[0]);
uvm_info(get_full_name(), format("Offset of pmp_addr_%d from pmpaddr0: 0x%0x",
i, cfg.offset), UVM_LOW);
}
}
// Now, check if we have to write to the appropriate pmpcfg CSR.
// Short circuit if we reach the end of the list
if (i == pmp_cfg.length - 1) {
instr ~= format("li x%0d, 0x%0x", scratch_reg[0], pmp_word);
instr ~= format("csrw 0x%0x, x%0d",
base_pmpcfg_addr + pmp_id,
scratch_reg[0]);
return;
}
else if ((i + 1) % cfg_per_csr == 0) {
// if we've filled up pmp_word, write to the corresponding CSR
instr ~= format("li x%0d, 0x%0x", scratch_reg[0], pmp_word);
instr ~= format("csrw 0x%0x, x%0d",
base_pmpcfg_addr + pmp_id,
scratch_reg[0]);
pmp_word = 0;
}
}
}
// This function creates a special PMP exception routine that is generated within the
// instr_fault, load_fault, and store_fault exception routines to prevent infinite loops.
// This routine will first find the correct pmpcfg CSR that corresponds to the address that
// caused the exception in the first place, and then will enable the appropriate access bit
// (X for instruction faults, W for store faults, and R for load faults).
//
// Note: If a pmpcfg CSR is locked, it is unable to be written to until a full reset, so in this
// case we will immediately jump to the <test_done> label if the faulting address matches to
// this region, otherwise we'll keep looping through the remaining CSRs.
//
// TODO(udinator) : investigate switching branch targets to named labels instead of numbers
// to better clarify where the multitude of jumps are actually going to.
void gen_pmp_exception_routine(riscv_reg_t[] scratch_reg,
exception_cause_t fault_type,
ref string[] instr) {
assert (scratch_reg.length == 6);
// mscratch : loop counter
// scratch_reg[0] : temporary storage
// scratch_reg[1] : &pmpaddr[i]
// scratch_reg[2] : &pmpcfg[i]
// scratch_reg[3] : 8-bit configuration fields
// scratch_reg[4] : 2-bit pmpcfg[i].A address matching mode
// scratch_reg[5] : holds the previous pmpaddr[i] value (necessary for TOR matching)
instr ~=
//////////////////////////////////////////////////
// Initialize loop counter and save to mscratch //
//////////////////////////////////////////////////
[format("li x%0d, 0", scratch_reg[0]),
format("csrw 0x%0x, x%0d", privileged_reg_t.MSCRATCH, scratch_reg[0]),
format("li x%0d, 0", scratch_reg[5]),
////////////////////////////////////////////////////
// calculate next pmpaddr and pmpcfg CSRs to read //
////////////////////////////////////////////////////
format("0: csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
format("mv x%0d, x%0d", scratch_reg[4], scratch_reg[0])];
// Generate a sequence of loads and branches that will compare the loop index to every
// value within [0 : pmp_num_regions] to manually check which PMP CSRs to read from
for (int i = 1; i < pmp_num_regions + 1; i++) {
int pmpaddr_addr = base_pmp_addr + i;
int pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr);
instr ~= format("li x%0d, %0d", scratch_reg[4], i-1);
instr ~= format("beq x%0d, x%0d, %0df", scratch_reg[0], scratch_reg[4], i);
}
// Generate the branch targets for the above sequence of loads and branches to actually
// read from the pmpaddr and pmpcfg CSRs
for (int i = 1; i < pmp_num_regions + 1; i++) {
int pmpaddr_addr = base_pmp_addr + i;
int pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr);
instr ~= format("%0d: csrr x%0d, 0x%0x", i, scratch_reg[1], base_pmp_addr + i - 1);
instr ~= format("csrr x%0d, 0x%0x", scratch_reg[2], base_pmpcfg_addr + ((i-1)/4));
instr ~= ("j 17f");
}
// Logic to store pmpaddr[i] and pmpcfg[i] and branch to a code section
// based on pmpcfg[i].A (address matching mode)
instr ~=
////////////////////////////////////////////
// get correct 8-bit configuration fields //
////////////////////////////////////////////
[format("17: li x%0d, %0d", scratch_reg[3], cfg_per_csr),
format("csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
// calculate offset to left-shift pmpcfg[i] (scratch_reg[2]),
// use scratch_reg[4] as temporary storage
//
// First calculate (loop_counter % cfg_per_csr)
format("slli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0],
XLEN - clog2(cfg_per_csr)),
format("srli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0],
XLEN - clog2(cfg_per_csr)),
// Calculate (cfg_per_csr - modded_loop_counter - 1) to determine how many 8bit slots to
// the left this needs to be shifted
format("sub x%0d, x%0d, x%0d", scratch_reg[4], scratch_reg[3], scratch_reg[0]),
format("addi x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], -1),
// Multiply this "slot offset" by 8 to get the actual number of bits it should
// be leftshifted.
format("slli x%0d, x%0d, 3", scratch_reg[4], scratch_reg[4]),
// Perform the leftshifting operation
format("sll x%0d, x%0d, x%0d", scratch_reg[3], scratch_reg[2], scratch_reg[4]),
// Add 8*modded_loop_counter to 8*(cfg_per_csr - modded_loop_counter - 1)
// stored in scratch_reg[4] to get "slot offset" for the pending rightshift operation.
format("slli x%0d, x%0d, 3", scratch_reg[0], scratch_reg[0]),
format("add x%0d, x%0d, x%0d", scratch_reg[4], scratch_reg[4], scratch_reg[0]),
// Perform the rightshift operation
format("srl x%0d, x%0d, x%0d", scratch_reg[3], scratch_reg[3], scratch_reg[4]),
///////////////////////////
// get pmpcfg[i].A field //
///////////////////////////
// pmpcfg[i].A will be bits [4:3] of the 8-bit configuration entry
format("slli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[3], XLEN - 5),
format("srli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], XLEN - 2),
//////////////////////////////////////////////////////////////////
// based on address match mode, branch to appropriate "handler" //
//////////////////////////////////////////////////////////////////
// pmpcfg[i].A == OFF
format("beqz x%0d, 20f", scratch_reg[4]),
// pmpcfg[i].A == TOR
// scratch_reg[5] will contain pmpaddr[i-1]
format("li x%0d, 1", scratch_reg[0]),
format("beq x%0d, x%0d, 21f", scratch_reg[4], scratch_reg[0]),
// pmpcfg[i].A == NA4
format("li x%0d, 2", scratch_reg[0]),
format("beq x%0d, x%0d, 25f", scratch_reg[4], scratch_reg[0]),
// pmpcfg[i].A == NAPOT
format("li x%0d, 3", scratch_reg[0]),
format("beq x%0d, x%0d, 27f", scratch_reg[4], scratch_reg[0]),
// Error check, if no address modes match, something has gone wrong
format("la x%0d, test_done", scratch_reg[0]),
format("jalr x0, x%0d, 0", scratch_reg[0]),
/////////////////////////////////////////////////////////////////
// increment loop counter and branch back to beginning of loop //
/////////////////////////////////////////////////////////////////
format("18: csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
// load pmpaddr[i] into scratch_reg[5] to store for iteration [i+1]
format("mv x%0d, x%0d", scratch_reg[5], scratch_reg[1]),
// increment loop counter by 1
format("addi x%0d, x%0d, 1", scratch_reg[0], scratch_reg[0]),
// store loop counter to MSCRATCH
format("csrw 0x%0x, x%0d", privileged_reg_t.MSCRATCH, scratch_reg[0]),
// load number of pmp regions - loop limit
format("li x%0d, %0d", scratch_reg[1], pmp_num_regions),
// if counter < pmp_num_regions => branch to beginning of loop,
// otherwise jump to the end of the loop
format("ble x%0d, x%0d, 19f", scratch_reg[1], scratch_reg[0]),
format("j 0b"),
// If we reach here, it means that no PMP entry has matched the request.
// We must immediately jump to <test_done> since the CPU is taking a PMP exception,
// but this routine is unable to find a matching PMP region for the faulting access -
// there is a bug somewhere.
format("19: la x%0d, test_done", scratch_reg[0]),
format("jalr x0, x%0d, 0", scratch_reg[0])];
/////////////////////////////////////////////////
// Sub-sections for all address matching modes //
/////////////////////////////////////////////////
// scratch_reg[0] : temporary storage
// scratch_reg[1] : pmpaddr[i]
// scratch_reg[2] : pmpcfg[i]
// scratch_reg[3] : 8-bit configuration fields
// scratch_reg[4] : temporary storage
// scratch_reg[5] : pmpaddr[i-1]
// Sub-section to deal with address matching mode OFF.
// If entry is OFF, simply continue looping through other PMP CSR.
instr ~= "20: j 18b" ;
// Sub-section to handle address matching mode TOR.
instr ~=
[format("21: csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
format("csrr x%0d, 0x%0x", scratch_reg[4], privileged_reg_t.MTVAL),
format("srli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[4]),
// If loop_counter==0, compare fault_addr to 0
format("bnez x%0d, 22f", scratch_reg[0]),
// If fault_addr < 0 : continue looping
format("bltz x%0d, 18b", scratch_reg[4]),
format("j 23f"),
// If fault_addr < pmpaddr[i-1] : continue looping
format("22: bgtu x%0d, x%0d, 18b", scratch_reg[5], scratch_reg[4]),
// If fault_addr >= pmpaddr[i] : continue looping
format("23: bleu x%0d, x%0d, 18b", scratch_reg[1], scratch_reg[4]),
// If we get here, there is a TOR match, if the entry is locked jump to
// <test_done>, otherwise modify access bits and return
format("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
format("beqz x%0d, 24f", scratch_reg[4]),
format("la x%0d, test_done", scratch_reg[0]),
format("jalr x0, x%0d, 0", scratch_reg[0]),
format("24: j 29f")];
// Sub-section to handle address matching mode NA4.
// TODO(udinator) : add rv64 support
instr ~=
[format("25: csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MTVAL),
format("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]),
// Zero out pmpaddr[i][31:30]
format("slli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[1]),
format("srli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[4]),
// If fault_addr[31:2] != pmpaddr[i][29:0] => there is a mismatch,
// so continue looping
format("bne x%0d, x%0d, 18b", scratch_reg[0], scratch_reg[4]),
// If we get here, there is an NA4 address match, jump to <test_done> if the
// entry is locked, otherwise modify access bits
format("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
format("beqz x%0d, 26f", scratch_reg[4]),
format("la x%0d, test_done", scratch_reg[0]),
format("jalr x0, x%0d, 0", scratch_reg[0]),
format("26: j 29f")];
// Sub-section to handle address matching mode NAPOT.
instr ~=
[format("27: csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MTVAL),
// get fault_addr[31:2]
format("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]),
// mask the bottom pmp_granularity bits of fault_addr
format("srli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0], pmp_granularity),
format("slli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0], pmp_granularity),
// get pmpaddr[i][29:0]
format("slli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[1]),
format("srli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[4]),
// mask the bottom pmp_granularity bits of pmpaddr[i]
format("srli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], pmp_granularity),
format("slli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], pmp_granularity),
// If masked_fault_addr != masked_pmpaddr[i] : mismatch, so continue looping
format("bne x%0d, x%0d, 18b", scratch_reg[0], scratch_reg[4]),
// If we get here there is an NAPOT address match, jump to <test_done> if
// the entry is locked, otherwise modify access bits
format("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
format("beqz x%0d, 29f", scratch_reg[4]),
format("la x%0d, test_done", scratch_reg[0]),
format("jalr x0, x%0d, 0", scratch_reg[0]),
format("28: j 29f")];
// This case statement creates a bitmask that enables the correct access permissions
// and ORs it with the 8-bit configuration fields.
switch (fault_type) {
case exception_cause_t.INSTRUCTION_ACCESS_FAULT:
instr ~= format("29: ori x%0d, x%0d, 4", scratch_reg[3], scratch_reg[3]);
break;
case exception_cause_t.STORE_AMO_ACCESS_FAULT:
// The combination of W:1 and R:0 is reserved, so if we are enabling write
// permissions, also enable read permissions to adhere to the spec.
instr ~= format("29: ori x%0d, x%0d, 3", scratch_reg[3], scratch_reg[3]);
break;
case exception_cause_t.LOAD_ACCESS_FAULT:
instr ~= format("29: ori x%0d, x%0d, 1", scratch_reg[3], scratch_reg[3]);
break;
default:
uvm_fatal(get_full_name(), "Invalid PMP fault type");
break;
}
instr ~=
[format("csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
// Calculate (loop_counter % cfg_per_csr) to find the index of the correct
// entry in pmpcfg[i].
//
// Calculate XLEN - $clog2(cfg_per_csr) to give how many low order bits
// of loop_counter we need to keep around
format("li x%0d, %0d", scratch_reg[4], XLEN - clog2(cfg_per_csr)),
// Now leftshift and rightshift loop_counter by this amount to clear all the upper
// bits
format("sll x%0d, x%0d, x%0d", scratch_reg[0], scratch_reg[0], scratch_reg[4]),
format("srl x%0d, x%0d, x%0d", scratch_reg[0], scratch_reg[0], scratch_reg[4]),
// Multiply the index by 8 to get the shift amount.
format("slli x%0d, x%0d, 3", scratch_reg[4], scratch_reg[0]),
// Shift the updated configuration byte to the proper alignment
format("sll x%0d, x%0d, x%0d", scratch_reg[3], scratch_reg[3], scratch_reg[4]),
// OR pmpcfg[i] with the updated configuration byte
format("or x%0d, x%0d, x%0d", scratch_reg[2], scratch_reg[2], scratch_reg[3]),
// Divide the loop counter by cfg_per_csr to determine which pmpcfg CSR to write to.
format("csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
format("srli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0], clog2(cfg_per_csr)),
// Write the updated pmpcfg[i] to the CSR bank and exit the handler.
//
// Don't touch scratch_reg[2], as it contains the updated pmpcfg[i] to be written.
// All other scratch_reg[*] can be used.
// scratch_reg[0] contains the index of the correct pmpcfg CSR.
// We simply check the index and then write to the correct pmpcfg CSR based on its value.
format("beqz x%0d, 30f", scratch_reg[0]),
format("li x%0d, 1", scratch_reg[4]),
format("beq x%0d, x%0d, 31f", scratch_reg[0], scratch_reg[4]),
format("li x%0d, 2", scratch_reg[4]),
format("beq x%0d, x%0d, 32f", scratch_reg[0], scratch_reg[4]),
format("li x%0d, 3", scratch_reg[4]),
format("beq x%0d, x%0d, 33f", scratch_reg[0], scratch_reg[4]),
format("30: csrw 0x%0x, x%0d", privileged_reg_t.PMPCFG0, scratch_reg[2]),
format("j 34f"),
format("31: csrw 0x%0x, x%0d", privileged_reg_t.PMPCFG1, scratch_reg[2]),
format("j 34f"),
format("32: csrw 0x%0x, x%0d", privileged_reg_t.PMPCFG2, scratch_reg[2]),
format("j 34f"),
format("33: csrw 0x%0x, x%0d", privileged_reg_t.PMPCFG3, scratch_reg[2]),
// End the pmp handler with a labeled nop instruction, this provides a branch target
// for the internal routine after it has "fixed" the pmp configuration CSR.
format("34: nop")];
}
// This function is used for a directed PMP test to test writes to all the pmpcfg and pmpaddr
// CSRs to test that writes succeed or fail appropriately.
void gen_pmp_write_test(riscv_reg_t[2] scratch_reg,
ref string[] instr) {
import esdl.base.rand: urandom;
ubvec!12 pmp_addr;
ubvec!12 pmpcfg_addr;
ubvec!XLEN pmp_val;
for (int i = 0; i < pmp_num_regions; i++) {
pmp_addr.assign(base_pmp_addr + i);
pmpcfg_addr.assign(base_pmpcfg_addr + (i / cfg_per_csr));
// We randomize the lower 31 bits of pmp_val and then add this to the
// address of <main>, guaranteeing that the random value written to
// pmpaddr[i] doesn't interfere with the safe region.
// `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val, pmp_val[31] == 1'b0;)
pmp_val = urandom!(ubvec!XLEN)();
pmp_val[31] = false;
instr ~= format("li x%0d, 0x%0x", scratch_reg[0], pmp_val);
instr ~= format("la x%0d, main", scratch_reg[1]);
instr ~= format("add x%0d, x%0d, x%0d",
scratch_reg[0], scratch_reg[0], scratch_reg[1]);
// Write the randomized address to pmpaddr[i].
// Original value of pmpaddr[i] will be written to scratch_reg[0].
instr ~= format("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmp_addr, scratch_reg[0]);
// Restore the original address to pmpaddr[i].
// New value of pmpaddr[i] will be written to scratch_reg[0].
instr ~= format("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmp_addr, scratch_reg[0]);
// Randomize value to be written to pmpcfg CSR.
//
// TODO: support rv64.
// `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val,
// foreach (pmp_val[i]) {
// // constrain each Lock bit to 0
// if ((i+1) % 8 == 0) {
// pmp_val[i] == 1'b0;
// }
// // prevent W=1/R=0 combination
// if (i % 8 == 0) { // this is an R bit
// !((pmp_val[i] == 0) && (pmp_val[i+1] == 1'b1));
// }
// }
// )
pmp_val = urandom!(ubvec!XLEN)();
for (size_t j=0; j!=XLEN/8; ++j) {
pmp_val[j*8+7] = false;
ubvec!XLEN mask = ~ (toubvec!XLEN(0b11));
ubvec!XLEN bits;
uint r;
switch (urandom(0, 3)) {
case 0: bits[1] = false; bits[0] = false;
break;
case 1: bits[1] = false; bits[0] = true;
break;
case 2: bits[1] = true; bits[0] = true;
break;
default: assert (false);
}
mask <<= j * 8;
bits <<= j * 8;
pmp_val &= mask;
pmp_val |= bits;
}
// If we're writing to the pmpcfg CSR that contains region0 config information,
// ensure that the "safe" region remains fully accessible.
if (pmpcfg_addr == base_pmpcfg_addr) {
pmp_val[0..8] = cast(ubyte) 0x0f;
}
instr ~= format("li x%0d, 0x%0x", scratch_reg[0], pmp_val);
// Write the randomized address to pmpcfg[i].
// Original value of pmpcfg[i] will be written to scratch_reg[0].
instr ~= format("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmpcfg_addr, scratch_reg[0]);
// Restore the original address to pmpcfg[i].
// New value of pmpcfg[i] will be written to scratch_reg[0].
instr ~= format("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmpcfg_addr, scratch_reg[0]);
}
}
}

View file

@ -0,0 +1,589 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// RISC-V privileged register class
module riscv.gen.riscv_privil_reg;
import riscv.gen.riscv_instr_pkg: privileged_reg_t, privileged_level_t,
reg_field_access_t;
import riscv.gen.target: XLEN;
import riscv.gen.riscv_reg: riscv_reg;
import std.format: format;
import uvm;
class riscv_privil_reg: riscv_reg!(privileged_reg_t)
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
override void init_reg(privileged_reg_t reg_name) {
super.init_reg(reg_name);
switch(reg_name) {
/////////////// Machine mode reigster //////////////
// Machine ISA Register
case privileged_reg_t.MISA:
privil_level = privileged_level_t.M_LEVEL;
add_field("WARL0", 26, reg_field_access_t.WARL);
add_field("WLRL", XLEN-28, reg_field_access_t.WLRL);
add_field("MXL", 2, reg_field_access_t.WARL);
break;
// Machine Vendor ID Register
case privileged_reg_t.MVENDORID:
privil_level = privileged_level_t.M_LEVEL;
add_field("OFFSET", 7, reg_field_access_t.WPRI);
add_field("BANK", XLEN-7, reg_field_access_t.WPRI);
break;
// Machine Architecture ID Register
case privileged_reg_t.MARCHID:
privil_level = privileged_level_t.M_LEVEL;
add_field("ARCHITECTURE_ID", XLEN, reg_field_access_t.WPRI);
break;
// Machine Implementation ID Register
case privileged_reg_t.MIMPID:
privil_level = privileged_level_t.M_LEVEL;
add_field("IMPLEMENTATION", XLEN, reg_field_access_t.WPRI);
break;
// Hart ID Register
case privileged_reg_t.MHARTID:
privil_level = privileged_level_t.M_LEVEL;
add_field("HART_ID", XLEN, reg_field_access_t.WPRI);
break;
// Machine Status Register
case privileged_reg_t.MSTATUS:
privil_level = privileged_level_t.M_LEVEL;
add_field("UIE", 1, reg_field_access_t.WARL);
add_field("SIE", 1, reg_field_access_t.WARL);
add_field("WPRI0", 1, reg_field_access_t.WPRI);
add_field("MIE", 1, reg_field_access_t.WARL);
add_field("UPIE", 1, reg_field_access_t.WARL);
add_field("SPIE", 1, reg_field_access_t.WARL);
add_field("WPRI1", 1, reg_field_access_t.WPRI);
add_field("MPIE", 1, reg_field_access_t.WARL);
add_field("SPP", 1, reg_field_access_t.WLRL);
add_field("VS", 2, reg_field_access_t.WARL);
add_field("MPP", 2, reg_field_access_t.WLRL);
add_field("FS", 2, reg_field_access_t.WARL);
add_field("XS", 2, reg_field_access_t.WARL);
add_field("MPRV", 1, reg_field_access_t.WARL);
add_field("SUM", 1, reg_field_access_t.WARL);
add_field("MXR", 1, reg_field_access_t.WARL);
add_field("TVM", 1, reg_field_access_t.WARL);
add_field("TW", 1, reg_field_access_t.WARL);
add_field("TSR", 1, reg_field_access_t.WARL);
if (XLEN == 32) {
add_field("WPRI3", 8, reg_field_access_t.WPRI);
}
else {
add_field("WPRI3", 9, reg_field_access_t.WPRI);
add_field("UXL", 2, reg_field_access_t.WARL);
add_field("SXL", 2, reg_field_access_t.WARL);
add_field("WPRI4", XLEN - 37, reg_field_access_t.WPRI);
}
add_field("SD", 1, reg_field_access_t.WARL);
break;
// Machine Trap-Vector Base-Address Register
case privileged_reg_t.MTVEC:
privil_level = privileged_level_t.M_LEVEL;
add_field("MODE", 2, reg_field_access_t.WARL);
add_field("BASE", XLEN - 2, reg_field_access_t.WARL);
break;
// Machine Exception Delegation Register
case privileged_reg_t.MEDELEG:
privil_level = privileged_level_t.M_LEVEL;
add_field("IAM", 1, reg_field_access_t.WARL);
add_field("IAF", 1, reg_field_access_t.WARL);
add_field("ILGL", 1, reg_field_access_t.WARL);
add_field("BREAK", 1, reg_field_access_t.WARL);
add_field("LAM", 1, reg_field_access_t.WARL);
add_field("LAF", 1, reg_field_access_t.WARL);
add_field("SAM", 1, reg_field_access_t.WARL);
add_field("SAF", 1, reg_field_access_t.WARL);
add_field("ECFU", 1, reg_field_access_t.WARL);
add_field("ECFS", 1, reg_field_access_t.WARL);
add_field("WARL0", 1, reg_field_access_t.WARL);
add_field("ECFM", 1, reg_field_access_t.WARL);
add_field("IPF", 1, reg_field_access_t.WARL);
add_field("LPF", 1, reg_field_access_t.WARL);
add_field("WARL1", 1, reg_field_access_t.WARL);
add_field("SPF", 1, reg_field_access_t.WARL);
add_field("WARL2", XLEN-16, reg_field_access_t.WARL);
break;
// Machine Interrupt Delegation Register
case privileged_reg_t.MIDELEG:
privil_level = privileged_level_t.M_LEVEL;
add_field("USIP", 1, reg_field_access_t.WARL);
add_field("SSIP", 1, reg_field_access_t.WARL);
add_field("WARL0", 1, reg_field_access_t.WARL);
add_field("MSIP", 1, reg_field_access_t.WARL);
add_field("UTIP", 1, reg_field_access_t.WARL);
add_field("STIP", 1, reg_field_access_t.WARL);
add_field("WARL1", 1, reg_field_access_t.WARL);
add_field("MTIP", 1, reg_field_access_t.WARL);
add_field("UEIP", 1, reg_field_access_t.WARL);
add_field("SEIP", 1, reg_field_access_t.WARL);
add_field("WARL2", 1, reg_field_access_t.WARL);
add_field("MEIP", 1, reg_field_access_t.WARL);
add_field("WARL3", XLEN-12, reg_field_access_t.WARL);
break;
// Machine trap-enable register
case privileged_reg_t.MIP:
privil_level = privileged_level_t.M_LEVEL;
add_field("USIP", 1, reg_field_access_t.WARL);
add_field("SSIP", 1, reg_field_access_t.WARL);
add_field("WPRI0", 1, reg_field_access_t.WPRI);
add_field("MSIP", 1, reg_field_access_t.WARL);
add_field("UTIP", 1, reg_field_access_t.WARL);
add_field("STIP", 1, reg_field_access_t.WARL);
add_field("WPRI1", 1, reg_field_access_t.WPRI);
add_field("MTIP", 1, reg_field_access_t.WARL);
add_field("UEIP", 1, reg_field_access_t.WARL);
add_field("SEIP", 1, reg_field_access_t.WARL);
add_field("WPRI2", 1, reg_field_access_t.WPRI);
add_field("MEIP", 1, reg_field_access_t.WARL);
add_field("WPRI3", XLEN - 12, reg_field_access_t.WPRI);
break;
// Machine Interrupt-enable register
case privileged_reg_t.MIE:
privil_level = privileged_level_t.M_LEVEL;
add_field("USIE", 1, reg_field_access_t.WARL);
add_field("SSIE", 1, reg_field_access_t.WARL);
add_field("WPRI0", 1, reg_field_access_t.WPRI);
add_field("MSIE", 1, reg_field_access_t.WARL);
add_field("UTIE", 1, reg_field_access_t.WARL);
add_field("STIE", 1, reg_field_access_t.WARL);
add_field("WPRI1", 1, reg_field_access_t.WPRI);
add_field("MTIE", 1, reg_field_access_t.WARL);
add_field("UEIE", 1, reg_field_access_t.WARL);
add_field("SEIE", 1, reg_field_access_t.WARL);
add_field("WPRI2", 1, reg_field_access_t.WPRI);
add_field("MEIE", 1, reg_field_access_t.WARL);
add_field("WPRI3", XLEN - 12, reg_field_access_t.WPRI);
break;
// Cycle Count Register
case privileged_reg_t.MCYCLE:
privil_level = privileged_level_t.M_LEVEL;
add_field("MCYCLE", 64, reg_field_access_t.WPRI);
break;
// Instruction Count Register
case privileged_reg_t.MINSTRET:
privil_level = privileged_level_t.M_LEVEL;
add_field("MINSTRET", 64, reg_field_access_t.WPRI);
break;
// Cycle Count Register - RV32I only
case privileged_reg_t.MCYCLEH:
privil_level = privileged_level_t.M_LEVEL;
add_field("MCYCLEH", 32, reg_field_access_t.WPRI);
break;
// Instruction Count Register - RV32I only
case privileged_reg_t.MINSTRETH:
privil_level = privileged_level_t.M_LEVEL;
add_field("MINSTRETH", 32, reg_field_access_t.WPRI);
break;
// Hardware Performance Monitor Counters
case privileged_reg_t.MHPMCOUNTER3:
..
case privileged_reg_t.MHPMCOUNTER31:
privil_level = privileged_level_t.M_LEVEL;
add_field(format("%s", reg_name), XLEN, reg_field_access_t.WARL);
break;
// Hardware Performance Monitor Events
case privileged_reg_t.MHPMEVENT3:
..
case privileged_reg_t.MHPMEVENT31:
privil_level = privileged_level_t.M_LEVEL;
add_field(format("%s", reg_name), XLEN, reg_field_access_t.WARL);
break;
// Hardware Performance Monitor Counters - RV32I only
case privileged_reg_t.MHPMCOUNTER3H:
..
case privileged_reg_t.MHPMCOUNTER31H:
if (XLEN != 32) {
uvm_fatal(get_full_name(), format("Register %s is only in RV32I", reg_name));
}
privil_level = privileged_level_t.M_LEVEL;
add_field(format("%s", reg_name), 32, reg_field_access_t.WARL);
break;
// Machine Counter Enable Register
case privileged_reg_t.MCOUNTEREN:
privil_level = privileged_level_t.M_LEVEL;
add_field("CY", 1, reg_field_access_t.WARL);
add_field("TM", 1, reg_field_access_t.WARL);
add_field("IR", 1, reg_field_access_t.WARL);
add_field("HPM3", 1, reg_field_access_t.WARL);
add_field("HPM4", 1, reg_field_access_t.WARL);
add_field("HPM5", 1, reg_field_access_t.WARL);
add_field("HPM6", 1, reg_field_access_t.WARL);
add_field("HPM7", 1, reg_field_access_t.WARL);
add_field("HPM8", 1, reg_field_access_t.WARL);
add_field("HPM9", 1, reg_field_access_t.WARL);
add_field("HPM10", 1, reg_field_access_t.WARL);
add_field("HPM11", 1, reg_field_access_t.WARL);
add_field("HPM12", 1, reg_field_access_t.WARL);
add_field("HPM13", 1, reg_field_access_t.WARL);
add_field("HPM14", 1, reg_field_access_t.WARL);
add_field("HPM15", 1, reg_field_access_t.WARL);
add_field("HPM16", 1, reg_field_access_t.WARL);
add_field("HPM17", 1, reg_field_access_t.WARL);
add_field("HPM18", 1, reg_field_access_t.WARL);
add_field("HPM19", 1, reg_field_access_t.WARL);
add_field("HPM20", 1, reg_field_access_t.WARL);
add_field("HPM21", 1, reg_field_access_t.WARL);
add_field("HPM22", 1, reg_field_access_t.WARL);
add_field("HPM23", 1, reg_field_access_t.WARL);
add_field("HPM24", 1, reg_field_access_t.WARL);
add_field("HPM25", 1, reg_field_access_t.WARL);
add_field("HPM26", 1, reg_field_access_t.WARL);
add_field("HPM27", 1, reg_field_access_t.WARL);
add_field("HPM28", 1, reg_field_access_t.WARL);
add_field("HPM29", 1, reg_field_access_t.WARL);
add_field("HPM30", 1, reg_field_access_t.WARL);
add_field("HPM31", 1, reg_field_access_t.WARL);
if (XLEN == 64) {
add_field("reg_field_access_t.WPRI", 32, reg_field_access_t.WPRI);
}
break;
// Machine Scratch Register
case privileged_reg_t.MSCRATCH:
privil_level = privileged_level_t.M_LEVEL;
add_field("MSCRATCH", XLEN, reg_field_access_t.WARL);
break;
// Machine Exception Program Counter
case privileged_reg_t.MEPC:
privil_level = privileged_level_t.M_LEVEL;
add_field("BASE", XLEN, reg_field_access_t.WARL);
break;
// Machine Cause Register
case privileged_reg_t.MCAUSE:
privil_level = privileged_level_t.M_LEVEL;
add_field("CODE", 4, reg_field_access_t.WLRL);
add_field("WLRL", XLEN-5, reg_field_access_t.WLRL);
add_field("INTERRUPT", 1, reg_field_access_t.WARL);
break;
// Machine Trap Value
case privileged_reg_t.MTVAL:
privil_level = privileged_level_t.M_LEVEL;
add_field("VALUE", XLEN, reg_field_access_t.WARL);
break;
// Physical Memory Protection Configuration Register
case privileged_reg_t.PMPCFG0:
privil_level = privileged_level_t.M_LEVEL;
add_field("PMP0CFG", 8, reg_field_access_t.WARL);
add_field("PMP1CFG", 8, reg_field_access_t.WARL);
add_field("PMP2CFG", 8, reg_field_access_t.WARL);
add_field("PMP3CFG", 8, reg_field_access_t.WARL);
if (XLEN==64) {
add_field("PMP4CFG", 8, reg_field_access_t.WARL);
add_field("PMP5CFG", 8, reg_field_access_t.WARL);
add_field("PMP6CFG", 8, reg_field_access_t.WARL);
add_field("PMP7CFG", 8, reg_field_access_t.WARL);
}
break;
// Physical Memory Protection Configuration Register
case privileged_reg_t.PMPCFG1:
privil_level = privileged_level_t.M_LEVEL;
if (XLEN!=32) {
uvm_fatal(get_full_name(), "CSR PMPCFG1 only exists in RV32.");
}
else {
add_field("PMP4CFG", 8, reg_field_access_t.WARL);
add_field("PMP5CFG", 8, reg_field_access_t.WARL);
add_field("PMP6CFG", 8, reg_field_access_t.WARL);
add_field("PMP7CFG", 8, reg_field_access_t.WARL);
}
break;
// Physical Memory Protection Configuration Register
case privileged_reg_t.PMPCFG2:
privil_level = privileged_level_t.M_LEVEL;
add_field("PMP8CFG", 8, reg_field_access_t.WARL);
add_field("PMP9CFG", 8, reg_field_access_t.WARL);
add_field("PMP10CFG", 8, reg_field_access_t.WARL);
add_field("PMP11CFG", 8, reg_field_access_t.WARL);
if (XLEN==64) {
add_field("PMP12CFG", 8, reg_field_access_t.WARL);
add_field("PMP13CFG", 8, reg_field_access_t.WARL);
add_field("PMP14CFG", 8, reg_field_access_t.WARL);
add_field("PMP15CFG", 8, reg_field_access_t.WARL);
}
break;
// Physical Memory Protection Configuration Register
case privileged_reg_t.PMPCFG3:
if (XLEN!=32) {
uvm_fatal(get_full_name(), "CSR PMPCFG3 only exists in RV32.");
}
privil_level = privileged_level_t.M_LEVEL;
add_field("PMP12CFG", 8, reg_field_access_t.WARL);
add_field("PMP13CFG", 8, reg_field_access_t.WARL);
add_field("PMP14CFG", 8, reg_field_access_t.WARL);
add_field("PMP15CFG", 8, reg_field_access_t.WARL);
break;
// Physical Memory Protection Configuration Registers
case privileged_reg_t.PMPADDR0:
..
case privileged_reg_t.PMPADDR15:
privil_level = privileged_level_t.M_LEVEL;
if (XLEN==64) {
add_field("ADDRESS", 54, reg_field_access_t.WARL);
add_field("WARL", 10, reg_field_access_t.WARL);
}
else {
add_field("ADDRESS", 32, reg_field_access_t.WARL);
}
break;
/////////////// Supervisor mode reigster //////////////
// Supervisor status register
case privileged_reg_t.SSTATUS:
privil_level = privileged_level_t.S_LEVEL;
add_field("UIE", 1, reg_field_access_t.WARL);
add_field("SIE", 1, reg_field_access_t.WARL);
add_field("WPRI0", 2, reg_field_access_t.WPRI);
add_field("UPIE", 1, reg_field_access_t.WARL);
add_field("SPIE", 1, reg_field_access_t.WARL);
add_field("WPRI1", 2, reg_field_access_t.WPRI);
add_field("SPP", 1, reg_field_access_t.WLRL);
add_field("WPRI2", 4, reg_field_access_t.WPRI);
add_field("FS", 2, reg_field_access_t.WARL);
add_field("XS", 2, reg_field_access_t.WARL);
add_field("WPRI3", 1, reg_field_access_t.WPRI);
add_field("SUM", 1, reg_field_access_t.WARL);
add_field("MXR", 1, reg_field_access_t.WARL);
if (XLEN == 32) {
add_field("WPRI4", 11, reg_field_access_t.WPRI);
} else {
add_field("WPRI4", 12, reg_field_access_t.WPRI);
add_field("UXL", 2, reg_field_access_t.WARL);
add_field("WPRI4", XLEN - 35, reg_field_access_t.WPRI);
}
add_field("SD", 1, reg_field_access_t.WARL);
break;
// Supervisor Trap Vector Base Address Register
case privileged_reg_t.STVEC:
privil_level = privileged_level_t.S_LEVEL;
add_field("MODE", 2, reg_field_access_t.WARL);
add_field("BASE", XLEN-2, reg_field_access_t.WLRL);
break;
// Supervisor Exception Delegation Register
case privileged_reg_t.SEDELEG:
privil_level = privileged_level_t.S_LEVEL;
add_field("IAM", 1, reg_field_access_t.WARL);
add_field("IAF", 1, reg_field_access_t.WARL);
add_field("II", 1, reg_field_access_t.WARL);
add_field("WPRI0", 1, reg_field_access_t.WPRI);
add_field("LAM", 1, reg_field_access_t.WARL);
add_field("LAF", 1, reg_field_access_t.WARL);
add_field("SAM", 1, reg_field_access_t.WARL);
add_field("SAF", 1, reg_field_access_t.WARL);
add_field("ECFU", 1, reg_field_access_t.WARL);
add_field("WPRI1", 1, reg_field_access_t.WPRI);
add_field("WARL0", 1, reg_field_access_t.WARL);
add_field("WPRI2", 1, reg_field_access_t.WPRI);
add_field("IPF", 1, reg_field_access_t.WARL);
add_field("LPF", 1, reg_field_access_t.WARL);
add_field("WARL1", 1, reg_field_access_t.WARL);
add_field("SPF", 1, reg_field_access_t.WARL);
add_field("WARL2", XLEN-16, reg_field_access_t.WARL);
break;
// Supervisor Interrupt Delegation Register
case privileged_reg_t.SIDELEG:
privil_level = privileged_level_t.S_LEVEL;
add_field("USIP", 1, reg_field_access_t.WARL);
add_field("SSIP", 1, reg_field_access_t.WARL);
add_field("WARL0", 1, reg_field_access_t.WARL);
add_field("WPRI0", 1, reg_field_access_t.WPRI);
add_field("UTIP", 1, reg_field_access_t.WARL);
add_field("STIP", 1, reg_field_access_t.WARL);
add_field("WARL1", 1, reg_field_access_t.WARL);
add_field("WPRI1", 1, reg_field_access_t.WPRI);
add_field("UEIP", 1, reg_field_access_t.WARL);
add_field("SEIP", 1, reg_field_access_t.WARL);
add_field("WARL2", 1, reg_field_access_t.WARL);
add_field("WPRI2", 1, reg_field_access_t.WPRI);
add_field("WARL3", XLEN-12, reg_field_access_t.WARL);
break;
// Supervisor trap-enable register
case privileged_reg_t.SIP:
privil_level = privileged_level_t.S_LEVEL;
add_field("USIP", 1, reg_field_access_t.WARL);
add_field("SSIP", 1, reg_field_access_t.WARL);
add_field("WPRI0", 2, reg_field_access_t.WPRI);
add_field("UTIP", 1, reg_field_access_t.WARL);
add_field("STIP", 1, reg_field_access_t.WARL);
add_field("WPRI1", 2, reg_field_access_t.WPRI);
add_field("UEIP", 1, reg_field_access_t.WARL);
add_field("SEIP", 1, reg_field_access_t.WARL);
add_field("WPRI2", 2, reg_field_access_t.WPRI);
add_field("WPRI3", XLEN - 12, reg_field_access_t.WPRI);
break;
// Supervisor interrupt-enable register
case privileged_reg_t.SIE:
privil_level = privileged_level_t.S_LEVEL;
add_field("USIE", 1, reg_field_access_t.WARL);
add_field("SSIE", 1, reg_field_access_t.WARL);
add_field("WPRI0", 2, reg_field_access_t.WPRI);
add_field("UTIE", 1, reg_field_access_t.WARL);
add_field("STIE", 1, reg_field_access_t.WARL);
add_field("WPRI1", 2, reg_field_access_t.WPRI);
add_field("UEIE", 1, reg_field_access_t.WARL);
add_field("SEIE", 1, reg_field_access_t.WARL);
add_field("WPRI2", XLEN - 10, reg_field_access_t.WPRI);
break;
// Supervisor Counter Enable Register
case privileged_reg_t.SCOUNTEREN:
privil_level = privileged_level_t.S_LEVEL;
add_field("CY", 1, reg_field_access_t.WARL);
add_field("TM", 1, reg_field_access_t.WARL);
add_field("IR", 1, reg_field_access_t.WARL);
add_field("HPM3", 1, reg_field_access_t.WARL);
add_field("HPM4", 1, reg_field_access_t.WARL);
add_field("HPM5", 1, reg_field_access_t.WARL);
add_field("HPM6", 1, reg_field_access_t.WARL);
add_field("HPM7", 1, reg_field_access_t.WARL);
add_field("HPM8", 1, reg_field_access_t.WARL);
add_field("HPM9", 1, reg_field_access_t.WARL);
add_field("HPM10", 1, reg_field_access_t.WARL);
add_field("HPM11", 1, reg_field_access_t.WARL);
add_field("HPM12", 1, reg_field_access_t.WARL);
add_field("HPM13", 1, reg_field_access_t.WARL);
add_field("HPM14", 1, reg_field_access_t.WARL);
add_field("HPM15", 1, reg_field_access_t.WARL);
add_field("HPM16", 1, reg_field_access_t.WARL);
add_field("HPM17", 1, reg_field_access_t.WARL);
add_field("HPM18", 1, reg_field_access_t.WARL);
add_field("HPM19", 1, reg_field_access_t.WARL);
add_field("HPM20", 1, reg_field_access_t.WARL);
add_field("HPM21", 1, reg_field_access_t.WARL);
add_field("HPM22", 1, reg_field_access_t.WARL);
add_field("HPM23", 1, reg_field_access_t.WARL);
add_field("HPM24", 1, reg_field_access_t.WARL);
add_field("HPM25", 1, reg_field_access_t.WARL);
add_field("HPM26", 1, reg_field_access_t.WARL);
add_field("HPM27", 1, reg_field_access_t.WARL);
add_field("HPM28", 1, reg_field_access_t.WARL);
add_field("HPM29", 1, reg_field_access_t.WARL);
add_field("HPM30", 1, reg_field_access_t.WARL);
add_field("HPM31", 1, reg_field_access_t.WARL);
if (XLEN == 64) {
add_field("reg_field_access_t.WPRI", 32, reg_field_access_t.WPRI);
}
break;
// Supervisor Scratch Register
case privileged_reg_t.SSCRATCH:
privil_level = privileged_level_t.S_LEVEL;
add_field("SSCRATCH", XLEN, reg_field_access_t.WARL);
break;
// Supervisor Exception Program Counter
case privileged_reg_t.SEPC:
privil_level = privileged_level_t.S_LEVEL;
add_field("BASE", XLEN, reg_field_access_t.WARL);
break;
// Supervisor Cause Register
case privileged_reg_t.SCAUSE:
privil_level = privileged_level_t.S_LEVEL;
add_field("CODE", 4, reg_field_access_t.WLRL);
add_field("WLRL", XLEN-5, reg_field_access_t.WLRL);
add_field("INTERRUPT", 1, reg_field_access_t.WARL);
break;
// Supervisor Trap Value
case privileged_reg_t.STVAL:
privil_level = privileged_level_t.S_LEVEL;
add_field("VALUE", XLEN, reg_field_access_t.WARL);
break;
// Supervisor Address Translation and Protection
case privileged_reg_t.SATP:
privil_level = privileged_level_t.S_LEVEL;
if (XLEN == 32) {
add_field("PPN", 22, reg_field_access_t.WARL);
add_field("ASID", 9, reg_field_access_t.WARL);
add_field("MODE", 1, reg_field_access_t.WARL);
}
else {
add_field("PPN", 44, reg_field_access_t.WARL);
add_field("ASID", 16, reg_field_access_t.WARL);
add_field("MODE", 4, reg_field_access_t.WARL);
}
break;
/////////////// User mode reigster //////////////
// User Status Register
case privileged_reg_t.USTATUS:
privil_level = privileged_level_t.U_LEVEL;
add_field("UIE", 1, reg_field_access_t.WARL);
add_field("WPRI0", 3, reg_field_access_t.WPRI);
add_field("UPIE", 1, reg_field_access_t.WARL);
add_field("WPRI1", XLEN-5, reg_field_access_t.WPRI);
break;
// User Trap Vector Base Address Register
case privileged_reg_t.UTVEC:
privil_level = privileged_level_t.U_LEVEL;
add_field("MODE", 2, reg_field_access_t.WARL);
add_field("BASE", XLEN-2, reg_field_access_t.WLRL);
break;
// User Interrupt-Enable register
case privileged_reg_t.UIE:
privil_level = privileged_level_t.U_LEVEL;
add_field("USIE", 1, reg_field_access_t.WARL);
add_field("WPRI0", 3, reg_field_access_t.WPRI);
add_field("UTIE", 1, reg_field_access_t.WARL);
add_field("WPRI1", 3, reg_field_access_t.WPRI);
add_field("UEIE", 1, reg_field_access_t.WARL);
add_field("WPRI2", XLEN-9, reg_field_access_t.WPRI);
break;
// User Trap-Enable register
case privileged_reg_t.UIP:
privil_level = privileged_level_t.U_LEVEL;
add_field("USIP", 1, reg_field_access_t.WARL);
add_field("WPRI0", 3, reg_field_access_t.WPRI);
add_field("UTIP", 1, reg_field_access_t.WARL);
add_field("WPRI1", 3, reg_field_access_t.WPRI);
add_field("UEIP", 1, reg_field_access_t.WARL);
add_field("WPRI2", XLEN-9, reg_field_access_t.WPRI);
break;
// User Scratch Register
case privileged_reg_t.USCRATCH:
privil_level = privileged_level_t.U_LEVEL;
add_field("MSCRATCH", XLEN, reg_field_access_t.WARL);
break;
// User Exception Program Counter
case privileged_reg_t.UEPC:
privil_level = privileged_level_t.U_LEVEL;
add_field("BASE", XLEN, reg_field_access_t.WARL);
break;
// User Cause Register
case privileged_reg_t.UCAUSE:
privil_level = privileged_level_t.U_LEVEL;
add_field("CODE", 4, reg_field_access_t.WLRL);
add_field("WLRL", XLEN-5, reg_field_access_t.WLRL);
add_field("INTERRUPT", 1, reg_field_access_t.WARL);
break;
// User Trap Value
case privileged_reg_t.UTVAL:
privil_level = privileged_level_t.U_LEVEL;
add_field("VALUE", XLEN, reg_field_access_t.WARL);
break;
default:
uvm_fatal(get_full_name(), format("reg %0s is not supported yet", reg_name));
}
}
}

View file

@ -0,0 +1,300 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This class provides some common routines for privileged mode operations
module riscv.gen.riscv_privileged_common_seq;
import riscv.gen.riscv_instr_pkg: privileged_mode_t, privileged_reg_t,
format_string, indent, satp_mode_t, hart_prefix, LABEL_STR_LEN;
import riscv.gen.target: supported_privileged_mode, support_umode_trap,
implemented_csr, XLEN, SATP_MODE;
import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config;
import riscv.gen.riscv_privil_reg: riscv_privil_reg;
import std.algorithm.searching: canFind;
import std.format: format;
import std.string: toLower;
import esdl.data.queue: Queue;
import esdl.data.bvec: ubvec, toubvec;
import esdl.rand: randomize;
import uvm;
class riscv_privileged_common_seq : uvm_sequence!(uvm_sequence_item,uvm_sequence_item)
{
riscv_instr_gen_config cfg;
int hart;
riscv_privil_reg mstatus;
riscv_privil_reg mie;
riscv_privil_reg sstatus;
riscv_privil_reg sie;
riscv_privil_reg ustatus;
riscv_privil_reg uie;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
void enter_privileged_mode(in privileged_mode_t mode,
out Queue!string instrs) {
import std.conv: to;
string label = format_string(format("%0sinit_%0s:",
hart_prefix(hart), mode), LABEL_STR_LEN);
string[] ret_instr = ["mret"];
riscv_privil_reg[] regs;
label = label.toLower();
setup_mmode_reg(mode, regs);
if (mode == privileged_mode_t.SUPERVISOR_MODE) {
setup_smode_reg(mode, regs);
}
if (mode == privileged_mode_t.USER_MODE) {
setup_umode_reg(mode, regs);
}
if (cfg.virtual_addr_translation_on) {
setup_satp(instrs);
}
gen_csr_instr(regs, instrs);
// Use mret/sret to switch to the target privileged mode
instrs ~= ret_instr[0];
foreach (instr; instrs) {
instr = indent ~ instr;
}
instrs.pushFront(label);
}
void enter_privileged_mode(in privileged_mode_t mode,
out string[] instrs) {
import std.conv: to;
string label = format_string(format("%0sinit_%0s:",
hart_prefix(hart), mode), LABEL_STR_LEN);
string[] ret_instr = ["mret"];
riscv_privil_reg[] regs;
label = label.toLower();
instrs ~= label;
setup_mmode_reg(mode, regs);
if (mode == privileged_mode_t.SUPERVISOR_MODE) {
setup_smode_reg(mode, regs);
}
if (mode == privileged_mode_t.USER_MODE) {
setup_umode_reg(mode, regs);
}
if (cfg.virtual_addr_translation_on) {
setup_satp(instrs);
}
gen_csr_instr(regs, instrs);
// Use mret/sret to switch to the target privileged mode
instrs ~= ret_instr[0];
foreach (i, ref instr; instrs) {
if (i != 0) // skip indent for label
instr = indent ~ instr;
}
// instrs.pushFront(label); // do it upfront
}
void setup_mmode_reg(privileged_mode_t mode, ref riscv_privil_reg[] regs) {
mstatus = riscv_privil_reg.type_id.create("mstatus");
mstatus.init_reg(privileged_reg_t.MSTATUS);
if (cfg.randomize_csr) {
mstatus.set_val(cfg.mstatus);
}
mstatus.set_field("MPRV", cfg.mstatus_mprv);
mstatus.set_field("MXR", cfg.mstatus_mxr);
mstatus.set_field("SUM", cfg.mstatus_sum);
mstatus.set_field("TVM", cfg.mstatus_tvm);
mstatus.set_field("TW", cfg.set_mstatus_tw);
mstatus.set_field("FS", cfg.mstatus_fs);
mstatus.set_field("VS", cfg.mstatus_vs);
if (!(canFind(supported_privileged_mode, privileged_mode_t.SUPERVISOR_MODE) && (XLEN != 32))) {
mstatus.set_field("SXL", toubvec!2(0b00));
}
else if (XLEN == 64) {
mstatus.set_field("SXL", toubvec!2(0b10));
}
if (!(canFind(supported_privileged_mode, privileged_mode_t.USER_MODE) && (XLEN != 32))) {
mstatus.set_field("UXL", toubvec!2(0b00));
} else if (XLEN == 64) {
mstatus.set_field("UXL", toubvec!2(0b10));
}
mstatus.set_field("XS", 0);
mstatus.set_field("SD", 0);
mstatus.set_field("UIE", 0);
// Set the previous privileged mode as the target mode
mstatus.set_field("MPP", mode);
mstatus.set_field("SPP", 0);
// Enable interrupt
mstatus.set_field("MPIE", cfg.enable_interrupt);
mstatus.set_field("MIE", cfg.enable_interrupt);
mstatus.set_field("SPIE", cfg.enable_interrupt);
mstatus.set_field("SIE", cfg.enable_interrupt);
mstatus.set_field("UPIE", cfg.enable_interrupt);
mstatus.set_field("UIE", support_umode_trap);
uvm_info(get_full_name(), format("mstatus_val: 0x%0x", mstatus.get_val()), UVM_LOW);
regs ~= mstatus;
// Enable external and timer interrupt
if (canFind(implemented_csr, privileged_reg_t.MIE)) {
mie = riscv_privil_reg.type_id.create("mie");
mie.init_reg(privileged_reg_t.MIE);
if (cfg.randomize_csr) {
mie.set_val(cfg.mie);
}
mie.set_field("UEIE", cfg.enable_interrupt);
mie.set_field("SEIE", cfg.enable_interrupt);
mie.set_field("MEIE", cfg.enable_interrupt);
mie.set_field("USIE", cfg.enable_interrupt);
mie.set_field("SSIE", cfg.enable_interrupt);
mie.set_field("MSIE", cfg.enable_interrupt);
mie.set_field("MTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
mie.set_field("STIE", cfg.enable_interrupt & cfg.enable_timer_irq);
mie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
regs ~= mie;
}
}
void setup_smode_reg(privileged_mode_t mode, ref riscv_privil_reg [] regs) {
sstatus = riscv_privil_reg.type_id.create("sstatus");
sstatus.init_reg(privileged_reg_t.SSTATUS);
sstatus.randomize();
if (cfg.randomize_csr) {
sstatus.set_val(cfg.sstatus);
}
sstatus.set_field("SPIE", cfg.enable_interrupt);
sstatus.set_field("SIE", cfg.enable_interrupt);
sstatus.set_field("UPIE", cfg.enable_interrupt);
sstatus.set_field("UIE", support_umode_trap);
if(XLEN==64) {
sstatus.set_field("UXL", toubvec!2(0b10));
}
sstatus.set_field("FS", cfg.mstatus_fs);
sstatus.set_field("XS", 0);
sstatus.set_field("SD", 0);
sstatus.set_field("UIE", 0);
sstatus.set_field("SPP", 0);
regs ~= sstatus;
// Enable external and timer interrupt
if (canFind(implemented_csr, privileged_reg_t.SIE)) {
sie = riscv_privil_reg.type_id.create("sie");
sie.init_reg(privileged_reg_t.SIE);
if (cfg.randomize_csr) {
sie.set_val(cfg.sie);
}
sie.set_field("UEIE", cfg.enable_interrupt);
sie.set_field("SEIE", cfg.enable_interrupt);
sie.set_field("USIE", cfg.enable_interrupt);
sie.set_field("SSIE", cfg.enable_interrupt);
sie.set_field("STIE", cfg.enable_interrupt & cfg.enable_timer_irq);
sie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
regs ~= sie;
}
}
void setup_umode_reg(privileged_mode_t mode, ref riscv_privil_reg[] regs) {
// For implementations that do not provide any U-mode CSRs, return immediately
if (! support_umode_trap) {
return;
}
else {
ustatus = riscv_privil_reg.type_id.create("ustatus");
ustatus.init_reg(privileged_reg_t.USTATUS);
ustatus.randomize();
if (cfg.randomize_csr) {
ustatus.set_val(cfg.ustatus);
}
ustatus.set_field("UIE", cfg.enable_interrupt);
ustatus.set_field("UPIE", cfg.enable_interrupt);
regs ~= ustatus;
if (canFind(implemented_csr, privileged_reg_t.UIE )) {
uie = riscv_privil_reg.type_id.create("uie");
uie.init_reg(privileged_reg_t.UIE);
if (cfg.randomize_csr) {
uie.set_val(cfg.uie);
}
uie.set_field("UEIE", cfg.enable_interrupt);
uie.set_field("USIE", cfg.enable_interrupt);
uie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
regs ~= uie;
}
}
}
void gen_csr_instr(riscv_privil_reg[] regs, ref Queue!string instrs) {
import std.conv: to;
foreach (r; regs) {
instrs ~= format("li x%0d, 0x%0x", cfg.gpr[0], r.get_val());
instrs ~= format("csrw 0x%0x, x%0d # %0s",
r.reg_name, cfg.gpr[0], r.reg_name.to!string());
}
}
void gen_csr_instr(riscv_privil_reg[] regs, ref string[] instrs) {
import std.conv: to;
foreach (r; regs) {
instrs ~= format("li x%0d, 0x%0x", cfg.gpr[0], r.get_val());
instrs ~= format("csrw 0x%0x, x%0d # %0s",
r.reg_name, cfg.gpr[0], r.reg_name.to!string());
}
}
void setup_satp(ref Queue!string instrs) {
riscv_privil_reg satp;
ubvec!XLEN satp_ppn_mask;
if (SATP_MODE == satp_mode_t.BARE) return;
else {
satp = riscv_privil_reg.type_id.create("satp");
satp.init_reg(privileged_reg_t.SATP);
satp.set_field("MODE", SATP_MODE);
instrs ~= format("li x%0d, 0x%0x", cfg.gpr[0], satp.get_val());
instrs ~= format("csrw 0x%0x, x%0d # satp", privileged_reg_t.SATP, cfg.gpr[0]);
satp_ppn_mask = ubvec!XLEN.max >> (XLEN - satp.get_field_by_name("PPN").bit_width);
// Load the root page table physical address
instrs ~= format("la x%0d, page_table_0", cfg.gpr[0]);
// Right shift to get PPN at 4k granularity
instrs ~= format("srli x%0d, x%0d, 12", cfg.gpr[0], cfg.gpr[0]);
instrs ~= format("li x%0d, 0x%0x", cfg.gpr[1], satp_ppn_mask);
instrs ~= format("and x%0d, x%0d, x%0d", cfg.gpr[0], cfg.gpr[0], cfg.gpr[1]);
// Set the PPN field for SATP
instrs ~= format("csrs 0x%0x, x%0d # satp", privileged_reg_t.SATP, cfg.gpr[0]);
}
}
void setup_satp(ref string[] instrs) {
riscv_privil_reg satp;
ubvec!XLEN satp_ppn_mask;
if (SATP_MODE == satp_mode_t.BARE) return;
else {
satp = riscv_privil_reg.type_id.create("satp");
satp.init_reg(privileged_reg_t.SATP);
satp.set_field("MODE", SATP_MODE);
instrs ~= format("li x%0d, 0x%0x", cfg.gpr[0], satp.get_val());
instrs ~= format("csrw 0x%0x, x%0d # satp", privileged_reg_t.SATP, cfg.gpr[0]);
satp_ppn_mask = ubvec!XLEN.max >> (XLEN - satp.get_field_by_name("PPN").bit_width);
// Load the root page table physical address
instrs ~= format("la x%0d, page_table_0", cfg.gpr[0]);
// Right shift to get PPN at 4k granularity
instrs ~= format("srli x%0d, x%0d, 12", cfg.gpr[0], cfg.gpr[0]);
instrs ~= format("li x%0d, 0x%0x", cfg.gpr[1], satp_ppn_mask);
instrs ~= format("and x%0d, x%0d, x%0d", cfg.gpr[0], cfg.gpr[0], cfg.gpr[1]);
// Set the PPN field for SATP
instrs ~= format("csrs 0x%0x, x%0d # satp", privileged_reg_t.SATP, cfg.gpr[0]);
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Psuedo instructions are used to simplify assembly program writing
module riscv.gen.riscv_pseudo_instr;
import riscv.gen.riscv_instr_pkg: riscv_pseudo_instr_name_t, riscv_instr_format_t,
riscv_instr_category_t, riscv_instr_group_t, format_string, MAX_INSTR_STR_LEN;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import std.string: toLower;
import esdl.rand: rand, constraint;
import uvm;
class riscv_pseudo_instr: riscv_instr
{
@rand riscv_pseudo_instr_name_t pseudo_instr_name;
// `add_pseudo_instr(LI, I_FORMAT, LOAD, RV32I)
constraint! q{
if (pseudo_instr_name == riscv_pseudo_instr_name_t.LI) {
instr_format == riscv_instr_format_t.I_FORMAT;
category == riscv_instr_category_t.LOAD;
group == riscv_instr_group_t.RV32I;
}
} riscv_RV32I_LI_c;
// `add_pseudo_instr(LA, I_FORMAT, LOAD, RV32I)
constraint! q{
if (pseudo_instr_name == riscv_pseudo_instr_name_t.LA) {
instr_format == riscv_instr_format_t.I_FORMAT;
category == riscv_instr_category_t.LOAD;
group == riscv_instr_group_t.RV32I;
}
} riscv_RV32I_LA_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
process_load_store = false;
this.instr_format = riscv_instr_format_t.I_FORMAT;
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
string asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
// instr rd,imm
asm_str = format("%0s%0s, %0s", asm_str, rd, get_imm());
if (comment != "")
asm_str ~= " #"~comment;
return asm_str.toLower();
}
override string get_instr_name() {
import std.conv: to;
return pseudo_instr_name.to!string();
}
}

View file

@ -0,0 +1,185 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// --------------------------------------------------
// Light weight RISC-V register class library
// --------------------------------------------------
// Base class for RISC-V register field
module riscv.gen.riscv_reg;
import esdl.data.bvec: ubvec, toubvec;
import riscv.gen.riscv_instr_pkg: reg_field_access_t, privileged_reg_t,
privileged_level_t, riscv_csr_t;
import riscv.gen.target: XLEN;
import std.format: format;
import esdl.rand: rand, constraint, randomize;
import uvm;
class riscv_reg_field: uvm_object
{
mixin uvm_object_utils;
uint bit_width;
ubvec!XLEN reset_val ;
@rand ubvec!XLEN val;
reg_field_access_t access_type;
bool hard_wired;
constraint! q{
(access_type == reg_field_access_t.WPRI) -> (val == 0);
} zero_reserved_field_c;
constraint! q{
(hard_wired == true) -> (val == reset_val);
} hardwired_fld_c;
this(string name = "") {
super(name);
}
override string convert2string() {
return(format("%0s bit_width:%0d val:0x%0x type:%0s",
get_name(), bit_width, val, access_type));
}
void post_randomize() {
ubvec!XLEN mask = ubvec!XLEN.max();
mask >>= (XLEN-bit_width);
val = mask & val;
}
}
version(CHECK_COMPILE) alias riscv_reg_privileged_reg_t = riscv_reg!(privileged_reg_t);
// Base class for RISC-V register
class riscv_reg(REG_T): uvm_object
{
mixin uvm_object_utils;
REG_T reg_name;
riscv_csr_t offset;
privileged_level_t privil_level;
ubvec!XLEN val;
@rand riscv_reg_field[] fld;
this(string name = "") {
super(name);
}
void init_reg(REG_T reg_name) {
this.reg_name = reg_name;
offset = toubvec!12(reg_name);
}
ubvec!XLEN get_val() {
import std.stdio: writeln;
int total_len = 0;
// total_len = fld.sum() with (item.bit_width);
foreach (f; fld) total_len = total_len + f.bit_width;
if (total_len != XLEN) {
foreach (f; fld) {
writeln(format(f.convert2string()));
uvm_fatal(get_full_name(),
format("Total field length %0d != XLEN %0d", total_len, XLEN));
}
}
val = 0;
foreach (f; fld) {
val = (val << f.bit_width) | f.val;
}
return val;
}
void add_field(string fld_name, uint bit_width,
reg_field_access_t access_type,
ubvec!XLEN reset_val = 0) {
riscv_reg_field new_fld;
new_fld = riscv_reg_field.type_id.create(fld_name);
new_fld.bit_width = bit_width;
new_fld.access_type = access_type;
new_fld.reset_val = reset_val;
fld ~= new_fld;
}
void set_field(T)(string fld_name, T val, bool hard_wired = false) {
ubvec!XLEN val_ = val;
set_field_bvec(fld_name, val_, hard_wired);
}
void set_field_bvec(string fld_name, ubvec!XLEN val, bool hard_wired = false) {
foreach (f; fld) {
if (fld_name == (f.get_name())) {
f.val = val;
f.hard_wired = hard_wired;
if (hard_wired) {
f.reset_val = val;
}
return;
}
}
uvm_fatal(get_full_name(), format("Cannot match found field %0s", fld_name));
}
riscv_reg_field get_field_by_name(string fld_name) {
foreach (f; fld) {
if (fld_name == (f.get_name())) {
return f;
}
}
uvm_fatal(get_full_name(), format("Cannot match found field %0s", fld_name));
return null;
}
void rand_field(string fld_name) {
riscv_reg_field fld_hd = get_field_by_name(fld_name);
// `DV_CHECK_RANDOMIZE_FATAL(fld_hd)
fld_hd.randomize();
}
void set_field_rand_mode(string fld_name, bool rand_on) {
riscv_reg_field fld_hd = get_field_by_name(fld_name);
// rand_mode!q{fld_hd}(rand_on); // TBD
}
void reset() {
foreach (f; fld) {
f.val = f.reset_val;
}
}
void set_val(ubvec!XLEN val) {
foreach (f; fld) {
if (! f.hard_wired) {
// Assign the valid msb to the field
f.val = (val >> (XLEN - f.bit_width));
uvm_info(get_full_name(),
format("Assign field %0s, bit_width:%0d, reg_val 0x%0x, fld_val:0x%0x",
f.get_name(), f.bit_width, val, f.val), UVM_LOW);
}
val <<= f.bit_width;
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.riscv_signature_pkg;
// Will be the lowest 8 bits of the data word
enum signature_type_t: byte {
// Information sent to the core relating its current status.
// Bits [12:8] of the data word will be the core_status_t value
// corresponding to the current core status.
CORE_STATUS,
// Information sent to the core conveying the uvm simulation result.
// Bit [8] of the data word will be the test_result_t value.
TEST_RESULT,
// Sent to the core to indicate a dump of GPRs to testbench.
// Will be followed by 32 writes of registers x0-x32.
WRITE_GPR,
// Sent to the core to indicate a write of a CSR's data.
// Bits [19:8] of the data word will be the CSR address.
// Will be followed by a second write of the actual data from the CSR.
WRITE_CSR
}
enum core_status_t: byte {
INITIALIZED,
IN_DEBUG_MODE,
IN_MACHINE_MODE,
IN_HYPERVISOR_MODE,
IN_SUPERVISOR_MODE,
IN_USER_MODE,
HANDLING_IRQ,
FINISHED_IRQ,
HANDLING_EXCEPTION,
INSTR_FAULT_EXCEPTION,
ILLEGAL_INSTR_EXCEPTION,
LOAD_FAULT_EXCEPTION,
STORE_FAULT_EXCEPTION,
EBREAK_EXCEPTION
}
enum test_result_t: bool {
TEST_PASS,
TEST_FAIL
}

View file

@ -0,0 +1,165 @@
/*
* Copyright 2020 Google LLC
* Copyright 2020 Andes Technology Co., Ltd.
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.gen.riscv_vector_cfg;
import riscv.gen.riscv_instr_pkg: riscv_vreg_t, vxrm_t, vtype_t;
import riscv.gen.target: XLEN, VLEN, MAX_LMUL, ELEN, SELEN;
import std.string: format, toUpper, toLower, strip;
import esdl.data.bvec: ubvec;
import esdl.rand: constraint, rand;
import uvm;
class riscv_vector_cfg : uvm_object
{
mixin uvm_object_utils;
@rand @UVM_DEFAULT vtype_t vtype;
@rand @UVM_DEFAULT ubvec!XLEN vl;
@rand @UVM_DEFAULT ubvec!XLEN vstart;
@rand @UVM_DEFAULT vxrm_t vxrm;
@rand @UVM_DEFAULT bool vxsat;
riscv_vreg_t[] reserved_vregs;
// Allowed effective element width based on the LMUL setting
@UVM_DEFAULT uint[] legal_eew;
// Allow only vector instructions from the random sequences
@rand bool only_vec_instr;
constraint! q{@soft only_vec_instr == false;} only_vec_instr_c;
// Allow vector floating-point instructions (Allows vtype.vsew to be set <16 or >32).
@rand bool vec_fp;
// Allow vector narrowing or widening instructions.
@rand bool vec_narrowing_widening;
// Allow vector quad-widening instructions.
@rand bool vec_quad_widening;
constraint! q{
(!vec_narrowing_widening) -> (!vec_quad_widening);
// FP requires at least 16 bits and quad-widening requires no more than ELEN/4 bits.
(ELEN < 64) -> (!(vec_fp && vec_quad_widening));
} vec_quad_widening_c ;
@rand bool allow_illegal_vec_instr;
constraint! q{@soft allow_illegal_vec_instr == false;} allow_illegal_vec_instr_c;
// Cause frequent hazards for the Vector Registers:
// * Write-After-Read (WAR)
// * Read-After-Write (RAW)
// * Read-After-Read (RAR)
// * Write-After-Write (WAW)
// These hazard conditions are induced by keeping a small (~5) list of registers to select from.
@rand bool vec_reg_hazards;
// Enable segmented load/store extension ops
@rand @UVM_DEFAULT bool enable_zvlsseg = true;
// Enable fault only first load ops
@rand @UVM_DEFAULT bool enable_fault_only_first_load;
constraint! q{
//solve vtype before vl;
//solve vl before vstart;
vstart inside [0:vl];
vl inside [1:VLEN/vtype.vsew];
} legal_c;
// Basic constraint for initial bringup
constraint! q{
vstart == 0;
vl == VLEN/vtype.vsew;
vtype.vediv == 1;
} bringup_c;
// For all widening instructions, the destination element width must be a supported element
// width and the destination LMUL value must also be a supported LMUL value
constraint! q{
vtype.vlmul inside [1, 2, 4, 8];
vtype.vlmul <= MAX_LMUL;
if (vec_narrowing_widening) {
(vtype.vlmul < 8) || (vtype.fractional_lmul == true);
}
if (vec_quad_widening) {
vtype.vlmul < 4 || (vtype.fractional_lmul == true);
}
} vlmul_c ;
constraint! q{
vtype.vsew inside [8, 16, 32, 64, 128];
vtype.vsew <= ELEN;
// TODO: Determine the legal range of floating point format
if (vec_fp) {vtype.vsew inside [32];}
if (vec_narrowing_widening) {vtype.vsew < ELEN;}
if (vec_quad_widening) {vtype.vsew < (ELEN >> 1);}
} vsew_c;
constraint! q{
enable_zvlsseg -> (vtype.vlmul < 8);
} vseg_c;
constraint! q{
vtype.vediv inside [1, 2, 4, 8];
vtype.vediv <= (vtype.vsew / SELEN);
} vdeiv_c;
this(string name = "") {
import esdl.base.cmdl: CommandLine;
super(name);
CommandLine cmdl = new CommandLine();
//if ($value$plusargs("enable_zvlsseg=%0d", enable_zvlsseg)) begin
if (cmdl.plusArgs("enable_zvlsseg=%d", enable_zvlsseg)) {
rand_mode!"enable_zvlsseg"(false);
}
if (cmdl.plusArgs("enable_fault_only_first_load=%d", enable_fault_only_first_load)) {
rand_mode!"enable_fault_only_first_load"(false);
}
}
void post_randomize() {
real temp_eew;
legal_eew.length = 0;
// Section 7.3 Vector loads and stores have the EEW encoded directly in the instruction.
// EMUL is calculated as EMUL =(EEW/SEW)*LMUL. If the EMUL would be out of range
// (EMUL>8 or EMUL<1/8), an illegal instruction exceptionis raised.
// EEW = SEW * EMUL / LMUL
for (real emul = 0.125; emul <= 8; emul = emul * 2) {
if (vtype.fractional_lmul == 0) {
temp_eew = cast(real) (vtype.vsew) * emul/cast(real) (vtype.vlmul);
}
else {
temp_eew = cast(real) (vtype.vsew) * emul * cast(real) (vtype.vlmul);
}
if (temp_eew >= 8 && temp_eew <= 1024) {
legal_eew ~= cast(uint) (temp_eew);
}
uvm_info(get_full_name(), format("Checking emul: %.2f", emul), UVM_LOW);
}
}
}

View file

@ -0,0 +1,140 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.ml.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 64;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M, riscv_instr_group_t.RV64I, riscv_instr_group_t.RV64M, riscv_instr_group_t.RV32C, riscv_instr_group_t.RV64C ];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [
interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,140 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.multi_harts.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 32;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M, riscv_instr_group_t.RV32C, riscv_instr_group_t.RV32A];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 2;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [
interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,50 @@
module riscv.gen.target;
version(RV32IMCB) {
pragma (msg, "Using target: RV32IMCB");
public import riscv.gen.target.rv32imcb.riscv_core_setting;
}
else version(RV64GCV) {
pragma (msg, "Using target: RV64GCV");
public import riscv.gen.target.rv64gcv.riscv_core_setting;
}
else version(RV64GC) {
pragma (msg, "Using target: RV64GC");
public import riscv.gen.target.rv64gc.riscv_core_setting;
}
else version(RV64IMCB) {
pragma (msg, "Using target: RV64IMCB");
public import riscv.gen.target.rv64imcb.riscv_core_setting;
}
else version(RV32IMAFDC) {
pragma (msg, "Using target: RV32IMAFDC");
public import riscv.gen.target.rv32imafdc.riscv_core_setting;
}
else version(ML) {
pragma (msg, "Using target: ML");
public import riscv.gen.target.ml.riscv_core_setting;
}
else version(MULTI_HARTS) {
pragma (msg, "Using target: MULTI_HARTS");
public import riscv.gen.target.multi_harts.riscv_core_setting;
}
else version(RV32IMC_SV32) {
pragma (msg, "Using target: RV32IMC_SV32");
public import riscv.gen.target.rv32imc_sv32.riscv_core_setting;
}
else version(RV32I) {
pragma (msg, "Using target: RV32I");
public import riscv.gen.target.rv32i.riscv_core_setting;
}
else version(RV64IMC) {
pragma (msg, "Using target: RV64IMC");
public import riscv.gen.target.rv64imc.riscv_core_setting;
}
else version(RV32IMC) {
pragma (msg, "Using target: RV32IMC");
public import riscv.gen.target.rv32imc.riscv_core_setting;
}
else {
pragma (msg, "Using Default target: RV64IMC");
public import riscv.gen.target.rv64imc.riscv_core_setting;
}

View file

@ -0,0 +1,142 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32i.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 32;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [ interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,148 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imafdc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 32;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [] ;
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV32F,
riscv_instr_group_t.RV32FC,
riscv_instr_group_t.RV32D,
riscv_instr_group_t.RV32DC,
riscv_instr_group_t.RV32A];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load / store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub - element, which must be at most 8 - bits.
enum int SELEN = 8;
// Maximum size of a single vector element(encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi - harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt - enable register
privileged_reg_t.MTVEC, // Machine trap - handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation - specific custom CSRs
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt / exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [ interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,144 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 32;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [ interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,144 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imc_sv32.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 32;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.SV32;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE , privileged_mode_t.USER_MODE ];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [ interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,145 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imcb.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 32;
// Enum for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV32B];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Enum for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [ interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE
];

View file

@ -0,0 +1,193 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64gc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.SV39;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.USER_MODE, privileged_mode_t.SUPERVISOR_MODE, privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV64I,
riscv_instr_group_t.RV64M,
riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV32A,
riscv_instr_group_t.RV64A,
riscv_instr_group_t.RV32F,
riscv_instr_group_t.RV64F,
riscv_instr_group_t.RV32D,
riscv_instr_group_t.RV64D,
riscv_instr_group_t.RV32X];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
enum int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = true;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Parameter for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// User mode CSR
privileged_reg_t.USTATUS, // User status
privileged_reg_t.UIE, // User interrupt-enable register
privileged_reg_t.UTVEC, // User trap-handler base address
privileged_reg_t.USCRATCH, // Scratch register for user trap handlers
privileged_reg_t.UEPC, // User exception program counter
privileged_reg_t.UCAUSE, // User trap cause
privileged_reg_t.UTVAL, // User bad address or instruction
privileged_reg_t.UIP, // User interrupt pending
// Supervisor mode CSR
privileged_reg_t.SSTATUS, // Supervisor status
privileged_reg_t.SEDELEG, // Supervisor exception delegation register
privileged_reg_t.SIDELEG, // Supervisor interrupt delegation register
privileged_reg_t.SIE, // Supervisor interrupt-enable register
privileged_reg_t.STVEC, // Supervisor trap-handler base address
privileged_reg_t.SCOUNTEREN, // Supervisor counter enable
privileged_reg_t.SSCRATCH, // Scratch register for supervisor trap handlers
privileged_reg_t.SEPC, // Supervisor exception program counter
privileged_reg_t.SCAUSE, // Supervisor trap cause
privileged_reg_t.STVAL, // Supervisor bad address or instruction
privileged_reg_t.SIP, // Supervisor interrupt pending
privileged_reg_t.SATP, // Supervisor address translation and protection
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MEDELEG, // Machine exception delegation register
privileged_reg_t.MIDELEG, // Machine interrupt delegation register
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP, // Machine interrupt pending
// Floating point CSR
privileged_reg_t.FCSR // Floating point control and status
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [
interrupt_cause_t.U_SOFTWARE_INTR,
interrupt_cause_t.S_SOFTWARE_INTR,
interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.U_TIMER_INTR,
interrupt_cause_t.S_TIMER_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.U_EXTERNAL_INTR,
interrupt_cause_t.S_EXTERNAL_INTR,
interrupt_cause_t.M_EXTERNAL_INTR
];
enum exception_cause_t[] implemented_exception = [
exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.STORE_AMO_ADDRESS_MISALIGNED,
exception_cause_t.STORE_AMO_ACCESS_FAULT,
exception_cause_t.ECALL_UMODE,
exception_cause_t.ECALL_SMODE,
exception_cause_t.ECALL_MMODE,
exception_cause_t.INSTRUCTION_PAGE_FAULT,
exception_cause_t.LOAD_PAGE_FAULT,
exception_cause_t.STORE_AMO_PAGE_FAULT
];

View file

@ -0,0 +1,190 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64gcv.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV32A,
riscv_instr_group_t.RV64I,
riscv_instr_group_t.RV64M,
riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV64A,
riscv_instr_group_t.RV32F,
riscv_instr_group_t.RV32D,
riscv_instr_group_t.RV64D,
riscv_instr_group_t.RVV ];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT,
mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
enum int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = true;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Parameter for vector extension
enum int VECTOR_EXTENSION_ENABLE = 1;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
static assert (VELEN == 2);
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
privileged_reg_t.USTATUS, // User status
privileged_reg_t.UIE, // User interrupt-enable register
privileged_reg_t.UTVEC, // User trap-handler base address
privileged_reg_t.USCRATCH, // Scratch register for user trap handlers
privileged_reg_t.UEPC, // User exception program counter
privileged_reg_t.UCAUSE, // User trap cause
privileged_reg_t.UTVAL, // User bad address or instruction
privileged_reg_t.UIP, // User interrupt pending
// Supervisor mode CSR
privileged_reg_t.SSTATUS, // Supervisor status
privileged_reg_t.SEDELEG, // Supervisor exception delegation register
privileged_reg_t.SIDELEG, // Supervisor interrupt delegation register
privileged_reg_t.SIE, // Supervisor interrupt-enable register
privileged_reg_t.STVEC, // Supervisor trap-handler base address
privileged_reg_t.SCOUNTEREN, // Supervisor counter enable
privileged_reg_t.SSCRATCH, // Scratch register for supervisor trap handlers
privileged_reg_t.SEPC, // Supervisor exception program counter
privileged_reg_t.SCAUSE, // Supervisor trap cause
privileged_reg_t.STVAL, // Supervisor bad address or instruction
privileged_reg_t.SIP, // Supervisor interrupt pending
privileged_reg_t.SATP, // Supervisor address translation and protection
// Machine mode mode CSR
privileged_reg_t.MEDELEG, // Machine exception delegation register
privileged_reg_t.MIDELEG, // Machine interrupt delegation register
// Floating point CSR
privileged_reg_t.FCSR, // Floating point control and status
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [interrupt_cause_t.U_SOFTWARE_INTR,
interrupt_cause_t.S_SOFTWARE_INTR,
interrupt_cause_t.U_TIMER_INTR,
interrupt_cause_t.S_TIMER_INTR,
interrupt_cause_t.U_EXTERNAL_INTR,
interrupt_cause_t.S_EXTERNAL_INTR,
interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR];
enum exception_cause_t[] implemented_exception = [exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.STORE_AMO_ADDRESS_MISALIGNED,
exception_cause_t.STORE_AMO_ACCESS_FAULT,
exception_cause_t.ECALL_UMODE,
exception_cause_t.ECALL_SMODE,
exception_cause_t.ECALL_MMODE,
exception_cause_t.INSTRUCTION_PAGE_FAULT,
exception_cause_t.LOAD_PAGE_FAULT,
exception_cause_t.STORE_AMO_PAGE_FAULT];

View file

@ -0,0 +1,145 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64imc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV64I,
riscv_instr_group_t.RV64M,
riscv_instr_group_t.RV64C];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT,
mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
enum int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Parameter for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
static assert (VELEN == 2);
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR];
enum exception_cause_t[] implemented_exception = [exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE];

View file

@ -0,0 +1,147 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64imcb.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
exception_cause_t, riscv_instr_group_t, privileged_reg_t;
import esdl: ubvec, flog2;
enum int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
enum satp_mode_t SATP_MODE = satp_mode_t.BARE;
// Supported Privileged mode
privileged_mode_t[] supported_privileged_mode = [privileged_mode_t.MACHINE_MODE];
// Unsupported instructions
riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV32B,
riscv_instr_group_t.RV64I,
riscv_instr_group_t.RV64M,
riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV64B];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT,
mtvec_mode_t.VECTORED];
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
enum int max_interrupt_vector_num = 16;
// Physical memory protection support
enum bool support_pmp = false;
// Debug mode support
enum bool support_debug_mode = false;
// Support delegate trap to user mode
enum bool support_umode_trap = false;
// Support sfence.vma instruction
enum bool support_sfence = false;
// Support unaligned load/store
enum bool support_unaligned_load_store = true;
// GPR setting
enum int NUM_FLOAT_GPR = 32;
enum int NUM_GPR = 32;
enum int NUM_VEC_GPR = 32;
// ----------------------------------------------------------------------------
// Vector extension configuration
// ----------------------------------------------------------------------------
// Parameter for vector extension
enum int VECTOR_EXTENSION_ENABLE = 0;
enum int VLEN = 512;
// Maximum size of a single vector element
enum int ELEN = 32;
// Minimum size of a sub-element, which must be at most 8-bits.
enum int SELEN = 8;
// Maximum size of a single vector element (encoded in vsew format)
enum int VELEN = flog2(ELEN) - 3;
static assert (VELEN == 2);
// Maxium LMUL supported by the core
enum int MAX_LMUL = 8;
// ----------------------------------------------------------------------------
// Multi-harts configuration
// ----------------------------------------------------------------------------
// Number of harts
enum int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
enum privileged_reg_t[] implemented_csr = [
// Machine mode mode CSR
privileged_reg_t.MVENDORID, // Vendor ID
privileged_reg_t.MARCHID, // Architecture ID
privileged_reg_t.MIMPID, // Implementation ID
privileged_reg_t.MHARTID, // Hardware thread ID
privileged_reg_t.MSTATUS, // Machine status
privileged_reg_t.MISA, // ISA and extensions
privileged_reg_t.MIE, // Machine interrupt-enable register
privileged_reg_t.MTVEC, // Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, // Machine counter enable
privileged_reg_t.MSCRATCH, // Scratch register for machine trap handlers
privileged_reg_t.MEPC, // Machine exception program counter
privileged_reg_t.MCAUSE, // Machine trap cause
privileged_reg_t.MTVAL, // Machine bad address or instruction
privileged_reg_t.MIP // Machine interrupt pending
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
enum interrupt_cause_t[] implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR];
enum exception_cause_t[] implemented_exception = [exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE];

View file

@ -0,0 +1,125 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.test.riscv_instr_base_test;
import uvm;
import riscv.gen;
// import riscv.gen.riscv_instr_gen_config;
// import riscv.gen.riscv_asm_program_gen;
// import riscv.gen.riscv_core_setting;
// // import riscv.gen.riscv_instr_registry;
// import riscv.gen.isa.riscv_instr;
import std.format: format;
import esdl;
// Base test
class riscv_instr_base_test: uvm_test
{
mixin uvm_component_utils;
riscv_instr_gen_config cfg;
// riscv_instr_registry registry;
string test_opts;
string asm_file_name = "riscv_asm_test";
riscv_asm_program_gen asm_gen;
string instr_seq;
int start_idx;
uvm_coreservice_t coreservice;
uvm_factory factory;
CommandLine cmd;
this(string name="", uvm_component parent=null) {
super(name, parent);
cmd = new CommandLine();
cmd.plusArgs("asm_file_name=%s", asm_file_name);
cmd.plusArgs("start_idx=%d", start_idx);
}
override void build_phase(uvm_phase phase) {
super.build_phase(phase);
coreservice = uvm_coreservice_t.get();
factory = coreservice.get_factory();
uvm_info(get_full_name(), "Create configuration instance", UVM_LOW);
cfg = riscv_instr_gen_config.type_id.create("cfg");
// registry = riscv_instr_registry.type_id.create("registry");
uvm_info(get_full_name(), "Create configuration instance...done", UVM_LOW);
uvm_info(get_full_name(), cfg.sprint(), UVM_LOW);
uvm_config_db!(riscv_instr_gen_config).set(null, "*", "instr_cfg", cfg);
if(cfg.asm_test_suffix != "")
asm_file_name = asm_file_name ~ "." ~ cfg.asm_test_suffix;
// Override the default riscv instruction sequence
if (cmd.plusArgs("instr_seq=%s", instr_seq)) {
factory.set_type_override_by_name("riscv_instr_sequence", instr_seq);
}
if (support_debug_mode) {
factory.set_inst_override_by_name("riscv_asm_program_gen",
"riscv_debug_rom_gen",
get_full_name() ~ ".asm_gen.debug_rom");
}
}
override void report_phase(uvm_phase phase) {
uvm_report_server rs;
int error_count;
rs = uvm_report_server.get_server();
error_count = rs.get_severity_count(UVM_WARNING) +
rs.get_severity_count(UVM_ERROR) +
rs.get_severity_count(UVM_FATAL);
if (error_count == 0) {
uvm_info("", "TEST PASSED", UVM_NONE);
}
else {
uvm_info("", "TEST FAILED", UVM_NONE);
}
uvm_trace("", "TEST GENERATION DONE", UVM_NONE);
super.report_phase(phase);
}
void apply_directed_instr() { }
override void run_phase(uvm_phase phase) {
int fd;
for (int i = 0; i < cfg.num_of_tests; i++) {
string test_name;
randomize_cfg();
// registry.create_instr_list(cfg);
asm_gen = riscv_asm_program_gen.type_id.create("asm_gen", null, get_full_name());
asm_gen.cfg = cfg;
asm_gen.get_directed_instr_stream();
test_name = format("%0s_%0d.S", asm_file_name, i+start_idx);
apply_directed_instr();
uvm_info(get_full_name(), "All directed instruction is applied", UVM_LOW);
asm_gen.gen_program();
asm_gen.gen_test_file(test_name);
}
}
void randomize_cfg() {
cfg.randomize();
uvm_info(get_full_name(), format("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW);
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import uvm;
import esdl;
int main(string[] args) {
import std.stdio: writeln;
uint random_seed;
uint thread_index;
uint thread_count;
CommandLine cmdl = new CommandLine(args);
if (cmdl.plusArgs("random_seed=" ~ "%d", random_seed))
writeln("Using random_seed: ", random_seed);
else random_seed = 1;
if (! cmdl.plusArgs("thread_index=" ~ "%d", thread_index))
thread_index = 0;
if (! cmdl.plusArgs("thread_count=" ~ "%d", thread_count))
thread_count = 1;
auto testbench = new uvm_testbench;
testbench.multicore(thread_index, thread_count);
testbench.elaborate("test", args);
testbench.set_seed(random_seed);
testbench.set_async_mode();
return testbench.start();
}

View file

@ -0,0 +1,98 @@
/*
* Copyright 2019 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Sanity test for riscv_instr_test class
module riscv.test.riscv_instr_test;
import esdl;
import uvm;
import riscv.gen;
import std.format: format;
import std.stdio: File;
import esdl.rand: randomize;
import riscv.test.riscv_instr_base_test;
import std.range : repeat;
class riscv_instr_test: riscv_instr_base_test
{
mixin uvm_component_utils;
riscv_instr_gen_config cfg;
string asm_file_name= "riscv_asm_test";
this(string name="", uvm_component parent=null) {
super(name, parent);
}
override void build_phase(uvm_phase phase)
{ super.build_phase(phase);
coreservice = uvm_coreservice_t.get();
factory = coreservice.get_factory();
uvm_info(get_full_name(), "Create configuration instance", UVM_LOW);
cfg = riscv_instr_gen_config.type_id.create("cfg");
uvm_info(get_full_name(), "Create configuration instance...done", UVM_LOW);
uvm_info(get_full_name(), cfg.sprint(), UVM_LOW);
uvm_config_db!(riscv_instr_gen_config).set(null, "*", "instr_cfg", cfg);
if(cfg.asm_test_suffix != "")
asm_file_name = asm_file_name ~ "." ~ cfg.asm_test_suffix;
if (support_debug_mode) {
factory.set_inst_override_by_name("riscv_asm_program_gen",
"riscv_debug_rom_gen",
get_full_name() ~ ".asm_gen.debug_rom");
}
}
override void run_phase(uvm_phase phase)
{
riscv_instr instr;
riscv_instr_name_t instr_name;
string test_name = format("%0s_0.S", asm_file_name);
auto fd = File(test_name,"w");
uvm_info(get_full_name(), "Creating instruction list", UVM_LOW);
cfg.instr_registry.create_instr_list(cfg);
uvm_info(get_full_name(), "Randomizing instruction list now...", UVM_LOW);
//10000.repeat();
for(int i = 0; i<100000; i++)
{
instr = cfg.instr_registry.get_rand_instr();
instr.randomize();
fd.writeln(instr.convert2asm());
}
//repeat (10000);
instr = cfg.instr_registry.get_rand_instr([riscv_instr_category_t.LOAD, riscv_instr_category_t.STORE]);
instr.randomize();
fd.writeln(instr.convert2asm());
// repeat (10000);
instr = cfg.instr_registry.get_rand_instr(([riscv_instr_category_t.LOAD, riscv_instr_category_t.STORE , riscv_instr_category_t.BRANCH]),
([riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M]));
instr.randomize();
fd.writeln(instr.convert2asm());
uvm_info(get_full_name(), format("%0s is generated", test_name), UVM_LOW);
}
override void randomize_cfg()
{
cfg.randomize();
uvm_info(get_full_name(), format("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW);
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright 2018 Google LLC
* Copyright 2022 Coverify Systems Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module riscv.test.riscv_instr_test_lib;
import uvm;
import riscv.gen;
import std.format: format;
import esdl;
import riscv.test.riscv_instr_base_test;
class riscv_rand_instr_test:riscv_instr_base_test
{
mixin uvm_component_utils;
riscv_instr_gen_config cfg;
string asm_file_name = "riscv_asm1_test";
uvm_coreservice_t coreservice;
uvm_factory factory;
this(string name="", uvm_component parent=null) {
super(name, parent);
}
override void build_phase(uvm_phase phase)
{ super.build_phase(phase);
coreservice = uvm_coreservice_t.get();
factory = coreservice.get_factory();
uvm_info(get_full_name(), "Create configuration instance", UVM_LOW);
cfg = riscv_instr_gen_config.type_id.create("cfg");
uvm_info(get_full_name(), "Create configuration instance...done", UVM_LOW);
uvm_info(get_full_name(), cfg.sprint(), UVM_LOW);
uvm_config_db!(riscv_instr_gen_config).set(null, "*", "instr_cfg", cfg);
if(cfg.asm_test_suffix != "")
asm_file_name = asm_file_name ~ "." ~ cfg.asm_test_suffix;
if (support_debug_mode) {
factory.set_inst_override_by_name("riscv_asm_program_gen",
"riscv_debug_rom_gen",
get_full_name() ~ ".asm_gen.debug_rom");
}
}
override void randomize_cfg()
{
cfg.instr_cnt = 1000;
cfg.num_of_sub_program = 5;
cfg.randomize();
uvm_info(get_full_name(), format("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW);
}
override void run_phase(uvm_phase phase)
{
string test_name;
randomize_cfg();
asm_gen = riscv_asm_program_gen.type_id.create("asm_gen", null, get_full_name());
apply_directed_instr();
}
override void apply_directed_instr()
{
uvm_info(get_full_name(), "all directed instruction printed here" , UVM_LOW);
// Mix below directed instruction streams with the random instruction
asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_loop_instr", 3);
asm_gen.add_directed_instr_stream("riscv_jal_instr", 4);
asm_gen.add_directed_instr_stream("riscv_hazard_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_load_store_hazard_instr_st ream", 4);
asm_gen.add_directed_instr_stream("riscv_multi_page_load_store_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_mem_region_stress_test", 4);
}
}
class riscv_ml_test: riscv_instr_base_test
{
mixin uvm_component_utils;
riscv_instr_gen_config cfg;
//string asm_file_name = "riscv_asm1_test";
uvm_coreservice_t coreservice;
uvm_factory factory;
this(string name="", uvm_component parent=null) {
super(name, parent);
}
override void build_phase(uvm_phase phase)
{
super.build_phase(phase);
coreservice = uvm_coreservice_t.get();
factory = coreservice.get_factory();
uvm_info(get_full_name(), "Create configuration instance", UVM_LOW);
cfg = riscv_instr_gen_config.type_id.create("cfg");
uvm_info(get_full_name(), "Create configuration instance...done", UVM_LOW);
uvm_info(get_full_name(), cfg.sprint(), UVM_LOW);
uvm_config_db!(riscv_instr_gen_config).set(null, "*", "instr_cfg", cfg);
}
override void randomize_cfg()
{
cfg.addr_translation_rnd_order_c.constraint_mode(0);
cfg.randomize();
cfg.addr_translation_rnd_order_c.constraint_mode(1);
uvm_info(get_full_name(), format("riscv_instr_gen_config is randomized:\n%0s",cfg.sprint()), UVM_LOW);
}
override void run_phase(uvm_phase phase)
{
randomize_cfg();
}
}

View file

@ -164,6 +164,483 @@ class riscv_instr_cover_group:
}
)
''' RV64M instruction '''
# Below instructions only do calculation based on lower 32 bits, and extend the result to 64
# bits. Add special covergroup for corner cases
@vsc.covergroup
class mulw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign])
@vsc.covergroup
class divw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class divuw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class remw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign])
@vsc.covergroup
class remuw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign])
''' RV64C instruction'''
@vsc.covergroup
class c_ld_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.lsu_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class c_ldsp_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
@vsc.covergroup
class c_sd_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.lsu_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_sdsp_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
@vsc.covergroup
class c_addiw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_subw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_addw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
''' RV64I Instruction '''
@vsc.covergroup
class lwu_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class ld_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class sd_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.lsu_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class sraw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class sllw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class srlw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign])
'''' // imm[5] could be 1 for RV64I SLLI/SRAI/SRLI'''
@vsc.covergroup
class srai64_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class slli64_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class srli64_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class sraiw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class slliw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class srliw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class addw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class subw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class addiw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_logical = vsc.coverpoint(lambda: self.instr.logical_similarity,
cp_t=vsc.enum_t(logical_similarity_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_imm_sign])
'''Category specific covergroups'''
'''Load instructions'''
@vsc.covergroup
@ -7576,6 +8053,31 @@ class riscv_instr_cover_group:
self.fle_d_cg_i = self.fle_d_cg(0)
self.fclass_s_cg_i = self.fclass_s_cg(1)
self.fclass_d_cg_i = self.fclass_d_cg(0)
self.mulw_cg_i = self.mulw_cg()
self.divw_cg_i = self.divw_cg()
self.divuw_cg_i = self.divuw_cg()
self.remw_cg_i = self.remw_cg()
self.remuw_cg_i = self.remuw_cg()
self.c_addiw_cg_i = self.c_addiw_cg()
self.c_subw_cg_i = self.c_subw_cg()
self.c_addw_cg_i = self.c_addw_cg()
self.c_ld_cg_i = self.c_ld_cg()
self.c_sd_cg_i = self.c_sd_cg()
self.c_ldsp_cg_i = self.c_ldsp_cg()
self.c_sdsp_cg_i = self.c_sdsp_cg()
self.lwu_cg_i = self.lwu_cg()
self.ld_cg_i = self.ld_cg()
self.sd_cg_i = self.sd_cg()
self.addiw_cg_i = self.addiw_cg()
self.slliw_cg_i = self.slliw_cg()
self.srliw_cg_i = self.srliw_cg()
self.sraiw_cg_i = self.sraiw_cg()
self.addw_cg_i = self.addw_cg()
self.subw_cg_i = self.subw_cg()
self.sllw_cg_i = self.sllw_cg()
self.srlw_cg_i = self.srlw_cg()
self.sraw_cg_i = self.sraw_cg()
def sample(self, instr):
self.instr_cnt += 1

View file

@ -1802,6 +1802,84 @@ def get_attr_list(instr_name):
riscv_instr_name_t.FCVT_D_WU: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV32D],
#RV64I
riscv_instr_name_t.LWU: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.LOAD,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.LD: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.LOAD,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SD: [riscv_instr_format_t.S_FORMAT,
riscv_instr_category_t.STORE,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SLLW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SLLIW: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SRLW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SRLIW: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SRAW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SRAIW: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.ADDW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.ADDIW: [riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64I],
riscv_instr_name_t.SUBW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64I],
# RV64M
riscv_instr_name_t.MULW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64M],
riscv_instr_name_t.DIVW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64M],
riscv_instr_name_t.DIVUW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64M],
riscv_instr_name_t.REMW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64M],
riscv_instr_name_t.REMUW: [riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64M],
# RV64C
riscv_instr_name_t.C_ADDIW: [riscv_instr_format_t.CI_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64C],
riscv_instr_name_t.C_SUBW: [riscv_instr_format_t.CA_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64C],
riscv_instr_name_t.C_ADDW: [riscv_instr_format_t.CA_FORMAT,
riscv_instr_category_t.ARITHMETIC,
riscv_instr_group_t.RV64C],
riscv_instr_name_t.C_LD: [riscv_instr_format_t.CL_FORMAT,
riscv_instr_category_t.LOAD,
riscv_instr_group_t.RV64C, imm_t.UIMM],
riscv_instr_name_t.C_SD: [riscv_instr_format_t.CS_FORMAT,
riscv_instr_category_t.STORE,
riscv_instr_group_t.RV64C, imm_t.UIMM],
riscv_instr_name_t.C_LDSP: [riscv_instr_format_t.CI_FORMAT,
riscv_instr_category_t.LOAD,
riscv_instr_group_t.RV64C, imm_t.UIMM],
riscv_instr_name_t.C_SDSP: [riscv_instr_format_t.CSS_FORMAT,
riscv_instr_category_t.STORE,
riscv_instr_group_t.RV64C, imm_t.UIMM],
}
# if instruction is not present in the dictionary,second argument well
# be assigned as default value of passed argument

View file

@ -104,7 +104,7 @@ class riscv_loop_instr(riscv_rand_instr_stream):
riscv_instr_name_t.C_BEQZ))):
self.loop_limit_val[i] == 0
self.loop_limit_reg[i] == riscv_reg_t.ZERO
self.loop_cnt_reg[i].inside(vsc.rangelist(compressed_gpr))
self.loop_cnt_reg[i].inside(vsc.rangelist(list(compressed_gpr)))
with vsc.else_then:
self.loop_limit_val[i].inside(vsc.rangelist((-20, 20)))
self.loop_limit_reg[i] != riscv_reg_t.ZERO

View file

@ -756,9 +756,11 @@ package riscv_instr_pkg;
UCAUSE = 'h042, // User trap cause
UTVAL = 'h043, // User bad address or instruction
UIP = 'h044, // User interrupt pending
// Unprivileged Floating-Point CSRs
FFLAGS = 'h001, // Floating-Point Accrued Exceptions
FRM = 'h002, // Floating-Point Dynamic Rounding Mode
FCSR = 'h003, // Floating-Point Control/Status Register (FRM + FFLAGS)
// Unprivileged Counter/Timers
CYCLE = 'hC00, // Cycle counter for RDCYCLE instruction
TIME = 'hC01, // Timer for RDTIME instruction
INSTRET = 'hC02, // Instructions-retired counter for RDINSTRET instruction
@ -824,23 +826,66 @@ package riscv_instr_pkg;
HPMCOUNTER30H = 'hC9E, // Upper 32 bits of HPMCOUNTER30, RV32I only
HPMCOUNTER31H = 'hC9F, // Upper 32 bits of HPMCOUNTER31, RV32I only
// Supervisor mode register
// Supervisor Trap Setup
SSTATUS = 'h100, // Supervisor status
SEDELEG = 'h102, // Supervisor exception delegation register
SIDELEG = 'h103, // Supervisor interrupt delegation register
SIE = 'h104, // Supervisor interrupt-enable register
STVEC = 'h105, // Supervisor trap-handler base address
SCOUNTEREN = 'h106, // Supervisor counter enable
// Supervisor Configuration
SENVCFG = 'h10A, // Supervisor environment configuration register
// Supervisor Trap Handling
SSCRATCH = 'h140, // Scratch register for supervisor trap handlers
SEPC = 'h141, // Supervisor exception program counter
SCAUSE = 'h142, // Supervisor trap cause
STVAL = 'h143, // Supervisor bad address or instruction
SIP = 'h144, // Supervisor interrupt pending
// Supervisor Protection and Translation
SATP = 'h180, // Supervisor address translation and protection
// Machine mode register
// Supervisor Debug/Trace Register
SCONTEXT = 'h5A8, // Supervisor environment configuration register.
// Hypervisor Trap Setup register
HSTATUS = 'h600, // Hypervisor status register
HEDELEG = 'h602, // Hypervisor exception delegation register
HIDELEG = 'h603, // Hypervisor interrupt delegation register
HIE = 'h604, // Hypervisor interrupt-enable register
HCOUNTEREN = 'h606, // Hypervisor counter enable
HGEIE = 'h607, // Hypervisor guest external interrupt-enable register
// Hypervisor Trap Handling
HTVAL = 'h643, // Hypervisor bad guest physical address
HIP = 'h644, // Hypervisor interrupt pending
HVIP = 'h645, // Hypervisor virtual interrupt pending
HTINST = 'h64A, // Hypervisor trap instruction (transformed)
HGEIP = 'hE12, // Hypervisor guest external interrupt pending
// Hypervisor configuration
HENVCFG = 'h60A, // Hypervisor environment configuration register
HENVCFGH = 'h61A, // Additional hypervisor env. conf. register, RV32 only
// Hypervisor guest address translation and protection
HGATP = 'h680, // Hypervisor guest address translation and protection
// Hypervisor Debug/Trace registers
HCONTEXT = 'h6A8, // Hypervisor-mode context register
// Hypervisor Counter/Timer Virtualization Registers
HTIMEDELTA = 'h605, // Delta for VS/VU-mode timer
HTIMEDELTAH = 'h615, // Upper 32 bits of htimedelta, HSXLEN=32 only
// Virtual Supervisor Registers
VSSTATUS = 'h200, // Virtual supervisor status register
VSIE = 'h204, // Virtual supervisor interrupt-enable register
VSTVEC = 'h205, // Virtual supervisor trap handler base address
VSSCRATCH = 'h240, // Virtual supervisor scratch register
VSEPC = 'h241, // Virtual supervisor exception program counter
VSCAUSE = 'h242, // Virtual supervisor trap cause
VSTVAL = 'h243, // Virtual supervisor bad address or instruction
VSIP = 'h244, // Virtual supervisor interrupt pending
VSATP = 'h280, // Virtual supervisor address translation and protection
// Machine mode registers
// Machine Information Registers
MVENDORID = 'hF11, // Vendor ID
MARCHID = 'hF12, // Architecture ID
MIMPID = 'hF13, // Implementation ID
MHARTID = 'hF14, // Hardware thread ID
MCONFIGPTR = 'hF15, // Pointer to configuration data structure
// Machine Trap Setup
MSTATUS = 'h300, // Machine status
MISA = 'h301, // ISA and extensions
MEDELEG = 'h302, // Machine exception delegation register
@ -848,15 +893,35 @@ package riscv_instr_pkg;
MIE = 'h304, // Machine interrupt-enable register
MTVEC = 'h305, // Machine trap-handler base address
MCOUNTEREN = 'h306, // Machine counter enable
MSTATUSH = 'h310, // Additional machine status register, RV32 only
// Machine Trap Handling
MSCRATCH = 'h340, // Scratch register for machine trap handlers
MEPC = 'h341, // Machine exception program counter
MCAUSE = 'h342, // Machine trap cause
MTVAL = 'h343, // Machine bad address or instruction
MIP = 'h344, // Machine interrupt pending
// Machine Configuration
MENVCFG = 'h30A, // Machine environment configuration register
MENVCFGH = 'h31A, // Additional machine env. conf. register, RV32 only
MSECCFG = 'h747, // Machine security configuration register
MSECCFGH = 'h757, // Additional machine security conf. register, RV32 only
// Machine Memory Protection
PMPCFG0 = 'h3A0, // Physical memory protection configuration
PMPCFG1 = 'h3A1, // Physical memory protection configuration, RV32 only
PMPCFG2 = 'h3A2, // Physical memory protection configuration
PMPCFG3 = 'h3A3, // Physical memory protection configuration, RV32 only
PMPCFG4 = 'h3A4, // Physical memory protection configuration
PMPCFG5 = 'h3A5, // Physical memory protection configuration, RV32 only
PMPCFG6 = 'h3A6, // Physical memory protection configuration
PMPCFG7 = 'h3A7, // Physical memory protection configuration, RV32 only
PMPCFG8 = 'h3A8, // Physical memory protection configuration
PMPCFG9 = 'h3A9, // Physical memory protection configuration, RV32 only
PMPCFG10 = 'h3AA, // Physical memory protection configuration
PMPCFG11 = 'h3AB, // Physical memory protection configuration, RV32 only
PMPCFG12 = 'h3AC, // Physical memory protection configuration
PMPCFG13 = 'h3AD, // Physical memory protection configuration, RV32 only
PMPCFG14 = 'h3AE, // Physical memory protection configuration
PMPCFG15 = 'h3AF, // Physical memory protection configuration, RV32 only
PMPADDR0 = 'h3B0, // Physical memory protection address register
PMPADDR1 = 'h3B1, // Physical memory protection address register
PMPADDR2 = 'h3B2, // Physical memory protection address register
@ -873,6 +938,54 @@ package riscv_instr_pkg;
PMPADDR13 = 'h3BD, // Physical memory protection address register
PMPADDR14 = 'h3BE, // Physical memory protection address register
PMPADDR15 = 'h3BF, // Physical memory protection address register
PMPADDR16 = 'h4C0, // Physical memory protection address register
PMPADDR17 = 'h3C1, // Physical memory protection address register
PMPADDR18 = 'h3C2, // Physical memory protection address register
PMPADDR19 = 'h3C3, // Physical memory protection address register
PMPADDR20 = 'h3C4, // Physical memory protection address register
PMPADDR21 = 'h3C5, // Physical memory protection address register
PMPADDR22 = 'h3C6, // Physical memory protection address register
PMPADDR23 = 'h3C7, // Physical memory protection address register
PMPADDR24 = 'h3C8, // Physical memory protection address register
PMPADDR25 = 'h3C9, // Physical memory protection address register
PMPADDR26 = 'h3CA, // Physical memory protection address register
PMPADDR27 = 'h3CB, // Physical memory protection address register
PMPADDR28 = 'h3CC, // Physical memory protection address register
PMPADDR29 = 'h3CD, // Physical memory protection address register
PMPADDR30 = 'h3CE, // Physical memory protection address register
PMPADDR31 = 'h3CF, // Physical memory protection address register
PMPADDR32 = 'h4D0, // Physical memory protection address register
PMPADDR33 = 'h3D1, // Physical memory protection address register
PMPADDR34 = 'h3D2, // Physical memory protection address register
PMPADDR35 = 'h3D3, // Physical memory protection address register
PMPADDR36 = 'h3D4, // Physical memory protection address register
PMPADDR37 = 'h3D5, // Physical memory protection address register
PMPADDR38 = 'h3D6, // Physical memory protection address register
PMPADDR39 = 'h3D7, // Physical memory protection address register
PMPADDR40 = 'h3D8, // Physical memory protection address register
PMPADDR41 = 'h3D9, // Physical memory protection address register
PMPADDR42 = 'h3DA, // Physical memory protection address register
PMPADDR43 = 'h3DB, // Physical memory protection address register
PMPADDR44 = 'h3DC, // Physical memory protection address register
PMPADDR45 = 'h3DD, // Physical memory protection address register
PMPADDR46 = 'h3DE, // Physical memory protection address register
PMPADDR47 = 'h3DF, // Physical memory protection address register
PMPADDR48 = 'h4E0, // Physical memory protection address register
PMPADDR49 = 'h3E1, // Physical memory protection address register
PMPADDR50 = 'h3E2, // Physical memory protection address register
PMPADDR51 = 'h3E3, // Physical memory protection address register
PMPADDR52 = 'h3E4, // Physical memory protection address register
PMPADDR53 = 'h3E5, // Physical memory protection address register
PMPADDR54 = 'h3E6, // Physical memory protection address register
PMPADDR55 = 'h3E7, // Physical memory protection address register
PMPADDR56 = 'h3E8, // Physical memory protection address register
PMPADDR57 = 'h3E9, // Physical memory protection address register
PMPADDR58 = 'h3EA, // Physical memory protection address register
PMPADDR59 = 'h3EB, // Physical memory protection address register
PMPADDR60 = 'h3EC, // Physical memory protection address register
PMPADDR61 = 'h3ED, // Physical memory protection address register
PMPADDR62 = 'h3EE, // Physical memory protection address register
PMPADDR63 = 'h3EF, // Physical memory protection address register
MCYCLE = 'hB00, // Machine cycle counter
MINSTRET = 'hB02, // Machine instructions-retired counter
MHPMCOUNTER3 = 'hB03, // Machine performance-monitoring counter
@ -965,6 +1078,7 @@ package riscv_instr_pkg;
MHPMEVENT29 = 'h33D, // Machine performance-monitoring event selector
MHPMEVENT30 = 'h33E, // Machine performance-monitoring event selector
MHPMEVENT31 = 'h33F, // Machine performance-monitoring event selector
// Debug/Trace Registers (shared with Debug Mode)
TSELECT = 'h7A0, // Debug/Trace trigger register select
TDATA1 = 'h7A1, // First Debug/Trace trigger data register
TDATA2 = 'h7A2, // Second Debug/Trace trigger data register
@ -972,7 +1086,8 @@ package riscv_instr_pkg;
TINFO = 'h7A4, // Debug trigger info register
TCONTROL = 'h7A5, // Debug trigger control register
MCONTEXT = 'h7A8, // Machine mode trigger context register
SCONTEXT = 'h7AA, // Supervisor mode trigger context register
MSCONTEXT = 'h7AA, // Supervisor mode trigger context register
// Debug Mode Registers
DCSR = 'h7B0, // Debug control and status register
DPC = 'h7B1, // Debug PC
DSCRATCH0 = 'h7B2, // Debug scratch register