Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Frontend scoreboard #2607

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,150 changes: 1,150 additions & 0 deletions verif/env/uvme/frontend/uvme_cva6_frontend_model.sv

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions verif/env/uvme/frontend/uvme_cva6_frontend_mon.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// Copyright 2024 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, 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
//
// https://solderpad.org/licenses/
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
//
// Original Author: Alae Eddine EZ ZEJJARI ([email protected]) – sub-contractor MU-Electronics for Thales group


`ifndef __UVME_CVA6_FRONTEND_MON_SV__
`define __UVME_CVA6_FRONTEND_MON_SV__


// Frontend transaction
class uvme_cva6_frontend_transaction_c extends uvm_sequence_item;

logic flush;
logic flush_bp;

uvme_frontend_icache_req_t icache_req;
uvme_frontend_icache_rsp_t icache_rsp;

uvme_frontend_bp_resolve_t resolve_branch;

logic fetch_valid[RTLCVA6Cfg.NrIssuePorts];
logic fetch_ready[RTLCVA6Cfg.NrIssuePorts];
uvme_frontend_fetched_data_t fetch_instr[RTLCVA6Cfg.NrIssuePorts];

logic boot_valid;

logic eret;
logic[RTLCVA6Cfg.VLEN-1:0] epc;

logic ex_valid;
logic halt;
logic[RTLCVA6Cfg.VLEN-1:0] trap_vector_base;

logic set_pc_commit;
logic[RTLCVA6Cfg.VLEN-1:0] pc_commit;

logic set_debug_pc;

`uvm_object_utils_begin(uvme_cva6_frontend_transaction_c)
`uvm_field_int ( flush , UVM_DEFAULT | UVM_BIN)
`uvm_field_int ( flush_bp , UVM_DEFAULT | UVM_BIN)
`uvm_object_utils_end

/**
* Default constructor.
*/
function new(string name="uvme_cva6_frontend_transaction");
super.new(name);
endfunction

endclass : uvme_cva6_frontend_transaction_c


// Frontend Monitor
// Instantiate a virtual interface of the frontend
// Capture all the necessary signals in a frontend transaction and send them through an analysis port.
class uvme_cva6_frontend_mon_c extends uvm_monitor;

`uvm_component_utils(uvme_cva6_frontend_mon_c)

// Objects
uvme_cva6_cfg_c cfg;

// Analysis Ports
uvm_analysis_port #(uvme_cva6_frontend_transaction_c) frontend_packets_collected;

// Handle to agent switch interface
virtual uvmt_frontend_intf frontend_vif;

event reset_asserted ;
event reset_deasserted ;

/**
* Constructor
*/
function new(string name="uvme_cva6_frontend_mon", uvm_component parent=null);
super.new(name, parent);
endfunction

/**
* Build Phase
*/
function void build_phase(uvm_phase phase);

super.build_phase(phase);

// Instantiation of the uvm_analysis_port
frontend_packets_collected = new("frontend_packets_collected" , this) ;

if (!uvm_config_db#(virtual uvmt_frontend_intf)::get(this, "", "cva6_frontend_bus", frontend_vif)) begin
`uvm_fatal("VIF", $sformatf("Could not find vif handle of type %s in uvm_config_db", $typename(frontend_vif)))
end
else begin
`uvm_info("VIF", $sformatf("Found vif handle of type %s in uvm_config_db", $typename(frontend_vif)), UVM_DEBUG)
end

void'(uvm_config_db#(uvme_cva6_cfg_c)::get(this, "", "cfg", cfg));
if (!cfg)
`uvm_fatal("CFG", "Configuration handle is null")

endfunction : build_phase

/**
* Pre reset phase
*/
virtual task pre_reset_phase(uvm_phase phase);
-> reset_asserted;
endtask : pre_reset_phase

/**
* Reset phase
*/
virtual task reset_phase(uvm_phase phase);
super.reset_phase(phase);
endtask : reset_phase

/**
* Post reset phase
*/
virtual task post_reset_phase(uvm_phase phase);
-> reset_deasserted;
endtask : post_reset_phase

/**
* Run Phase
*/
task run_phase(uvm_phase phase);
forever begin
@(reset_deasserted);
fork
receive_frontend_transaction_task(phase);
join_none
@(reset_asserted);
disable fork;
end
endtask : run_phase

/**
* Task receive frontend request and response
*/
task receive_frontend_transaction_task(uvm_phase phase);
uvme_cva6_frontend_transaction_c frontend_transaction;
int predict;
int boot_valid = 1;

