diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index 05b72a03..2cb4e724 100644 --- a/vendor/google_riscv-dv.lock.hjson +++ b/vendor/google_riscv-dv.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/google/riscv-dv - rev: 6e0dc183a4678bfd581c1021b5ab7705f31d14a5 + rev: cc4b87057cb38c91cb0c2ecb065e38281df7aa97 } } diff --git a/vendor/google_riscv-dv/euvm/README.md b/vendor/google_riscv-dv/euvm/README.md new file mode 100644 index 00000000..a31a6860 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/README.md @@ -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 +``` diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/custom/riscv_custom_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/custom/riscv_custom_instr.d new file mode 100644 index 00000000..23de4d0c --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/custom/riscv_custom_instr.d @@ -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(); + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/custom/riscv_custom_instr_enum.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/custom/riscv_custom_instr_enum.d new file mode 100644 index 00000000..02d28c4b --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/custom/riscv_custom_instr_enum.d @@ -0,0 +1,4 @@ +module riscv.gen.isa.custom.riscv_custom_instr_enum; + +//TODO custom instruction added +// CUSTOM_i, diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/package.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/package.d new file mode 100644 index 00000000..0aaa8dc0 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/package.d @@ -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; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_amo_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_amo_instr.d new file mode 100644 index 00000000..c3d7665d --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_amo_instr.d @@ -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; + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_b_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_b_instr.d new file mode 100644 index 00000000..76b7a6be --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_b_instr.d @@ -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); + // } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_compressed_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_compressed_instr.d new file mode 100644 index 00000000..4ccde660 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_compressed_instr.d @@ -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); + } + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_floating_point_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_floating_point_instr.d new file mode 100644 index 00000000..4a886ff3 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_floating_point_instr.d @@ -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; + // } + // } + + // } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_instr.d new file mode 100644 index 00000000..9cc3ab5b --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_instr.d @@ -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" + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_instr_register.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_instr_register.d new file mode 100644 index 00000000..97db1d17 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_instr_register.d @@ -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); +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_vector_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_vector_instr.d new file mode 100644 index 00000000..ee171929 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_vector_instr.d @@ -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; + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zba_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zba_instr.d new file mode 100644 index 00000000..b3a5d3f9 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zba_instr.d @@ -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)); + } + +} + + + diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbb_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbb_instr.d new file mode 100644 index 00000000..ad3e5543 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbb_instr.d @@ -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)); + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbc_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbc_instr.d new file mode 100644 index 00000000..9e51a4fd --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbc_instr.d @@ -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)); + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbs_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbs_instr.d new file mode 100644 index 00000000..1fc93764 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/riscv_zbs_instr.d @@ -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)); + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv128c_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv128c_instr.d new file mode 100644 index 00000000..a85c1bc7 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv128c_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32a_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32a_instr.d new file mode 100644 index 00000000..c8495c96 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32a_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32b_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32b_instr.d new file mode 100644 index 00000000..9322ea8a --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32b_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32c_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32c_instr.d new file mode 100644 index 00000000..91607c4a --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32c_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32d_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32d_instr.d new file mode 100644 index 00000000..c14bfbce --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32d_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32dc_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32dc_instr.d new file mode 100644 index 00000000..d4a91e9e --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32dc_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32f_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32f_instr.d new file mode 100644 index 00000000..d8cc6d06 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32f_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32fc_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32fc_instr.d new file mode 100644 index 00000000..862384ec --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32fc_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32i_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32i_instr.d new file mode 100644 index 00000000..0b179cbc --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32i_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32m_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32m_instr.d new file mode 100644 index 00000000..9506051e --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32m_instr.d @@ -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); } + } + diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32v_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32v_instr.d new file mode 100644 index 00000000..8352bfbd --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32v_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zba_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zba_instr.d new file mode 100644 index 00000000..5f4fca60 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zba_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbb_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbb_instr.d new file mode 100644 index 00000000..8fb208ce --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbb_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbc_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbc_instr.d new file mode 100644 index 00000000..d292bb28 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbc_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbs_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbs_instr.d new file mode 100644 index 00000000..319f7e72 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv32zbs_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64a_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64a_instr.d new file mode 100644 index 00000000..413b5b27 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64a_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64b_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64b_instr.d new file mode 100644 index 00000000..da6a5afa --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64b_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64c_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64c_instr.d new file mode 100644 index 00000000..2977d703 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64c_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64d_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64d_instr.d new file mode 100644 index 00000000..5cb1bbdd --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64d_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64f_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64f_instr.d new file mode 100644 index 00000000..ad45a696 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64f_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64i_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64i_instr.d new file mode 100644 index 00000000..525756d7 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64i_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64m_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64m_instr.d new file mode 100644 index 00000000..7fd35a42 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64m_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64zba_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64zba_instr.d new file mode 100644 index 00000000..6604ba3c --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64zba_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64zbb_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64zbb_instr.d new file mode 100644 index 00000000..e93e30a5 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/isa/rv64zbb_instr.d @@ -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); } + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/package.d b/vendor/google_riscv-dv/euvm/riscv/gen/package.d new file mode 100644 index 00000000..b8da18b3 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/package.d @@ -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; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_amo_instr_lib.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_amo_instr_lib.d new file mode 100644 index 00000000..b9ac34b9 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_amo_instr_lib.d @@ -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; + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_asm_program_gen.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_asm_program_gen.d new file mode 100644 index 00000000..5c68c533 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_asm_program_gen.d @@ -0,0 +1,1881 @@ +/* + * 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. + */ + +//----------------------------------------------------------------------------------------- +// RISC-V assembly program generator +// +// This is the main class to generate a complete RISC-V program, including the init routine, +// instruction section, data section, stack section, page table, interrupt and exception +// handling etc. Check gen_program() function to see how the program is generated. +//----------------------------------------------------------------------------------------- +module riscv.gen.riscv_asm_program_gen; + +import riscv.gen.riscv_signature_pkg: core_status_t, signature_type_t, test_result_t; +import riscv.gen.riscv_instr_gen_config: riscv_instr_gen_config; + +import riscv.gen.riscv_instr_pkg: privileged_reg_t, privileged_mode_t, + exception_cause_t, interrupt_cause_t, get_label, indent, hart_prefix, + riscv_instr_group_t, satp_mode_t, program_id_t, format_string, misa_ext_t, + vreg_init_method_t, mem_region_t, mtvec_mode_t, push_gpr_to_kernel_stack, + pop_gpr_from_kernel_stack, riscv_reg_t, + DATA_WIDTH, SINGLE_PRECISION_FRACTION_BITS, LABEL_STR_LEN, + DOUBLE_PRECISION_FRACTION_BITS; +import riscv.gen.target: support_pmp, max_interrupt_vector_num, + implemented_csr, support_debug_mode, supported_isa, + supported_privileged_mode, support_umode_trap, + NUM_GPR, ELEN, VLEN, NUM_VEC_GPR, NUM_FLOAT_GPR, NUM_HARTS, SATP_MODE, XLEN; +import riscv.gen.isa.riscv_instr: riscv_instr; +import riscv.gen.riscv_instr_stream: riscv_instr_stream, riscv_rand_instr_stream; +import riscv.gen.riscv_data_page_gen: riscv_data_page_gen; +import riscv.gen.riscv_instr_sequence: riscv_instr_sequence; +import riscv.gen.riscv_callstack_gen: riscv_callstack_gen; +import riscv.gen.riscv_page_table_list: riscv_page_table_list; +import riscv.gen.riscv_privileged_common_seq: riscv_privileged_common_seq; + + +import std.algorithm: canFind; +import std.string: toLower; +import std.format: format; + +import esdl.data.queue: Queue; +import esdl.data.bvec: ubvec, toubvec; +import esdl.rand: randomize; +import esdl.base.rand: urandom, shuffle; +import esdl.solver: CstVecDistSolver, CstVecDistRange; +import esdl.base.cmdl: CommandLine; + +import uvm; + +class riscv_asm_program_gen : uvm_object +{ + riscv_instr_gen_config cfg; + riscv_data_page_gen data_page_gen; + // User mode programs + riscv_instr_sequence[NUM_HARTS] main_program; + riscv_instr_sequence[][NUM_HARTS] sub_program; + riscv_asm_program_gen debug_rom; + // Kernel programs + // These programs are called in the interrupt/exception handling routine based on the privileged + // mode settings. For example, when the interrupt/exception is delegated to S-mode, if both SUM + // and MPRV equal 1, kernel program can fetch/load/store from U-mode pages, + // umode_program is designed for this purpose. There can be other cases that + // instruction can only be fetched from S-mode pages but load/store can access U-mode pages, or + // everything needs to be in S-mode pages. + riscv_instr_sequence umode_program; + riscv_instr_sequence smode_program; + riscv_instr_sequence smode_lsu_program; + riscv_instr_stream[] directed_instr; + string[] instr_stream; + riscv_callstack_gen callstack_gen; + riscv_privileged_common_seq privil_seq; + // Directed instruction ratio, occurance per 1000 instructions + uint[string] directed_instr_stream_ratio; + riscv_page_table_list!(SATP_MODE) page_table_list; + int hart; + + mixin uvm_object_utils; + + this(string name = "") { + super(name); + } + + //--------------------------------------------------------------------------------------- + // Main function to generate the whole program + //--------------------------------------------------------------------------------------- + + // This is the main function to generate all sections of the program. + void gen_program() { + instr_stream.length = 0; + // Generate program header + gen_program_header(); + for (int hart = 0; hart < cfg.num_of_harts; hart++) { + string[] sub_program_name; + instr_stream ~= (format("h%0d_start:", hart)); + if (!cfg.bare_program_mode) { + setup_misa(); + // Create all page tables + create_page_table(hart); + // Setup privileged mode registers and enter target privileged mode + pre_enter_privileged_mode(hart); + } + // Init section + gen_init_section(hart); + // If PMP is supported, we want to generate the associated trap handlers and the test_done + // section at the start of the program so we can allow access through the pmpcfg0 CSR + if (support_pmp && !cfg.bare_program_mode) { + gen_trap_handlers(hart); + // Ecall handler + gen_ecall_handler(hart); + // Instruction fault handler + gen_instr_fault_handler(hart); + // Load fault handler + gen_load_fault_handler(hart); + // Store fault handler + gen_store_fault_handler(hart); + if (hart == 0) { + gen_test_done(); + } + } + // Generate sub program + gen_sub_program(hart, sub_program[hart], sub_program_name, cfg.num_of_sub_program); + // Generate main program + main_program[hart] = riscv_instr_sequence.type_id.create(get_label("main", hart)); + main_program[hart].instr_cnt = cfg.main_program_instr_cnt; + main_program[hart].is_debug_program = 0; + main_program[hart].label_name = main_program[hart].get_name(); + generate_directed_instr_stream(hart, + main_program[hart].label_name, + main_program[hart].instr_cnt, + 1, + false, + main_program[hart].directed_instr + ); + main_program[hart].cfg = cfg; + main_program[hart].randomize(); + main_program[hart].gen_instr(true, cfg.no_branch_jump); + // Setup jump instruction among main program and sub programs + gen_callstack(main_program[hart], sub_program[hart], sub_program_name, + cfg.num_of_sub_program); + uvm_info(get_full_name(), "Generating callstack...done", UVM_LOW); + main_program[hart].post_process_instr(); + uvm_info(get_full_name(), "Post-processing main program...done", UVM_LOW); + main_program[hart].generate_instr_stream(); + uvm_info(get_full_name(), "Generating main program instruction stream...done", UVM_LOW); + instr_stream ~= main_program[hart].instr_string_list.toArray(); + // If PMP is supported, need to jump from end of main program to test_done section at the end + // of main_program, as the test_done will have moved to the beginning of the program + instr_stream ~= format("%sla x%0d, test_done", indent, cfg.scratch_reg); + instr_stream ~= format("%sjalr x0, x%0d, 0", indent, cfg.scratch_reg); + // Test done section + // If PMP isn't supported, generate this in the normal location + if ((hart == 0) & !support_pmp) { + gen_test_done(); + } + // Shuffle the sub programs and insert to the instruction stream + insert_sub_program(sub_program[hart], instr_stream); + uvm_info(get_full_name(), "Inserting sub-programs...done", UVM_LOW); + uvm_info(get_full_name(), "Main/sub program generation...done", UVM_LOW); + // Program end + gen_program_end(hart); + if (!cfg.bare_program_mode) { + // Generate debug rom section + if (support_debug_mode) { + gen_debug_rom(hart); + } + } + gen_section((hart_prefix(hart) ~ "instr_end"), ["nop"]); + } + for (int hart = 0; hart < cfg.num_of_harts; hart++) { + // Starting point of data section + gen_data_page_begin(hart); + if (!cfg.no_data_page) { + // User data section + gen_data_page(hart); + // AMO memory region + if ((hart == 0) && (canFind(supported_isa, riscv_instr_group_t.RV32A))) { + gen_data_page(hart, false, true); + } + } + // Stack section + gen_stack_section(hart); + if (!cfg.bare_program_mode) { + // Generate kernel program/data/stack section + gen_kernel_sections(hart); + } + // Page table + if (!cfg.bare_program_mode) { + gen_page_table_section(hart); + } + } + } + + //--------------------------------------------------------------------------------------- + // Generate kernel program/data/stack sections + //--------------------------------------------------------------------------------------- + void gen_kernel_sections(int hart) { + if (SATP_MODE != satp_mode_t.BARE) { + instr_stream ~= ".align 12"; + } + else { + instr_stream ~= ".align 2"; + } + instr_stream ~= get_label("kernel_instr_start:", hart); + instr_stream ~= ".text"; + // Kernel programs + if (cfg.virtual_addr_translation_on) { + umode_program = riscv_instr_sequence.type_id.create(get_label("umode_program", hart)); + gen_kernel_program(hart, umode_program); + smode_program = riscv_instr_sequence.type_id.create(get_label("smode_program", hart)); + gen_kernel_program(hart, smode_program); + smode_lsu_program = riscv_instr_sequence.type_id. + create(get_label("smode_lsu_program", hart)); + gen_kernel_program(hart, smode_lsu_program); + } + // All trap/interrupt handling is in the kernel region + // Trap/interrupt delegation to user mode is not supported now + // Trap handler + gen_all_trap_handler(hart); + // Interrupt handling subroutine + foreach (mode; supported_privileged_mode) { + gen_interrupt_handler_section(mode, hart); + } + instr_stream ~= get_label("kernel_instr_end: nop", hart); + // User stack and data pages may not be accessible when executing trap handling programs in + // machine/supervisor mode. Generate separate kernel data/stack sections to solve it. + if (cfg.virtual_addr_translation_on) { + if (SATP_MODE != satp_mode_t.BARE) { + instr_stream ~= ".align 12"; + } else { + instr_stream ~= ".align 2"; + } + // Kernel data pages + instr_stream ~= get_label("kernel_data_start:", hart); + if(!cfg.no_data_page) { + // Data section + gen_data_page(hart, true); + } + } + // Kernel stack section + gen_kernel_stack_section(hart); + } + + void gen_kernel_program(int hart, riscv_instr_sequence seq) { + seq.instr_cnt = cfg.kernel_program_instr_cnt; + generate_directed_instr_stream(hart, + seq.get_name(), + seq.instr_cnt, + 0, + true, + seq.directed_instr, + ); + seq.label_name = seq.get_name(); + seq.is_debug_program = 0; + seq.cfg = cfg; + seq.randomize(); + seq.gen_instr(false, cfg.no_branch_jump); + seq.post_process_instr(); + seq.generate_instr_stream(); + instr_stream ~= seq.instr_string_list.toArray(); + } + + //--------------------------------------------------------------------------------------- + // Generate any subprograms and set up the callstack + //--------------------------------------------------------------------------------------- + + void gen_sub_program(int hart, + ref riscv_instr_sequence[] sub_program, + ref string[] sub_program_name, + in int num_sub_program, + bool is_debug = false, + string prefix = "sub") { + if (num_sub_program > 0) { + sub_program.length = num_sub_program; + foreach (j, ref subp; sub_program) { + subp = riscv_instr_sequence.type_id.create(get_label(format("%s_%0d", prefix, j + 1), hart)); + uvm_info(get_full_name(), format("sub program name: %s", subp.get_name()), UVM_LOW); + subp.is_debug_program = is_debug; + if (is_debug) { + subp.instr_cnt = cfg.debug_sub_program_instr_cnt[j]; + } else { + subp.instr_cnt = cfg.sub_program_instr_cnt[j]; + } + generate_directed_instr_stream(hart, + subp.get_name(), + subp.instr_cnt, + 0, + false, + subp.directed_instr); + subp.label_name = subp.get_name(); + subp.cfg = cfg; + subp.randomize(); + subp.gen_instr(false, cfg.no_branch_jump); + sub_program_name ~= subp.label_name; + } + } + } + + void gen_callstack(riscv_instr_sequence main_program, + ref riscv_instr_sequence [] sub_program, + ref string[] sub_program_name, + in int num_sub_program) { + if(num_sub_program != 0) { + callstack_gen = riscv_callstack_gen.type_id.create("callstack_gen"); + callstack_gen.init(num_sub_program+1); + uvm_info(get_full_name(), "Randomizing call stack", UVM_LOW); + callstack_gen.randomize(); + program_id_t pid; + int idx; + // Insert the jump instruction based on the call stack + foreach (i, ref prog; callstack_gen.program_h) { + foreach (j, ref subp; prog.sub_program_id) { + idx++; + pid = cast(ubvec!16) (prog.sub_program_id[j] - 1); + uvm_info(get_full_name(), + format("Gen jump instr %0d -> sub[%0d] %0d", i, j, pid+1), UVM_LOW); + if (i == 0) + main_program.insert_jump_instr(sub_program_name[pid], idx); + else + sub_program[i-1].insert_jump_instr(sub_program_name[pid], idx); + } + } + // else { + // uvm_fatal(get_full_name(), "Failed to generate callstack"); + // } + } + uvm_info(get_full_name(), "Randomizing call stack..done", UVM_LOW); + } + + void insert_sub_program(riscv_instr_sequence[] sub_program, + ref Queue!string instr_string_list) { + sub_program.shuffle(); + foreach(subp; sub_program) { + subp.post_process_instr(); + subp.generate_instr_stream(); + instr_string_list ~= subp.instr_string_list; + } + } + + void insert_sub_program(riscv_instr_sequence[] sub_program, + ref string[] instr_string_list) { + sub_program.shuffle(); + foreach(subp; sub_program) { + subp.post_process_instr(); + subp.generate_instr_stream(); + instr_string_list ~= subp.instr_string_list.toArray; + } + } + + //--------------------------------------------------------------------------------------- + // Major sections - init, stack, data, test_done etc. + //--------------------------------------------------------------------------------------- + + void gen_program_header() { + string[] str; + instr_stream ~= ".include \"user_define.h\""; + instr_stream ~= ".globl _start"; + instr_stream ~= ".section .text"; + if (cfg.disable_compressed_instr) { + instr_stream ~= ".option norvc;"; + } + str ~= ".include \"user_init.s\""; + str ~= format("csrr x5, 0x%0x", privileged_reg_t.MHARTID); + for (int hart = 0; hart < cfg.num_of_harts; hart++) { + str ~= format("li x6, %0d", hart); + str ~= format("beq x5, x6, %0df", hart); + } + gen_section("_start", str); + for (int hart = 0; hart < cfg.num_of_harts; hart++) { + instr_stream ~= format("%0d: la x%0d, h%0d_start", hart, cfg.scratch_reg, hart); + instr_stream ~= format("jalr x0, x%0d, 0", cfg.scratch_reg); + } + } + + void gen_program_end(int hart) { + if (hart == 0) { + // Use write_tohost to terminate spike simulation + gen_section("write_tohost", ["sw gp, tohost, t5"]); + gen_section("_exit", ["j write_tohost"]); + } + } + + void gen_data_page_begin(int hart) { + instr_stream ~= ".section .data"; + if (hart == 0) { + instr_stream ~= ".align 6; .global tohost; tohost: .dword 0;"; + instr_stream ~= ".align 6; .global fromhost; fromhost: .dword 0;"; + } + } + + void gen_data_page(int hart, bool is_kernel = false, bool amo = false) { + string data_page; + data_page_gen = riscv_data_page_gen.type_id.create("data_page_gen"); + data_page_gen.cfg = cfg; + data_page_gen.gen_data_page(hart, cfg.data_page_pattern, is_kernel, amo); + instr_stream ~= data_page_gen.data_page_str; + } + + // Generate the user stack section + void gen_stack_section(int hart) { + string hart_prefix_string = hart_prefix(hart); + if (cfg.use_push_data_section) { + instr_stream ~= format(".pushsection .%0suser_stack,\"aw\",@progbits;", + hart_prefix_string); + } else { + instr_stream ~= format(".section .%0suser_stack,\"aw\",@progbits;", + hart_prefix_string); + } + if (SATP_MODE != satp_mode_t.BARE) { + instr_stream ~= ".align 12"; + } else { + instr_stream ~= ".align 2"; + } + instr_stream ~= get_label("user_stack_start:", hart); + instr_stream ~= format(".rept %0d", cfg.stack_len - 1); + instr_stream ~= format(".%0dbyte 0x0", XLEN/8); + instr_stream ~= ".endr"; + instr_stream ~= get_label("user_stack_end:", hart); + instr_stream ~= format(".%0dbyte 0x0", XLEN/8); + if (cfg.use_push_data_section) { + instr_stream ~= ".popsection;"; + } + } + + // The kernal stack is used to save user program context before executing exception handling + void gen_kernel_stack_section(int hart) { + string hart_prefix_string = hart_prefix(hart); + if (cfg.use_push_data_section) { + instr_stream ~= format(".pushsection .%0skernel_stack,\"aw\",@progbits;", + hart_prefix_string); + } else { + instr_stream ~= format(".section .%0skernel_stack,\"aw\",@progbits;", + hart_prefix_string); + } + if (SATP_MODE != satp_mode_t.BARE) { + instr_stream ~= ".align 12"; + } else { + instr_stream ~= ".align 2"; + } + instr_stream ~= get_label("kernel_stack_start:", hart); + instr_stream ~= format(".rept %0d", cfg.kernel_stack_len - 1); + instr_stream ~= format(".%0dbyte 0x0", XLEN/8); + instr_stream ~= ".endr"; + instr_stream ~= get_label("kernel_stack_end:", hart); + instr_stream ~= format(".%0dbyte 0x0", XLEN/8); + if (cfg.use_push_data_section) { + instr_stream ~= ".popsection;"; + } + } + + void gen_init_section(int hart) { + string str; + str = format_string(get_label("init:", hart), LABEL_STR_LEN); + instr_stream ~= str; + if (cfg.enable_floating_point) { + init_floating_point_gpr(); + } + init_gpr(); + // Init stack pointer to point to the end of the user stack + str = indent ~ format("la x%0d, %0suser_stack_end", cfg.sp, hart_prefix(hart)); + instr_stream ~= str; + if (cfg.enable_vector_extension) { + randomize_vec_gpr_and_csr(); + } + core_is_initialized(); + gen_dummy_csr_write(); // TODO add a way to disable xStatus read + if (support_pmp) { + str = indent ~ "j main"; + instr_stream ~= str; + } + } + + // Setup MISA based on supported extensions + void setup_misa() { + ubvec!XLEN misa; + misa[XLEN-2..XLEN] = (XLEN == 32) ? toubvec!2(0b01) : + (XLEN == 64) ? toubvec!2(0b10) : toubvec!2(0b11); + if (cfg.check_misa_init_val) { + instr_stream ~= indent ~ format("csrr x15, 0x%0x", privileged_reg_t.MISA); + } + foreach (sisa; supported_isa) { + switch (sisa) { + case riscv_instr_group_t.RV32C, riscv_instr_group_t.RV64C, + riscv_instr_group_t.RV128C: misa[misa_ext_t.MISA_EXT_C] = true; break; + case riscv_instr_group_t.RV32I, riscv_instr_group_t.RV64I, + riscv_instr_group_t.RV128I: misa[misa_ext_t.MISA_EXT_I] = true; break; + case riscv_instr_group_t.RV32M, + riscv_instr_group_t.RV64M: misa[misa_ext_t.MISA_EXT_M] = true; break; + case riscv_instr_group_t.RV32A, + riscv_instr_group_t.RV64A: misa[misa_ext_t.MISA_EXT_A] = true; break; + case riscv_instr_group_t.RV32B, + riscv_instr_group_t.RV64B: misa[misa_ext_t.MISA_EXT_B] = true; break; + case riscv_instr_group_t.RV32F, riscv_instr_group_t.RV64F, + riscv_instr_group_t.RV32FC: misa[misa_ext_t.MISA_EXT_F] = true; break; + case riscv_instr_group_t.RV32D, riscv_instr_group_t.RV64D, + riscv_instr_group_t.RV32DC: misa[misa_ext_t.MISA_EXT_D] = true; break; + case riscv_instr_group_t.RVV: misa[misa_ext_t.MISA_EXT_V] = true; break; + case riscv_instr_group_t.RV32X, + riscv_instr_group_t.RV64X: misa[misa_ext_t.MISA_EXT_X] = true; break; + case riscv_instr_group_t.RV32ZBA, riscv_instr_group_t.RV32ZBB, + riscv_instr_group_t.RV32ZBC, riscv_instr_group_t.RV32ZBS, + riscv_instr_group_t.RV64ZBA, riscv_instr_group_t.RV64ZBB, + riscv_instr_group_t.RV64ZBC, riscv_instr_group_t.RV64ZBS: break; // No Misa bit for Zb* extensions + default : uvm_fatal(get_full_name(), format("%0s is not yet supported", sisa)); + } + } + if (canFind(supported_privileged_mode, privileged_mode_t.SUPERVISOR_MODE)) { + misa[misa_ext_t.MISA_EXT_S] = true; + } + instr_stream ~= indent ~ format("li x%0d, 0x%0x", cfg.gpr[0], misa); + instr_stream ~= indent ~ format("csrw 0x%0x, x%0d", privileged_reg_t.MISA, cfg.gpr[0]); + } + + // Write to the signature_addr with values to indicate to the core testbench + // that is safe to start sending interrupt and debug stimulus + void core_is_initialized() { + string[] instr; + if (cfg.require_signature_addr) { + if (cfg.signature_addr != 0xdead_beef) { + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.INITIALIZED); + format_section(instr); + instr_stream ~= instr; + } + else { + uvm_fatal(get_full_name(), "The signature_addr is not properly configured!"); + } + } + } + + // Generate some dummy writes to xSTATUS/xIE at the beginning of the test to check + // repeated writes to these CSRs. + void gen_dummy_csr_write() { + string[] instr; + if (cfg.enable_dummy_csr_write) { + switch (cfg.init_privileged_mode) { + case privileged_mode_t.MACHINE_MODE: + instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[0], privileged_reg_t.MSTATUS); + instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[1], privileged_reg_t.MIE); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.MSTATUS, cfg.gpr[0]); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.MIE, cfg.gpr[1]); + break; + case privileged_mode_t.SUPERVISOR_MODE: + instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[0], privileged_reg_t.SSTATUS); + instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[1], privileged_reg_t.SIE); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.SSTATUS, cfg.gpr[0]); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.SIE, cfg.gpr[1]); + break; + case privileged_mode_t.USER_MODE: + static if (!support_umode_trap) { + return; + } + else { + instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[0], privileged_reg_t.USTATUS); + instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[1], privileged_reg_t.UIE); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.USTATUS, cfg.gpr[0]); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.UIE, cfg.gpr[1]); + break; + } + default: + uvm_fatal(get_full_name(), "Unsupported boot mode"); + } + format_section(instr); + instr_stream ~= instr; + } + } + + // Initialize general purpose registers with random value + void init_gpr() { + static CstVecDistSolver!(ubvec!DATA_WIDTH) _gpr_solver; + string str; + ubvec!DATA_WIDTH reg_val; + // Init general purpose registers with random values + for(int i = 0; i < NUM_GPR; i++) { + if (i.inside(cfg.sp, cfg.tp)) continue; + + if (_gpr_solver is null) { + _gpr_solver = new CstVecDistSolver!(ubvec!DATA_WIDTH)(null); + _gpr_solver ~= CstVecDistRange!(ubvec!DATA_WIDTH)(ubvec!DATA_WIDTH(0), + ubvec!DATA_WIDTH(0), + 1, false); + _gpr_solver ~= CstVecDistRange!(ubvec!DATA_WIDTH)(ubvec!DATA_WIDTH(0x1), + ubvec!DATA_WIDTH(0xF), + 1, false); + _gpr_solver ~= CstVecDistRange!(ubvec!DATA_WIDTH)(ubvec!DATA_WIDTH(0x10), + ubvec!DATA_WIDTH(0xEFFF_FFFF), + 1, false); + _gpr_solver ~= CstVecDistRange!(ubvec!DATA_WIDTH)(ubvec!DATA_WIDTH(0x8000_0000), + ubvec!DATA_WIDTH(0x8000_0000), + 1, false); + _gpr_solver ~= CstVecDistRange!(ubvec!DATA_WIDTH)(ubvec!DATA_WIDTH(0xF000_0000), + ubvec!DATA_WIDTH(0xFFFF_FFFF), + 1, false); + } + reg_val = _gpr_solver.urandom(); + str = format("%0sli x%0d, 0x%0x", indent, i, reg_val); + instr_stream ~= str; + } + } + + // Initialize vector general purpose registers + void init_vec_gpr() { + int SEW; + int LMUL; + int EDIV = 1; + int len = (ELEN <= XLEN) ? ELEN : XLEN; + int num_elements = VLEN / len; + if (!(canFind(supported_isa, riscv_instr_group_t.RVV))) return; + LMUL = 1; + SEW = (ELEN <= XLEN) ? ELEN : XLEN; + instr_stream ~= format("li x%0d, %0d", cfg.gpr[1], cfg.vector_cfg.vl); + instr_stream ~= format("%svsetvli x%0d, x%0d, e%0d, m%0d, d%0d", + indent, cfg.gpr[0], cfg.gpr[1], SEW, LMUL, EDIV); + instr_stream ~= "vec_reg_init:"; + + // Vector registers will be initialized using one of the following three methods + switch (cfg.vreg_init_method) { + case vreg_init_method_t.SAME_VALUES_ALL_ELEMS: + for (int v = 0; v < NUM_VEC_GPR; v++) { + instr_stream ~= format("%0svmv.v.x v%0d, x%0d", indent, v, v); + } + break; + case vreg_init_method_t.RANDOM_VALUES_VMV: + for (int v = 0; v < NUM_VEC_GPR; v++) { + for (int e = 0; e < num_elements; e++) { + if (e > 0) instr_stream ~= format("%0svmv.v.v v0, v%0d", indent, v); + instr_stream ~= format("%0sli x%0d, 0x%0x", + indent, cfg.gpr[0], urandom(0, 2 ^^ SEW)); + if (v > 0) { + instr_stream ~= format("%0svslide1up.vx v%0d, v0, x%0d", + indent, v, cfg.gpr[0]); + } + else { + instr_stream ~= format("%0svslide1up.vx v%0d, v1, x%0d", + indent, v, cfg.gpr[0]); + } + } + } + break; + case vreg_init_method_t.RANDOM_VALUES_LOAD: + // Select those memory regions that are big enough for load a vreg + mem_region_t[] valid_mem_region; + foreach (region; cfg.mem_region) { + if (region.size_in_bytes * 8 >= VLEN) valid_mem_region ~= region; + } + if (valid_mem_region.length == 0) + uvm_fatal(get_full_name(), "Couldn't find a memory region big enough to initialize the vector registers"); + + for (int v = 0; v < NUM_VEC_GPR; v++) { + assert (valid_mem_region.length != 0); + uint region = urandom(0, cast(uint) valid_mem_region.length); + instr_stream ~= format("%0sla t0, %0s", indent, valid_mem_region[region]); + instr_stream ~= format("%0svle.v v%0d, (t0)", indent, v); + } + break; + default : break; + } + } + + // Initialize floating point general purpose registers + void init_floating_point_gpr() { + int int_gpr; + string str; + for (int i = 0; i < NUM_FLOAT_GPR; i++) { + if (canFind( supported_isa, riscv_instr_group_t.RV64D)) { + if (urandom!bool()) init_floating_point_gpr_with_spf(i); + else init_floating_point_gpr_with_dpf(i); + } + else init_floating_point_gpr_with_spf(i); + } + // Initialize rounding mode of FCSR + str = format("%0sfsrmi %0d", indent, cfg.fcsr_rm); + instr_stream ~= str; + } + + // get instructions initialize floating_point_gpr with single precision floating value + void init_floating_point_gpr_with_spf(int int_floating_gpr) { + string str; + ubvec!32 imm = cast(ubvec!32) get_rand_spf_value(); + str = format("%0sli x%0d, %0d", indent, cfg.gpr[0], imm); + instr_stream ~= str; + str = format("%0sfmv.w.x f%0d, x%0d", indent, int_floating_gpr, cfg.gpr[0]); + instr_stream ~= str; + } + + // get instructions initialize floating_point_gpr with double precision floating value + void init_floating_point_gpr_with_dpf(int int_floating_gpr) { + string str; + ubvec!64 imm = get_rand_dpf_value(); + int int_gpr1 = cfg.gpr[0]; + int int_gpr2 = cfg.gpr[1]; + + str = format("%0sli x%0d, %0d", indent, int_gpr1, imm[32..64]); + instr_stream ~= str; + // shift to upper 32bits + for(int i=0 ; i<2 ; ++i) { + str = format("%0sslli x%0d, x%0d, 16", indent, int_gpr1, int_gpr1); + instr_stream ~= str; + } + str = format("%0sli x%0d, %0d", indent, int_gpr2, imm[0..32]); + instr_stream ~= str; + str = format("%0sor x%0d, x%0d, x%0d", indent, int_gpr2, int_gpr2, int_gpr1); + instr_stream ~= str; + str = format("%0sfmv.d.x f%0d, x%0d", indent, int_floating_gpr, int_gpr2); + instr_stream ~= str; + } + + // get a random single precision floating value + ubvec!XLEN get_rand_spf_value() { + ubvec!XLEN value; + int randint = urandom(0,6); + switch ( randint) { + case 0: value = urandom!q{[]}(0x7f80_0000, 0xff80_0000); break; + case 1: value = urandom!q{[]}(0x7f7f_ffff, 0xff7f_ffff); break; + case 2: value = urandom!q{[]}(0x0000_0000, 0x8000_0000); break; + case 3: value = urandom!q{[]}(0x7f80_0001, 0x7fc0_0000); break; + case 4: value[SINGLE_PRECISION_FRACTION_BITS..31] = + toubvec!XLEN(urandom(1, 2 ^^ (31-SINGLE_PRECISION_FRACTION_BITS))); break; + case 5: value[SINGLE_PRECISION_FRACTION_BITS..31] = 0; break; + default: break; + } + + return value; + } + + // get a random double precision floating value + ubvec!XLEN get_rand_dpf_value() { + ubvec!64 value; + + int randint = urandom(0,6); + switch ( randint) { + case 0: value = toubvec!64(urandom!q{[]}(0x7ff0_0000_0000_0000, 0xfff0_0000_0000_0000)); break; + case 1: value = toubvec!64(urandom!q{[]}(0x7fef_ffff_ffff_ffff, 0xffef_ffff_ffff_ffff)); break; + case 2: value = toubvec!64(urandom!q{[]}(0x0000_0000_0000_0000, 0x8000_0000_0000_0000)); break; + case 3: value = toubvec!64(urandom!q{[]}(0x7ff0_0000_0000_0001, 0x7ff8_0000_0000_0000)); break; + case 4: value[DOUBLE_PRECISION_FRACTION_BITS..63] = + toubvec!64(urandom(1, 2 ^^ (63-SINGLE_PRECISION_FRACTION_BITS))); break; + case 5: value[DOUBLE_PRECISION_FRACTION_BITS..63] = 0; break; + default: break; + } + return value; + } + + // Generate "test_done" section, test is finished by an ECALL instruction + // The ECALL trap handler will handle the clean up procedure before finishing the test. + void gen_test_done() { + string str = format_string("test_done:", LABEL_STR_LEN); + instr_stream ~= str; + instr_stream ~= (indent ~ "li gp, 1"); + if (cfg.bare_program_mode) { + instr_stream ~= indent ~ "j write_tohost"; + } else { + instr_stream ~= indent ~ "ecall"; + } + } + + // Dump all GPR to the starting point of the program + // TB can check the GPR value for this memory location to compare with expected value generated + // by the ISA simulator. If the processor doesn't have a good tracer unit, it might not be + // possible to compare the GPR value after each instruction execution. + void gen_register_dump(ref string[] instr) { + string str; + // Load base address + str = format("la x%0d, _start", cfg.gpr[0]); + instr ~= str; + // Generate sw/sd instructions + for(int i = 0; i < 32; i++) { + if(XLEN == 64) { + str = format("sd x%0d, %0d(x%0d)", i, i*(XLEN/8), cfg.gpr[0]); + } + else { + str = format("sw x%0d, %0d(x%0d)", i, i*(XLEN/8), cfg.gpr[0]); + } + instr ~= str; + } + } + + //--------------------------------------------------------------------------------------- + // Privileged mode entering routine + //--------------------------------------------------------------------------------------- + + void pre_enter_privileged_mode(int hart) { + string[] instr; + string[] str; + // Setup kerenal stack pointer + str ~= format("la x%0d, %0skernel_stack_end", cfg.tp, hart_prefix(hart)); + gen_section(get_label("kernel_sp", hart), str); + // Setup interrupt and exception delegation + if (!cfg.no_delegation && (cfg.init_privileged_mode != privileged_mode_t.MACHINE_MODE)) { + gen_delegation(hart); + } + // Setup trap vector register + trap_vector_init(hart); + // Setup PMP CSRs + setup_pmp(hart); + // Generate PMPADDR write test sequence + gen_pmp_csr_write(hart); + // Initialize PTE (link page table based on their real physical address) + if (cfg.virtual_addr_translation_on) { + page_table_list.process_page_table(instr); + gen_section(get_label("process_pt", hart), instr); + } + // Setup mepc register, jump to init entry + setup_epc(hart); + // Initialization of any implementation-specific custom CSRs + setup_custom_csrs(hart); + // Setup initial privilege mode + gen_privileged_mode_switch_routine(hart); + } + + void gen_privileged_mode_switch_routine(int hart) { + privil_seq = riscv_privileged_common_seq.type_id.create("privil_seq"); + foreach (mode; supported_privileged_mode) { + string[] instr; + string[] csr_handshake; + string ret_instr; + if (mode != cfg.init_privileged_mode) continue; + uvm_info(get_full_name(), format("Generating privileged mode routing for %0s", mode), UVM_LOW); + // Enter privileged mode + privil_seq.cfg = cfg; + privil_seq.hart = hart; + privil_seq.randomize(); + privil_seq.enter_privileged_mode(mode, instr); + if (cfg.require_signature_addr) { + ret_instr = instr[$-1]; + instr.length -= 1; // pop_back + // Want to write the main system CSRs to the testbench before indicating that initialization + // is complete, for any initial state analysis + switch (mode) { + case privileged_mode_t.SUPERVISOR_MODE: + gen_signature_handshake(csr_handshake, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.SSTATUS); + gen_signature_handshake(csr_handshake, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.SIE); + break; + case privileged_mode_t.USER_MODE: + gen_signature_handshake(csr_handshake, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.USTATUS); + gen_signature_handshake(csr_handshake, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.UIE); + break; + default: uvm_info(get_full_name(), format("Unsupported privileged_mode %0s", mode), UVM_LOW); + } + // Write M-mode CSRs to testbench by default, as these should be implemented + gen_signature_handshake(csr_handshake, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.MSTATUS); + gen_signature_handshake(csr_handshake, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.MIE); + format_section(csr_handshake); + instr ~= csr_handshake; + instr ~= ret_instr; + } + instr_stream ~= instr; + } + } + + // Setup EPC before entering target privileged mode + void setup_epc(int hart) { + import std.conv: to; + + string[] instr; + string mode_name; + instr = [format("la x%0d, %0sinit", cfg.gpr[0], hart_prefix(hart))]; + if(cfg.virtual_addr_translation_on) { + // For supervisor and user mode, use virtual address instead of physical address. + // Virtual address starts from address 0x0, here only the lower 12 bits are kept + // as virtual address offset. + instr ~= format("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN - 12); + instr ~= format("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN - 12); + } + mode_name = (cfg.init_privileged_mode).to!string(); + instr ~= format("csrw 0x%0x, x%0d", privileged_reg_t.MEPC, cfg.gpr[0]); + gen_section(get_label("mepc_setup", hart), instr); + } + + // Setup PMP CSR configuration + void setup_pmp(int hart) { + string[] instr; + if (support_pmp) { + cfg.pmp_cfg.setup_pmp(); + cfg.pmp_cfg.gen_pmp_instr([cfg.scratch_reg, cfg.gpr[0]], instr); + gen_section(get_label("pmp_setup", hart), instr); + } + } + + // Generates a directed stream of instructions to write random values to all supported + // pmpaddr CSRs to test write accessibility. + // The original CSR values are restored afterwards. + void gen_pmp_csr_write(int hart) { + string[] instr; + if (support_pmp && cfg.pmp_cfg.enable_write_pmp_csr) { + cfg.pmp_cfg.gen_pmp_write_test([cfg.scratch_reg, cfg.pmp_reg], instr); + gen_section(get_label("pmp_csr_write_test", hart), instr); + } + } + + // Handles creation of a subroutine to initialize any custom CSRs + void setup_custom_csrs(int hart) { + string[] instr; + init_custom_csr(instr); + gen_section(get_label("custom_csr_setup", hart), instr); + } + + // This function should be overridden in the riscv_asm_program_gen extended class + // corresponding to the RTL implementation if it has any custom CSRs defined. + // + // All that needs to be done in the overridden function is to manually create + // the instruction strings to set up any custom CSRs and then to push those strings + // into the instr queue. + void init_custom_csr(ref Queue!string instr) { + instr ~= "nop"; + } + + void init_custom_csr(ref string[] instr) { + instr ~= "nop"; + } + + //--------------------------------------------------------------------------------------- + // Privileged CSR setup for interrupt and exception handling and delegation + //--------------------------------------------------------------------------------------- + + // Interrupt and exception delegation setting. + // The lower level exception and interrupt can be delegated to higher level handler. + void gen_delegation(int hart) { + gen_delegation_instr(hart, + privileged_reg_t.MEDELEG, + privileged_reg_t.MIDELEG, + cfg.m_mode_exception_delegation, + cfg.m_mode_interrupt_delegation); + if (support_umode_trap) { + gen_delegation_instr(hart, + privileged_reg_t.SEDELEG, + privileged_reg_t.SIDELEG, + cfg.s_mode_exception_delegation, + cfg.s_mode_interrupt_delegation); + } + } + + void gen_delegation_instr(int hart, + privileged_reg_t edeleg, + privileged_reg_t ideleg, + bool[exception_cause_t] edeleg_enable, + bool[interrupt_cause_t] ideleg_enable) { + import std.conv: to; + ubvec!XLEN deleg_val; + string section_name; + string[] instr; + // Exception delegation setup + foreach (cause, ref enable; edeleg_enable) { + if (enable) { + deleg_val |= 1 << cause; + } + } + instr = [format("li x%0d, 0x%0x", cfg.gpr[0], deleg_val), + format("csrw 0x%0x, x%0d # %0s", edeleg, cfg.gpr[0], edeleg)]; + // Interrupt delegation setup + deleg_val = 0; + foreach (cause, ref enable; ideleg_enable) { + if (enable) { + deleg_val |= 1 << cause; + } + } + instr ~= format("li x%0d, 0x%0x", cfg.gpr[0], deleg_val); + instr ~= format("csrw 0x%0x, x%0d # %0s", ideleg, cfg.gpr[0], ideleg); + section_name = (edeleg).to!string; + section_name = section_name.toLower(); + gen_section(get_label(format("%0s_setup", section_name), hart), instr); + } + + // Setup trap vector - MTVEC, STVEC, UTVEC + void trap_vector_init(int hart) { + import std.conv: to; + + string[] instr; + privileged_reg_t trap_vec_reg; + string tvec_name; + foreach(mode; supported_privileged_mode) { + switch (mode) { + case privileged_mode_t.MACHINE_MODE: trap_vec_reg = privileged_reg_t.MTVEC; break; + case privileged_mode_t.SUPERVISOR_MODE: trap_vec_reg = privileged_reg_t.STVEC; break; + case privileged_mode_t.USER_MODE: trap_vec_reg = privileged_reg_t.UTVEC; break; + default: uvm_info(get_full_name(), format("Unsupported privileged_mode %0s", mode), UVM_LOW); + } + // Skip utvec init if trap delegation to u_mode is not supported + if ((mode == privileged_mode_t.USER_MODE) && + !support_umode_trap) continue; + if (mode < cfg.init_privileged_mode) continue; + tvec_name = trap_vec_reg.to!string(); + instr ~= format("la x%0d, %0s%0s_handler", + cfg.gpr[0], hart_prefix(hart), tvec_name.toLower()); + if (SATP_MODE != satp_mode_t.BARE && mode != privileged_mode_t.MACHINE_MODE) { + // For supervisor and user mode, use virtual address instead of physical address. + // Virtual address starts from address 0x0, here only the lower 20 bits are kept + // as virtual address offset. + instr ~= format("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN - 20); + instr ~= format("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN - 20); + } + instr ~= format("ori x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], cfg.mtvec_mode); + instr ~= format("csrw 0x%0x, x%0d # %0s", + trap_vec_reg, cfg.gpr[0], to!string(trap_vec_reg)); + } + gen_section(get_label("trap_vec_init", hart), instr); + } + + //--------------------------------------------------------------------------------------- + // Exception handling routine + //--------------------------------------------------------------------------------------- + + // Trap handling routine + void gen_all_trap_handler(int hart) { + string[] instr; + // If PMP isn't supported, generate the relevant trap handler sections as per usual + if (!support_pmp) { + gen_trap_handlers(hart); + // Ecall handler + gen_ecall_handler(hart); + // Instruction fault handler + gen_instr_fault_handler(hart); + // Load fault handler + gen_load_fault_handler(hart); + // Store fault handler + gen_store_fault_handler(hart); + } + // Ebreak handler + gen_ebreak_handler(hart); + // Illegal instruction handler + gen_illegal_instr_handler(hart); + // Generate page table fault handling routine + // Page table fault is always handled in machine mode, as virtual address translation may be + // broken when page fault happens. + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.HANDLING_EXCEPTION); + if(page_table_list !is null) { + page_table_list.gen_page_fault_handling_routine(instr); + } + else { + instr ~= "nop"; + } + gen_section(get_label("pt_fault_handler", hart), instr); + } + + void gen_trap_handlers(int hart) { + foreach (mode; supported_privileged_mode) { + if(mode < cfg.init_privileged_mode) continue; + switch (mode) { + case privileged_mode_t.MACHINE_MODE: + gen_trap_handler_section(hart, "m", + privileged_reg_t.MCAUSE, + privileged_reg_t.MTVEC, + privileged_reg_t.MTVAL, + privileged_reg_t.MEPC, + privileged_reg_t.MSCRATCH, + privileged_reg_t.MSTATUS, + privileged_reg_t.MIE, + privileged_reg_t.MIP); + break; + case privileged_mode_t.SUPERVISOR_MODE: + gen_trap_handler_section(hart, "s", + privileged_reg_t.SCAUSE, + privileged_reg_t.STVEC, + privileged_reg_t.STVAL, + privileged_reg_t.SEPC, + privileged_reg_t.SSCRATCH, + privileged_reg_t.SSTATUS, + privileged_reg_t.SIE, + privileged_reg_t.SIP); + break; + case privileged_mode_t.USER_MODE: + if (support_umode_trap) { + gen_trap_handler_section(hart, "u", + privileged_reg_t.UCAUSE, + privileged_reg_t.UTVEC, + privileged_reg_t.UTVAL, + privileged_reg_t.UEPC, + privileged_reg_t.USCRATCH, + privileged_reg_t.USTATUS, + privileged_reg_t.UIE, + privileged_reg_t.UIP); + } + break; + default: uvm_fatal(get_full_name(), format("Unsupported privileged_mode %0s", mode)); + } + } + } + + // Generate the interrupt and trap handler for different privileged mode. + // The trap handler checks the xCAUSE to determine the type of the exception and jumps to + // corresponding exeception handling routine. + void gen_trap_handler_section(int hart, + string mode, + privileged_reg_t cause, privileged_reg_t tvec, + privileged_reg_t tval, privileged_reg_t epc, + privileged_reg_t scratch, privileged_reg_t status, + privileged_reg_t ie, privileged_reg_t ip) { + import std.conv: to; + bool is_interrupt = true; + string tvec_name; + string[] instr; + if (cfg.mtvec_mode == mtvec_mode_t.VECTORED) { + gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr); + } + else { + // Push user mode GPR to kernel stack before executing exception handling, this is to avoid + // exception handling routine modify user program state unexpectedly + push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + // Checking xStatus can be optional if ISS (like spike) has different implementation of + // certain fields compared with the RTL processor. + if (cfg.check_xstatus) { + instr ~= format("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], status, status); + } + instr ~= + // Use scratch CSR to save a GPR value + // Check if the exception is caused by an interrupt, if yes, jump to interrupt + // handler Interrupt is indicated by xCause[XLEN-1] + [format("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause), + format("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN-1), + format("bne x%0d, x0, %0s%0smode_intr_handler", cfg.gpr[0], hart_prefix(hart), mode)]; + } + // The trap handler will occupy one 4KB page, it will be allocated one entry in the page table + // with a specific privileged mode. + if (SATP_MODE != satp_mode_t.BARE) { + instr_stream ~= ".align 12"; + } + else { + instr_stream ~= format(".align %d", cfg.tvec_alignment); + } + tvec_name = tvec.to!string(); + gen_section(get_label(format("%0s_handler", tvec_name.toLower()), hart), instr); + // Exception handler + instr = []; + if (cfg.mtvec_mode == mtvec_mode_t.VECTORED) { + push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + } + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.HANDLING_EXCEPTION); + instr ~= + // The trap is caused by an exception, read back xCAUSE, xEPC to see if these + // CSR values are set properly. The checking is done by comparing against the log + // generated by ISA simulator (spike). + [format("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], epc, epc), + format("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause), + // Breakpoint + format("li x%0d, 0x%0x # BREAKPOINT", cfg.gpr[1], exception_cause_t.BREAKPOINT), + format("beq x%0d, x%0d, %0sebreak_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + // Check if it's an ECALL exception. Jump to ECALL exception handler + format("li x%0d, 0x%0x # ECALL_UMODE", cfg.gpr[1], exception_cause_t.ECALL_UMODE), + format("beq x%0d, x%0d, %0secall_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x # ECALL_SMODE", cfg.gpr[1], exception_cause_t.ECALL_SMODE), + format("beq x%0d, x%0d, %0secall_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x # ECALL_MMODE", cfg.gpr[1], exception_cause_t.ECALL_MMODE), + format("beq x%0d, x%0d, %0secall_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + // Page table fault or access fault conditions + format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.INSTRUCTION_ACCESS_FAULT), + format("beq x%0d, x%0d, %0sinstr_fault_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.LOAD_ACCESS_FAULT), + format("beq x%0d, x%0d, %0sload_fault_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.STORE_AMO_ACCESS_FAULT), + format("beq x%0d, x%0d, %0sstore_fault_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.INSTRUCTION_PAGE_FAULT), + format("beq x%0d, x%0d, %0spt_fault_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.LOAD_PAGE_FAULT), + format("beq x%0d, x%0d, %0spt_fault_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.STORE_AMO_PAGE_FAULT), + format("beq x%0d, x%0d, %0spt_fault_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + // Illegal instruction exception + format("li x%0d, 0x%0x # ILLEGAL_INSTRUCTION", cfg.gpr[1], exception_cause_t.ILLEGAL_INSTRUCTION), + format("beq x%0d, x%0d, %0sillegal_instr_handler", + cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)), + // Skip checking tval for illegal instruction as it's implementation specific + format("csrr x%0d, 0x%0x # %0s", cfg.gpr[1], tval, tval), + // use JALR to jump to test_done. + format("1: la x%0d, test_done", cfg.scratch_reg), + format("jalr x1, x%0d, 0", cfg.scratch_reg) + ]; + gen_section(get_label(format("%0smode_exception_handler", mode), hart), instr); + } + + // Generate for interrupt vector table + void gen_interrupt_vector_table(int hart, + string mode, + privileged_reg_t status, + privileged_reg_t cause, + privileged_reg_t ie, + privileged_reg_t ip, + privileged_reg_t scratch, + ref string[] instr) { + import std.conv: to; + // In vector mode, the BASE address is shared between interrupt 0 and exception handling. + // When vectored interrupts are enabled, interrupt cause 0, which corresponds to user-mode + // software interrupts, are vectored to the same location as synchronous exceptions. This + // ambiguity does not arise in practice, since user-mode software interrupts are either + // disabled or delegated + instr ~= ".option norvc;" ~ format("j %0s%0smode_exception_handler", hart_prefix(hart), mode); + // Redirect the interrupt to the corresponding interrupt handler + for (int i = 1; i < max_interrupt_vector_num; i++) { + instr ~= format("j %0s%0smode_intr_vector_%0d", hart_prefix(hart), mode, i); + } + if (!cfg.disable_compressed_instr) { + instr ~= ".option rvc;"; + } + for (int i = 1; i < max_interrupt_vector_num; i++) { + string[] intr_handler; + push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, intr_handler); + gen_signature_handshake(intr_handler, signature_type_t.CORE_STATUS, + core_status_t.HANDLING_IRQ); + intr_handler ~= [format("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause), + // Terminate the test if xCause[31] != 0 (indicating exception) + format("srli x%0d, x%0d, 0x%0x", cfg.gpr[0], cfg.gpr[0], XLEN-1), + format("beqz x%0d, 1f", cfg.gpr[0])]; + gen_signature_handshake(intr_handler, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + status); + gen_signature_handshake(intr_handler, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + cause); + gen_signature_handshake(intr_handler, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + ie); + gen_signature_handshake(intr_handler, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + ip); + // Jump to commmon interrupt handling routine + intr_handler ~= + [format("j %0s%0smode_intr_handler", hart_prefix(hart), mode), + format("1: la x%0d, test_done", cfg.scratch_reg), + format("jalr x0, x%0d, 0", cfg.scratch_reg)]; + + gen_section(get_label(format("%0smode_intr_vector_%0d", mode, i), hart), intr_handler); + } + } + + // ECALL trap handler + // It does some clean up like dump GPRs before communicating with host to terminate the test. + // User can extend this function if some custom clean up routine is needed. + void gen_ecall_handler(int hart) { + string[] instr; + dump_perf_stats(instr); + gen_register_dump(instr); + instr ~= format("la x%0d, write_tohost", cfg.scratch_reg); + instr ~= format("jalr x0, x%0d, 0", cfg.scratch_reg); + gen_section(get_label("ecall_handler", hart), instr); + } + + // Ebreak trap handler + // When breakpoint exception happens, epc will be written with ebreak instruction + // itself. Add epc by 4 and resume execution. + // Note the breakpoint could be triggered by a C.EBREAK instruction, the generated program + // guarantees that epc + 4 is a valid instruction boundary + // TODO: Support random operations in debug mode + // TODO: Support ebreak exception delegation + // TODO: handshake the correct Xcause CSR based on delegation privil. mode + void gen_ebreak_handler(int hart) { + string[] instr; + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.EBREAK_EXCEPTION); + gen_signature_handshake(instr, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.MCAUSE); + instr ~= [format("csrr x%0d, 0x%0x", cfg.gpr[0], privileged_reg_t.MEPC), + format("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]), + format("csrw 0x%0x, x%0d", privileged_reg_t.MEPC, cfg.gpr[0])]; + pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + instr ~= "mret"; + gen_section(get_label("ebreak_handler", hart), instr); + } + + // Illegal instruction handler + // Note: Save the illegal instruction to MTVAL is optional in the spec, and mepc could be + // a virtual address that cannot be used in machine mode handler. As a result, there's no way to + // know the illegal instruction is compressed or not. This hanlder just simply adds the PC by + // 4 and resumes execution. The way that the illegal instruction is injected guarantees that + // PC + 4 is a valid instruction boundary. + // TODO: handshake the corret Xcause CSR based on delegation setup + void gen_illegal_instr_handler(int hart) { + string[] instr; + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.ILLEGAL_INSTR_EXCEPTION); + gen_signature_handshake(instr, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.MCAUSE); + instr ~= [format("csrr x%0d, 0x%0x", cfg.gpr[0], privileged_reg_t.MEPC), + format("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]), + format("csrw 0x%0x, x%0d", privileged_reg_t.MEPC, cfg.gpr[0])]; + pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + instr ~= "mret"; + gen_section(get_label("illegal_instr_handler", hart), instr); + } + + // TODO: handshake correct csr based on delegation + void gen_instr_fault_handler(int hart) { + string[] instr; + riscv_reg_t[6] regs; + + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.INSTR_FAULT_EXCEPTION); + gen_signature_handshake(instr, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, privileged_reg_t.MCAUSE); + if (cfg.pmp_cfg.enable_pmp_exception_handler) { + cfg.pmp_cfg.gen_pmp_exception_routine(cfg.gpr ~ cfg.scratch_reg ~ cfg.pmp_reg, + exception_cause_t.INSTRUCTION_ACCESS_FAULT, + instr); + } + pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + instr ~= "mret"; + gen_section(get_label("instr_fault_handler", hart), instr); + } + + // TODO: handshake correct csr based on delegation + void gen_load_fault_handler(int hart) { + string[] instr; + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.LOAD_FAULT_EXCEPTION); + gen_signature_handshake(instr, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.MCAUSE); + if (cfg.pmp_cfg.enable_pmp_exception_handler) { + cfg.pmp_cfg.gen_pmp_exception_routine(cfg.gpr ~ cfg.scratch_reg ~ cfg.pmp_reg, + exception_cause_t.LOAD_ACCESS_FAULT, + instr); + } + pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + instr ~= "mret"; + gen_section(get_label("load_fault_handler", hart), instr); + } + + // TODO: handshake correct csr based on delegation + void gen_store_fault_handler(int hart) { + string[] instr; + gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.STORE_FAULT_EXCEPTION); + gen_signature_handshake(instr, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + privileged_reg_t.MCAUSE); + if (cfg.pmp_cfg.enable_pmp_exception_handler) { + cfg.pmp_cfg.gen_pmp_exception_routine(cfg.gpr ~ cfg.scratch_reg ~ cfg.pmp_reg, + exception_cause_t.STORE_AMO_ACCESS_FAULT, + instr); + } + pop_gpr_from_kernel_stack(privileged_reg_t.MSTATUS, privileged_reg_t.MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr); + instr ~= "mret"; + gen_section(get_label("store_fault_handler", hart), instr); + } + + //--------------------------------------------------------------------------------------- + // Page table setup + //--------------------------------------------------------------------------------------- + + // Create page table if virtual address translation is supported. + // The page is created based on the address translation mode - SV32, SV39, SV48 + // Right now only the lowest level 4KB page table is configured as leaf page table entry (PTE), + // all the other super pages are link PTE. + void create_page_table(int hart) { + string[] instr; + if (cfg.virtual_addr_translation_on) { + page_table_list = riscv_page_table_list!(SATP_MODE).type_id.create("page_table_list"); + page_table_list.cfg = cfg; + page_table_list.create_page_table_list(); + page_table_list.enable_exception = cfg.enable_page_table_exception; + uvm_info(get_full_name(), + format("Randomizing page tables, totally %0d page tables, mode = %0s", + page_table_list.page_table.length, cfg.init_privileged_mode), UVM_LOW); + page_table_list.privileged_mode = cfg.init_privileged_mode; + page_table_list.randomize(); + page_table_list.randomize_page_table(); + uvm_info(get_full_name(), "Finished creating page tables", UVM_LOW); + } + } + + // Generate the page table section of the program + // The page table is generated as a group of continuous 4KB data sections. + void gen_page_table_section(int hart) { + string[] page_table_section; + if (page_table_list !is null) { + if (cfg.use_push_data_section) { + instr_stream ~= format(".pushsection .%0spage_table,\"aw\",@progbits;", + hart_prefix(hart)); + } + else { + instr_stream ~= format(".section .%0spage_table,\"aw\",@progbits;", + hart_prefix(hart)); + } + foreach(table; page_table_list.page_table) { + table.gen_page_table_section(page_table_section); + instr_stream ~= page_table_section; + } + if (cfg.use_push_data_section) { + instr_stream ~= ".popsection;"; + } + } + } + + // Only extend this function if the core utilizes a PLIC for handling interrupts + // In this case, the core will write to a specific location as the response to the interrupt, and + // external PLIC unit can detect this response and process the interrupt clean up accordingly. + void gen_plic_section(ref string[] interrupt_handler_instr) { + // Utilize the memory mapped handshake scheme to signal the testbench that the interrupt + // handling has been completed and we are about to xRET out of the handler + gen_signature_handshake(interrupt_handler_instr, + signature_type_t.CORE_STATUS, + core_status_t.FINISHED_IRQ); + } + + void gen_plic_section(ref Queue!string interrupt_handler_instr) { + // Utilize the memory mapped handshake scheme to signal the testbench that the interrupt + // handling has been completed and we are about to xRET out of the handler + gen_signature_handshake(interrupt_handler_instr, + signature_type_t.CORE_STATUS, + core_status_t.FINISHED_IRQ); + } + + // Interrupt handler routine + void gen_interrupt_handler_section(privileged_mode_t mode, int hart){ + string mode_prefix; + string ls_unit; + privileged_reg_t status, ip, ie, scratch; + string[] interrupt_handler_instr; + ls_unit = (XLEN == 32) ? "w" : "d"; + if (mode < cfg.init_privileged_mode) return; + if (mode == privileged_mode_t.USER_MODE && !support_umode_trap) return; + switch (mode) { + case privileged_mode_t.MACHINE_MODE: + mode_prefix = "m"; + status = privileged_reg_t.MSTATUS; + ip = privileged_reg_t.MIP; + ie = privileged_reg_t.MIE; + scratch = privileged_reg_t.MSCRATCH; + break; + case privileged_mode_t.SUPERVISOR_MODE: + mode_prefix = "s"; + status = privileged_reg_t.SSTATUS; + ip = privileged_reg_t.SIP; + ie = privileged_reg_t.SIE; + scratch = privileged_reg_t.SSCRATCH; + break; + case privileged_mode_t.USER_MODE: + mode_prefix = "u"; + status = privileged_reg_t.USTATUS; + ip = privileged_reg_t.UIP; + ie = privileged_reg_t.UIE; + scratch = privileged_reg_t.USCRATCH; + break; + default: uvm_fatal(get_full_name(), format("Unsupported mode: %0s", mode)); + } + // If nested interrupts are enabled, set xSTATUS.xIE in the interrupt handler + // to re-enable interrupt handling capabilities + if (cfg.enable_nested_interrupt) { + interrupt_handler_instr ~= format("csrr x%0d, 0x%0x", cfg.gpr[0], scratch); + interrupt_handler_instr ~= format("bgtz x%0d, 1f", cfg.gpr[0]); + interrupt_handler_instr ~= format("csrwi 0x%0x, 0x1", scratch); + switch (status) { + case privileged_reg_t.MSTATUS: + interrupt_handler_instr ~= format("csrsi 0x%0x, 0x%0x", status, 8); + break; + case privileged_reg_t.SSTATUS: + interrupt_handler_instr ~= format("csrsi 0x%0x, 0x%0x", status, 2); + break; + case privileged_reg_t.USTATUS: + interrupt_handler_instr ~= format("csrsi 0x%0x, 0x%0x", status, 1); + break; + default: uvm_fatal(get_full_name(), format("Unsupported status %0s", status)); + } + interrupt_handler_instr ~= format("1: csrwi 0x%0x,0", scratch); + } + // Read back interrupt related privileged CSR + // The value of these CSR are checked by comparing with spike simulation result. + interrupt_handler_instr ~= [format("csrr x%0d, 0x%0x # %0s;", cfg.gpr[0], status, status), + format("csrr x%0d, 0x%0x # %0s;", cfg.gpr[0], ie, ie), + format("csrr x%0d, 0x%0x # %0s;", cfg.gpr[0], ip, ip), + // Clean all the pending interrupt + format("csrrc x%0d, 0x%0x, x%0d # %0s;", + cfg.gpr[0], ip, cfg.gpr[0], ip)]; + gen_plic_section(interrupt_handler_instr); + // Restore user mode GPR value from kernel stack before return + pop_gpr_from_kernel_stack(status, scratch, cfg.mstatus_mprv, + cfg.sp, cfg.tp, interrupt_handler_instr); + interrupt_handler_instr ~= format("%0sret;", mode_prefix); + if (SATP_MODE != satp_mode_t.BARE) { + // The interrupt handler will use one 4KB page + instr_stream ~= ".align 12"; + } + else { + instr_stream ~= ".align 2"; + } + gen_section(get_label(format("%0smode_intr_handler", mode_prefix), hart), + interrupt_handler_instr); + } + + //--------------------------------------------------------------------------------------- + // Helper functions + //--------------------------------------------------------------------------------------- + + // Format a code section, without generating it + void format_section(ref Queue!string instr) { + string prefix = format_string(" ", LABEL_STR_LEN); + foreach (ii; instr) { + ii = prefix ~ ii; + } + } + + void format_section(ref string[] instr) { + string prefix = format_string(" ", LABEL_STR_LEN); + foreach (ii; instr) { + ii = prefix ~ ii; + } + } + + // Generate a code section + void gen_section(string label, Queue!string instr) { + string str; + if (label != "") { + str = format_string(format("%0s:", label), LABEL_STR_LEN); + instr_stream ~= str; + } + foreach (ii; instr) { + str = indent ~ ii; + instr_stream ~= str; + } + instr_stream ~= ""; + } + + void gen_section(string label, string[] instr) { + string str; + if(label != "") { + str = format_string(format("%0s:", label), LABEL_STR_LEN); + instr_stream ~= str; + } + foreach(i; instr) { + str = indent ~ i; + instr_stream ~= str; + } + instr_stream ~= ""; + } + + // Dump performance CSRs if applicable + void dump_perf_stats(ref string[] instr) { + foreach(icsr; implemented_csr) { + if (icsr >= privileged_reg_t.MCYCLE && icsr <= privileged_reg_t.MHPMCOUNTER31H) { + gen_signature_handshake(instr, + signature_type_t.WRITE_CSR, + core_status_t.INITIALIZED, + test_result_t.TEST_FAIL, + icsr); + } + } + } + + // Write the generated program to a file + void gen_test_file(string test_name) { + import std.stdio: File; + import std.path: dirName; + import std.file: mkdirRecurse; + //int fd; + mkdirRecurse(dirName(test_name)); + auto fd = File(test_name,"w"); + foreach (instr; instr_stream) { + fd.writeln(instr); + } + // $fclose(fd); + uvm_info(get_full_name(), format("%0s is generated", test_name), UVM_LOW); + } + + // Helper function to generate the proper sequence of handshake instructions + // to signal the testbench (see riscv_signature_pkg.sv) + void gen_signature_handshake(ref string[] instr, + in signature_type_t signature_type, + core_status_t core_status = core_status_t.INITIALIZED, + test_result_t test_result = test_result_t.TEST_FAIL, + privileged_reg_t csr = privileged_reg_t.MSCRATCH, + string addr_label = "") { + if (cfg.require_signature_addr) { + string[] str; + str = [format("li x%0d, 0x%0h", cfg.gpr[1], cfg.signature_addr)]; + instr ~= str; + switch (signature_type) { + // A single data word is written to the signature address. + // Bits [7:0] contain the signature_type of CORE_STATUS, and the upper + // XLEN-8 bits contain the core_status_t data. + case signature_type_t.CORE_STATUS: + str = [format("li x%0d, 0x%0h", cfg.gpr[0], core_status), + format("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]), + format("addi x%0d, x%0d, 0x%0h", cfg.gpr[0], + cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr ~= str; + break; + // A single data word is written to the signature address. + // Bits [7:0] contain the signature_type of TEST_RESULT, and the upper + // XLEN-8 bits contain the test_result_t data. + case signature_type_t.TEST_RESULT: + str = [format("li x%0d, 0x%0h", cfg.gpr[0], test_result), + format("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]), + format("addi x%0d, x%0d, 0x%0h", cfg.gpr[0], + cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr ~= str; + break; + // The first write to the signature address contains just the + // signature_type of WRITE_GPR. + // It is followed by 32 consecutive writes to the signature address, + // each writing the data contained in one GPR, starting from x0 as the + // first write, and ending with x31 as the 32nd write. + case signature_type_t.WRITE_GPR: + str = [format("li x%0d, 0x%0h", cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr ~= str; + for (int i = 0; i < 32; i++) { + str = [format("sw x%0x, 0(x%0d)", i, cfg.gpr[1])]; + instr ~= str; + } + break; + // The first write to the signature address contains the + // signature_type of WRITE_CSR in bits [7:0], and the CSR address in + // the upper XLEN-8 bits. + // It is followed by a second write to the signature address, + // containing the data stored in the specified CSR. + case signature_type_t.WRITE_CSR: + if (!(canFind(implemented_csr, csr))) { + return; + } + str = [format("li x%0d, 0x%0h", cfg.gpr[0], csr), + format("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]), + format("addi x%0d, x%0d, 0x%0h", cfg.gpr[0], + cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1]), + format("csrr x%0d, 0x%0h", cfg.gpr[0], csr), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr ~= str; + break; + default: + uvm_fatal(get_full_name(), "signature_type is not defined"); + } + } + } + + void gen_signature_handshake(ref Queue!string instr, + in signature_type_t signature_type, + core_status_t core_status = core_status_t.INITIALIZED, + test_result_t test_result = test_result_t.TEST_FAIL, + privileged_reg_t csr = privileged_reg_t.MSCRATCH, + string addr_label = "") { + if (cfg.require_signature_addr) { + Queue!string str; + str = [format("li x%0d, 0x%0h", cfg.gpr[1], cfg.signature_addr)]; + instr = instr ~ str; + switch (signature_type) { + // A single data word is written to the signature address. + // Bits [7:0] contain the signature_type of CORE_STATUS, and the upper + // XLEN-8 bits contain the core_status_t data. + case signature_type_t.CORE_STATUS: + str = [format("li x%0d, 0x%0h", cfg.gpr[0], core_status), + format("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]), + format("addi x%0d, x%0d, 0x%0h", cfg.gpr[0], + cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr = instr ~ str; + break; + // A single data word is written to the signature address. + // Bits [7:0] contain the signature_type of TEST_RESULT, and the upper + // XLEN-8 bits contain the test_result_t data. + case signature_type_t.TEST_RESULT: + str = [format("li x%0d, 0x%0h", cfg.gpr[0], test_result), + format("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]), + format("addi x%0d, x%0d, 0x%0h", cfg.gpr[0], + cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr = instr ~ str; + break; + // The first write to the signature address contains just the + // signature_type of WRITE_GPR. + // It is followed by 32 consecutive writes to the signature address, + // each writing the data contained in one GPR, starting from x0 as the + // first write, and ending with x31 as the 32nd write. + case signature_type_t.WRITE_GPR: + str = [format("li x%0d, 0x%0h", cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr = instr ~ str; + for(int i = 0; i < 32; i++) { + str = [format("sw x%0x, 0(x%0d)", i, cfg.gpr[1])]; + instr = instr ~ str; + } + break; + // The first write to the signature address contains the + // signature_type of WRITE_CSR in bits [7:0], and the CSR address in + // the upper XLEN-8 bits. + // It is followed by a second write to the signature address, + // containing the data stored in the specified CSR. + case signature_type_t.WRITE_CSR: + if (!(canFind(implemented_csr, csr))) { + return; + } + str = [format("li x%0d, 0x%0h", cfg.gpr[0], csr), + format("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]), + format("addi x%0d, x%0d, 0x%0h", cfg.gpr[0], + cfg.gpr[0], signature_type), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1]), + format("csrr x%0d, 0x%0h", cfg.gpr[0], csr), + format("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])]; + instr = instr ~ str; + break; + default: + uvm_fatal(get_full_name(), "signature_type is not defined"); + } + } + } + + //--------------------------------------------------------------------------------------- + // Inject directed instruction stream + //--------------------------------------------------------------------------------------- + + void add_directed_instr_stream(string name, uint ratio) { + directed_instr_stream_ratio[name] = ratio; + uvm_info(get_full_name(), format("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio), + UVM_LOW); + } + + void get_directed_instr_stream() { + import std.conv: to; + string args, val; + string stream_name_opts, stream_freq_opts; + string stream_name; + int stream_freq; + string[] opts; + CommandLine cmdl = new CommandLine(); + for (int i=0; i 1) && (cfg.vector_cfg.vtype.fractional_lmul)) { + lmul = format("mf%0d", cfg.vector_cfg.vtype.vlmul); + } + else { + lmul = format("m%0d", cfg.vector_cfg.vtype.vlmul); + } + instr_stream ~= format("%svsetvli x%0d, x%0d, e%0d, m%0d, d%0d", + indent, + cfg.gpr[0], + cfg.gpr[1], + cfg.vector_cfg.vtype.vsew, + lmul, + cfg.vector_cfg.vtype.vediv); + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_callstack_gen.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_callstack_gen.d new file mode 100644 index 00000000..3f82db18 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_callstack_gen.d @@ -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 %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)); + } + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_custom_instr_enum.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_custom_instr_enum.d new file mode 100644 index 00000000..187345f7 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_custom_instr_enum.d @@ -0,0 +1,3 @@ +//TODO custom instruction added +// CUSTOM_i, +module riscv.gen.riscv_custom_instr_enum; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_data_page_gen.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_data_page_gen.d new file mode 100644 index 00000000..33f71f3c --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_data_page_gen.d @@ -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;"; + } + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_debug_rom_gen.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_debug_rom_gen.d new file mode 100644 index 00000000..7605fd61 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_debug_rom_gen.d @@ -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; + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_defines.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_defines.d new file mode 100644 index 00000000..73f8de5e --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_defines.d @@ -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); diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_directed_instr_lib.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_directed_instr_lib.d new file mode 100644 index 00000000..3238b803 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_directed_instr_lib.d @@ -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(); + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_illegal_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_illegal_instr.d new file mode 100644 index 00000000..9a71e2a5 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_illegal_instr.d @@ -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); + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_gen_config.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_gen_config.d new file mode 100644 index 00000000..c273bb82 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_gen_config.d @@ -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; + } + } + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_pkg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_pkg.d new file mode 100644 index 00000000..7519973a --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_pkg.d @@ -0,0 +1,1539 @@ +/* + * 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. + */ + + +module riscv.gen.riscv_instr_pkg; + +import riscv.gen.target: XLEN, NUM_HARTS, SATP_MODE, implemented_csr; +import std.traits: EnumMembers; + +import esdl.data.bvec: bvec, ubvec; +import esdl.rand: rand; +import uvm; + +// Data section setting + +// use uvm_cmdline_processor.get_inst() directly +// uvm_cmdline_processor inst; + + +struct mem_region_t +{ + string name; + uint size_in_bytes; + ubvec!3 xwr; // Excutable,Writable,Readale +} + +enum vreg_init_method_t: ubyte { + SAME_VALUES_ALL_ELEMS, + RANDOM_VALUES_VMV, + RANDOM_VALUES_LOAD +} + +enum satp_mode_t: ubyte { + BARE = 0b0000, + SV32 = 0b0001, + SV39 = 0b1000, + SV48 = 0b1001, + SV57 = 0b1010, + SV64 = 0b1011 +} + +enum f_rounding_mode_t: ubyte { + RNE = 0b000, + RTZ = 0b001, + RDN = 0b010, + RUP = 0b011, + RMM = 0b100 +} + +enum mtvec_mode_t: ubyte { + DIRECT = 0b00, + VECTORED = 0b01 +} + +enum imm_t: ubyte { + IMM, // Signed immediate + UIMM, // Unsigned immediate + NZUIMM, // Non-zero unsigned immediate + NZIMM // Non-zero signed immediate +} + +// Privileged mode +enum privileged_mode_t: ubyte { + USER_MODE = 0b00, + SUPERVISOR_MODE = 0b01, + RESERVED_MODE = 0b10, + MACHINE_MODE = 0b11 +} + +enum riscv_instr_group_t: ubyte { + RV32I, + RV64I, + RV32M, + RV64M, + RV32A, + RV64A, + RV32F, + RV32FC, + RV64F, + RV32D, + RV32DC, + RV64D, + RV32C, + RV64C, + RV128I, + RV128C, + RVV, + RV32B, + RV32ZBA, + RV32ZBB, + RV32ZBC, + RV32ZBS, + RV64B, + RV64ZBA, + RV64ZBB, + RV64ZBC, + RV64ZBS, + RV32X, + RV64X +} + + +enum riscv_instr_name_t: ushort { + // RV32I instructions + LUI, + AUIPC, + JAL, + JALR, + BEQ, + BNE, + BLT, + BGE, + BLTU, + BGEU, + LB, + LH, + LW, + LBU, + LHU, + SB, + SH, + SW, + ADDI, + SLTI, + SLTIU, + XORI, + ORI, + ANDI, + SLLI, + SRLI, + SRAI, + ADD, + SUB, + SLL, + SLT, + SLTU, + XOR, + SRL, + SRA, + OR, + AND, + NOP, + FENCE, + FENCE_I, + ECALL, + EBREAK, + CSRRW, + CSRRS, + CSRRC, + CSRRWI, + CSRRSI, + CSRRCI, + // RV32ZBA instructions + SH1ADD, + SH2ADD, + SH3ADD, + // RV32ZBB instructions + ANDN, + CLZ, + CPOP, + CTZ, + MAX, + MAXU, + MIN, + MINU, + ORC_B, + ORN, + REV8, + ROL, + ROR, + RORI, + SEXT_B, + SEXT_H, + XNOR, + ZEXT_H, + // RV32ZBC instructions + CLMUL, + CLMULH, + CLMULR, + // RV32ZBS instructions + BCLR, + BCLRI, + BEXT, + BEXTI, + BINV, + BINVI, + BSET, + BSETI, + // RV32B instructions + // Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs). + GORC, + GORCI, + CMIX, + CMOV, + PACK, + PACKU, + PACKH, + XPERM_N, + XPERM_B, + XPERM_H, + SLO, + SRO, + SLOI, + SROI, + GREV, + GREVI, + FSL, + FSR, + FSRI, + CRC32_B, + CRC32_H, + CRC32_W, + CRC32C_B, + CRC32C_H, + CRC32C_W, + SHFL, + UNSHFL, + SHFLI, + UNSHFLI, + BCOMPRESS, + BDECOMPRESS, + BFP, + // RV64ZBA instructions + ADD_UW, + SH1ADD_UW, + SH2ADD_UW, + SH3ADD_UW, + SLLI_UW, + // RV64ZBB instructions + CLZW, + CPOPW, + CTZW, + ROLW, + RORW, + RORIW, + //RV64B instructions + // Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs). + BMATOR, + BMATXOR, + BMATFLIP, + CRC32_D, + CRC32C_D, + SHFLW, + UNSHFLW, + BCOMPRESSW, + BDECOMPRESSW, + BFPW, + SLOW, + SROW, + SLOIW, + SROIW, + GREVW, + GREVIW, + FSLW, + FSRW, + FSRIW, + GORCW, + GORCIW, + PACKW, + PACKUW, + XPERM_W, + // RV32M instructions + MUL, + MULH, + MULHSU, + MULHU, + DIV, + DIVU, + REM, + REMU, + // RV64M instructions + MULW, + DIVW, + DIVUW, + REMW, + REMUW, + // RV32F instructions + FLW, + FSW, + FMADD_S, + FMSUB_S, + FNMSUB_S, + FNMADD_S, + FADD_S, + FSUB_S, + FMUL_S, + FDIV_S, + FSQRT_S, + FSGNJ_S, + FSGNJN_S, + FSGNJX_S, + FMIN_S, + FMAX_S, + FCVT_W_S, + FCVT_WU_S, + FMV_X_W, + FEQ_S, + FLT_S, + FLE_S, + FCLASS_S, + FCVT_S_W, + FCVT_S_WU, + FMV_W_X, + // RV64F instruction + FCVT_L_S, + FCVT_LU_S, + FCVT_S_L, + FCVT_S_LU, + // RV32D instructions + FLD, + FSD, + FMADD_D, + FMSUB_D, + FNMSUB_D, + FNMADD_D, + FADD_D, + FSUB_D, + FMUL_D, + FDIV_D, + FSQRT_D, + FSGNJ_D, + FSGNJN_D, + FSGNJX_D, + FMIN_D, + FMAX_D, + FCVT_S_D, + FCVT_D_S, + FEQ_D, + FLT_D, + FLE_D, + FCLASS_D, + FCVT_W_D, + FCVT_WU_D, + FCVT_D_W, + FCVT_D_WU, + // RV64D + FCVT_L_D, + FCVT_LU_D, + FMV_X_D, + FCVT_D_L, + FCVT_D_LU, + FMV_D_X, + // RV64I + LWU, + LD, + SD, + ADDIW, + SLLIW, + SRLIW, + SRAIW, + ADDW, + SUBW, + SLLW, + SRLW, + SRAW, + // RV32C + C_LW, + C_SW, + C_LWSP, + C_SWSP, + C_ADDI4SPN, + C_ADDI, + C_LI, + C_ADDI16SP, + C_LUI, + C_SRLI, + C_SRAI, + C_ANDI, + C_SUB, + C_XOR, + C_OR, + C_AND, + C_BEQZ, + C_BNEZ, + C_SLLI, + C_MV, + C_EBREAK, + C_ADD, + C_NOP, + C_J, + C_JAL, + C_JR, + C_JALR, + // RV64C + C_ADDIW, + C_SUBW, + C_ADDW, + C_LD, + C_SD, + C_LDSP, + C_SDSP, + // RV128C + C_SRLI64, + C_SRAI64, + C_SLLI64, + C_LQ, + C_SQ, + C_LQSP, + C_SQSP, + // RV32FC + C_FLW, + C_FSW, + C_FLWSP, + C_FSWSP, + // RV32DC + C_FLD, + C_FSD, + C_FLDSP, + C_FSDSP, + // RV32A + LR_W, + SC_W, + AMOSWAP_W, + AMOADD_W, + AMOAND_W, + AMOOR_W, + AMOXOR_W, + AMOMIN_W, + AMOMAX_W, + AMOMINU_W, + AMOMAXU_W, + // RV64A + LR_D, + SC_D, + AMOSWAP_D, + AMOADD_D, + AMOAND_D, + AMOOR_D, + AMOXOR_D, + AMOMIN_D, + AMOMAX_D, + AMOMINU_D, + AMOMAXU_D, + // Vector instructions + VSETVL, + VSETVLI, + VADD, + VSUB, + VRSUB, + VWADDU, + VWSUBU, + VWADD, + VWSUB, + VADC, + VMADC, + VSBC, + VMSBC, + VAND, + VOR, + VXOR, + VSLL, + VSRL, + VSRA, + VNSRL, + VNSRA, + VMSEQ, + VMSNE, + VMSLTU, + VMSLT, + VMSLEU, + VMSLE, + VMSGTU, + VMSGT, + VMINU, + VMIN, + VMAXU, + VMAX, + VMUL, + VMULH, + VMULHU, + VMULHSU, + VDIVU, + VDIV, + VREMU, + VREM, + VWMUL, + VWMULU, + VWMULSU, + VMACC, + VNMSAC, + VMADD, + VNMSUB, + VWMACCU, + VWMACC, + VWMACCSU, + VWMACCUS, + //VQMACCU, + //VQMACC, + //VQMACCSU, + //VQMACCUS, + VMERGE, + VMV, + VSADDU, + VSADD, + VSSUBU, + VSSUB, + VAADDU, + VAADD, + VASUBU, + VASUB, + VSSRL, + VSSRA, + VNCLIPU, + VNCLIP, + // 14. Vector Floating-Point Instructions + VFADD, + VFSUB, + VFRSUB, + VFMUL, + VFDIV, + VFRDIV, + VFWMUL, + VFMACC, + VFNMACC, + VFMSAC, + VFNMSAC, + VFMADD, + VFNMADD, + VFMSUB, + VFNMSUB, + VFWMACC, + VFWNMACC, + VFWMSAC, + VFWNMSAC, + VFSQRT_V, + VFMIN, + VFMAX, + VFSGNJ, + VFSGNJN, + VFSGNJX, + VMFEQ, + VMFNE, + VMFLT, + VMFLE, + VMFGT, + VMFGE, + VFCLASS_V, + VFMERGE, + VFMV, + VFCVT_XU_F_V, + VFCVT_X_F_V, + VFCVT_F_XU_V, + VFCVT_F_X_V, + VFWCVT_XU_F_V, + VFWCVT_X_F_V, + VFWCVT_F_XU_V, + VFWCVT_F_X_V, + VFWCVT_F_F_V, + VFNCVT_XU_F_W, + VFNCVT_X_F_W, + VFNCVT_F_XU_W, + VFNCVT_F_X_W, + VFNCVT_F_F_W, + VFNCVT_ROD_F_F_W, + // 15. Vector reduction instruction + VREDSUM_VS, + VREDMAXU_VS, + VREDMAX_VS, + VREDMINU_VS, + VREDMIN_VS, + VREDAND_VS, + VREDOR_VS, + VREDXOR_VS, + VWREDSUMU_VS, + VWREDSUM_VS, + VFREDOSUM_VS, + VFREDSUM_VS, + VFREDMAX_VS, + VFWREDOSUM_VS, + VFWREDSUM_VS, + // Vector mask instruction + VMAND_MM, + VMNAND_MM, + VMANDNOT_MM, + VMXOR_MM, + VMOR_MM, + VMNOR_MM, + VMORNOT_MM, + VMXNOR_MM, + VPOPC_M, + VFIRST_M, + VMSBF_M, + VMSIF_M, + VMSOF_M, + VIOTA_M, + VID_V, + // Vector permutation instruction + VMV_X_S, + VMV_S_X, + VFMV_F_S, + VFMV_S_F, + VSLIDEUP, + VSLIDEDOWN, + VSLIDE1UP, + VSLIDE1DOWN, + VRGATHER, + VCOMPRESS, + VMV1R_V, + VMV2R_V, + VMV4R_V, + VMV8R_V, + // Vector load/store instruction + VLE_V, + VSE_V, + VLSE_V, + VSSE_V, + VLXEI_V, + VSXEI_V, + VSUXEI_V, + VLEFF_V, + // Segmented load/store instruction + VLSEGE_V, + VSSEGE_V, + VLSEGEFF_V, + VLSSEGE_V, + VSSSEGE_V, + VLXSEGEI_V, + VSXSEGEI_V, + VSUXSEGEI_V, + // Vector AMO instruction + // EEW vector AMOs + VAMOSWAPE_V, + VAMOADDE_V, + VAMOXORE_V, + VAMOANDE_V, + VAMOORE_V, + VAMOMINE_V, + VAMOMAXE_V, + VAMOMINUE_V, + VAMOMAXUE_V, + // Supervisor instruction + DRET, + MRET, + URET, + SRET, + WFI, + SFENCE_VMA, + // Custom instructions + // `include "isa/custom/riscv_custom_instr_enum.sv" + // You can add other instructions here + INVALID_INSTR +} + +// Maximum virtual address bits used by the program +enum uint MAX_USED_VADDR_BITS = 30; + +enum uint SINGLE_PRECISION_FRACTION_BITS = 23; +enum uint DOUBLE_PRECISION_FRACTION_BITS = 52; + + +enum riscv_reg_t: ubyte { // 5'b + ZERO = 0b00000, + RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, + S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6 +} + +enum riscv_fpr_t: ubyte { // 5'b + FT0, FT1, FT2, FT3, FT4, FT5, FT6, FT7, FS0, FS1, FA0, FA1, FA2, FA3, FA4, FA5, + FA6, FA7, FS2, FS3, FS4, FS5, FS6, FS7, FS8, FS9, FS10, FS11, FT8, FT9, FT10, FT11 +} + +enum riscv_vreg_t: ubyte { + V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, + V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31 +} + + +enum riscv_instr_format_t: ubyte { // 6'b + J_FORMAT = 0, + U_FORMAT, + I_FORMAT, + B_FORMAT, + R_FORMAT, + S_FORMAT, + R4_FORMAT, + // Compressed instruction format + CI_FORMAT, + CB_FORMAT, + CJ_FORMAT, + CR_FORMAT, + CA_FORMAT, + CL_FORMAT, + CS_FORMAT, + CSS_FORMAT, + CIW_FORMAT, + // Vector instruction format + VSET_FORMAT, + VA_FORMAT, + VS2_FORMAT, // op vd,vs2 + VL_FORMAT, + VS_FORMAT, + VLX_FORMAT, + VSX_FORMAT, + VLS_FORMAT, + VSS_FORMAT, + VAMO_FORMAT +} + + +// Vector arithmetic instruction variant +enum va_variant_t: ubyte { + VV, + VI, + VX, + VF, + WV, + WI, + WX, + VVM, + VIM, + VXM, + VFM, + VS, + VM +} + +enum riscv_instr_category_t: ubyte { // 6'b + LOAD = 0, + STORE, + SHIFT, + ARITHMETIC, + LOGICAL, + COMPARE, + BRANCH, + JUMP, + SYNCH, + SYSTEM, + COUNTER, + CSR, + CHANGELEVEL, + TRAP, + INTERRUPT, + // `VECTOR_INCLUDE("riscv_instr_pkg_inc_riscv_instr_category_t.sv") + AMO // (last one) +} + +alias riscv_csr_t = ubvec!12; + +enum privileged_reg_t: ushort { // 12'b + // User mode register + USTATUS = 0x000, // User status + UIE = 0x004, // User interrupt-enable register + UTVEC = 0x005, // User trap-handler base address + USCRATCH = 0x040, // Scratch register for user trap handlers + UEPC = 0x041, // User exception program counter + UCAUSE = 0x042, // User trap cause + UTVAL = 0x043, // User bad address or instruction + UIP = 0x044, // User interrupt pending + // Unprivileged Floating-Point CSRs + FFLAGS = 0x001, // Floating-Point Accrued Exceptions + FRM = 0x002, // Floating-Point Dynamic Rounding Mode + FCSR = 0x003, // Floating-Point Control/Status Register (FRM + FFLAGS) + // Unprivileged Counter/Timers + CYCLE = 0xC00, // Cycle counter for RDCYCLE instruction + TIME = 0xC01, // Timer for RDTIME instruction + INSTRET = 0xC02, // Instructions-retired counter for RDINSTRET instruction + HPMCOUNTER3 = 0xC03, // Performance-monitoring counter + HPMCOUNTER4 = 0xC04, // Performance-monitoring counter + HPMCOUNTER5 = 0xC05, // Performance-monitoring counter + HPMCOUNTER6 = 0xC06, // Performance-monitoring counter + HPMCOUNTER7 = 0xC07, // Performance-monitoring counter + HPMCOUNTER8 = 0xC08, // Performance-monitoring counter + HPMCOUNTER9 = 0xC09, // Performance-monitoring counter + HPMCOUNTER10 = 0xC0A, // Performance-monitoring counter + HPMCOUNTER11 = 0xC0B, // Performance-monitoring counter + HPMCOUNTER12 = 0xC0C, // Performance-monitoring counter + HPMCOUNTER13 = 0xC0D, // Performance-monitoring counter + HPMCOUNTER14 = 0xC0E, // Performance-monitoring counter + HPMCOUNTER15 = 0xC0F, // Performance-monitoring counter + HPMCOUNTER16 = 0xC10, // Performance-monitoring counter + HPMCOUNTER17 = 0xC11, // Performance-monitoring counter + HPMCOUNTER18 = 0xC12, // Performance-monitoring counter + HPMCOUNTER19 = 0xC13, // Performance-monitoring counter + HPMCOUNTER20 = 0xC14, // Performance-monitoring counter + HPMCOUNTER21 = 0xC15, // Performance-monitoring counter + HPMCOUNTER22 = 0xC16, // Performance-monitoring counter + HPMCOUNTER23 = 0xC17, // Performance-monitoring counter + HPMCOUNTER24 = 0xC18, // Performance-monitoring counter + HPMCOUNTER25 = 0xC19, // Performance-monitoring counter + HPMCOUNTER26 = 0xC1A, // Performance-monitoring counter + HPMCOUNTER27 = 0xC1B, // Performance-monitoring counter + HPMCOUNTER28 = 0xC1C, // Performance-monitoring counter + HPMCOUNTER29 = 0xC1D, // Performance-monitoring counter + HPMCOUNTER30 = 0xC1E, // Performance-monitoring counter + HPMCOUNTER31 = 0xC1F, // Performance-monitoring counter + CYCLEH = 0xC80, // Upper 32 bits of CYCLE, RV32I only + TIMEH = 0xC81, // Upper 32 bits of TIME, RV32I only + INSTRETH = 0xC82, // Upper 32 bits of INSTRET, RV32I only + HPMCOUNTER3H = 0xC83, // Upper 32 bits of HPMCOUNTER3, RV32I only + HPMCOUNTER4H = 0xC84, // Upper 32 bits of HPMCOUNTER4, RV32I only + HPMCOUNTER5H = 0xC85, // Upper 32 bits of HPMCOUNTER5, RV32I only + HPMCOUNTER6H = 0xC86, // Upper 32 bits of HPMCOUNTER6, RV32I only + HPMCOUNTER7H = 0xC87, // Upper 32 bits of HPMCOUNTER7, RV32I only + HPMCOUNTER8H = 0xC88, // Upper 32 bits of HPMCOUNTER8, RV32I only + HPMCOUNTER9H = 0xC89, // Upper 32 bits of HPMCOUNTER9, RV32I only + HPMCOUNTER10H = 0xC8A, // Upper 32 bits of HPMCOUNTER10, RV32I only + HPMCOUNTER11H = 0xC8B, // Upper 32 bits of HPMCOUNTER11, RV32I only + HPMCOUNTER12H = 0xC8C, // Upper 32 bits of HPMCOUNTER12, RV32I only + HPMCOUNTER13H = 0xC8D, // Upper 32 bits of HPMCOUNTER13, RV32I only + HPMCOUNTER14H = 0xC8E, // Upper 32 bits of HPMCOUNTER14, RV32I only + HPMCOUNTER15H = 0xC8F, // Upper 32 bits of HPMCOUNTER15, RV32I only + HPMCOUNTER16H = 0xC90, // Upper 32 bits of HPMCOUNTER16, RV32I only + HPMCOUNTER17H = 0xC91, // Upper 32 bits of HPMCOUNTER17, RV32I only + HPMCOUNTER18H = 0xC92, // Upper 32 bits of HPMCOUNTER18, RV32I only + HPMCOUNTER19H = 0xC93, // Upper 32 bits of HPMCOUNTER19, RV32I only + HPMCOUNTER20H = 0xC94, // Upper 32 bits of HPMCOUNTER20, RV32I only + HPMCOUNTER21H = 0xC95, // Upper 32 bits of HPMCOUNTER21, RV32I only + HPMCOUNTER22H = 0xC96, // Upper 32 bits of HPMCOUNTER22, RV32I only + HPMCOUNTER23H = 0xC97, // Upper 32 bits of HPMCOUNTER23, RV32I only + HPMCOUNTER24H = 0xC98, // Upper 32 bits of HPMCOUNTER24, RV32I only + HPMCOUNTER25H = 0xC99, // Upper 32 bits of HPMCOUNTER25, RV32I only + HPMCOUNTER26H = 0xC9A, // Upper 32 bits of HPMCOUNTER26, RV32I only + HPMCOUNTER27H = 0xC9B, // Upper 32 bits of HPMCOUNTER27, RV32I only + HPMCOUNTER28H = 0xC9C, // Upper 32 bits of HPMCOUNTER28, RV32I only + HPMCOUNTER29H = 0xC9D, // Upper 32 bits of HPMCOUNTER29, RV32I only + HPMCOUNTER30H = 0xC9E, // Upper 32 bits of HPMCOUNTER30, RV32I only + HPMCOUNTER31H = 0xC9F, // Upper 32 bits of HPMCOUNTER31, RV32I only + // Supervisor mode register + // Supervisor Trap Setup + SSTATUS = 0x100, // Supervisor status + SEDELEG = 0x102, // Supervisor exception delegation register + SIDELEG = 0x103, // Supervisor interrupt delegation register + SIE = 0x104, // Supervisor interrupt-enable register + STVEC = 0x105, // Supervisor trap-handler base address + SCOUNTEREN = 0x106, // Supervisor counter enable + // Supervisor Configuration + SENVCFG = 0x10A, // Supervisor environment configuration register + // Supervisor Trap Handling + SSCRATCH = 0x140, // Scratch register for supervisor trap handlers + SEPC = 0x141, // Supervisor exception program counter + SCAUSE = 0x142, // Supervisor trap cause + STVAL = 0x143, // Supervisor bad address or instruction + SIP = 0x144, // Supervisor interrupt pending + // Supervisor Protection and Translation + SATP = 0x180, // Supervisor address translation and protection + // Supervisor Debug/Trace Register + SCONTEXT = 0x5A8, // Supervisor environment configuration register. + // Hypervisor Trap Setup register + HSTATUS = 0x600, // Hypervisor status register + HEDELEG = 0x602, // Hypervisor exception delegation register + HIDELEG = 0x603, // Hypervisor interrupt delegation register + HIE = 0x604, // Hypervisor interrupt-enable register + HCOUNTEREN = 0x606, // Hypervisor counter enable + HGEIE = 0x607, // Hypervisor guest external interrupt-enable register + // Hypervisor Trap Handling + HTVAL = 0x643, // Hypervisor bad guest physical address + HIP = 0x644, // Hypervisor interrupt pending + HVIP = 0x645, // Hypervisor virtual interrupt pending + HTINST = 0x64A, // Hypervisor trap instruction (transformed) + HGEIP = 0xE12, // Hypervisor guest external interrupt pending + // Hypervisor configuration + HENVCFG = 0x60A, // Hypervisor environment configuration register + HENVCFGH = 0x61A, // Additional hypervisor env. conf. register, RV32 only + // Hypervisor guest address translation and protection + HGATP = 0x680, // Hypervisor guest address translation and protection + // Hypervisor Debug/Trace registers + HCONTEXT = 0x6A8, // Hypervisor-mode context register + // Hypervisor Counter/Timer Virtualization Registers + HTIMEDELTA = 0x605, // Delta for VS/VU-mode timer + HTIMEDELTAH = 0x615, // Upper 32 bits of htimedelta, HSXLEN=32 only + // Virtual Supervisor Registers + VSSTATUS = 0x200, // Virtual supervisor status register + VSIE = 0x204, // Virtual supervisor interrupt-enable register + VSTVEC = 0x205, // Virtual supervisor trap handler base address + VSSCRATCH = 0x240, // Virtual supervisor scratch register + VSEPC = 0x241, // Virtual supervisor exception program counter + VSCAUSE = 0x242, // Virtual supervisor trap cause + VSTVAL = 0x243, // Virtual supervisor bad address or instruction + VSIP = 0x244, // Virtual supervisor interrupt pending + VSATP = 0x280, // Virtual supervisor address translation and protection + // Machine mode registers + // Machine Information Registers + MVENDORID = 0xF11, // Vendor ID + MARCHID = 0xF12, // Architecture ID + MIMPID = 0xF13, // Implementation ID + MHARTID = 0xF14, // Hardware thread ID + MCONFIGPTR = 0xF15, // Pointer to configuration data structure + // Machine Trap Setup + MSTATUS = 0x300, // Machine status + MISA = 0x301, // ISA and extensions + MEDELEG = 0x302, // Machine exception delegation register + MIDELEG = 0x303, // Machine interrupt delegation register + MIE = 0x304, // Machine interrupt-enable register + MTVEC = 0x305, // Machine trap-handler base address + MCOUNTEREN = 0x306, // Machine counter enable + MSTATUSH = 0x310, // Additional machine status register, RV32 only + // Machine Trap Handling + MSCRATCH = 0x340, // Scratch register for machine trap handlers + MEPC = 0x341, // Machine exception program counter + MCAUSE = 0x342, // Machine trap cause + MTVAL = 0x343, // Machine bad address or instruction + MIP = 0x344, // Machine interrupt pending + // Machine Configuration + MENVCFG = 0x30A, // Machine environment configuration register + MENVCFGH = 0x31A, // Additional machine env. conf. register, RV32 only + MSECCFG = 0x747, // Machine security configuration register + MSECCFGH = 0x757, // Additional machine security conf. register, RV32 only + // Machine Memory Protection + PMPCFG0 = 0x3A0, // Physical memory protection configuration + PMPCFG1 = 0x3A1, // Physical memory protection configuration, RV32 only + PMPCFG2 = 0x3A2, // Physical memory protection configuration + PMPCFG3 = 0x3A3, // Physical memory protection configuration, RV32 only + PMPCFG4 = 0x3A4, // Physical memory protection configuration + PMPCFG5 = 0x3A5, // Physical memory protection configuration, RV32 only + PMPCFG6 = 0x3A6, // Physical memory protection configuration + PMPCFG7 = 0x3A7, // Physical memory protection configuration, RV32 only + PMPCFG8 = 0x3A8, // Physical memory protection configuration + PMPCFG9 = 0x3A9, // Physical memory protection configuration, RV32 only + PMPCFG10 = 0x3AA, // Physical memory protection configuration + PMPCFG11 = 0x3AB, // Physical memory protection configuration, RV32 only + PMPCFG12 = 0x3AC, // Physical memory protection configuration + PMPCFG13 = 0x3AD, // Physical memory protection configuration, RV32 only + PMPCFG14 = 0x3AE, // Physical memory protection configuration + PMPCFG15 = 0x3AF, // Physical memory protection configuration, RV32 only + PMPADDR0 = 0x3B0, // Physical memory protection address register + PMPADDR1 = 0x3B1, // Physical memory protection address register + PMPADDR2 = 0x3B2, // Physical memory protection address register + PMPADDR3 = 0x3B3, // Physical memory protection address register + PMPADDR4 = 0x3B4, // Physical memory protection address register + PMPADDR5 = 0x3B5, // Physical memory protection address register + PMPADDR6 = 0x3B6, // Physical memory protection address register + PMPADDR7 = 0x3B7, // Physical memory protection address register + PMPADDR8 = 0x3B8, // Physical memory protection address register + PMPADDR9 = 0x3B9, // Physical memory protection address register + PMPADDR10 = 0x3BA, // Physical memory protection address register + PMPADDR11 = 0x3BB, // Physical memory protection address register + PMPADDR12 = 0x3BC, // Physical memory protection address register + PMPADDR13 = 0x3BD, // Physical memory protection address register + PMPADDR14 = 0x3BE, // Physical memory protection address register + PMPADDR15 = 0x3BF, // Physical memory protection address register + PMPADDR16 = 0x4C0, // Physical memory protection address register + PMPADDR17 = 0x3C1, // Physical memory protection address register + PMPADDR18 = 0x3C2, // Physical memory protection address register + PMPADDR19 = 0x3C3, // Physical memory protection address register + PMPADDR20 = 0x3C4, // Physical memory protection address register + PMPADDR21 = 0x3C5, // Physical memory protection address register + PMPADDR22 = 0x3C6, // Physical memory protection address register + PMPADDR23 = 0x3C7, // Physical memory protection address register + PMPADDR24 = 0x3C8, // Physical memory protection address register + PMPADDR25 = 0x3C9, // Physical memory protection address register + PMPADDR26 = 0x3CA, // Physical memory protection address register + PMPADDR27 = 0x3CB, // Physical memory protection address register + PMPADDR28 = 0x3CC, // Physical memory protection address register + PMPADDR29 = 0x3CD, // Physical memory protection address register + PMPADDR30 = 0x3CE, // Physical memory protection address register + PMPADDR31 = 0x3CF, // Physical memory protection address register + PMPADDR32 = 0x4D0, // Physical memory protection address register + PMPADDR33 = 0x3D1, // Physical memory protection address register + PMPADDR34 = 0x3D2, // Physical memory protection address register + PMPADDR35 = 0x3D3, // Physical memory protection address register + PMPADDR36 = 0x3D4, // Physical memory protection address register + PMPADDR37 = 0x3D5, // Physical memory protection address register + PMPADDR38 = 0x3D6, // Physical memory protection address register + PMPADDR39 = 0x3D7, // Physical memory protection address register + PMPADDR40 = 0x3D8, // Physical memory protection address register + PMPADDR41 = 0x3D9, // Physical memory protection address register + PMPADDR42 = 0x3DA, // Physical memory protection address register + PMPADDR43 = 0x3DB, // Physical memory protection address register + PMPADDR44 = 0x3DC, // Physical memory protection address register + PMPADDR45 = 0x3DD, // Physical memory protection address register + PMPADDR46 = 0x3DE, // Physical memory protection address register + PMPADDR47 = 0x3DF, // Physical memory protection address register + PMPADDR48 = 0x4E0, // Physical memory protection address register + PMPADDR49 = 0x3E1, // Physical memory protection address register + PMPADDR50 = 0x3E2, // Physical memory protection address register + PMPADDR51 = 0x3E3, // Physical memory protection address register + PMPADDR52 = 0x3E4, // Physical memory protection address register + PMPADDR53 = 0x3E5, // Physical memory protection address register + PMPADDR54 = 0x3E6, // Physical memory protection address register + PMPADDR55 = 0x3E7, // Physical memory protection address register + PMPADDR56 = 0x3E8, // Physical memory protection address register + PMPADDR57 = 0x3E9, // Physical memory protection address register + PMPADDR58 = 0x3EA, // Physical memory protection address register + PMPADDR59 = 0x3EB, // Physical memory protection address register + PMPADDR60 = 0x3EC, // Physical memory protection address register + PMPADDR61 = 0x3ED, // Physical memory protection address register + PMPADDR62 = 0x3EE, // Physical memory protection address register + PMPADDR63 = 0x3EF, // Physical memory protection address register + MCYCLE = 0xB00, // Machine cycle counter + MINSTRET = 0xB02, // Machine instructions-retired counter + MHPMCOUNTER3 = 0xB03, // Machine performance-monitoring counter + MHPMCOUNTER4 = 0xB04, // Machine performance-monitoring counter + MHPMCOUNTER5 = 0xB05, // Machine performance-monitoring counter + MHPMCOUNTER6 = 0xB06, // Machine performance-monitoring counter + MHPMCOUNTER7 = 0xB07, // Machine performance-monitoring counter + MHPMCOUNTER8 = 0xB08, // Machine performance-monitoring counter + MHPMCOUNTER9 = 0xB09, // Machine performance-monitoring counter + MHPMCOUNTER10 = 0xB0A, // Machine performance-monitoring counter + MHPMCOUNTER11 = 0xB0B, // Machine performance-monitoring counter + MHPMCOUNTER12 = 0xB0C, // Machine performance-monitoring counter + MHPMCOUNTER13 = 0xB0D, // Machine performance-monitoring counter + MHPMCOUNTER14 = 0xB0E, // Machine performance-monitoring counter + MHPMCOUNTER15 = 0xB0F, // Machine performance-monitoring counter + MHPMCOUNTER16 = 0xB10, // Machine performance-monitoring counter + MHPMCOUNTER17 = 0xB11, // Machine performance-monitoring counter + MHPMCOUNTER18 = 0xB12, // Machine performance-monitoring counter + MHPMCOUNTER19 = 0xB13, // Machine performance-monitoring counter + MHPMCOUNTER20 = 0xB14, // Machine performance-monitoring counter + MHPMCOUNTER21 = 0xB15, // Machine performance-monitoring counter + MHPMCOUNTER22 = 0xB16, // Machine performance-monitoring counter + MHPMCOUNTER23 = 0xB17, // Machine performance-monitoring counter + MHPMCOUNTER24 = 0xB18, // Machine performance-monitoring counter + MHPMCOUNTER25 = 0xB19, // Machine performance-monitoring counter + MHPMCOUNTER26 = 0xB1A, // Machine performance-monitoring counter + MHPMCOUNTER27 = 0xB1B, // Machine performance-monitoring counter + MHPMCOUNTER28 = 0xB1C, // Machine performance-monitoring counter + MHPMCOUNTER29 = 0xB1D, // Machine performance-monitoring counter + MHPMCOUNTER30 = 0xB1E, // Machine performance-monitoring counter + MHPMCOUNTER31 = 0xB1F, // Machine performance-monitoring counter + MCYCLEH = 0xB80, // Upper 32 bits of MCYCLE, RV32I only + MINSTRETH = 0xB82, // Upper 32 bits of MINSTRET, RV32I only + MHPMCOUNTER3H = 0xB83, // Upper 32 bits of HPMCOUNTER3, RV32I only + MHPMCOUNTER4H = 0xB84, // Upper 32 bits of HPMCOUNTER4, RV32I only + MHPMCOUNTER5H = 0xB85, // Upper 32 bits of HPMCOUNTER5, RV32I only + MHPMCOUNTER6H = 0xB86, // Upper 32 bits of HPMCOUNTER6, RV32I only + MHPMCOUNTER7H = 0xB87, // Upper 32 bits of HPMCOUNTER7, RV32I only + MHPMCOUNTER8H = 0xB88, // Upper 32 bits of HPMCOUNTER8, RV32I only + MHPMCOUNTER9H = 0xB89, // Upper 32 bits of HPMCOUNTER9, RV32I only + MHPMCOUNTER10H = 0xB8A, // Upper 32 bits of HPMCOUNTER10, RV32I only + MHPMCOUNTER11H = 0xB8B, // Upper 32 bits of HPMCOUNTER11, RV32I only + MHPMCOUNTER12H = 0xB8C, // Upper 32 bits of HPMCOUNTER12, RV32I only + MHPMCOUNTER13H = 0xB8D, // Upper 32 bits of HPMCOUNTER13, RV32I only + MHPMCOUNTER14H = 0xB8E, // Upper 32 bits of HPMCOUNTER14, RV32I only + MHPMCOUNTER15H = 0xB8F, // Upper 32 bits of HPMCOUNTER15, RV32I only + MHPMCOUNTER16H = 0xB90, // Upper 32 bits of HPMCOUNTER16, RV32I only + MHPMCOUNTER17H = 0xB91, // Upper 32 bits of HPMCOUNTER17, RV32I only + MHPMCOUNTER18H = 0xB92, // Upper 32 bits of HPMCOUNTER18, RV32I only + MHPMCOUNTER19H = 0xB93, // Upper 32 bits of HPMCOUNTER19, RV32I only + MHPMCOUNTER20H = 0xB94, // Upper 32 bits of HPMCOUNTER20, RV32I only + MHPMCOUNTER21H = 0xB95, // Upper 32 bits of HPMCOUNTER21, RV32I only + MHPMCOUNTER22H = 0xB96, // Upper 32 bits of HPMCOUNTER22, RV32I only + MHPMCOUNTER23H = 0xB97, // Upper 32 bits of HPMCOUNTER23, RV32I only + MHPMCOUNTER24H = 0xB98, // Upper 32 bits of HPMCOUNTER24, RV32I only + MHPMCOUNTER25H = 0xB99, // Upper 32 bits of HPMCOUNTER25, RV32I only + MHPMCOUNTER26H = 0xB9A, // Upper 32 bits of HPMCOUNTER26, RV32I only + MHPMCOUNTER27H = 0xB9B, // Upper 32 bits of HPMCOUNTER27, RV32I only + MHPMCOUNTER28H = 0xB9C, // Upper 32 bits of HPMCOUNTER28, RV32I only + MHPMCOUNTER29H = 0xB9D, // Upper 32 bits of HPMCOUNTER29, RV32I only + MHPMCOUNTER30H = 0xB9E, // Upper 32 bits of HPMCOUNTER30, RV32I only + MHPMCOUNTER31H = 0xB9F, // Upper 32 bits of HPMCOUNTER31, RV32I only + MCOUNTINHIBIT = 0x320, // Machine counter-inhibit register + MHPMEVENT3 = 0x323, // Machine performance-monitoring event selector + MHPMEVENT4 = 0x324, // Machine performance-monitoring event selector + MHPMEVENT5 = 0x325, // Machine performance-monitoring event selector + MHPMEVENT6 = 0x326, // Machine performance-monitoring event selector + MHPMEVENT7 = 0x327, // Machine performance-monitoring event selector + MHPMEVENT8 = 0x328, // Machine performance-monitoring event selector + MHPMEVENT9 = 0x329, // Machine performance-monitoring event selector + MHPMEVENT10 = 0x32A, // Machine performance-monitoring event selector + MHPMEVENT11 = 0x32B, // Machine performance-monitoring event selector + MHPMEVENT12 = 0x32C, // Machine performance-monitoring event selector + MHPMEVENT13 = 0x32D, // Machine performance-monitoring event selector + MHPMEVENT14 = 0x32E, // Machine performance-monitoring event selector + MHPMEVENT15 = 0x32F, // Machine performance-monitoring event selector + MHPMEVENT16 = 0x330, // Machine performance-monitoring event selector + MHPMEVENT17 = 0x331, // Machine performance-monitoring event selector + MHPMEVENT18 = 0x332, // Machine performance-monitoring event selector + MHPMEVENT19 = 0x333, // Machine performance-monitoring event selector + MHPMEVENT20 = 0x334, // Machine performance-monitoring event selector + MHPMEVENT21 = 0x335, // Machine performance-monitoring event selector + MHPMEVENT22 = 0x336, // Machine performance-monitoring event selector + MHPMEVENT23 = 0x337, // Machine performance-monitoring event selector + MHPMEVENT24 = 0x338, // Machine performance-monitoring event selector + MHPMEVENT25 = 0x339, // Machine performance-monitoring event selector + MHPMEVENT26 = 0x33A, // Machine performance-monitoring event selector + MHPMEVENT27 = 0x33B, // Machine performance-monitoring event selector + MHPMEVENT28 = 0x33C, // Machine performance-monitoring event selector + MHPMEVENT29 = 0x33D, // Machine performance-monitoring event selector + MHPMEVENT30 = 0x33E, // Machine performance-monitoring event selector + MHPMEVENT31 = 0x33F, // Machine performance-monitoring event selector + // Debug/Trace Registers (shared with Debug Mode) + TSELECT = 0x7A0, // Debug/Trace trigger register select + TDATA1 = 0x7A1, // First Debug/Trace trigger data register + TDATA2 = 0x7A2, // Second Debug/Trace trigger data register + TDATA3 = 0x7A3, // Third Debug/Trace trigger data register + TINFO = 0x7A4, // Debug trigger info register + TCONTROL = 0x7A5, // Debug trigger control register + MCONTEXT = 0x7A8, // Machine mode trigger context register + MSCONTEXT = 0x7AA, // Supervisor mode trigger context register + // Debug Mode Registers + DCSR = 0x7B0, // Debug control and status register + DPC = 0x7B1, // Debug PC + DSCRATCH0 = 0x7B2, // Debug scratch register + DSCRATCH1 = 0x7B3, // Debug scratch register (last one) + VSTART = 0x008, // Vector start position + VXSTAT = 0x009, // Fixed point saturate flag + VXRM = 0x00A, // Fixed point rounding mode + VL = 0xC20, // Vector length + VTYPE = 0xC21, // Vector data type register + VLENB = 0xC22 // VLEN/8 (vector register length in bytes) +} + +enum privileged_reg_fld_t: ubyte { + RSVD, // Reserved field + MXL, // mis.mxl + EXTENSION, // mis.extension + MODE, // satp.mode + ASID, // satp.asid + PPN // satp.ppn +} + +enum privileged_level_t: ubyte { + M_LEVEL = 0b11, // Machine mode + S_LEVEL = 0b01, // Supervisor mode + U_LEVEL = 0b00 // User mode +} + +enum reg_field_access_t: ubyte { + WPRI, // Reserved Writes Preserve Values, Reads Ignore Value + WLRL, // Write/Read Only Legal Values + WARL // Write Any Values, Reads Legal Values +} + +//Pseudo instructions +enum riscv_pseudo_instr_name_t: ubyte { + LI = 0, + LA +} + +// Data pattern of the memory model +enum data_pattern_t: ubyte { + RAND_DATA = 0, + ALL_ZERO, + INCR_VAL +} + +enum pte_permission_t: ubyte { + NEXT_LEVEL_PAGE = 0b000, // Pointer to next level of page table. + READ_ONLY_PAGE = 0b001, // Read-only page. + READ_WRITE_PAGE = 0b011, // Read-write page. + EXECUTE_ONLY_PAGE = 0b100, // Execute-only page. + READ_EXECUTE_PAGE = 0b101, // Read-execute page. + R_W_EXECUTE_PAGE = 0b111 // Read-write-execute page +} + +enum interrupt_cause_t: ubyte { + U_SOFTWARE_INTR = 0x0, + S_SOFTWARE_INTR = 0x1, + M_SOFTWARE_INTR = 0x3, + U_TIMER_INTR = 0x4, + S_TIMER_INTR = 0x5, + M_TIMER_INTR = 0x7, + U_EXTERNAL_INTR = 0x8, + S_EXTERNAL_INTR = 0x9, + M_EXTERNAL_INTR = 0xB +} + +enum exception_cause_t: ubyte { + INSTRUCTION_ADDRESS_MISALIGNED = 0x0, + INSTRUCTION_ACCESS_FAULT = 0x1, + ILLEGAL_INSTRUCTION = 0x2, + BREAKPOINT = 0x3, + LOAD_ADDRESS_MISALIGNED = 0x4, + LOAD_ACCESS_FAULT = 0x5, + STORE_AMO_ADDRESS_MISALIGNED = 0x6, + STORE_AMO_ACCESS_FAULT = 0x7, + ECALL_UMODE = 0x8, + ECALL_SMODE = 0x9, + ECALL_MMODE = 0xB, + INSTRUCTION_PAGE_FAULT = 0xC, + LOAD_PAGE_FAULT = 0xD, + STORE_AMO_PAGE_FAULT = 0xF +} + +enum misa_ext_t: int { + MISA_EXT_A = 0, + MISA_EXT_B, + MISA_EXT_C, + MISA_EXT_D, + MISA_EXT_E, + MISA_EXT_F, + MISA_EXT_G, + MISA_EXT_H, + MISA_EXT_I, + MISA_EXT_J, + MISA_EXT_K, + MISA_EXT_L, + MISA_EXT_M, + MISA_EXT_N, + MISA_EXT_O, + MISA_EXT_P, + MISA_EXT_Q, + MISA_EXT_R, + MISA_EXT_S, + MISA_EXT_T, + MISA_EXT_U, + MISA_EXT_V, + MISA_EXT_W, + MISA_EXT_X, + MISA_EXT_Y, + MISA_EXT_Z +} + +enum hazard_e: ubyte { + NO_HAZARD, + RAW_HAZARD, + WAR_HAZARD, + WAW_HAZARD +} + +// `include "riscv_core_setting.sv" + +// PMP address matching mode +enum pmp_addr_mode_t: ubyte { + OFF = 0b00, + TOR = 0b01, + NA4 = 0b10, + NAPOT = 0b11 +} + +// // PMP configuration register layout +// // This configuration struct includes the pmp address for simplicity +// // TODO (udinator) allow a full 34 bit address for rv32? +// `ifdef _VCP //GRK958 +// typedef struct packed { +// bit l; +// bit [1:0] zero; +// pmp_addr_mode_t a; +// bit x; +// bit w; +// bit r; +// // RV32: the pmpaddr is the top 32 bits of a 34 bit PMP address +// // RV64: the pmpaddr is the top 54 bits of a 56 bit PMP address +// bit [XLEN - 1 : 0] addr; +// // The offset from the address of
- automatically populated by the +// // PMP generation routine. +// bit [XLEN - 1 : 0] offset; +// `else +struct pmp_cfg_reg_t { + @rand bool l; + ubvec!2 zero; + @rand pmp_addr_mode_t a; + @rand bool x; + @rand bool w; + @rand bool r; + // RV32: the pmpaddr is the top 32 bits of a 34 bit PMP address + // RV64: the pmpaddr is the top 54 bits of a 56 bit PMP address + ubvec!XLEN addr; + // The offset from the address of
- automatically populated by the + // PMP generation routine. + @rand ubvec!XLEN offset; +} + + +string hart_prefix(int hart = 0) { + if (NUM_HARTS <= 1) { + return ""; + } + else { + import std.string: format; + return format("h%0d_", hart); + } +} + +string get_label(string label, int hart = 0) { + return hart_prefix(hart) ~ label; +} + +struct vtype_t { + @UVM_DEFAULT { + @rand bool ill; + @rand bool fractional_lmul; + @rand ubvec!(XLEN-8) reserved; + @rand uint vediv; + @rand uint vsew; + @rand uint vlmul; + } +} + + +enum vxrm_t: ubyte { + RoundToNearestUp, + RoundToNearestEven, + RoundDown, + RoundToOdd +} + +enum b_ext_group_t: int { + ZBA, + ZBB, + ZBS, + ZBP, + ZBE, + ZBF, + ZBC, + ZBR, + ZBM, + ZBT, + ZB_TMP // for uncategorized instructions +} + +// `VECTOR_INCLUDE("riscv_instr_pkg_inc_variables.sv") + +alias program_id_t = ubvec!16; + +// xSTATUS bit mask +enum ubvec!XLEN MPRV_BIT_MASK = 0x1 << 17; +enum ubvec!XLEN SUM_BIT_MASK = 0x1 << 18; +enum ubvec!XLEN MPP_BIT_MASK = 0x3 << 11; + +enum int IMM25_WIDTH = 25; +enum int IMM12_WIDTH = 12; +enum int INSTR_WIDTH = 32; +enum int DATA_WIDTH = 32; + +// Enum Ints for output assembly program formatting +enum int MAX_INSTR_STR_LEN = 13; +enum int LABEL_STR_LEN = 18; + +// Enum Int for program generation +enum int MAX_CALLSTACK_DEPTH = 20; +enum int MAX_SUB_PROGRAM_CNT = 20; +enum int MAX_CALL_PER_FUNC = 5; + +template SPACES(uint spaces) { + static if (spaces == 0) enum SPACES = ""; + else enum SPACES = SPACES!(spaces-1) ~ " "; +} + +string spaces_string(uint len) { + import std.algorithm: fill; + char[] str = new char[len]; + fill(str, ' '); + return cast(string) str; +} + +enum string indent = SPACES!LABEL_STR_LEN; + +// Format the string to a fixed length +string format_string(string str, int len = 10) { + if (len < str.length) return str; + else { + static string spaces; + if (spaces.length == 0) spaces = spaces_string(len); + string formatted_str = str ~ spaces[0..len-str.length]; + return formatted_str; + } +} + +// Print the data in the following format +// 0xabcd, 0x1234, 0x3334 ... + +string format_data(ubyte[] data, uint byte_per_group=4) { + import std.string: format; + string str = "0x"; + foreach (i, d; data) { + if ((i % byte_per_group == 0) && (i != data.length - 1) && (i != 0)) { + str ~= ", 0x"; + } + str ~= format("%02x", d); + } + return str; +} + +// Get the instr name enum from a string +riscv_instr_name_t get_instr_name(string str) { + import std.string: toUpper; + alias enum_wrapper = uvm_enum_wrapper!riscv_instr_name_t; + riscv_instr_name_t value; + if (enum_wrapper.from_name(toUpper(str), value)) { + return value; + } + else { + return riscv_instr_name_t.INVALID_INSTR; + } +} + +// Push general purpose register to stack, this is needed before trap handling4 +void push_gpr_to_kernel_stack(privileged_reg_t status, + privileged_reg_t scratch, + bool mprv, + riscv_reg_t sp, + riscv_reg_t tp, + ref string[] instr) { + import std.algorithm: canFind; + import std.string: format; + + string store_instr = (XLEN == 32) ? "sw" : "sd"; + if (canFind(implemented_csr, scratch)) { + // Use kernal stack for handling exceptions + // Save the user mode stack pointer to the scratch register + instr ~= format("csrrw x%0d, 0x%0x, x%0d", sp, scratch, sp); + // Move TP to SP + instr ~= format("add x%0d, x%0d, zero", sp, tp); + } + // If MPRV is set and MPP is S/U mode, it means the address translation and memory protection + // for load/store instruction is the same as the mode indicated by MPP. In this case, we + // need to use the virtual address to access the kernel stack. + if ((status == privileged_reg_t.MSTATUS) && (SATP_MODE != satp_mode_t.BARE)) { + // We temporarily use tp to check mstatus to avoid changing other GPR. The value of sp has + // been saved to xScratch and can be restored later. + if (mprv) { + instr ~= format("csrr x%0d, 0x%0x // MSTATUS", tp, status); + instr ~= format("srli x%0d, x%0d, 11", tp, tp); // Move MPP to bit 0 + instr ~= format("andi x%0d, x%0d, 0x3", tp, tp); // keep the MPP bits + // Check if MPP equals to M-mode('b11) + instr ~= format("xori x%0d, x%0d, 0x3", tp, tp); // Check if MPP equals to M-mode('b11) + instr ~= format("bnez x%0d, 1f", tp); // Use physical address for kernel SP + // Use virtual address for stack pointer + instr ~= format("slli x%0d, x%0d, %0d", sp, sp, XLEN - MAX_USED_VADDR_BITS); + instr ~= format("srli x%0d, x%0d, %0d", sp, sp, XLEN - MAX_USED_VADDR_BITS); + } + } + // Reserve space from kernel stack to save all 32 GPR except for x0 + instr ~= format("1: addi x%0d, x%0d, -%0d", sp, sp, 31 * (XLEN/8)); + // Push all GPRs to kernel stack + for (int i = 1; i < 32; i++) { + instr ~= format("%0s x%0d, %0d(x%0d)", store_instr, i, i * (XLEN/8), sp); + } +} + +// Pop general purpose register from stack, this is needed before returning to user program +void pop_gpr_from_kernel_stack(privileged_reg_t status, + privileged_reg_t scratch, + bool mprv, + riscv_reg_t sp, + riscv_reg_t tp, + ref string[] instr) { + import std.algorithm: canFind; + import std.string: format; + + string load_instr = (XLEN == 32) ? "lw" : "ld"; + // Pop user mode GPRs from kernel stack + for (int i = 1; i < 32; i++) { + instr ~= format("%0s x%0d, %0d(x%0d)", load_instr, i, i * (XLEN/8), sp); + } + // Restore kernel stack pointer + instr ~= format("addi x%0d, x%0d, %0d", sp, sp, 31 * (XLEN/8)); + if (canFind(implemented_csr, scratch)) { + // Move SP to TP + instr ~= format("add x%0d, x%0d, zero", tp, sp); + // Restore user mode stack pointer + instr ~= format("csrrw x%0d, 0x%0x, x%0d", sp, scratch, sp); + } +} + +void get_int_arg_value(string cmdline_str, ref int val) { + import std.conv: to; + string s; + if (uvm_cmdline_processor.get_inst().get_arg_value(cmdline_str, s)) { + val = s.to!int; + } +} + + +// Get a bool argument from comand line +void get_bool_arg_value(string cmdline_str, ref bool val) { + import std.conv: to; + string s; + if (uvm_cmdline_processor.get_inst().get_arg_value(cmdline_str, s)) { + val = s.to!bool; + } +} + +// Get a hex argument from command line +void get_hex_arg_value(string cmdline_str, ref int val) { + import std.conv: to; + string s; + if(uvm_cmdline_processor.get_inst().get_arg_value(cmdline_str, s)) { + val = s.to!int(16); + } +} + + +class cmdline_enum_processor(T) +{ + static void get_array_values(string cmdline_str, ref T[] vals) { + import std.format: format; + string s; + uvm_cmdline_processor.get_inst().get_arg_value(cmdline_str, s); + if (s != "") { + string[] cmdline_list; + T value; + uvm_string_split(s, ',', cmdline_list); + vals.length = cmdline_list.length; + foreach (i, str; cmdline_list) { + import std.string: toUpper; + if (uvm_enum_wrapper!T.from_name(toUpper(str), value)) { + vals[i] = value; + } + else { + uvm_fatal("riscv_instr_pkg", + format("Invalid value (%0s) specified in command line: %0s", + str, cmdline_str)); + } + } + } + } +} + +enum riscv_reg_t[] all_gpr = [EnumMembers!riscv_reg_t]; + +enum riscv_reg_t[] compressed_gpr = [riscv_reg_t.S0, riscv_reg_t.S1, + riscv_reg_t.A0, riscv_reg_t.A1, + riscv_reg_t.A2, riscv_reg_t.A3, + riscv_reg_t.A4, riscv_reg_t.A5]; + +enum riscv_instr_category_t[] all_categories = + [EnumMembers!riscv_instr_category_t]; + +void get_val(string str, out bvec!XLEN val, bool hex = 0) { + import std.string: format; + import std.conv: to; + if (str[0..2] == "0x") { + str = str[2..$]; + val = str.to!int(16); + return; + } + + if (hex) { + val = str.to!int(16); + } + else { + if (str[0] == '-') { + str = str[1..$]; + val = -(str.to!int()); + } + else { + val = str.to!int(); + } + } + uvm_info("riscv_instr_pkg", format("imm:%0s -> 0x%0x/%0d", str, val, + cast(bvec!XLEN) val), UVM_FULL); +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_registry.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_registry.d new file mode 100644 index 00000000..1a7b2af7 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_registry.d @@ -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; + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_sequence.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_sequence.d new file mode 100644 index 00000000..aca8a03e --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_sequence.d @@ -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
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); + } + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_stream.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_stream.d new file mode 100644 index 00000000..2aeb7811 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_instr_stream.d @@ -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; + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_load_store_instr_lib.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_load_store_instr_lib.d new file mode 100644 index 00000000..9e9458e1 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_load_store_instr_lib.d @@ -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= 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; + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_loop_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_loop_instr.d new file mode 100644 index 00000000..d5eb618c --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_loop_instr.d @@ -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); + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table.d new file mode 100644 index 00000000..a5a9ca58 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table.d @@ -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; + } + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_entry.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_entry.d new file mode 100644 index 00000000..8c005c9b --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_entry.d @@ -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; + } +} + + diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_exception_cfg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_exception_cfg.d new file mode 100644 index 00000000..4ec483bd --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_exception_cfg.d @@ -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; + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_list.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_list.d new file mode 100644 index 00000000..bc3df4e0 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_page_table_list.d @@ -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); + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_pmp_cfg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_pmp_cfg.d new file mode 100644 index 00000000..9216fa5a --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_pmp_cfg.d @@ -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
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
, + // 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
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
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+
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 [
: 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 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 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 + // , 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 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 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
, 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]); + } + } +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_privil_reg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_privil_reg.d new file mode 100644 index 00000000..ef1b6efb --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_privil_reg.d @@ -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)); + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_privileged_common_seq.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_privileged_common_seq.d new file mode 100644 index 00000000..3f445d1f --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_privileged_common_seq.d @@ -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]); + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_pseudo_instr.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_pseudo_instr.d new file mode 100644 index 00000000..2f166e32 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_pseudo_instr.d @@ -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(); + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_reg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_reg.d new file mode 100644 index 00000000..474d45c0 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_reg.d @@ -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; + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_signature_pkg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_signature_pkg.d new file mode 100644 index 00000000..2a6e3553 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_signature_pkg.d @@ -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 +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/riscv_vector_cfg.d b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_vector_cfg.d new file mode 100644 index 00000000..de57e26a --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/riscv_vector_cfg.d @@ -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); + } + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/ml/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/ml/riscv_core_setting.d new file mode 100644 index 00000000..77c22266 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/ml/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/multi_harts/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/multi_harts/riscv_core_setting.d new file mode 100644 index 00000000..252cac3e --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/multi_harts/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/package.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/package.d new file mode 100644 index 00000000..c0518960 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/package.d @@ -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; + } diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32i/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32i/riscv_core_setting.d new file mode 100644 index 00000000..a0298a0c --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32i/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imafdc/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imafdc/riscv_core_setting.d new file mode 100644 index 00000000..722e5c78 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imafdc/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imc/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imc/riscv_core_setting.d new file mode 100644 index 00000000..4e37d6d3 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imc/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imc_sv32/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imc_sv32/riscv_core_setting.d new file mode 100644 index 00000000..20928f42 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imc_sv32/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imcb/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imcb/riscv_core_setting.d new file mode 100644 index 00000000..c9bf7097 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv32imcb/riscv_core_setting.d @@ -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 + ]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64gc/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64gc/riscv_core_setting.d new file mode 100644 index 00000000..19e90e4e --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64gc/riscv_core_setting.d @@ -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 +]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64gcv/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64gcv/riscv_core_setting.d new file mode 100644 index 00000000..fad33cb9 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64gcv/riscv_core_setting.d @@ -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]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64imc/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64imc/riscv_core_setting.d new file mode 100644 index 00000000..cf290e6f --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64imc/riscv_core_setting.d @@ -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]; diff --git a/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64imcb/riscv_core_setting.d b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64imcb/riscv_core_setting.d new file mode 100644 index 00000000..74455044 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/gen/target/rv64imcb/riscv_core_setting.d @@ -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]; diff --git a/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_base_test.d b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_base_test.d new file mode 100644 index 00000000..ff9ba027 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_base_test.d @@ -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); + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_gen.d b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_gen.d new file mode 100644 index 00000000..a7fca1a9 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_gen.d @@ -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(); +} diff --git a/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_test.d b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_test.d new file mode 100644 index 00000000..3d96c575 --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_test.d @@ -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); + } + +} diff --git a/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_test_lib.d b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_test_lib.d new file mode 100644 index 00000000..41557c2c --- /dev/null +++ b/vendor/google_riscv-dv/euvm/riscv/test/riscv_instr_test_lib.d @@ -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(); + } + +} diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py index d6b1bab9..0c61c341 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py @@ -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 diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py index 807148c9..82f0d7c8 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py @@ -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 diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_loop_instr.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_loop_instr.py index 8f1100b3..708c742f 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_loop_instr.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_loop_instr.py @@ -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 diff --git a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv index 0524f66d..348689a7 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv @@ -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