[dv] Update tl_intg for chip-level
1. address Sri's comments at #6852
2. Move cpu_stub point prior to the place where design generates ecc
values, so that the ecc gen and ecc check are in the design data path
3. add knob `en_tl_intg_gen` to decide if TB need to generate ecc or
not. For block level, set to 1, for chip, set to 0
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/cip_lib/cip_base_env.sv b/hw/dv/sv/cip_lib/cip_base_env.sv
index bb5724f..93ff2c2 100644
--- a/hw/dv/sv/cip_lib/cip_base_env.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env.sv
@@ -11,7 +11,7 @@
`uvm_component_param_utils(cip_base_env #(CFG_T, VIRTUAL_SEQUENCER_T, SCOREBOARD_T, COV_T))
tl_agent m_tl_agents[string];
- tl_reg_adapter#(cip_tl_seq_item) m_tl_reg_adapters[string];
+ tl_reg_adapter #(tl_seq_item) m_tl_reg_adapters[string];
alert_esc_agent m_alert_agent[string];
push_pull_agent#(.DeviceDataWidth(EDN_DATA_WIDTH)) m_edn_pull_agent;
@@ -20,6 +20,10 @@
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
+ // use cip_tl_seq_item to create tl_seq_item with correct integrity values and obtain integrity
+ // related functions
+ if (cfg.en_tl_intg_gen) tl_seq_item::type_id::set_type_override(cip_tl_seq_item::get_type());
+
// Retrieve the virtual interfaces from uvm_config_db.
if (!uvm_config_db#(intr_vif)::get(this, "", "intr_vif", cfg.intr_vif) &&
cfg.num_interrupts > 0) begin
@@ -33,7 +37,7 @@
// Create & configure the TL agent.
foreach (cfg.m_tl_agent_cfgs[i]) begin
m_tl_agents[i] = tl_agent::type_id::create({"m_tl_agent_", i}, this);
- m_tl_reg_adapters[i] = tl_reg_adapter#(cip_tl_seq_item)::type_id::create(
+ m_tl_reg_adapters[i] = tl_reg_adapter#(tl_seq_item)::type_id::create(
{"m_tl_reg_adapter_", i});
m_tl_reg_adapters[i].cfg = cfg.m_tl_agent_cfgs[i];
uvm_config_db#(tl_agent_cfg)::set(this, $sformatf("m_tl_agent_%s*", i), "cfg",
diff --git a/hw/dv/sv/cip_lib/cip_base_env_cfg.sv b/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
index 5a41fbc..9908873 100644
--- a/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
@@ -13,6 +13,9 @@
// Override this alert name at `initialize` if it's not as below
string tl_intg_alert_name = "fatal_fault";
+ // Enables TL integrity generation & checking with *_user bits.
+ // Assume ALL TL agents have integrity check enabled or disabled altogether.
+ bit en_tl_intg_gen = 1;
alert_esc_agent_cfg m_alert_agent_cfg[string];
push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH)) m_edn_pull_agent_cfg;
diff --git a/hw/dv/sv/cip_lib/cip_base_pkg.sv b/hw/dv/sv/cip_lib/cip_base_pkg.sv
index c6a0a4e..7e7e165 100644
--- a/hw/dv/sv/cip_lib/cip_base_pkg.sv
+++ b/hw/dv/sv/cip_lib/cip_base_pkg.sv
@@ -25,6 +25,7 @@
string msg_id = "cip_base_pkg";
parameter uint EDN_BUS_WIDTH = 32;
parameter uint EDN_DATA_WIDTH = EDN_BUS_WIDTH + 1; // 32 bits bus data, 1 bit fips
+ parameter uint MAX_TL_ECC_ERRORS = 3;
typedef enum {
err_update,
@@ -35,7 +36,7 @@
TlIntgErrNone,
TlIntgErrCmd,
TlIntgErrData,
- TlIntgErrBoth // have both payload and data intg errors
+ TlIntgErrBoth // Inject errors in both command and data.
} tl_intg_err_e;
typedef class cip_tl_seq_item;
diff --git a/hw/dv/sv/cip_lib/cip_base_scoreboard.sv b/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
index 7bac7de..cc75e4e 100644
--- a/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
+++ b/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
@@ -255,7 +255,6 @@
bit is_tl_unmapped_addr, is_tl_err, mem_access_err;
bit csr_aligned_err, csr_size_err, tl_item_err;
bit has_intg_err;
- cip_tl_seq_item cip_tl_item;
if (!is_tl_access_mapped_addr(item, ral_name)) begin
is_tl_unmapped_addr = 1;
@@ -269,8 +268,8 @@
csr_aligned_err = !is_tl_csr_write_addr_word_aligned(item, ral_name);
csr_size_err = !is_tl_csr_write_size_gte_csr_width(item, ral_name);
tl_item_err = item.get_exp_d_error();
- `downcast(cip_tl_item, item)
- has_intg_err = !cip_tl_item.is_a_user_ok(.throw_error(0));
+
+ if (cfg.en_tl_intg_gen) has_intg_err = !item.is_a_chan_intg_ok(.throw_error(0));
if (!is_tl_err && (mem_access_err || csr_aligned_err || csr_size_err || tl_item_err ||
has_intg_err)) begin
diff --git a/hw/dv/sv/cip_lib/cip_base_test.sv b/hw/dv/sv/cip_lib/cip_base_test.sv
index 6599af2..2006952 100644
--- a/hw/dv/sv/cip_lib/cip_base_test.sv
+++ b/hw/dv/sv/cip_lib/cip_base_test.sv
@@ -8,12 +8,5 @@
`uvm_component_new
- virtual function void build_phase(uvm_phase phase);
- super.build_phase(phase);
-
- // use cip_tl_seq_item to create tl_seq_item with correct integrity values and obtain integrity
- // related functions
- tl_seq_item::type_id::set_type_override(cip_tl_seq_item::get_type());
- endfunction
endclass : cip_base_test
diff --git a/hw/dv/sv/cip_lib/doc/index.md b/hw/dv/sv/cip_lib/doc/index.md
index 41c6ced..6a272d7 100644
--- a/hw/dv/sv/cip_lib/doc/index.md
+++ b/hw/dv/sv/cip_lib/doc/index.md
@@ -196,6 +196,10 @@
cases, including unmapped address error, protocol error, memory access error
etc. All the items sent in this task will trigger d_error and won't change the
CSR/memory value.
+* **task run_tl_intg_err_vseq**: This task will test TLUL integrity error. It contains
+ 2 parallel threads. One thread calls `csr_rw` seq to do random CSR accesses. The
+ other issues a TLUL item with integrity error on `a_user` and then check the fatal
+ alert is triggered.
* **task run_stress_all_with_rand_reset_vseq**: This task runs 3 parallel threads,
which are ip_stress_all_vseq, run_tl_errors_vseq and reset sequence. After
reset occurs, the other threads will be killed and then all the CSRs will be read
@@ -250,6 +254,13 @@
type ENV_T = cip_base_env) extends uvm_test;
```
+### cip_tl_seq_item
+This is extended class of tl_seq_item to generate correct integrity values in
+a_user and d_user. If DUT relies on the agent to generate integrity for TLUL, set
+`cfg.en_tl_intg_gen = 1`, cip_tl_seq_item will override tl_seq_item, and integrity
+values will be generated. If TLUL integrity is handled in the DUT, set
+`cfg.en_tl_intg_gen = 0`, then `a_user` and `d_user` will be fully randomized.
+
## Extending from CIP library classes
Let's say we are verifying an actual comportable IP `uart` which has `uart_tx`
and `uart_rx` interface. User then develops the `uart_agent` to be able to talk
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh
index 8742ce8..83a3b64 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh
@@ -243,6 +243,8 @@
endtask
virtual task run_tl_intg_err_vseq_sub(int num_times = 1, string ral_name);
+ `DV_CHECK_EQ(cfg.en_tl_intg_gen, 1)
+
for (int trans = 1; trans <= num_times; trans++) begin
`uvm_info(`gfn, $sformatf("Running run_tl_intg_err_vseq %0d/%0d", trans, num_times),
UVM_LOW)
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_tl_seq_item.sv b/hw/dv/sv/cip_lib/seq_lib/cip_tl_seq_item.sv
index 0cdbf10..06993e3 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_tl_seq_item.sv
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_tl_seq_item.sv
@@ -5,22 +5,27 @@
// extend tl_seq_item to return a|d_user data with ECC value
class cip_tl_seq_item extends tl_seq_item;
- `uvm_object_utils_begin(cip_tl_seq_item)
- `uvm_object_utils_end
-
`uvm_object_new
tlul_pkg::tl_type_e tl_type = DataType;
tl_intg_err_e tl_intg_err_type = TlIntgErrNone;
// the max errors that we can detect
- int max_ecc_errors = 3;
+ int max_ecc_errors = MAX_TL_ECC_ERRORS;
+
+ `uvm_object_utils_begin(cip_tl_seq_item)
+ `uvm_field_enum(tlul_pkg::tl_type_e, tl_type, UVM_DEFAULT)
+ `uvm_field_enum(tl_intg_err_e, tl_intg_err_type, UVM_DEFAULT)
+ `uvm_field_int(max_ecc_errors, UVM_DEFAULT)
+ `uvm_object_utils_end
function void post_randomize();
- update_a_chan_intg_val(tl_intg_err_type);
+ a_user = compute_a_user();
+ inject_a_chan_intg_err();
endfunction
- // calculate ecc value for a_user
- virtual function tl_a_user_t get_a_user_val();
+ // calculate ecc value for a_user and return a_user
+ // class member a_user isn't updated in this function
+ virtual function tl_a_user_t compute_a_user();
tl_a_user_t user;
tl_h2d_cmd_intg_t cmd_intg_payload;
logic [H2DCmdFullWidth - 1 : 0] cmd_with_intg;
@@ -39,12 +44,12 @@
user.rsvd = '0;
user.tl_type = tl_type;
user.cmd_intg = cmd_with_intg[H2DCmdFullWidth -1 -: H2DCmdIntgWidth];
- user.data_intg = data_with_intg[DataFullWidth -1 -: DataIntgWidth];;
+ user.data_intg = data_with_intg[DataFullWidth -1 -: DataIntgWidth];
return user;
- endfunction // get_a_user_val
+ endfunction : compute_a_user
// device facing version of the function above
- virtual function tl_d_user_t get_d_user_val();
+ virtual function tl_d_user_t compute_d_user();
tl_d_user_t user;
tl_d2h_rsp_intg_t rsp_intg_payload;
logic [D2HRspFullWidth - 1:0] rsp_with_intg;
@@ -62,132 +67,111 @@
user.rsp_intg = rsp_with_intg[D2HRspFullWidth -1 -: D2HRspIntgWidth];
user.data_intg = data_with_intg[DataFullWidth -1 -: DataIntgWidth];
return user;
- endfunction // get_d_user_val
+ endfunction : compute_d_user
// update data and ecc value for a channel
- virtual function void update_a_chan_intg_val(tl_intg_err_e tl_intg_err_type = TlIntgErrNone);
- tl_a_user_t cur_user = get_a_user_val();
- tl_a_user_t final_user;
- cip_tl_seq_item cur_item;
- bit [DataIntgWidth + $bits(tl_h2d_cmd_intg_t) - 1 : 0] cmd_and_intg_err_mask;
- bit [DataIntgWidth + BUS_DW - 1 : 0] data_and_intg_err_mask;
+ virtual function void inject_a_chan_intg_err();
+ // define a struct type local a_user to access ECC or other field easily
+ tl_a_user_t l_a_user = tl_a_user_t'(a_user);
- `downcast(cur_item, this.clone())
+ if (tl_intg_err_type == TlIntgErrNone) return;
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(cmd_and_intg_err_mask,
- if (tl_intg_err_type inside {TlIntgErrCmd, TlIntgErrBoth}) {
- $countones(cmd_and_intg_err_mask) inside {[1 : max_ecc_errors]};
- } else {
- cmd_and_intg_err_mask == '0;
- })
- {a_addr, a_opcode, a_mask, final_user.tl_type, final_user.cmd_intg} = {
- cur_item.a_addr,
- cur_item.a_opcode,
- cur_item.a_mask,
- cur_user.tl_type,
- cur_user.cmd_intg} ^ cmd_and_intg_err_mask;
+ if (tl_intg_err_type inside {TlIntgErrCmd, TlIntgErrBoth}) begin
+ bit [DataIntgWidth + $bits(tl_h2d_cmd_intg_t) - 1 : 0] cmd_and_intg_err_mask;
+ // Pre-populate str with format specifiers for the updated values that will be set later.
+ string str = {"TL data or integrity bits have been flipped, see the changes as below:\n",
+ $sformatf("\t a_addr: 0x%0x\n", a_addr), " -> 0x%0x",
+ $sformatf("\t a_opcode: 0x%0x\n", a_opcode), " -> 0x%0x",
+ $sformatf("\t a_mask: 0x%0x\n", a_mask), " -> 0x%0x",
+ $sformatf("\t tl_type: 0x%0x\n", l_a_user.tl_type), " -> 0x%0x",
+ $sformatf("\t cmd_intg: 0x%0x\n", l_a_user.cmd_intg), " -> 0x%0x"};
- if (cmd_and_intg_err_mask != '0) begin
- string str = "TL cmd or integrity bits have been flipped, see the changes as below:\n";
- str = $sformatf("%s\t a_addr: 0x%0x -> 0x%0x\n", str, cur_item.a_addr, a_addr);
- str = $sformatf("%s\t a_opcode: 0x%0x -> 0x%0x\n", str, cur_item.a_opcode, a_opcode);
- str = $sformatf("%s\t a_mask: 0x%0x -> 0x%0x\n", str, cur_item.a_mask, a_mask);
- str = $sformatf("%s\t tl_type: 0x%0x -> 0x%0x\n", str, cur_user.tl_type, final_user.tl_type);
- str = $sformatf("%s\t cmd_intg: 0x%0x -> 0x%0x\n", str, cur_user.cmd_intg,
- final_user.cmd_intg);
+ // Flip cmd or intg ecc
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(cmd_and_intg_err_mask,
+ $countones(cmd_and_intg_err_mask) inside {[1 : max_ecc_errors]};)
+ {a_addr, a_opcode, a_mask, l_a_user.tl_type, l_a_user.cmd_intg} ^= cmd_and_intg_err_mask;
+
+ str = $sformatf(str, a_addr, a_opcode, a_mask, l_a_user.tl_type, l_a_user.cmd_intg);
`uvm_info(`gfn, str, UVM_LOW)
end
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(data_and_intg_err_mask,
- if (tl_intg_err_type inside {TlIntgErrData, TlIntgErrBoth}) {
- $countones(data_and_intg_err_mask) inside {[1 : max_ecc_errors]};
- } else {
- data_and_intg_err_mask == '0;
- })
- {a_data, final_user.data_intg} = {cur_item.a_data, final_user.data_intg} ^
- data_and_intg_err_mask;
+ if (tl_intg_err_type inside {TlIntgErrData, TlIntgErrBoth}) begin
+ bit [DataIntgWidth + BUS_DW - 1 : 0] data_and_intg_err_mask;
+ // Pre-populate str with format specifiers for the updated values that will be set later.
+ string str = {"TL data or integrity bits have been flipped, see the changes as below:\n",
+ $sformatf("\t a_data: 0x%0x\n", a_data), " -> 0x%0x"};
- if (cmd_and_intg_err_mask != '0) begin
- string str = "TL data or integrity bits have been flipped, see the changes as below: \n";
- str = $sformatf("%s\t a_data: 0x%0x -> 0x%0x\n", str, cur_item.a_data, a_data);
- str = $sformatf("%s\t data_intg: 0x%0x -> 0x%0x\n", str, cur_user.data_intg,
- final_user.data_intg);
+ // Flip data or intg ecc
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(data_and_intg_err_mask,
+ $countones(data_and_intg_err_mask) inside {[1 : max_ecc_errors]};)
+ {a_data, l_a_user.data_intg} ^= data_and_intg_err_mask;
+
+ str = $sformatf(str, a_data);
`uvm_info(`gfn, str, UVM_LOW)
end
- a_user = final_user;
- endfunction // update_a_chan_intg_val
+ a_user = l_a_user;
+ endfunction : inject_a_chan_intg_err
// update data and ecc value for d channel
- virtual function void update_d_chan_intg_val(tl_intg_err_e tl_intg_err_type = TlIntgErrNone);
- tl_d_user_t cur_user = get_d_user_val();
- tl_d_user_t final_user;
- cip_tl_seq_item cur_item;
- bit [DataIntgWidth + $bits(tl_d2h_rsp_intg_t) - 1 : 0] rsp_and_intg_err_mask;
- bit [DataIntgWidth + BUS_DW - 1 : 0] data_and_intg_err_mask;
+ virtual function void inject_d_chan_intg_err();
+ // define a struct type local d_user to access ECC or other field easily
+ tl_d_user_t l_d_user = tl_d_user_t'(d_user);
- `downcast(cur_item, this.clone())
+ if (tl_intg_err_type == TlIntgErrNone) return;
+ if (tl_intg_err_type inside {TlIntgErrCmd, TlIntgErrBoth}) begin
+ bit [DataIntgWidth + $bits(tl_d2h_rsp_intg_t) - 1 : 0] rsp_and_intg_err_mask;
+ // Pre-populate str with format specifiers for the updated values that will be set later.
+ string str = {"TL data or integrity bits have been flipped, see the changes as below:\n",
+ $sformatf("\t d_opcode: 0x%0x\n", d_opcode), " -> 0x%0x",
+ $sformatf("\t d_size: 0x%0x\n", d_size), " -> 0x%0x",
+ $sformatf("\t d_error: 0x%0x\n", d_error), " -> 0x%0x",
+ $sformatf("\t rsp_intg: 0x%0x\n", l_d_user.rsp_intg), " -> 0x%0x"};
+
+ // Flip cmd or intg ecc
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(rsp_and_intg_err_mask,
- if (tl_intg_err_type inside {TlIntgErrCmd, TlIntgErrBoth}) {
- $countones(rsp_and_intg_err_mask) inside {[1 : max_ecc_errors]};
- } else {
- rsp_and_intg_err_mask == '0;
- })
- {d_opcode, d_size, d_error, final_user.rsp_intg} = {
- cur_item.d_opcode,
- cur_item.d_size,
- cur_item.d_error,
- cur_user.rsp_intg} ^ rsp_and_intg_err_mask;
+ $countones(rsp_and_intg_err_mask) inside {[1 : max_ecc_errors]};)
+ {d_opcode, d_size, d_error, l_d_user.rsp_intg} ^= rsp_and_intg_err_mask;
- if (rsp_and_intg_err_mask != '0) begin
- string str = "TL cmd or integrity bits have been flipped, see the changes as below:\n";
- str = $sformatf("%s\t d_opcode: 0x%0x -> 0x%0x\n", str, cur_item.d_opcode, d_opcode);
- str = $sformatf("%s\t d_size: 0x%0x -> 0x%0x\n", str, cur_item.d_size, d_size);
- str = $sformatf("%s\t d_error: 0x%0x -> 0x%0x\n", str, cur_item.d_error, d_error);
- str = $sformatf("%s\t rsp_intg: 0x%0x -> 0x%0x\n", str, cur_user.rsp_intg,
- final_user.rsp_intg);
+ str = $sformatf(str, d_opcode, d_size, d_error, l_d_user.rsp_intg);
`uvm_info(`gfn, str, UVM_LOW)
end
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(data_and_intg_err_mask,
- if (tl_intg_err_type inside {TlIntgErrData, TlIntgErrBoth}) {
- $countones(data_and_intg_err_mask) inside {[1 : max_ecc_errors]};
- } else {
- data_and_intg_err_mask == '0;
- })
- {a_data, final_user.data_intg} = {cur_item.a_data, final_user.data_intg} ^
- data_and_intg_err_mask;
+ if (tl_intg_err_type inside {TlIntgErrData, TlIntgErrBoth}) begin
+ bit [DataIntgWidth + BUS_DW - 1 : 0] data_and_intg_err_mask;
+ // Pre-populate str with format specifiers for the updated values that will be set later.
+ string str = {"TL data or integrity bits have been flipped, see the changes as below:\n",
+ $sformatf("\t a_data: 0x%0x\n", d_data), " -> 0x%0x"};
- if (rsp_and_intg_err_mask != '0) begin
- string str = "TL data or integrity bits have been flipped, see the changes as below: \n";
- str = $sformatf("%s\t a_data: 0x%0x -> 0x%0x\n", str, cur_item.a_data, a_data);
- str = $sformatf("%s\t data_intg: 0x%0x -> 0x%0x\n", str, cur_user.data_intg,
- final_user.data_intg);
+ // Flip data or intg ecc
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(data_and_intg_err_mask,
+ $countones(data_and_intg_err_mask) inside {[1 : max_ecc_errors]};)
+ {d_data, l_d_user.data_intg} ^= data_and_intg_err_mask;
+
+ str = $sformatf(str, d_data);
`uvm_info(`gfn, str, UVM_LOW)
end
- d_user = final_user;
- endfunction // update_d_chan_intg_val
+ d_user = l_d_user;
+ endfunction : inject_d_chan_intg_err
- virtual function bit is_a_user_ok(bit throw_error = 1'b1);
- tl_a_user_t exp_user = get_a_user_val();
- tl_a_user_t act_user = tl_a_user_t'(a_user);
+ virtual function bit is_a_chan_intg_ok(bit throw_error = 1'b1);
+ tl_a_user_t exp_a_user = compute_a_user();
+ tl_a_user_t act_a_user = tl_a_user_t'(a_user);
// TODO, #6887, dat_intg isn't implemented in design
- // is_a_user_ok = (act_user.cmd_intg == exp_user.cmd_intg) &&
- // (act_user.data_intg == exp_user.data_intg);
- is_a_user_ok = (act_user.cmd_intg == exp_user.cmd_intg);
+ // is_a_chan_intg_ok = act_a_user == exp_a_user;
+ is_a_chan_intg_ok = (act_a_user.cmd_intg == exp_a_user.cmd_intg);
- if (!is_a_user_ok) begin
- `uvm_info(`gfn, $sformatf(
- "cmd_intg act (0x%0x) != exp (0x%0x), data_intg act (0x%0x) != exp (0x%0x)",
- act_user.cmd_intg, exp_user.cmd_intg, act_user.data_intg, exp_user.data_intg),
- UVM_LOW)
+ if (!is_a_chan_intg_ok) begin
+ string str = $sformatf("cmd_intg act (%p) != exp (%p)", act_a_user, exp_a_user);
+ if (throw_error) begin
+ `uvm_error(`gfn, str)
+ end else begin
+ `uvm_info(`gfn, str, UVM_MEDIUM)
+ end
end
- if (!is_a_user_ok && throw_error) begin
- `uvm_error(`gfn, "a_user integrity check fails")
- end
- endfunction // is_a_user_ok
+ endfunction : is_a_chan_intg_ok
endclass
diff --git a/hw/dv/sv/tl_agent/tl_seq_item.sv b/hw/dv/sv/tl_agent/tl_seq_item.sv
index 9eac0aa..9881bd3 100644
--- a/hw/dv/sv/tl_agent/tl_seq_item.sv
+++ b/hw/dv/sv/tl_agent/tl_seq_item.sv
@@ -309,6 +309,23 @@
`uvm_error(`gfn, $sformatf("a_source: 0x%0h & d_source: 0x%0h mismatch", a_source, d_source))
endfunction
+ // Compute and check the integrity of the a_channel payload.
+ //
+ // The TL agent is generic and adheres to the TLUL spec, which does not define
+ // how the integrity of the payload on each channel is computed / checked. That
+ // is up to the chip implementation. Typically, parity / ECC scheme is used, with
+ // the redundant bits transmitted through *_user.
+ //
+ // Returns 1 if the integrity of a_channel is maintained, 0 otherwise. This base
+ // class implementation vacuously returns 1.
+ virtual function bit is_a_chan_intg_ok(bit throw_error = 1'b1);
+ return 1;
+ endfunction
+
+ // d_channel version of the function above
+ virtual function bit is_d_chan_intg_ok(bit throw_error = 1'b1);
+ return 1;
+ endfunction
endclass
`undef chk_prot_a_opcode
diff --git a/hw/top_earlgrey/dv/tb/chip_hier_macros.svh b/hw/top_earlgrey/dv/tb/chip_hier_macros.svh
index c82d2b4..4c14773 100644
--- a/hw/top_earlgrey/dv/tb/chip_hier_macros.svh
+++ b/hw/top_earlgrey/dv/tb/chip_hier_macros.svh
@@ -8,6 +8,7 @@
`define ALERT_HANDLER_HIER `CHIP_HIER.u_alert_handler
`define CLKMGR_HIER `CHIP_HIER.u_clkmgr_aon
`define CPU_HIER `CHIP_HIER.u_rv_core_ibex
+`define CPU_TL_ADAPT_D_HIER `CPU_HIER.tl_adapter_host_d_ibex
`define EFLASH_HIER `CHIP_HIER.u_flash_eflash.u_flash
`define GPIO_HIER `CHIP_HIER.u_gpio
`define OTP_CTRL_HIER `CHIP_HIER.u_otp_ctrl
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index 3122139..f004968 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -360,12 +360,18 @@
void'($value$plusargs("stub_cpu=%0b", stub_cpu));
if (stub_cpu) begin
force `CPU_HIER.clk_i = 1'b0;
- force `CPU_HIER.tl_d_o = cpu_d_tl_if.h2d;
+ // tl type is used to calculate ECC and we use DataType for cpu data interface
+ force cpu_d_tl_if.h2d.a_user.tl_type = tlul_pkg::DataType;
+ force `CPU_TL_ADAPT_D_HIER.tl_out = cpu_d_tl_if.h2d;
+ force cpu_d_tl_if.d2h = `CPU_TL_ADAPT_D_HIER.tl_i;
end else begin
+ // when en_sim_sram == 1, need to make sure the access to sim_sram doesn't appear on
+ // cpu_d_tl_if, otherwise, we may have unmapped access as scb doesn't regnize addresses of
+ // sim_sram. `CPU_HIER.tl_d_* is the right place to avoid seeing sim_sram accesses
force cpu_d_tl_if.h2d = `CPU_HIER.tl_d_o;
+ force cpu_d_tl_if.d2h = `CPU_HIER.tl_d_i;
end
end
- assign cpu_d_tl_if.d2h = `CPU_HIER.tl_d_i;
// otp test_access memory is only accessible after otp_init and lc_dft_en = 1.
// TODO: remove them once the otp/pwr otp/lc connections are completed.
diff --git a/hw/top_earlgrey/dv/tests/chip_base_test.sv b/hw/top_earlgrey/dv/tests/chip_base_test.sv
index f9fa64a..1da340b 100644
--- a/hw/top_earlgrey/dv/tests/chip_base_test.sv
+++ b/hw/top_earlgrey/dv/tests/chip_base_test.sv
@@ -20,6 +20,9 @@
string sw_images_plusarg;
super.build_phase(phase);
+ // TL integrity gen is in the design data path, no need to generate it in the agent
+ cfg.en_tl_intg_gen = 0;
+
// Knob to en/dis stubbing cpu (disabled by default).
void'($value$plusargs("stub_cpu=%0b", cfg.stub_cpu));
// Set tl_agent's is_active bit based on the retrieved stub_cpu value.