forever begin
@(posedge frontend_vif.clk);
frontend_transaction = new();
frontend_transaction.flush = frontend_vif.flush_i;
frontend_transaction.flush_bp = frontend_vif.flush_bp_i;
frontend_transaction.icache_rsp.req = frontend_vif.icache_dreq_o.req;
frontend_transaction.icache_rsp.kill_s1 = frontend_vif.icache_dreq_o.kill_s1;
frontend_transaction.icache_rsp.kill_s2 = frontend_vif.icache_dreq_o.kill_s2;
frontend_transaction.icache_rsp.vaddr = frontend_vif.icache_dreq_o.vaddr;
frontend_transaction.icache_req.ready = frontend_vif.icache_dreq_i.ready;
frontend_transaction.icache_req.valid = frontend_vif.icache_dreq_i.valid;
frontend_transaction.icache_req.data = frontend_vif.icache_dreq_i.data;
frontend_transaction.icache_req.vaddr = frontend_vif.icache_dreq_i.vaddr;
frontend_transaction.resolve_branch = frontend_vif.resolved_branch_i;
for(int i = 0; i < RTLCVA6Cfg.NrIssuePorts; i++) begin
frontend_transaction.fetch_valid[i] = frontend_vif.fetch_entry_valid_o[i];
frontend_transaction.fetch_ready[i] = frontend_vif.fetch_entry_ready_i[i];
frontend_transaction.fetch_instr[i].address = frontend_vif.fetch_entry_o[i].address;
frontend_transaction.fetch_instr[i].instruction = frontend_vif.fetch_entry_o[i].instruction;
predict = frontend_vif.fetch_entry_o[i].branch_predict.cf;
frontend_transaction.fetch_instr[i].predict = predict;
frontend_transaction.fetch_instr[i].predicted_address = frontend_vif.fetch_entry_o[i].branch_predict.predict_address;
end
frontend_transaction.eret = frontend_vif.eret_i;
frontend_transaction.epc = frontend_vif.epc_i;
frontend_transaction.ex_valid = frontend_vif.ex_valid_i;
frontend_transaction.halt = frontend_vif.halt_i;
frontend_transaction.trap_vector_base = frontend_vif.trap_vector_base_i;
frontend_transaction.set_pc_commit = frontend_vif.set_pc_commit_i;
frontend_transaction.pc_commit = frontend_vif.pc_commit_i;
frontend_transaction.set_debug_pc = frontend_vif.set_debug_pc_i;
if(boot_valid == 1) begin
frontend_transaction.boot_valid = 1;
end else begin
frontend_transaction.boot_valid = 0;
end
boot_valid = 0;

frontend_packets_collected.write(frontend_transaction);
end // forever
endtask : receive_frontend_transaction_task
endclass : uvme_cva6_frontend_mon_c


`endif // __UVME_CVA6_FRONTEND_MON_SV__
170 changes: 170 additions & 0 deletions verif/env/uvme/frontend/uvme_cva6_frontend_sb.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Copyright 2024 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, 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
//
// https://solderpad.org/licenses/
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
//
// Original Author: Alae Eddine EZ ZEJJARI ([email protected]) – sub-contractor MU-Electronics for Thales group


`ifndef __UVME_CVA6_FRONTEND_SB_SV__
`define __UVME_CVA6_FRONTEND_SB_SV__


// Frontend Scoreboard
// The scoreboard contains a frontend model and monitor of the Frontend interface
// The scoreboard captures the decoded committed instructions using an analysis port and counts all instruction types.
// It also captures transactions monitored through an analysis port and counts all types of instructions sent to the decode stage, requests sent to the cache, and cache responses.
class uvme_cva6_frontend_sb_c extends uvm_scoreboard;

// Objects
uvme_cva6_cfg_c cfg;

uvm_tlm_analysis_fifo#(uvma_isacov_mon_trn_c) isa_trn_fifo;
uvm_tlm_analysis_fifo#(uvme_cva6_frontend_transaction_c) frontend_trn_fifo;
uvma_isacov_mon_trn_c#(ILEN,XLEN) isa_instr;
uvme_cva6_frontend_transaction_c frontend_instr;

uvme_cva6_frontend_model_c frontend_model;
uvme_cva6_frontend_mon_c frontend_mon;

int fetched_inst_count;
int req_cache_inst_count;
int cached_inst_count;
int axi_inst_count;
int mispredict_count;
int branch_inst_count;
int branch_mispredict_count;
int ret_inst_count;
int ret_mispredict_count;
int jump_inst_count;
int jump_mispredict_count;
int isa_inst_count;

`uvm_component_utils_begin(uvme_cva6_frontend_sb_c)
`uvm_component_utils_end

/**
* Default constructor.
*/
function new(string name="uvme_cva6_frontend_sb_c", uvm_component parent=null);
super.new(name, parent);
endfunction

/**
* Create and configures sub-scoreboards via:
*/
virtual function void build_phase(uvm_phase phase);

void'(uvm_config_db#(uvme_cva6_cfg_c)::get(this, "", "cfg", cfg));
if (!cfg)
`uvm_fatal("CFG", "Configuration handle is null")

