[ibex, dv] Makes delays between req, gnt and rvalid configurable

This commit adds functionalty to the memory response agent to make delays more
configurable.
There are two delays
- Delay between req and gnt
- Delay between gnt and rvalid

For each of these delays we have three modes:
* Fully random delay
* Fixed delay
* Biased delay. Randomised delays but allow biasing towards 0 delay, to give a mix of runs with back
to back transfers with no delay and some with delays.

Signed-off-by: Prajwala Puttappa <prajwalaputtappa@lowrisc.org>
This commit is contained in:
Prajwala Puttappa 2022-02-24 15:03:11 +00:00 committed by prajwalaputtappa
parent 46c397501d
commit af0c027867
6 changed files with 73 additions and 60 deletions

View file

@ -19,10 +19,10 @@ package ibex_mem_intf_agent_pkg;
typedef uvm_sequencer#(ibex_mem_intf_seq_item) ibex_mem_intf_request_sequencer;
`include "ibex_mem_intf_monitor.sv"
`include "ibex_mem_intf_response_agent_cfg.sv"
`include "ibex_mem_intf_response_driver.sv"
`include "ibex_mem_intf_response_sequencer.sv"
`include "ibex_mem_intf_response_seq_lib.sv"
`include "ibex_mem_intf_response_agent_cfg.sv"
`include "ibex_mem_intf_response_agent.sv"
`include "ibex_mem_intf_request_driver.sv"
`include "ibex_mem_intf_request_agent.sv"

View file

@ -34,7 +34,8 @@ class ibex_mem_intf_response_agent extends uvm_agent;
driver.seq_item_port.connect(sequencer.seq_item_export);
monitor.addr_ph_port.connect(sequencer.addr_ph_port.analysis_export);
end
driver.vif = cfg.vif;
driver.cfg = cfg;
sequencer.cfg = cfg;
endfunction : connect_phase
function void reset();

View file

@ -13,11 +13,17 @@ class ibex_mem_intf_response_agent_cfg extends uvm_object;
// delay between request and grant
int unsigned gnt_delay_min = 0;
int unsigned gnt_delay_max = 1000;
int unsigned gnt_delay_max = 10;
// Pick the weight assigned to choosing medium and long gaps between request and grant
int unsigned gnt_pick_medium_speed_weight = 1;
int unsigned gnt_pick_slow_speed_weight = 1;
// delay between grant and rvalid
int unsigned valid_delay_min = 1;
int unsigned valid_delay_max = 1000;
int unsigned valid_delay_min = 0;
int unsigned valid_delay_max = 20;
// Pick the weight assigned to choosing medium and long gaps between grant and rvalid
int unsigned valid_pick_medium_speed_weight = 1;
int unsigned valid_pick_slow_speed_weight = 1;
// Enables/disable all protocol delays.
rand bit zero_delays;

View file

@ -8,10 +8,7 @@
class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item);
virtual ibex_mem_intf vif;
int unsigned min_grant_delay = 0;
int unsigned max_grant_delay = 10;
ibex_mem_intf_response_agent_cfg cfg;
`uvm_component_utils(ibex_mem_intf_response_driver)
`uvm_component_new
@ -25,12 +22,12 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
virtual task run_phase(uvm_phase phase);
reset_signals();
wait (vif.response_driver_cb.reset === 1'b0);
wait (cfg.vif.response_driver_cb.reset === 1'b0);
forever begin
fork : drive_stimulus
send_grant();
get_and_drive();
wait (vif.response_driver_cb.reset === 1'b1);
wait (cfg.vif.response_driver_cb.reset === 1'b1);
join_any
// Will only be reached after mid-test reset
disable fork;
@ -50,27 +47,27 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
end
end while (req != null);
reset_signals();
wait (vif.response_driver_cb.reset === 1'b0);
wait (cfg.vif.response_driver_cb.reset === 1'b0);
endtask
virtual protected task reset_signals();
vif.response_driver_cb.rvalid <= 1'b0;
vif.response_driver_cb.grant <= 1'b0;
vif.response_driver_cb.rdata <= 'b0;
vif.response_driver_cb.rintg <= 'b0;
vif.response_driver_cb.error <= 1'b0;
cfg.vif.response_driver_cb.rvalid <= 1'b0;
cfg.vif.response_driver_cb.grant <= 1'b0;
cfg.vif.response_driver_cb.rdata <= 'b0;
cfg.vif.response_driver_cb.rintg <= 'b0;
cfg.vif.response_driver_cb.error <= 1'b0;
endtask : reset_signals
virtual protected task get_and_drive();
wait (vif.response_driver_cb.reset === 1'b0);
wait (cfg.vif.response_driver_cb.reset === 1'b0);
fork
begin
forever begin
ibex_mem_intf_seq_item req, req_c;
vif.wait_clks(1);
cfg.vif.wait_clks(1);
seq_item_port.get_next_item(req);
$cast(req_c, req.clone());
if(~vif.response_driver_cb.reset) begin
if(~cfg.vif.response_driver_cb.reset) begin
rdata_queue.put(req_c);
end
seq_item_port.item_done();
@ -85,23 +82,27 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
virtual protected task send_grant();
int gnt_delay;
forever begin
while(vif.response_driver_cb.request !== 1'b1) begin
vif.wait_neg_clks(1);
while(cfg.vif.response_driver_cb.request !== 1'b1) begin
cfg.vif.wait_neg_clks(1);
end
if (!std::randomize(gnt_delay) with {
gnt_delay dist {
min_grant_delay :/ 1,
[min_grant_delay+1 : max_grant_delay-1] :/ 1,
max_grant_delay :/ 1
};
}) begin
`uvm_fatal(`gfn, $sformatf("Cannot randomize grant"))
if(cfg.zero_delays) begin
gnt_delay = 0;
end else begin
if (!std::randomize(gnt_delay) with {
gnt_delay dist {
cfg.gnt_delay_min :/ 10,
[cfg.gnt_delay_min+1 : cfg.gnt_delay_max-1] :/ cfg.valid_pick_medium_speed_weight,
cfg.gnt_delay_max :/ cfg.valid_pick_slow_speed_weight
};
}) begin
`uvm_fatal(`gfn, $sformatf("Cannot randomize grant"))
end
end
vif.wait_neg_clks(gnt_delay);
if(~vif.response_driver_cb.reset) begin
vif.response_driver_cb.grant <= 1'b1;
vif.wait_neg_clks(1);
vif.response_driver_cb.grant <= 1'b0;
cfg.vif.wait_neg_clks(gnt_delay);
if(~cfg.vif.response_driver_cb.reset) begin
cfg.vif.response_driver_cb.grant <= 1'b1;
cfg.vif.wait_neg_clks(1);
cfg.vif.response_driver_cb.grant <= 1'b0;
end
end
endtask : send_grant
@ -109,19 +110,19 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
virtual protected task send_read_data();
ibex_mem_intf_seq_item tr;
forever begin
vif.wait_clks(1);
vif.response_driver_cb.rvalid <= 1'b0;
vif.response_driver_cb.rdata <= 'x;
vif.response_driver_cb.rintg <= 'x;
vif.response_driver_cb.error <= 'x;
cfg.vif.wait_clks(1);
cfg.vif.response_driver_cb.rvalid <= 1'b0;
cfg.vif.response_driver_cb.rdata <= 'x;
cfg.vif.response_driver_cb.rintg <= 'x;
cfg.vif.response_driver_cb.error <= 'x;
rdata_queue.get(tr);
if(vif.response_driver_cb.reset) continue;
vif.wait_clks(tr.rvalid_delay);
if(~vif.response_driver_cb.reset) begin
vif.response_driver_cb.rvalid <= 1'b1;
vif.response_driver_cb.error <= tr.error;
vif.response_driver_cb.rdata <= tr.data;
vif.response_driver_cb.rintg <= tr.intg;
if(cfg.vif.response_driver_cb.reset) continue;
cfg.vif.wait_clks(tr.rvalid_delay);
if(~cfg.vif.response_driver_cb.reset) begin
cfg.vif.response_driver_cb.rvalid <= 1'b1;
cfg.vif.response_driver_cb.error <= tr.error;
cfg.vif.response_driver_cb.rdata <= tr.data;
cfg.vif.response_driver_cb.rintg <= tr.intg;
end
end
endtask : send_read_data

View file

@ -8,15 +8,13 @@
class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
int max_rvalid_delay = 20;
int min_rvalid_delay = 0;
ibex_mem_intf_seq_item item;
mem_model m_mem;
bit enable_error = 1'b0;
ibex_mem_intf_seq_item item;
mem_model m_mem;
bit enable_error = 1'b0;
// Used to ensure that whenever inject_error() is called, the very next transaction will inject an
// error, and that enable_error will not be flipped back to 0 immediately
bit error_synch = 1'b1;
bit is_dmem_seq = 1'b0;
bit error_synch = 1'b1;
bit is_dmem_seq = 1'b0;
`uvm_object_utils(ibex_mem_intf_response_seq)
`uvm_declare_p_sequencer(ibex_mem_intf_response_sequencer)
@ -41,12 +39,18 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
data == item.data;
intg == item.intg;
be == item.be;
rvalid_delay dist {
min_rvalid_delay :/ 5,
[min_rvalid_delay + 1 : max_rvalid_delay / 2 - 1] :/ 3,
[max_rvalid_delay / 2 : max_rvalid_delay - 1] :/ 1,
max_rvalid_delay :/ 1
};
if (p_sequencer.cfg.zero_delays) {
rvalid_delay == 0;
} else {
rvalid_delay dist {
p_sequencer.cfg.valid_delay_min :/ 5,
[p_sequencer.cfg.valid_delay_min + 1 : p_sequencer.cfg.valid_delay_max / 2 - 1] :/ 3,
[p_sequencer.cfg.valid_delay_max / 2 : p_sequencer.cfg.valid_delay_max - 1]
:/ p_sequencer.cfg.valid_pick_medium_speed_weight,
p_sequencer.cfg.valid_delay_max
:/ p_sequencer.cfg.valid_pick_slow_speed_weight
};
}
error == enable_error;
}) begin
`uvm_fatal(`gfn, "Cannot randomize response request")

View file

@ -10,6 +10,7 @@ class ibex_mem_intf_response_sequencer extends uvm_sequencer #(ibex_mem_intf_seq
// TLM port to peek the address phase from the response monitor
uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) addr_ph_port;
ibex_mem_intf_response_agent_cfg cfg;
`uvm_component_utils(ibex_mem_intf_response_sequencer)