mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 13:17:41 -04:00
CORE-DV : Remove c.zext.w instruction from rv32zcb & update the zcb generation (#1585)
This commit is contained in:
parent
797f0a90c6
commit
f301d69675
5 changed files with 557 additions and 46 deletions
118
verif/env/corev-dv/custom/riscv_zcb_instr.sv
vendored
118
verif/env/corev-dv/custom/riscv_zcb_instr.sv
vendored
|
@ -54,64 +54,110 @@ class riscv_zcb_instr_c extends riscv_custom_instr;
|
|||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
asm_str = format_string(get_cus_instr_name(), MAX_INSTR_STR_LEN);
|
||||
case (instr_name)
|
||||
C_LBU : asm_str = $sformatf("%0s %0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
C_LH : asm_str = $sformatf("%0s %0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
C_LHU : asm_str = $sformatf("%0s %0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
C_SB : asm_str = $sformatf("%0s %0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
|
||||
C_SH : asm_str = $sformatf("%0s %0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
|
||||
C_MUL : asm_str = $sformatf("%0s %0s, %0s", asm_str, rd.name(), rs2.name());
|
||||
C_ZEXT_B : asm_str = $sformatf("%0s %0s", asm_str, rd.name());
|
||||
C_SEXT_B : asm_str = $sformatf("%0s %0s", asm_str, rd.name());
|
||||
C_ZEXT_H : asm_str = $sformatf("%0s %0s", asm_str, rd.name());
|
||||
C_SEXT_H : asm_str = $sformatf("%0s %0s", asm_str, rd.name());
|
||||
C_ZEXT_W : asm_str = $sformatf("%0s %0s", asm_str, rd.name());
|
||||
C_NOT : asm_str = $sformatf("%0s %0s", asm_str, rd.name());
|
||||
C_LBU : asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
C_LH : asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
C_LHU : asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
C_SB : asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
|
||||
C_SH : asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
|
||||
C_MUL : asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
|
||||
C_ZEXT_B : asm_str = $sformatf("%0s%0s", asm_str, rd.name());
|
||||
C_SEXT_B : asm_str = $sformatf("%0s%0s", asm_str, rd.name());
|
||||
C_ZEXT_H : asm_str = $sformatf("%0s%0s", asm_str, rd.name());
|
||||
C_SEXT_H : asm_str = $sformatf("%0s%0s", asm_str, rd.name());
|
||||
C_ZEXT_W : asm_str = $sformatf("%0s%0s", asm_str, rd.name());
|
||||
C_NOT : asm_str = $sformatf("%0s%0s", asm_str, rd.name());
|
||||
endcase
|
||||
return asm_str.tolower();
|
||||
endfunction : convert2asm
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2bin(string prefix = "");
|
||||
string binary;
|
||||
case (instr_name) inside
|
||||
//`uvm_info(`gfn, $sformatf("rs1 = %0s, imm = %b,
|
||||
C_LBU:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rs1, imm[0], imm[1], rd, get_c_opcode()});
|
||||
C_LHU:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rs1, 1'b0, imm[1], rd, get_c_opcode()});
|
||||
C_LH:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rs1 , 1'b1, imm[1],rd , get_c_opcode()});
|
||||
C_SB:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rs1, imm[0], imm[1] ,rs2 , get_c_opcode()});
|
||||
C_SH:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rs1, 1'b0, imm[1], rs2, get_c_opcode()});
|
||||
C_ZEXT_B:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 5'b11000, get_c_opcode()});
|
||||
C_SEXT_B:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 5'b11001, get_c_opcode()});
|
||||
C_ZEXT_H:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 5'b11010, get_c_opcode()});
|
||||
C_SEXT_H:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 5'b11011, get_c_opcode()});
|
||||
C_ZEXT_W:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 5'b11100, get_c_opcode()});
|
||||
C_NOT:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 5'b11101, get_c_opcode()});
|
||||
C_MUL:
|
||||
binary = $sformatf("0x%4h", {get_func6(), rd, 2'b10, rs2, get_c_opcode()});
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
return {prefix, binary};
|
||||
endfunction : convert2bin
|
||||
|
||||
//TODO- work-around : Can't use the original methode of riscv_instr.sv
|
||||
//so I create the same one with diffrent name
|
||||
virtual function string get_cus_instr_name();
|
||||
get_cus_instr_name = instr_name.name();
|
||||
foreach(get_cus_instr_name[i]) begin
|
||||
if (get_cus_instr_name[i] == "_") begin
|
||||
get_cus_instr_name[i] = ".";
|
||||
end
|
||||
end
|
||||
return get_cus_instr_name;
|
||||
endfunction
|
||||
|
||||
virtual function bit [1:0] get_c_opcode();
|
||||
case (instr_name) inside
|
||||
C_LBU,C_LH,C_LHU,C_SB,C_SH : get_c_opcode = 2'b00;
|
||||
C_MUL,C_ZEXT_B,C_SEXT_B,C_ZEXT_H,
|
||||
C_SEXT_H,C_ZEXT_W : get_c_opcode = 2'b01;
|
||||
C_MUL,C_ZEXT_B,C_SEXT_B,
|
||||
C_SEXT_H,C_ZEXT_H,C_ZEXT_W : get_c_opcode = 2'b01;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
virtual function bit [2:0] get_func3();
|
||||
virtual function bit [5:0] get_func6();
|
||||
case (instr_name) inside
|
||||
C_LBU : get_func3 = 3'b100;
|
||||
C_LH : get_func3 = 3'b100;
|
||||
C_LHU : get_func3 = 3'b100;
|
||||
C_SB : get_func3 = 3'b100;
|
||||
C_SH : get_func3 = 3'b100;
|
||||
C_MUL : get_func3 = 3'b100;
|
||||
C_ZEXT_B : get_func3 = 3'b100;
|
||||
C_SEXT_B : get_func3 = 3'b100;
|
||||
C_ZEXT_H : get_func3 = 3'b100;
|
||||
C_SEXT_H : get_func3 = 3'b100;
|
||||
C_ZEXT_W : get_func3 = 3'b100;
|
||||
C_NOT : get_func3 = 3'b100;
|
||||
C_LBU : get_func6 = 6'b100000;
|
||||
C_LH : get_func6 = 6'b100001;
|
||||
C_LHU : get_func6 = 6'b100001;
|
||||
C_SB : get_func6 = 6'b100010;
|
||||
C_SH : get_func6 = 6'b100011;
|
||||
C_MUL : get_func6 = 6'b100111;
|
||||
C_ZEXT_B : get_func6 = 6'b100111;
|
||||
C_SEXT_B : get_func6 = 6'b100111;
|
||||
C_ZEXT_H : get_func6 = 6'b100111;
|
||||
C_SEXT_H : get_func6 = 6'b100111;
|
||||
C_ZEXT_W : get_func6 = 6'b100111;
|
||||
C_NOT : get_func6 = 6'b100111;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
virtual function void set_rand_mode();
|
||||
case (instr_name) inside
|
||||
"C_LBU", "C_LH","C_LHU" : begin
|
||||
C_LBU, C_LH, C_LHU : begin
|
||||
has_rs2 = 1'b0;
|
||||
end
|
||||
"C_SB", "C_SH" : begin
|
||||
C_SB, C_SH : begin
|
||||
has_rd = 1'b0;
|
||||
end
|
||||
"C_MUL" : begin
|
||||
C_MUL : begin
|
||||
has_rs1 = 1'b0;
|
||||
has_imm = 1'b0;
|
||||
end
|
||||
"C_ZEXT_B", "C_SEXT_B",
|
||||
"C_ZEXT_H", "C_SEXT_H",
|
||||
"C_ZEXT_W", "C_NOT" : begin
|
||||
C_ZEXT_B, C_SEXT_B,
|
||||
C_ZEXT_H, C_SEXT_H,
|
||||
C_NOT,C_ZEXT_W : begin
|
||||
has_rs1 = 1'b0;
|
||||
has_rs2 = 1'b0;
|
||||
has_imm = 1'b0;
|
||||
|
@ -134,8 +180,8 @@ class riscv_zcb_instr_c extends riscv_custom_instr;
|
|||
C_LBU,C_LH,C_LHU,C_SB,C_SH,
|
||||
C_MUL,
|
||||
C_ZEXT_B,C_SEXT_B,C_ZEXT_H,
|
||||
C_SEXT_H,C_ZEXT_W,
|
||||
C_NOT
|
||||
C_SEXT_H,
|
||||
C_NOT,C_ZEXT_W
|
||||
});
|
||||
endfunction
|
||||
|
||||
|
|
19
verif/env/corev-dv/custom/rv32zcb_instr.sv
vendored
19
verif/env/corev-dv/custom/rv32zcb_instr.sv
vendored
|
@ -9,15 +9,14 @@
|
|||
// Original Author: Ayoub JALALI (ayoub.jalali@external.thalesgroup.com)
|
||||
// ------------------------------------------------------------------------------ //
|
||||
|
||||
`DEFINE_ZCB_INSTR(C_LBU, R_FORMAT, ARITHMETIC, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_LH, R_FORMAT, ARITHMETIC, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_LHU, R_FORMAT, ARITHMETIC, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_SB, R_FORMAT, ARITHMETIC, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_SH, R_FORMAT, ARITHMETIC, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_LBU, CL_FORMAT, LOAD, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_LH, CL_FORMAT, LOAD, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_LHU, CL_FORMAT, LOAD, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_SB, CS_FORMAT, STORE, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_SH, CS_FORMAT, STORE, RV32X, UIMM)
|
||||
`DEFINE_ZCB_INSTR(C_MUL, R_FORMAT, ARITHMETIC, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_ZEXT_B, R_FORMAT, LOGICAL, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_SEXT_B, R_FORMAT, LOGICAL, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_ZEXT_H, R_FORMAT, LOGICAL, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_SEXT_H, R_FORMAT, LOGICAL, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_ZEXT_W, R_FORMAT, LOGICAL, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_ZEXT_B, R_FORMAT, ARITHMETIC, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_SEXT_B, R_FORMAT, ARITHMETIC, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_ZEXT_H, R_FORMAT, ARITHMETIC, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_SEXT_H, R_FORMAT, ARITHMETIC, RV32X)
|
||||
`DEFINE_ZCB_INSTR(C_NOT, R_FORMAT, LOGICAL, RV32X)
|
||||
|
|
13
verif/env/corev-dv/custom/rv64zcb_instr.sv
vendored
Normal file
13
verif/env/corev-dv/custom/rv64zcb_instr.sv
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2023 Thales DIS
|
||||
// Copyright 2022 OpenHW Group
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Ayoub JALALI (ayoub.jalali@external.thalesgroup.com)
|
||||
// ------------------------------------------------------------------------------ //
|
||||
|
||||
`DEFINE_ZCB_INSTR(C_ZEXT_W, R_FORMAT, ARITHMETIC, RV64X)
|
||||
|
2
verif/env/corev-dv/cva6_instr_test_pkg.sv
vendored
2
verif/env/corev-dv/cva6_instr_test_pkg.sv
vendored
|
@ -24,11 +24,13 @@ package cva6_instr_test_pkg;
|
|||
`include "cva6_asm_program_gen.sv"
|
||||
`include "cva6_instr_base_test.sv"
|
||||
`include "cva6_instr_hazard_test.sv"
|
||||
`include "cva6_load_store_instr_lib.sv"
|
||||
`include "cvxif_custom_instr.sv"
|
||||
`include "riscv_zicond_instr.sv"
|
||||
`include "riscv_zcb_instr.sv"
|
||||
`include "rv32x_instr.sv"
|
||||
`include "rv32zicond_instr.sv"
|
||||
`include "rv32zcb_instr.sv"
|
||||
`include "rv64zcb_instr.sv"
|
||||
|
||||
endpackage : cva6_instr_test_pkg;
|
||||
|
|
451
verif/env/corev-dv/cva6_load_store_instr_lib.sv
vendored
Normal file
451
verif/env/corev-dv/cva6_load_store_instr_lib.sv
vendored
Normal file
|
@ -0,0 +1,451 @@
|
|||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// CVA6 class extend from riscv-dv class for all load/store instruction stream
|
||||
|
||||
class cva6_load_store_base_instr_stream_c extends riscv_load_store_base_instr_stream;
|
||||
|
||||
cva6_instr_gen_config_c cfg_cva6; // Configuration class handle
|
||||
|
||||
`uvm_object_utils(cva6_load_store_base_instr_stream_c)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
// Generate each load/store instruction
|
||||
virtual function void gen_load_store_instr();
|
||||
bit enable_compressed_load_store, enable_zcb;
|
||||
riscv_instr instr;
|
||||
if(avail_regs.size() > 0) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(avail_regs,
|
||||
unique{avail_regs};
|
||||
avail_regs[0] inside {[S0 : A5]};
|
||||
foreach(avail_regs[i]) {
|
||||
!(avail_regs[i] inside {cfg_cva6.reserved_regs, reserved_rd});
|
||||
},
|
||||
"Cannot randomize avail_regs")
|
||||
end
|
||||
//cast riscv cfg into cva6 cfg
|
||||
`DV_CHECK_FATAL($cast(cfg_cva6, cfg), "Could not cast cfg into cfg_cva6")
|
||||
if ((rs1_reg inside {[S0 : A5], SP}) && !cfg_cva6.disable_compressed_instr) begin
|
||||
enable_compressed_load_store = 1;
|
||||
end
|
||||
if ((RV32C inside {riscv_instr_pkg::supported_isa}) && cfg_cva6.enable_zcb_extension) begin
|
||||
enable_zcb = 1;
|
||||
end
|
||||
foreach(addr[i]) begin
|
||||
// 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 = {LB, LBU, SB};
|
||||
if((offset[i] inside {[0:2]}) && enable_compressed_load_store &&
|
||||
enable_zcb && rs1_reg != SP) begin
|
||||
`uvm_info(`gfn, "Add Zcb byte load/store to allowed instr", UVM_LOW)
|
||||
allowed_instr = {C_LBU, C_SB};
|
||||
end
|
||||
if (!cfg_cva6.enable_unaligned_load_store) begin
|
||||
if (addr[i][0] == 1'b0) begin
|
||||
allowed_instr = {LH, LHU, SH, allowed_instr};
|
||||
if(((offset[i] == 0) || (offset[i] == 2)) && enable_compressed_load_store &&
|
||||
enable_zcb && rs1_reg != SP) begin
|
||||
`uvm_info(`gfn, "Add Zcb half-word load/store to allowed instr", UVM_LOW)
|
||||
allowed_instr = {C_LHU, C_LH, C_SH};
|
||||
end
|
||||
end
|
||||
if (addr[i] % 4 == 0) begin
|
||||
allowed_instr = {LW, SW, allowed_instr};
|
||||
if (cfg_cva6.enable_floating_point) begin
|
||||
allowed_instr = {FLW, FSW, allowed_instr};
|
||||
end
|
||||
if((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
|
||||
(RV32C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
if (rs1_reg == SP) begin
|
||||
`uvm_info(`gfn, "Add LWSP/SWSP to allowed instr", UVM_LOW)
|
||||
allowed_instr = {C_LWSP, C_SWSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
if (cfg_cva6.enable_floating_point && (RV32FC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLW, C_FSW, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if ((XLEN >= 64) && (addr[i] % 8 == 0)) begin
|
||||
allowed_instr = {LWU, LD, SD, allowed_instr};
|
||||
if (cfg_cva6.enable_floating_point && (RV32D inside {supported_isa})) begin
|
||||
allowed_instr = {FLD, FSD, allowed_instr};
|
||||
end
|
||||
if((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
|
||||
(RV64C inside {riscv_instr_pkg::supported_isa} &&
|
||||
enable_compressed_load_store)) begin
|
||||
if (rs1_reg == SP) begin
|
||||
allowed_instr = {C_LDSP, C_SDSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
if (cfg_cva6.enable_floating_point && (RV32DC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLD, C_FSD, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin // unaligned load/store
|
||||
allowed_instr = {LW, SW, LH, LHU, SH, allowed_instr};
|
||||
// Compressed load/store still needs to be aligned
|
||||
if ((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
|
||||
(RV32C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
if (rs1_reg == SP) begin
|
||||
allowed_instr = {C_LWSP, C_SWSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
end
|
||||
end
|
||||
if (XLEN >= 64) begin
|
||||
allowed_instr = {LWU, LD, SD, allowed_instr};
|
||||
if ((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
|
||||
(RV64C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
if (rs1_reg == SP) begin
|
||||
allowed_instr = {C_LWSP, C_SWSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
instr = riscv_instr::get_load_store_instr(allowed_instr);
|
||||
instr.has_rs1 = 0;
|
||||
instr.has_imm = 0;
|
||||
randomize_gpr(instr);
|
||||
instr.rs1 = rs1_reg;
|
||||
instr.imm_str = $sformatf("%0d", $signed(offset[i]));
|
||||
instr.process_load_store = 0;
|
||||
instr_list.push_back(instr);
|
||||
load_store_instr.push_back(instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// A single load/store instruction
|
||||
class cva6_single_load_store_instr_stream_c extends cva6_load_store_base_instr_stream_c;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store == 1;
|
||||
num_mixed_instr < 5;
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_single_load_store_instr_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
// Back to back load/store instructions
|
||||
class cva6_load_store_stress_instr_stream_c extends cva6_load_store_base_instr_stream_c;
|
||||
|
||||
int unsigned max_instr_cnt = 30;
|
||||
int unsigned min_instr_cnt = 10;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[min_instr_cnt:max_instr_cnt]};
|
||||
num_mixed_instr == 0;
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_load_store_stress_instr_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
|
||||
// Back to back load/store instructions
|
||||
class cva6_load_store_shared_mem_stream_c extends cva6_load_store_stress_instr_stream_c;
|
||||
|
||||
`uvm_object_utils(cva6_load_store_shared_mem_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
function void pre_randomize();
|
||||
load_store_shared_memory = 1;
|
||||
super.pre_randomize();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Random load/store sequence
|
||||
// A random mix of load/store instructions and other instructions
|
||||
class cva6_load_store_rand_instr_stream_c extends cva6_load_store_base_instr_stream_c;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[10:30]};
|
||||
num_mixed_instr inside {[10:30]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_load_store_rand_instr_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
// Use a small set of GPR to create various WAW, RAW, WAR hazard scenario
|
||||
class cva6_hazard_instr_stream_c extends cva6_load_store_base_instr_stream_c;
|
||||
|
||||
int unsigned num_of_avail_regs = 6;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[10:30]};
|
||||
num_mixed_instr inside {[10:30]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_hazard_instr_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
function void pre_randomize();
|
||||
avail_regs = new[num_of_avail_regs];
|
||||
super.pre_randomize();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// 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 cva6_load_store_hazard_instr_stream_c extends cva6_load_store_base_instr_stream_c;
|
||||
|
||||
rand int hazard_ratio;
|
||||
|
||||
constraint hazard_ratio_c {
|
||||
hazard_ratio inside {[20:100]};
|
||||
}
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[10:20]};
|
||||
num_mixed_instr inside {[1:7]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_load_store_hazard_instr_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
virtual function void randomize_offset();
|
||||
int offset_, addr_;
|
||||
offset = new[num_load_store];
|
||||
addr = new[num_load_store];
|
||||
for (int i = 0; i < num_load_store; i++) begin
|
||||
if ((i > 0) && ($urandom_range(0, 100) < hazard_ratio)) begin
|
||||
offset[i] = offset[i-1];
|
||||
addr[i] = addr[i-1];
|
||||
end else begin
|
||||
if (!std::randomize(offset_, addr_) with {
|
||||
if (locality == NARROW) {
|
||||
soft offset_ inside {[-16:16]};
|
||||
} else if (locality == HIGH) {
|
||||
soft offset_ inside {[-64:64]};
|
||||
} else if (locality == MEDIUM) {
|
||||
soft offset_ inside {[-256:256]};
|
||||
} else if (locality == SPARSE) {
|
||||
soft offset_ inside {[-2048:2047]};
|
||||
}
|
||||
addr_ == base + offset_;
|
||||
addr_ inside {[0 : max_load_store_offset - 1]};
|
||||
}) begin
|
||||
`uvm_fatal(`gfn, "Cannot randomize load/store offset")
|
||||
end
|
||||
offset[i] = offset_;
|
||||
addr[i] = addr_;
|
||||
end
|
||||
end
|
||||
endfunction : randomize_offset
|
||||
|
||||
endclass
|
||||
|
||||
// Back to back access to multiple data pages
|
||||
// This is useful to test data TLB switch and replacement
|
||||
class cva6_multi_page_load_store_instr_stream_c extends riscv_mem_access_stream;
|
||||
|
||||
riscv_load_store_stress_instr_stream load_store_instr_stream[];
|
||||
rand int unsigned num_of_instr_stream;
|
||||
rand int unsigned data_page_id[];
|
||||
rand riscv_reg_t rs1_reg[];
|
||||
|
||||
constraint default_c {
|
||||
foreach(data_page_id[i]) {
|
||||
data_page_id[i] < max_data_page_id;
|
||||
}
|
||||
data_page_id.size() == num_of_instr_stream;
|
||||
rs1_reg.size() == num_of_instr_stream;
|
||||
unique {rs1_reg};
|
||||
foreach(rs1_reg[i]) {
|
||||
!(rs1_reg[i] inside {cfg.reserved_regs, ZERO});
|
||||
}
|
||||
}
|
||||
|
||||
constraint page_c {
|
||||
solve num_of_instr_stream before data_page_id;
|
||||
num_of_instr_stream inside {[1 : max_data_page_id]};
|
||||
unique {data_page_id};
|
||||
}
|
||||
|
||||
// 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 reasonable_c {
|
||||
num_of_instr_stream inside {[2:8]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_multi_page_load_store_instr_stream_c)
|
||||
`uvm_object_new
|
||||
|
||||
// Generate each load/store seq, and mix them together
|
||||
function void post_randomize();
|
||||
load_store_instr_stream = new[num_of_instr_stream];
|
||||
foreach(load_store_instr_stream[i]) begin
|
||||
load_store_instr_stream[i] = riscv_load_store_stress_instr_stream::type_id::
|
||||
create($sformatf("load_store_instr_stream_%0d", i));
|
||||
load_store_instr_stream[i].min_instr_cnt = 5;
|
||||
load_store_instr_stream[i].max_instr_cnt = 10;
|
||||
load_store_instr_stream[i].cfg = cfg;
|
||||
load_store_instr_stream[i].hart = hart;
|
||||
load_store_instr_stream[i].sp_c.constraint_mode(0);
|
||||
// Make sure each load/store sequence doesn't override the rs1 of other sequences.
|
||||
foreach(rs1_reg[j]) begin
|
||||
if(i != j) begin
|
||||
load_store_instr_stream[i].reserved_rd =
|
||||
{load_store_instr_stream[i].reserved_rd, rs1_reg[j]};
|
||||
end
|
||||
end
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(load_store_instr_stream[i],
|
||||
rs1_reg == local::rs1_reg[i];
|
||||
data_page_id == local::data_page_id[i];,
|
||||
"Cannot randomize load/store instruction")
|
||||
// Mix the instruction stream of different page access, this could trigger the scenario of
|
||||
// frequent data TLB switch
|
||||
if(i == 0) begin
|
||||
instr_list = load_store_instr_stream[i].instr_list;
|
||||
end else begin
|
||||
mix_instr_stream(load_store_instr_stream[i].instr_list);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Access the different locations of the same memory regions
|
||||
class cva6_mem_region_stress_test_c extends cva6_multi_page_load_store_instr_stream_c;
|
||||
|
||||
`uvm_object_utils(cva6_mem_region_stress_test_c)
|
||||
`uvm_object_new
|
||||
|
||||
constraint page_c {
|
||||
num_of_instr_stream inside {[2:5]};
|
||||
foreach (data_page_id[i]) {
|
||||
if (i > 0) {
|
||||
data_page_id[i] == data_page_id[i-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endclass
|
||||
|
||||
// Random load/store sequence to full address range
|
||||
// The address range is not preloaded with data pages, use store instruction to initialize first
|
||||
class cva6_load_store_rand_addr_instr_stream_c extends cva6_load_store_base_instr_stream_c;
|
||||
|
||||
rand bit [XLEN-1:0] addr_offset;
|
||||
|
||||
// Find an unused 4K page from address 1M onward
|
||||
constraint addr_offset_c {
|
||||
|addr_offset[XLEN-1:20] == 1'b1;
|
||||
// TODO(taliu) Support larger address range
|
||||
addr_offset[XLEN-1:31] == 0;
|
||||
addr_offset[11:0] == 0;
|
||||
}
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[5:10]};
|
||||
num_mixed_instr inside {[5:10]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_load_store_rand_addr_instr_stream_c)
|
||||
|
||||
virtual function void randomize_offset();
|
||||
int offset_, addr_;
|
||||
offset = new[num_load_store];
|
||||
addr = new[num_load_store];
|
||||
for (int i=0; i<num_load_store; i++) begin
|
||||
if (!std::randomize(offset_) with {
|
||||
offset_ inside {[-2048:2047]};
|
||||
}
|
||||
) begin
|
||||
`uvm_fatal(`gfn, "Cannot randomize load/store offset")
|
||||
end
|
||||
offset[i] = offset_;
|
||||
addr[i] = addr_offset + offset_;
|
||||
end
|
||||
endfunction `uvm_object_new
|
||||
|
||||
virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
|
||||
riscv_instr instr[$];
|
||||
riscv_pseudo_instr li_instr;
|
||||
riscv_instr store_instr;
|
||||
riscv_instr add_instr;
|
||||
int min_offset[$];
|
||||
int max_offset[$];
|
||||
min_offset = offset.min();
|
||||
max_offset = offset.max();
|
||||
// Use LI to initialize the address offset
|
||||
li_instr = riscv_pseudo_instr::type_id::create("li_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(li_instr,
|
||||
pseudo_instr_name == LI;
|
||||
rd inside {cfg.gpr};
|
||||
rd != gpr;
|
||||
)
|
||||
li_instr.imm_str = $sformatf("0x%0x", addr_offset);
|
||||
// Add offset to the base address
|
||||
add_instr = riscv_instr::get_instr(ADD);
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(add_instr,
|
||||
rs1 == gpr;
|
||||
rs2 == li_instr.rd;
|
||||
rd == gpr;
|
||||
)
|
||||
instr.push_back(li_instr);
|
||||
instr.push_back(add_instr);
|
||||
// Create SW instruction template
|
||||
store_instr = riscv_instr::get_instr(SB);
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(store_instr,
|
||||
instr_name == SB;
|
||||
rs1 == gpr;
|
||||
)
|
||||
// Initialize the location which used by load instruction later
|
||||
foreach (load_store_instr[i]) begin
|
||||
if (load_store_instr[i].category == LOAD) begin
|
||||
riscv_instr store;
|
||||
store = riscv_instr::type_id::create("store");
|
||||
store.copy(store_instr);
|
||||
store.rs2 = riscv_reg_t'(i % 32);
|
||||
store.imm_str = load_store_instr[i].imm_str;
|
||||
// TODO: C_FLDSP is in both rv32 and rv64 ISA
|
||||
case (load_store_instr[i].instr_name) inside
|
||||
LB, LBU : store.instr_name = SB;
|
||||
LH, LHU : store.instr_name = SH;
|
||||
LW, C_LW, C_LWSP, FLW, C_FLW, C_FLWSP : store.instr_name = SW;
|
||||
LD, C_LD, C_LDSP, FLD, C_FLD, LWU : store.instr_name = SD;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unexpected op: %0s",
|
||||
load_store_instr[i].convert2asm()))
|
||||
endcase
|
||||
instr.push_back(store);
|
||||
end
|
||||
end
|
||||
instr_list = {instr, instr_list};
|
||||
super.add_rs1_init_la_instr(gpr, id, 0);
|
||||
endfunction
|
||||
|
||||
endclass
|
Loading…
Add table
Add a link
Reference in a new issue