isa_trn_fifo = new("isa_trn_fifo", this);
frontend_trn_fifo = new("frontend_trn_fifo", this);

this.frontend_mon = uvme_cva6_frontend_mon_c::type_id::create("frontend_mon", this);
if(cfg.enable_frontend_model) begin
this.frontend_model = uvme_cva6_frontend_model_c::type_id::create("frontend_model", this);
end

endfunction

/**
* Connect the analysis port
*/
function void connect_phase(uvm_phase phase);

super.connect_phase(phase);

//Establishing connections between monitor ports and scoreboard
frontend_mon.frontend_packets_collected.connect(this.frontend_trn_fifo.analysis_export);
if( cfg.enable_frontend_model) begin
//Establishing connections between monitor ports and model if the model is enabled
this.frontend_mon.frontend_packets_collected.connect(frontend_model.mon2mod_export);
`uvm_info(get_type_name(), $sformatf("FRENTEND MODEL IS ACTIVE"), UVM_LOW)
end

endfunction

/**
* Frontend-scoreboard run phase.
*/
task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
begin
// Count the instruction coming from the isacove
forever begin
isa_trn_fifo.get(isa_instr);
isa_inst_count++;
if(isa_instr.instr.group == BRANCH_GROUP)
branch_inst_count++;
else if(isa_instr.instr.group == RET_GROUP)
ret_inst_count++;
else if(isa_instr.instr.group == JUMP_GROUP)
jump_inst_count++;
end
end
begin
// Count the instruction coming from the Frontend
forever begin
frontend_trn_fifo.get(frontend_instr);
scoreboarding_frontend();
end
end
join_any
endtask


function void scoreboarding_frontend();

if(frontend_instr.icache_req.valid) cached_inst_count++;

if(frontend_instr.icache_rsp.req && frontend_instr.icache_req.ready) req_cache_inst_count++;

for(int i = 0; i < RTLCVA6Cfg.NrIssuePorts; i++) begin
if(frontend_instr.fetch_valid[i] && frontend_instr.fetch_ready[i]) fetched_inst_count++;
end

if(frontend_instr.resolve_branch.is_mispredict) mispredict_count++;

if(frontend_instr.resolve_branch.is_mispredict && frontend_instr.resolve_branch.cf_type == 1) branch_mispredict_count++;

if(frontend_instr.resolve_branch.is_mispredict && frontend_instr.resolve_branch.cf_type == 4) ret_mispredict_count++;

if(frontend_instr.resolve_branch.is_mispredict && (frontend_instr.resolve_branch.cf_type == 2 || frontend_instr.resolve_branch.cf_type == 3)) jump_mispredict_count++;

endfunction : scoreboarding_frontend

/**
* Disply the final results of the scoreboarding
*/
function void check_phase(uvm_phase phase);

super.check_phase(phase);
`uvm_info("Frontend scorboard checks", $sformatf("number of fetch requested by the frotend req_cache_inst_count = %d", req_cache_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of fetch sent by the cache cached_inst_count = %d", cached_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of instruction sent to decode fetched_inst_count = %d", fetched_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of instruction seen in the isa isa_inst_count = %d", isa_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of mispredict seen in the execut stage mispredict_count = %d", mispredict_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of branch instruction seen in the isa branch_inst_count = %d", branch_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of branch mispredict seen in the execute stage branch_commit_count = %d", branch_mispredict_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of ret instruction seen in the isa ret_inst_count = %d", ret_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of ret mispredict seen in the execute stage ret_commit_count = %d", ret_mispredict_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of ret instruction seen in the isa jump_inst_count = %d", jump_inst_count), UVM_NONE)
`uvm_info("Frontend scorboard checks", $sformatf("number of jump mispredict seen in the execute stage jump_mispredict_count = %d", jump_mispredict_count), UVM_NONE)
endfunction

endclass : uvme_cva6_frontend_sb_c
`endif // __UVME_CVA6_FRONTEND_SB_SV__
3 changes: 3 additions & 0 deletions verif/env/uvme/uvme_cva6_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c;
// Software interrupt supported
rand bit sw_int_supported;

rand bit enable_frontend_model;

`uvm_object_utils_begin(uvme_cva6_cfg_c)
`uvm_field_int ( enabled , UVM_DEFAULT )
`uvm_field_enum(uvm_active_passive_enum, is_active , UVM_DEFAULT )
Expand Down Expand Up @@ -103,6 +105,7 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c;
soft trn_log_enabled == 1;
soft force_disable_csr_checks == 0;
soft sys_clk_period == uvme_cva6_sys_default_clk_period; // see uvme_cva6_constants.sv
soft enable_frontend_model == 1; // see uvme_cva6_constants.sv
}

constraint cva6_riscv_cons {
Expand Down
Loading
Loading