diff --git a/verif/env/uvme/cov/uvme_axi_covg.sv b/verif/env/uvme/cov/uvme_axi_covg.sv new file mode 100644 index 000000000..ba1c0b608 --- /dev/null +++ b/verif/env/uvme/cov/uvme_axi_covg.sv @@ -0,0 +1,269 @@ +// Copyright 2023 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. +// 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: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) – sub-contractor MU-Electronics for Thales group + + +`ifndef __UVME_AXI_COVG_SV__ +`define __UVME_AXI_COVG_SV__ + + /* + * Covergroups + * Decalred at package-level to enable mutliple instances per monitor class (e.g. read/write) + */ + +covergroup cg_axi_w_channel(string name) + with function sample(uvma_axi_transaction_c item, bit RVA); + + option.per_instance = 1; + option.name = name; + + awready_to_valid: coverpoint (item.aw_delay) { + bins dly[] = {[0:16]}; + } + + wready_to_valid: coverpoint (item.w_data_trs[0].w_delay) { + bins dly[] = {[0:16]}; + } + + awsize: coverpoint (item.aw_size){ + bins size[] = {[0:3]}; + ignore_bins IGN_SIZE3 = {3} iff(uvme_cva6_pkg::XLEN == 32); + } + + awlock: coverpoint (item.aw_lock){ + bins lock[] = {[0:1]}; + ignore_bins IGN_EXCLUSIVE = {1} iff(!RVA); + } + + wstrb: coverpoint (item.w_data_trs[0].w_strb) { + bins strb1 = {1}; + bins strb2 = {2}; + bins strb3 = {3}; + bins strb4 = {4}; + bins strb8 = {8}; + bins strb12 = {12}; + bins strb15 = {15}; + bins strb16 = {16}; + bins strb32 = {32}; + bins strb48 = {48}; + bins strb64 = {64}; + bins strb128 = {128}; + bins strb192 = {192}; + bins strb240 = {240}; + bins strb255 = {255}; + ignore_bins IGN_STRB255 = {255} iff(uvme_cva6_pkg::XLEN == 32); + } + + aw_axi_cross: cross awready_to_valid, wready_to_valid, awsize, awlock{ + illegal_bins ILLEGAL_BINS = binsof(awlock) intersect{1} && + binsof(awsize) intersect{[0:1]}; + ignore_bins IGN_CROSS = binsof(awsize) intersect{3} iff(uvme_cva6_pkg::XLEN == 32); + } +endgroup : cg_axi_w_channel + +covergroup cg_axi_b_channel(string name) + with function sample(uvma_axi_transaction_c item, bit RVA); + + option.per_instance = 1; + option.name = name; + + bid: coverpoint (item.b_id){ + bins one = {[1:3]}; + illegal_bins ILLEGAL_BINS = {2}; + ignore_bins IGN_EXID = {3} iff(!RVA); + } + bresp: coverpoint (item.b_resp){ + bins zero = {0}; + bins one = {1}; + bins two = {2}; + bins three = {3}; + } + + b_axi_cross: cross bid, bresp; +endgroup : cg_axi_b_channel + +covergroup cg_axi_ar_channel(string name) + with function sample(uvma_axi_transaction_c item, bit RVA); + + option.per_instance = 1; + option.name = name; + + arid: coverpoint (item.ar_id) { + bins ID[] = {[0:1]}; + } + + arlen: coverpoint (item.ar_len) { + bins LEN[] = {[0:1]}; + } + + arsize: coverpoint (item.ar_size) { + bins SIZE[] = {[0:3]} iff(item.ar_len == 0); + } + + arready_to_valid: coverpoint (item.ar_delay) { + bins dly[] = {[0:16]}; + } + + arlock: coverpoint (item.ar_lock){ + bins lock[] = {[0:1]}; + ignore_bins IGN_EXCLUSIVE = {1} iff(!RVA); + } + + ar_axi_cross: cross arready_to_valid, arid, arlen; + + ar_size_axi_cross: cross arready_to_valid, arid, arsize { + illegal_bins ILLEGAL_BINS = binsof(arid) intersect{0} && + binsof(arsize) intersect{[0:2]}; + ignore_bins IGN_CROSS = binsof(arid) intersect{1} && binsof(arsize) intersect{3} iff(uvme_cva6_pkg::XLEN == 32); + } + + ar_lock_size_axi_cross: cross arready_to_valid, arlock, arsize{ + illegal_bins ILLEGAL_BINS = binsof(arlock) intersect{1} && + binsof(arsize) intersect{[0:1]}; + ignore_bins IGN_CROSS = binsof(arlock) intersect{0} && binsof(arsize) intersect{3} iff(uvme_cva6_pkg::XLEN == 32); + } + +endgroup : cg_axi_ar_channel + +covergroup cg_axi_r_channel(string name) + with function sample(uvma_axi_transaction_c item, int index, bit RVA); + + option.per_instance = 1; + option.name = name; + + rid: coverpoint (item.r_data_trs[index].r_id) { + bins ID[] = {[0:3]}; + illegal_bins ILLEGAL_BINS = {2}; + ignore_bins IGN_EXID = {3} iff(!RVA); + } + + rlast: coverpoint (item.r_data_trs[index].r_last); + + rresp: coverpoint (item.r_data_trs[index].r_resp){ + bins zero = {0}; + bins one = {1}; + bins two = {2}; + bins three = {3}; + } + + r_axi_cross: cross rid, rlast, rresp { + illegal_bins ILLEGAL_BINS = binsof(rid) intersect{3} && binsof(rlast) intersect{0}; + } +endgroup : cg_axi_r_channel + +/** + * Component encapsulating Open Bus Interface functional coverage model. + */ +class uvme_axi_covg_c extends uvm_component; + + // Objects + uvme_cva6_cntxt_c cntxt; + uvme_cva6_cfg_c cfg; + bit RVA; + + // TLM + uvm_tlm_analysis_fifo #(uvma_axi_transaction_c) uvme_axi_cov_resp_fifo; + + // Covergroup instances + cg_axi_w_channel w_axi_cg; + cg_axi_b_channel b_axi_cg; + cg_axi_ar_channel ar_axi_cg; + cg_axi_r_channel r_axi_cg; + + `uvm_component_utils_begin(uvme_axi_covg_c) + `uvm_field_object(cfg, UVM_DEFAULT) + `uvm_field_object(cntxt, UVM_DEFAULT) + `uvm_component_utils_end + + + /** + * Default constructor. + */ + extern function new(string name="uvma_axi_cov_model", uvm_component parent=null); + + /** + * 1. Ensures cfg & cntxt handles are not null. + * 2. Builds fifos. + */ + extern virtual function void build_phase(uvm_phase phase); + + /** + * Forks all sampling loops + */ + extern virtual task run_phase(uvm_phase phase); + +endclass : uvme_axi_covg_c + + +function uvme_axi_covg_c::new(string name="uvma_axi_cov_model", uvm_component parent=null); + + super.new(name, parent); + +endfunction : new + + +// A significant chunk of the build_phase method is common between this +// coverage model and the sequencer (uvma_obi_memory_sqr). This is +// appropriate so the duplicated code has a lint waiver. +// +function void uvme_axi_covg_c::build_phase(uvm_phase phase); + + super.build_phase(phase); + + void'(uvm_config_db#(uvme_cva6_cfg_c)::get(this, "", "cfg", cfg)); + if (cfg == null) begin + `uvm_fatal("cfg", "Context handle is null") + end + + void'(uvm_config_db#(uvme_cva6_cntxt_c)::get(this, "", "cntxt", cntxt)); + if (cntxt == null) begin + `uvm_fatal("CNTXT", "Context handle is null") + end + + RVA = cfg.ext_a_supported; + + uvme_axi_cov_resp_fifo = new("uvme_axi_cov_resp_fifo" , this); + + w_axi_cg = new("w_axi_cg"); + b_axi_cg = new("b_axi_cg"); + ar_axi_cg = new("ar_axi_cg"); + r_axi_cg = new("r_axi_cg"); + +endfunction : build_phase + +task uvme_axi_covg_c::run_phase(uvm_phase phase); + + super.run_phase(phase); + `uvm_info(get_type_name(), $sformatf("cov_model_enabled = %d", cfg.cov_model_enabled), UVM_HIGH) + `uvm_info(get_type_name(), $sformatf("ATOMIC ENABLE = %d", RVA), UVM_HIGH) + forever begin + uvma_axi_transaction_c resp_item; + + uvme_axi_cov_resp_fifo.get(resp_item); + case (resp_item.access_type) + UVMA_AXI_ACCESS_WRITE : begin + + w_axi_cg.sample(resp_item, RVA); + b_axi_cg.sample(resp_item, RVA); + + end + UVMA_AXI_ACCESS_READ : begin + + ar_axi_cg.sample(resp_item, RVA); + for(int i = 0; i <= resp_item.ar_len; i++) begin + r_axi_cg.sample(resp_item, i, RVA); + end + + end + endcase + + end + +endtask : run_phase + +`endif // __UVME_AXI_COVG_SV__ diff --git a/verif/env/uvme/cov/uvme_axi_ext_covg.sv b/verif/env/uvme/cov/uvme_axi_ext_covg.sv new file mode 100644 index 000000000..149d2a952 --- /dev/null +++ b/verif/env/uvme/cov/uvme_axi_ext_covg.sv @@ -0,0 +1,306 @@ +// Copyright 2023 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. +// 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: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) – sub-contractor MU-Electronics for Thales group + + +`ifndef __UVME_AXI_EXT_COVG_SV__ +`define __UVME_AXI_EXT_COVG_SV__ + + /* + * Covergroups + * Decalred at package-level to enable mutliple instances per monitor class (e.g. read/write) + */ + +covergroup cg_axi_aw_order(string name) + with function sample(uvma_axi_transaction_c item[], int t_b1_to_aw, int t_w1_to_aw, bit RVA); + + option.per_instance = 1; + option.name = name; + + outstanding_resp: coverpoint (t_b1_to_aw < 0){ + bins normal = {0}; + bins outstanding = {1}; + } + + awlock1: coverpoint (item[0].aw_lock){ + bins lock[] = {[0:1]}; + ignore_bins IGN_EXCLUSIVE = {1} iff(!RVA); + } + + awlock2: coverpoint (item[1].aw_lock){ + bins lock[] = {[0:1]}; + ignore_bins IGN_EXCLUSIVE = {1} iff(!RVA); + } + + aw_axi_cross: cross outstanding_resp, awlock1, awlock2; +endgroup : cg_axi_aw_order + +covergroup cg_axi_ar_order(string name) + with function sample(uvma_axi_transaction_c item[], int t_r1_to_ar, int t_r1l_to_ar, int t_r1_to_r2, int t_r1l_to_r2l, bit RVA); + + option.per_instance = 1; + option.name = name; + + outstanding_resp: coverpoint (t_r1_to_ar < 0){ + bins normal = {0}; + bins outstanding = {1}; + } + + outstanding_last_resp: coverpoint (t_r1l_to_ar < 0 && t_r1_to_ar > 0){ + bins normal = {0}; + bins outstanding = {1}; + } + + outoforder_resp_id0: coverpoint (t_r1_to_r2 < 0){ + bins normal = {0} iff(item[0].ar_id == 0); + bins outoforder = {1} iff(item[0].ar_id == 0); + } + + outoforder_resp_id1: coverpoint (t_r1_to_r2 < 0){ + bins normal = {0} iff(item[0].ar_id == 1); + bins outoforder = {1} iff(item[0].ar_id == 1); + } + + outoforder_last_resp_id0: coverpoint (t_r1l_to_r2l < 0){ + bins normal = {0} iff(item[0].ar_id == 0); + bins outoforder = {1} iff(item[0].ar_id == 0); + } + + outoforder_last_resp_id1: coverpoint (t_r1l_to_r2l < 0){ + bins normal = {0} iff(item[0].ar_id == 1); + bins outoforder = {1} iff(item[0].ar_id == 1); + } + + arid1: coverpoint (item[0].ar_id){ + bins id[] = {[0:1]}; + } + + arlen1: coverpoint (item[0].ar_len){ + bins len[] = {[0:1]}; + } + + arlock1: coverpoint (item[0].ar_lock){ + bins lock[] = {[0:1]}; + ignore_bins IGN_EXCLUSIVE = {1} iff(!RVA); + } + + arid2: coverpoint (item[1].ar_id){ + bins id[] = {[0:1]}; + } + + arlen2: coverpoint (item[1].ar_len){ + bins len[] = {[0:1]}; + } + + arlock2: coverpoint (item[1].ar_lock){ + bins lock[] = {[0:1]}; + ignore_bins IGN_EXCLUSIVE = {1} iff(!RVA); + } + + ar_axi_outstanding_cross: cross outstanding_resp, outstanding_last_resp, arid1, arlen1, arlock1, arid2, arlen2, arlock2{ + ignore_bins IGN_CROSS1 = binsof(outstanding_resp) intersect{1} && + binsof(outstanding_last_resp) intersect{1}; + } + + aw_axi_outoforder_id0_cross: cross outoforder_resp_id0, outoforder_last_resp_id0, arlen1, arlock1, arlen2, arlock2{ + ignore_bins IGN_CROSS1 = binsof(outoforder_resp_id0) intersect{1} && + binsof(outoforder_last_resp_id0) intersect{0} && + binsof(arlen2) intersect{0}; + ignore_bins IGN_CROSS2 = binsof(outoforder_resp_id0) intersect{0} && + binsof(outoforder_last_resp_id0) intersect{1} && + binsof(arlen1) intersect{0}; + } + + aw_axi_outoforder_id1_cross: cross outoforder_resp_id1, outoforder_last_resp_id1, arlen1, arlock1, arlen2, arlock2{ + ignore_bins IGN_CROSS1 = binsof(outoforder_resp_id1) intersect{1} && + binsof(outoforder_last_resp_id1) intersect{0} && + binsof(arlen2) intersect{0}; + ignore_bins IGN_CROSS2 = binsof(outoforder_resp_id1) intersect{0} && + binsof(outoforder_last_resp_id1) intersect{1} && + binsof(arlen1) intersect{0}; + } +endgroup : cg_axi_ar_order + +/** + * Component encapsulating Open Bus Interface functional coverage model. + */ +class uvme_axi_ext_covg_c extends uvm_component; + + // Objects + uvme_cva6_cntxt_c cntxt; + uvme_cva6_cfg_c cfg; + bit RVA; + + // Time between write transfer + int t_b1_to_aw; // <0 (outstanding) + int t_w1_to_aw; // <0 (outstanding) + + // Time between read transfer + int t_r1_to_ar; // <0 (outstanding) + int t_r1l_to_ar; // <0 (outstanding) + int t_r1_to_r2; // <0 (r2 run before r1) + int t_r1l_to_r2l; // <0 (last r2 run before last r1) + + // Covergroup instances + cg_axi_aw_order aw_axi_order_cg; + cg_axi_ar_order ar_axi_order_cg; + + // + uvma_axi_transaction_c aw_trs_fifo[]; + uvma_axi_transaction_c ar_trs_fifo[]; + + int order_resp; + + // TLM + uvm_tlm_analysis_fifo #(uvma_axi_transaction_c) uvme_axi_cov_fifo; + + `uvm_component_utils_begin(uvme_axi_ext_covg_c) + `uvm_component_utils_end + + /** + * Default constructor. + */ + extern function new(string name="uvme_axi_ext_covg", uvm_component parent=null); + + /** + * 1. Ensures cfg & cntxt handles are not null. + * 2. Builds fifos. + */ + extern virtual function void build_phase(uvm_phase phase); + + /** + * Forks all sampling loops + */ + extern virtual task run_phase(uvm_phase phase); + + /** + * Forks all sampling loops + */ + extern virtual function int aw_time_operations(); + + /** + * Forks all sampling loops + */ + extern virtual function int ar_time_operations(); + +endclass : uvme_axi_ext_covg_c + + +function uvme_axi_ext_covg_c::new(string name="uvme_axi_ext_covg", uvm_component parent=null); + + super.new(name, parent); + +endfunction : new + +function void uvme_axi_ext_covg_c::build_phase(uvm_phase phase); + + super.build_phase(phase); + + void'(uvm_config_db#(uvme_cva6_cfg_c)::get(this, "", "cfg", cfg)); + if (cfg == null) begin + `uvm_fatal("cfg", "Context handle is null") + end + + void'(uvm_config_db#(uvme_cva6_cntxt_c)::get(this, "", "cntxt", cntxt)); + if (cntxt == null) begin + `uvm_fatal("CNTXT", "Context handle is null") + end + + RVA = cfg.ext_a_supported; + + aw_axi_order_cg = new("aw_axi_order_cg"); + ar_axi_order_cg = new("ar_axi_order_cg"); + + uvme_axi_cov_fifo = new("uvme_axi_cov_fifo" , this); + +endfunction : build_phase + +task uvme_axi_ext_covg_c::run_phase(uvm_phase phase); + + super.run_phase(phase); + forever begin + uvma_axi_transaction_c resp_item; + + uvme_axi_cov_fifo.get(resp_item); + case (resp_item.access_type) + + UVMA_AXI_ACCESS_WRITE : begin + + aw_trs_fifo = new [aw_trs_fifo.size()+1] (aw_trs_fifo); + aw_trs_fifo[aw_trs_fifo.size()-1] = new resp_item; + if(aw_trs_fifo.size() == 2) begin + order_resp = aw_time_operations(); + aw_axi_order_cg.sample(aw_trs_fifo, t_b1_to_aw, t_w1_to_aw, RVA); + if(order_resp == 1) aw_trs_fifo[0] = new aw_trs_fifo[1]; + aw_trs_fifo = new [aw_trs_fifo.size()-1] (aw_trs_fifo); + end + + end + UVMA_AXI_ACCESS_READ : begin + + ar_trs_fifo = new [ar_trs_fifo.size()+1] (ar_trs_fifo); + ar_trs_fifo[ar_trs_fifo.size()-1] = new resp_item; + + if(ar_trs_fifo.size() == 2) begin + + order_resp = ar_time_operations(); + ar_axi_order_cg.sample(ar_trs_fifo, t_r1_to_ar, t_r1l_to_ar, t_r1_to_r2, t_r1l_to_r2l, RVA); + if(order_resp == 1) ar_trs_fifo[0] = new ar_trs_fifo[1]; + ar_trs_fifo = new [ar_trs_fifo.size()-1] (ar_trs_fifo); + + end + + end + endcase + end + +endtask : run_phase + +function int uvme_axi_ext_covg_c::ar_time_operations(); + int order_resp = 1; + uvma_axi_transaction_c axi_transaction; + + if(ar_trs_fifo[0].ar_start_time > ar_trs_fifo[1].ar_start_time) begin + + axi_transaction = new ar_trs_fifo[0]; + ar_trs_fifo[0] = new ar_trs_fifo[1]; + ar_trs_fifo[1] = new axi_transaction; + order_resp = 0; + + end + + t_r1_to_ar = ar_trs_fifo[1].ar_start_time - ar_trs_fifo[0].r_data_trs[0].r_start_time; + t_r1l_to_ar = ar_trs_fifo[1].ar_start_time - ar_trs_fifo[0].r_data_trs[ar_trs_fifo[0].r_data_trs.size()-1].r_start_time; + t_r1_to_r2 = ar_trs_fifo[1].r_data_trs[0].r_start_time - ar_trs_fifo[0].r_data_trs[0].r_start_time; + t_r1l_to_r2l = ar_trs_fifo[1].r_data_trs[ar_trs_fifo[1].r_data_trs.size()-1].r_start_time - ar_trs_fifo[0].r_data_trs[ar_trs_fifo[0].r_data_trs.size()-1].r_start_time; + + return order_resp; + +endfunction : ar_time_operations + +function int uvme_axi_ext_covg_c::aw_time_operations(); + int order_resp = 1; + uvma_axi_transaction_c axi_transaction; + + if(aw_trs_fifo[0].aw_start_time > aw_trs_fifo[1].aw_start_time) begin + + axi_transaction = new aw_trs_fifo[0]; + aw_trs_fifo[0] = new aw_trs_fifo[1]; + aw_trs_fifo[1] = new axi_transaction; + order_resp = 0; + + end + + t_b1_to_aw = aw_trs_fifo[1].aw_start_time - aw_trs_fifo[0].b_start_time; + t_w1_to_aw = aw_trs_fifo[1].aw_start_time - aw_trs_fifo[0].w_data_trs[0].w_start_time; + + return order_resp; + +endfunction : aw_time_operations + +`endif // __UVME_AXI_EXT_COVG_SV__ diff --git a/verif/env/uvme/cov/uvme_cva6_cov_model.sv b/verif/env/uvme/cov/uvme_cva6_cov_model.sv index 2f30fa10b..e360163b7 100644 --- a/verif/env/uvme/cov/uvme_cva6_cov_model.sv +++ b/verif/env/uvme/cov/uvme_cva6_cov_model.sv @@ -35,6 +35,8 @@ class uvme_cva6_cov_model_c extends uvm_component; uvme_cva6_config_covg_c config_covg; uvme_illegal_instr_cov_model_c illegal_covg; uvme_exception_cov_model_c exception_covg; + uvme_axi_covg_c axi_covg; + uvme_axi_ext_covg_c axi_ext_covg; // uvm_analysis_export#(uvma_clknrst_mon_trn_c) reset_export; @@ -119,6 +121,15 @@ function void uvme_cva6_cov_model_c::build_phase(uvm_phase phase); uvm_config_db#(uvme_cva6_cfg_c)::set(this, "config_covg", "cfg", cfg); uvm_config_db#(uvme_cva6_cntxt_c)::set(this, "config_covg", "cntxt", cntxt); + if(cfg.axi_cfg.cov_model_enabled) begin + axi_covg = uvme_axi_covg_c::type_id::create("axi_covg", this); + axi_ext_covg = uvme_axi_ext_covg_c::type_id::create("axi_ext_covg", this); + uvm_config_db#(uvme_cva6_cfg_c)::set(this, "axi_covg", "cfg", cfg); + uvm_config_db#(uvme_cva6_cntxt_c)::set(this, "axi_covg", "cntxt", cntxt); + uvm_config_db#(uvme_cva6_cfg_c)::set(this, "axi_ext_covg", "cfg", cfg); + uvm_config_db#(uvme_cva6_cntxt_c)::set(this, "axi_ext_covg", "cntxt", cntxt); + end + endfunction : build_phase function void uvme_cva6_cov_model_c::connect_phase(uvm_phase phase); diff --git a/verif/env/uvme/uvme_cva6_cfg.sv b/verif/env/uvme/uvme_cva6_cfg.sv index bf7833609..19be98eff 100644 --- a/verif/env/uvme/uvme_cva6_cfg.sv +++ b/verif/env/uvme/uvme_cva6_cfg.sv @@ -194,6 +194,7 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c; if (cov_model_enabled) { cvxif_cfg.cov_model_enabled == 1; isacov_cfg.cov_model_enabled == 1; + axi_cfg.cov_model_enabled == 1; //env coverage models cov_cvxif_model_enabled == 1; cov_isa_model_enabled == 1; diff --git a/verif/env/uvme/uvme_cva6_env.sv b/verif/env/uvme/uvme_cva6_env.sv index c4dd106e0..4bcf20a6f 100644 --- a/verif/env/uvme/uvme_cva6_env.sv +++ b/verif/env/uvme/uvme_cva6_env.sv @@ -381,6 +381,11 @@ function void uvme_cva6_env_c::connect_coverage_model(); clknrst_agent.mon_ap.connect(cov_model.reset_export); rvfi_agent.rvfi_core_ap.connect(isacov_agent.monitor.rvfi_instr_imp); + if(cfg.axi_cfg.cov_model_enabled) begin + axi_agent.vsequencer.synchronizer.uvma_sqr_trs_port.connect(cov_model.axi_covg.uvme_axi_cov_resp_fifo.analysis_export); + axi_agent.vsequencer.synchronizer.uvma_sqr_trs_port.connect(cov_model.axi_ext_covg.uvme_axi_cov_fifo.analysis_export); + end + endfunction: connect_coverage_model `endif // __UVME_CVA6_ENV_SV__ diff --git a/verif/env/uvme/uvme_cva6_pkg.sv b/verif/env/uvme/uvme_cva6_pkg.sv index 9205a67f3..1c814d5a8 100644 --- a/verif/env/uvme/uvme_cva6_pkg.sv +++ b/verif/env/uvme/uvme_cva6_pkg.sv @@ -51,6 +51,9 @@ package uvme_cva6_pkg; import uvmc_rvfi_scoreboard_pkg::*; import uvmc_rvfi_reference_model_pkg::*; import uvma_isacov_pkg::*; + import "DPI-C" function read_elf(input string filename); + import "DPI-C" function byte get_section(output longint address, output longint len); + import "DPI-C" context function void read_section_sv(input longint address, inout byte buffer[]); // Default legal opcode and funct7 for RV32I instructions bit [6:0] legal_i_opcode[$] = '{7'b0000011, @@ -96,12 +99,15 @@ package uvme_cva6_pkg; `include "uvme_illegal_instr_covg.sv" `include "uvme_exception_covg.sv" `include "uvme_cva6_config_covg.sv" + `include "uvme_axi_covg.sv" + `include "uvme_axi_ext_covg.sv" `include "uvme_cva6_cov_model.sv" `include "uvme_cva6_env.sv" // Virtual sequences `include "uvme_cva6_base_vseq.sv" `include "uvme_cva6_reset_vseq.sv" + `include "uvme_axi_fw_preload_seq.sv" // `include "uvme_cva6_interrupt_noise_vseq.sv" `include "uvme_cva6_vseq_lib.sv" diff --git a/verif/env/uvme/vseq/uvme_axi_fw_preload_seq.sv b/verif/env/uvme/vseq/uvme_axi_fw_preload_seq.sv new file mode 100644 index 000000000..3439cafce --- /dev/null +++ b/verif/env/uvme/vseq/uvme_axi_fw_preload_seq.sv @@ -0,0 +1,84 @@ +// 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. +// 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: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) – sub-contractor MU-Electronics for Thales group + + +`ifndef __UVME_AXI_FW_PRELOAD_SEQ_SV__ +`define __UVME_AXI_FW_PRELOAD_SEQ_SV__ + + +/** + * Virtual sequence preloads the CVA6 memory. + */ +class uvme_axi_fw_preload_seq_c extends uvma_axi_fw_preload_seq_c; + + uvml_mem_c mem; + static uvm_cmdline_processor uvcl = uvm_cmdline_processor::get_inst(); + + bit[63:0] value; + logic [7:0][7:0] mem_row; + string binary = ""; + longint address; + longint len; + byte buffer[]; + + `uvm_object_utils(uvme_axi_fw_preload_seq_c) + + /** + * Default constructor. + */ + extern function new(string name="uvma_axi_fw_preload_seq"); + + extern virtual task body(); + +endclass : uvme_axi_fw_preload_seq_c + +function uvme_axi_fw_preload_seq_c::new(string name="uvma_axi_fw_preload_seq"); + + super.new(name); + mem = uvml_mem_c::type_id::create("mem"); + mem.mem_default = MEM_DEFAULT_0; + +endfunction : new + +task uvme_axi_fw_preload_seq_c::body(); + + void'(uvcl.get_arg_value("+elf_file=", binary)); + + if (binary != "") begin + void'(read_elf(binary)); + wait(p_sequencer.cntxt.axi_vi.clk); + // while there are more sections to process + while (get_section(address, len)) begin + automatic int num_words0 = (len+7)/8; + `uvm_info( "Core Test", $sformatf("Loading Address: %x, Length: %x", address, len), UVM_HIGH) + buffer = new [num_words0*8]; + void'(read_section_sv(address, buffer)); + // preload memories + // 64-bit + for (int i = 0; i < num_words0; i++) begin + mem_row = '0; + for (int j = 0; j < 8; j++) begin + mem_row[j] = buffer[i*8 + j]; + end + mem.write(address + i*8 + 0, mem_row[0]); + mem.write(address + i*8 + 1, mem_row[1]); + mem.write(address + i*8 + 2, mem_row[2]); + mem.write(address + i*8 + 3, mem_row[3]); + mem.write(address + i*8 + 4, mem_row[4]); + mem.write(address + i*8 + 5, mem_row[5]); + mem.write(address + i*8 + 6, mem_row[6]); + mem.write(address + i*8 + 7, mem_row[7]); + end + p_sequencer.cntxt.mem = mem; + end + end + +endtask : body + +`endif // __UVME_AXI_FW_PRELOAD_SEQ_SV__ diff --git a/verif/sim/Makefile b/verif/sim/Makefile index 5c4f8c6d4..b0f862d7f 100644 --- a/verif/sim/Makefile +++ b/verif/sim/Makefile @@ -179,7 +179,7 @@ export DV_UVMA_RVFI_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_rvfi export DV_UVMA_ISACOV_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_isacov export DV_UVMA_CLKNRST_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_clknrst export DV_UVMA_CVXIF_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_cvxif -export DV_UVMA_AXI_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_axi +export DV_UVMA_AXI_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_axi5 export DV_UVMA_INTERRUPT_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_interrupt export DV_UVMA_DEBUG_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_debug export DV_UVMA_OBI_PATH = $(CORE_V_VERIF)/lib/uvm_agents/uvma_obi diff --git a/verif/tb/uvmt/cva6_tb_wrapper.sv b/verif/tb/uvmt/cva6_tb_wrapper.sv index a63ebf0cd..011b84b75 100644 --- a/verif/tb/uvmt/cva6_tb_wrapper.sv +++ b/verif/tb/uvmt/cva6_tb_wrapper.sv @@ -201,6 +201,7 @@ module cva6_tb_wrapper import uvmt_cva6_pkg::*; #( assign axi_slave.aw_prot = axi_ariane_req.aw.prot; assign axi_slave.aw_qos = axi_ariane_req.aw.qos; assign axi_slave.aw_region = axi_ariane_req.aw.region; + assign axi_slave.aw_atop = axi_ariane_req.aw.atop; assign axi_slave.aw_user = 0; // W Channel assign axi_slave.w_data = axi_ariane_req.w.data; diff --git a/verif/tb/uvmt/uvmt_axi_assert.sv b/verif/tb/uvmt/uvmt_axi_assert.sv index 843153cdf..747c215bc 100644 --- a/verif/tb/uvmt/uvmt_axi_assert.sv +++ b/verif/tb/uvmt/uvmt_axi_assert.sv @@ -5,48 +5,27 @@ // 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: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) +// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) – sub-contractor MU-Electronics for Thales group -module uvmt_axi_assert (uvma_axi_intf.passive axi_assert, input bit clk, input rst_n); +module uvmt_axi_assert (uvma_axi_intf axi_assert_if); import uvm_pkg::*; + uvma_axi_assert axi_mix_assert(.axi_assert(axi_assert_if)); - bind uvmt_axi_assert - uvma_axi_aw_assert axi_aw_assert(.axi_assert(axi_assert), - .clk(clk), - .rst_n(rst_n) - ); + uvma_axi_aw_assert axi_aw_assert(.axi_assert(axi_assert_if)); - bind uvmt_axi_assert - uvma_axi_ar_assert axi_ar_assert(.axi_assert(axi_assert), - .clk(clk), - .rst_n(rst_n) - ); + uvma_axi_ar_assert axi_ar_assert(.axi_assert(axi_assert_if)); - bind uvmt_axi_assert - uvma_axi_w_assert axi_w_assert(.axi_assert(axi_assert), - .clk(clk), - .rst_n(rst_n) - ); + uvma_axi_w_assert axi_w_assert(.axi_assert(axi_assert_if)); - bind uvmt_axi_assert - uvma_axi_r_assert axi_r_assert(.axi_assert(axi_assert), - .clk(clk), - .rst_n(rst_n) - ); + uvma_axi_r_assert axi_r_assert(.axi_assert(axi_assert_if)); - bind uvmt_axi_assert - uvma_axi_b_assert axi_b_assert(.axi_assert(axi_assert), - .clk(clk), - .rst_n(rst_n) - ); + uvma_axi_b_assert axi_b_assert(.axi_assert(axi_assert_if)); - bind uvmt_axi_assert - uvmt_cva6_axi_assert cva6_axi_assert(.axi_assert(axi_assert), - .clk(clk), - .rst_n(rst_n) - ); + uvma_axi_amo_assert axi_amo_assert(.axi_assert(axi_assert_if)); + + uvmt_cva6_axi_assert cva6_axi_assert(.axi_assert_if(axi_assert_if)); endmodule : uvmt_axi_assert diff --git a/verif/tb/uvmt/uvmt_cva6_axi_assert.sv b/verif/tb/uvmt/uvmt_cva6_axi_assert.sv index 8e74ad88a..d4c49dc89 100644 --- a/verif/tb/uvmt/uvmt_cva6_axi_assert.sv +++ b/verif/tb/uvmt/uvmt_cva6_axi_assert.sv @@ -5,93 +5,98 @@ // 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: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) +// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com) – sub-contractor MU-Electronics for Thales group // *************************** AXI features supported by CVA6 ************************** // -module uvmt_cva6_axi_assert (uvma_axi_intf axi_assert, input bit clk, input rst_n); +module uvmt_cva6_axi_assert (uvma_axi_intf axi_assert_if); import uvm_pkg::*; //check if the CVA6 identify read transaction with an ID equal to 0 or 1 property AXI4_CVA6_ARID; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_id == 0 || axi_assert.ar_id == 1; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_id == 0 || axi_assert_if.ar_id == 1 || (axi_assert_if.ar_id == 3 && axi_assert_if.ar_lock == 1); endproperty //check if the CVA6 identify write transaction with an ID equal to 0 or 1 property AXI4_CVA6_AWID; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_id == 1; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_id == 1 || (axi_assert_if.aw_id == 3 && axi_assert_if.aw_atop != 0) || (axi_assert_if.aw_id == 3 && axi_assert_if.aw_lock == 1); endproperty //Check if user-defined extension for read address channel is equal to 0b00 property AXI4_CVA6_ARUSER; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_user == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_user == 0; endproperty //Check if user-defined extension for write address channel is equal to 0b00 property AXI4_CVA6_AWUSER; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_user == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_user == 0; endproperty //Check if Quality of Service identifier for write transaction is equal to 0b0000 property AXI4_CVA6_AWQOS; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_qos == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_qos == 0; endproperty //Check if Quality of Service identifier for read transaction is equal to 0b0000 property AXI4_CVA6_ARQOS; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_qos == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_qos == 0; endproperty //Check if Region indicator for write transaction is equal to 0b0000 property AXI4_CVA6_AWREGION; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_region == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_region == 0; endproperty //Check if Region indicator for read transaction is equal to 0b0000 property AXI4_CVA6_ARREGION; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_region == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_region == 0; endproperty //Check if AWCACHE is always equal to 0b0000 property AXI4_CVA6_AWCACHE; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_cache == 2; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_cache == 2; endproperty //Check if ARCACHE is always equal to 0b0000 property AXI4_CVA6_ARCACHE; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_cache == 2; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_cache == 2; endproperty //Check if Protection attributes for write transaction always take the 0b000 property AXI4_CVA6_AWPROT; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_prot == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_prot == 0; endproperty //Check if Protection attributes for read transaction always take the 0b000 property AXI4_CVA6_ARPROT; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_prot == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_prot == 0; endproperty //Check if all write transaction performed by CVA6 are of type INCR property AXI4_CVA6_AWBURST; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_burst == 1; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_burst == 1; endproperty //Check if all read transaction performed by CVA6 are of type INCR property AXI4_CVA6_ARBURST; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_burst == 1; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_burst == 1; endproperty //Check if all write transaction performed by CVA6 are equal to 0 property AXI4_CVA6_AWLEN; - @(posedge clk) disable iff (!rst_n) axi_assert.aw_valid |-> axi_assert.aw_len == 0; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> axi_assert_if.aw_len == 0; endproperty //Check if all Read transaction performed by CVA6 are equal to 0 or 1 property AXI4_CVA6_ARLEN; - @(posedge clk) disable iff (!rst_n) axi_assert.ar_valid |-> axi_assert.ar_len == 0 || axi_assert.ar_len == 1; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.ar_valid |-> axi_assert_if.ar_len == 0 || axi_assert_if.ar_len == 1; + endproperty + + //Check if all Write transaction performed by CVA6 are of type Non atomic, AtomicLoad or AtomicSwap + property AXI4_CVA6_AWATOP; + @(posedge axi_assert_if.clk) disable iff (!axi_assert_if.rst_n) axi_assert_if.aw_valid |-> (axi_assert_if.aw_atop[5:4] == 0 || axi_assert_if.aw_atop[5:4] == 2 || axi_assert_if.aw_atop[5:4] == 3) && axi_assert_if.aw_atop[3] == 0; endproperty /********************************************** Assert Property ******************************************************/ @@ -144,6 +149,9 @@ module uvmt_cva6_axi_assert (uvma_axi_intf axi_assert, input bit clk, input rst cva6_awlen : assert property (AXI4_CVA6_AWLEN) else `uvm_error (" AXI4 protocol checks assertion ", "Violation of AXI4_CVA6_AWLEN"); + cva6_awatop : assert property (AXI4_CVA6_AWATOP) + else `uvm_error (" AXI4 protocol checks assertion ", "Violation of AXI4_CVA6_AWATOP"); + /********************************************** Cover Property ******************************************************/ @@ -179,7 +187,7 @@ module uvmt_cva6_axi_assert (uvma_axi_intf axi_assert, input bit clk, input rst cov_cva6_awlen : cover property(AXI4_CVA6_AWLEN); - + cov_cva6_awatop : cover property(AXI4_CVA6_AWATOP); endmodule : uvmt_cva6_axi_assert diff --git a/verif/tb/uvmt/uvmt_cva6_tb.sv b/verif/tb/uvmt/uvmt_cva6_tb.sv index 0c423ddac..31f8fe674 100644 --- a/verif/tb/uvmt/uvmt_cva6_tb.sv +++ b/verif/tb/uvmt/uvmt_cva6_tb.sv @@ -88,7 +88,7 @@ module uvmt_cva6_tb; uvma_rvfi_csr_if#(uvme_cva6_pkg::XLEN) rvfi_csr_if [RVFI_NRET-1:0](); - uvmt_default_inputs_intf default_inputs_vif(); + uvmt_default_inputs_intf default_inputs_vif(); //bind assertion module for cvxif interface bind uvmt_cva6_dut_wrap @@ -98,10 +98,8 @@ module uvmt_cva6_tb; ); //bind assertion module for axi interface bind uvmt_cva6_dut_wrap - uvmt_axi_assert axi_assert(.axi_assert(axi_if.passive), - .clk(clknrst_if.clk), - .rst_n(clknrst_if.reset_n) - ); + uvmt_axi_assert axi_assert(.axi_assert_if(axi_if)); + // DUT Wrapper Interfaces uvmt_rvfi_if #( // RVFI @@ -238,6 +236,14 @@ module uvmt_cva6_tb; // Specify time format for simulation (units_number, precision_number, suffix_string, minimum_field_width) $timeformat(-9, 3, " ns", 8); + axi_if.aw_assertion_enabled = 1; + axi_if.w_assertion_enabled = 1; + axi_if.b_assertion_enabled = 1; + axi_if.ar_assertion_enabled = 1; + axi_if.r_assertion_enabled = 1; + axi_if.axi_assertion_enabled = 1; + axi_if.axi_amo_assertion_enabled = 1; + // Add interfaces handles to uvm_config_db uvm_config_db#(virtual uvma_clknrst_if )::set(.cntxt(null), .inst_name("*.env.clknrst_agent"), .field_name("vif"), .value(clknrst_if)); uvm_config_db#(virtual uvma_cvxif_intf )::set(.cntxt(null), .inst_name("*.env.cvxif_agent"), .field_name("vif"), .value(cvxif_if) ); diff --git a/verif/tests/uvmt/base-tests/uvmt_cva6_base_test.sv b/verif/tests/uvmt/base-tests/uvmt_cva6_base_test.sv index eeb8f7757..8eece8272 100644 --- a/verif/tests/uvmt/base-tests/uvmt_cva6_base_test.sv +++ b/verif/tests/uvmt/base-tests/uvmt_cva6_base_test.sv @@ -40,6 +40,12 @@ class uvmt_cva6_base_test_c extends uvm_test; uvme_cva6_env_c env ; uvme_cva6_vsqr_c vsequencer; + typedef enum { + UVMA_AXI_VERSION_1P1, + UVMA_AXI_VERSION_1P2, + UVMA_AXI_VERSION_1P3 + } uvma_axi_version_enum; + // Handles testbench interfaces virtual uvmt_rvfi_if rvfi_vif; // virtual peripheral status // virtual uvmt_cva6_core_cntrl_if core_cntrl_vif; // control inputs to the core @@ -50,6 +56,8 @@ class uvmt_cva6_base_test_c extends uvm_test; // Variable can be modified from command line, to change the AXI agent mode int force_axi_mode = -1; + uvm_factory factory; + `uvm_component_utils_begin(uvmt_cva6_base_test_c) `uvm_field_object(test_cfg , UVM_DEFAULT) @@ -74,6 +82,16 @@ class uvmt_cva6_base_test_c extends uvm_test; soft test_cfg.tpt == NO_TEST_PROGRAM; } + constraint memory_region_cfg { + env_cfg.axi_cfg.axi_region_enabled == 0; + env_cfg.axi_cfg.axi_prot_enabled == 0; + env_cfg.axi_cfg.m_addr_start == 64'h0; + env_cfg.axi_cfg.m_addr_end == 64'h7fffffffffffffff; + env_cfg.axi_cfg.m_num_part == 1; + env_cfg.axi_cfg.m_part_st[0].axi_prot_type_access == 0; + env_cfg.axi_cfg.m_part_st[0].m_type_access == 3; + } + /** * 1. Replaces default report server with rs. @@ -223,6 +241,26 @@ function void uvmt_cva6_base_test_c::build_phase(uvm_phase phase); create_env (); create_components(); + `uvm_info("BASE TEST", $sformatf("AXI config version = %s", env_cfg.axi_cfg.version), UVM_LOW) + + factory = uvm_factory::get(); + + case (env_cfg.axi_cfg.version) + UVMA_AXI_VERSION_1P2 : begin + factory.set_type_override_by_name("uvma_axi_synchronizer_c", "uvma_axi_ext_synchronizer_c"); + `uvm_info("BASE TEST", $sformatf("AXI EXT SYNCHRONIZER"), UVM_LOW) + end + UVMA_AXI_VERSION_1P3 : begin + factory.set_type_override_by_name("uvma_axi_synchronizer_c", "uvma_axi_amo_synchronizer_c"); + `uvm_info("BASE TEST", $sformatf("AXI AMO SYNCHRONIZER"), UVM_LOW) + end + endcase + + if(!env_cfg.axi_cfg.preload_mem) begin + factory.set_type_override_by_name("uvma_axi_fw_preload_seq_c", "uvme_axi_fw_preload_seq_c"); + end + + endfunction : build_phase