Hi,
I have a basic testbench architecture where I have a driver, sequencer, sequence, seq_item. Now I want to layer the current sequence, what i exactly want to do is to use the current sequence’s generated data, modify it and drive it using the same driver.
The basic idea behind is somewhat like this:
consider one protocol that generates data packets, now there is another protocol that takes the data packet from prev protocol as input and then modifies it.
I tried creating an example of what I am trying to do which is as follows (There might be some basic thing that I am lacking in my env please let me know if you know any solution):
// CODE START //
`include "uvm_macros.svh"
interface dut_if;
logic clock, reset;
logic [7:0] data;
endinterface
module dut(dut_if dif);
import uvm_pkg::*;
initial begin
forever begin
@(posedge dif.clock);
`uvm_info("", $sformatf("Driven Data seen on interface data=%d", dif.data), UVM_MEDIUM)
end
end
endmodule
package my_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
class seq_item_base extends uvm_sequence_item;
`uvm_object_utils(seq_item_base)
rand int data;
constraint c_data { data == 5; }
function new (string name = "");
super.new(name);
endfunction
endclass: seq_item_base
class seq_item_1 extends seq_item_base;
`uvm_object_utils(seq_item_1)
rand int data1;
constraint c_data1 { data1 == 30; }
function new (string name = "");
super.new(name);
endfunction
endclass: seq_item_1
class seq_item_2 extends seq_item_base;
`uvm_object_utils(seq_item_2)
rand int data2;
function new (string name = "");
super.new(name);
endfunction
endclass: seq_item_2
class my_sequencer extends uvm_sequencer #(seq_item_base);
`uvm_component_utils(my_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class my_l1_seqr extends uvm_sequencer #(seq_item_1);
`uvm_component_utils(my_l1_seqr)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class sequence1 extends uvm_sequence #(seq_item_1);
`uvm_object_utils(sequence1)
rand int m_data;
function new (string name = "");
super.new(name);
endfunction
task body;
repeat(4)
begin
// 1. Create a sequence item of the given type
req = seq_item_1::type_id::create("req");
`uvm_info ("", $sformatf("About to call start_item"), UVM_MEDIUM)
// 2. Start the item on the sequencer which will send this to the driver
start_item(req);
`uvm_info ("", $sformatf("start_item() fn call done"), UVM_MEDIUM)
// 3. Do some late randomization to create a different content in this transaction object
assert(req.randomize());
`uvm_info ("", $sformatf("randomized with data=0x%0d", req.data), UVM_MEDIUM)
req.data = req.data1 + req.data;
// 4. Call finish_item to let driver continue driving the transaction object or sequence item
finish_item(req);
`uvm_info ("", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
end
endtask: body
endclass: sequence1
class sequence2 extends uvm_sequence #(seq_item_2);
`uvm_object_utils(sequence2)
uvm_sequencer #(seq_item_1) up_sequencer;
function new (string name = "");
super.new(name);
endfunction
task body;
seq_item_1 si1;
seq_item_2 si2;
forever begin
up_sequencer.get_next_item(si1);
si2 = seq_item_2::type_id::create();
start_item(si2);
si2.data = si1.data + 300;
finish_item(si2);
end
up_sequencer.item_done();
endtask
endclass: sequence2
class my_driver extends uvm_driver #(seq_item_base);
`uvm_component_utils(my_driver)
virtual dut_if dut_vi;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
// Get interface reference from config database
if( !uvm_config_db #(virtual dut_if)::get(this, "", "dut_if", dut_vi) )
`uvm_error("", "uvm_config_db::get failed")
endfunction
task run_phase(uvm_phase phase);
forever
begin
seq_item_port.get_next_item(req);
// Wiggle pins of DUT
@(posedge dut_vi.clock);
dut_vi.data = req.data;
`uvm_info("", $sformatf("Data recieved in the driver : data = %d", req.data), UVM_MEDIUM)
seq_item_port.item_done();
end
endtask
endclass: my_driver
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
my_sequencer m_seqr;
my_driver m_driv;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
m_seqr = my_sequencer::type_id::create("m_seqr", this);
m_driv = my_driver ::type_id::create("m_driv", this);
endfunction
function void connect_phase(uvm_phase phase);
m_driv.seq_item_port.connect(m_seqr.seq_item_export );
endfunction
endclass: my_agent
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_agent m_agent;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
m_agent = my_agent::type_id::create("m_agent", this);
endfunction
endclass: my_env
class my_test extends uvm_test;
`uvm_component_utils(my_test)
//sequence1 seq1;
my_l1_seqr l1_seqr;
sequence2 seq2;
my_env m_env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
m_env = my_env::type_id::create("m_env", this);
l1_seqr = my_l1_seqr::type_id::create("l1_seqr", this);
//seq1 = sequence1::type_id::create("seq1", this);
seq2 = sequence2::type_id::create("seq2", this);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
//seq1.start(m_env.m_agent.m_seqr);
seq2.start(l1_seqr);
phase.drop_objection(this);
endtask
endclass: my_test
endpackage: my_pkg
module top;
import uvm_pkg::*;
import my_pkg::*;
dut_if dut_if1 ();
dut dut1 ( .dif(dut_if1) );
// Clock generator
initial
begin
dut_if1.clock = 0;
forever #5 dut_if1.clock = ~dut_if1.clock;
end
initial
begin
uvm_config_db #(virtual dut_if)::set(null, "*", "dut_if", dut_if1);
uvm_top.finish_on_completion = 1;
run_test("my_test");
end
endmodule: top
// CODE END //