blob: fad2265fcd817bbff3653b89821299365e14ddfa [file] [log] [blame] [edit]
`include "svunit_defines.svh"
import uvm_pkg::*;
`include "uvm_macros.svh"
import svunit_pkg::*;
// Mock sequencer for sending transactions to the driver
class mock_sequencer extends uvm_sequencer #(my_transaction);
`uvm_sequencer_utils(mock_sequencer)
function new(input string name, uvm_component parent=null);
super.new(name, parent);
endfunction : new
// Check whether item_done was just called for the specified
// transaction_id.
// Return 1 if transaction_id matches, 0 otherwise.
function bit check_item_done(int transaction_id);
return transaction_id === m_wait_for_item_transaction_id;
endfunction
endclass
// Mock sequence to run on the mock sequencer.
class mock_sequence extends uvm_sequence #(my_transaction);
`uvm_sequence_utils(mock_sequence, mock_sequencer)
endclass
// SVUnit module must end with '_unit_test'
module my_driver_unit_test;
string name = "my_driver_ut";
svunit_testcase svunit_ut;
// This is the UUT that we're
// running the Unit Tests on
my_driver dut;
// The mock sequencer
mock_sequencer sequencer;
// Create the interface
logic clock;
wire select;
wire [3:0] data;
my_interface my_interface(.*);
// Build - runs once
function void build();
svunit_ut = new(name);
dut = my_driver::type_id::create("dut", null);
dut._if = my_interface;
// Connect transaction port to the driver
sequencer = mock_sequencer::type_id::create("sequencer", null);
dut.seq_item_port.connect(sequencer.seq_item_export);
dut.seq_item_port.resolve_bindings();
endfunction
// Setup before each test
task setup();
svunit_ut.setup();
// Clear the bus
clock = 0;
my_interface.cb.select <= 0;
my_interface.cb.data <= 0;
repeat (2) toggle_clock();
endtask
// Teardown after each test
task teardown();
svunit_ut.teardown();
endtask
// All tests are defined between the
// SVUNIT_TESTS_BEGIN/END macros
//
// Each individual test must be
// defined between `SVTEST(_NAME_) and `SVTEST_END
`SVUNIT_TESTS_BEGIN
// Test that driver sends one packet
`SVTEST(one_packet)
mock_sequence m_seq;
my_transaction req;
int data_to_send = 3;
req = new();
req.data = data_to_send;
m_seq = new();
// Run driver
fork: run
dut.run_phase(null);
begin
sequencer.wait_for_grant(m_seq);
sequencer.send_request(m_seq, req);
end
join_none
toggle_clock();
// Check that correct pins were driven
`FAIL_UNLESS(select === 1'b1);
`FAIL_UNLESS(data === data_to_send);
toggle_clock();
`FAIL_UNLESS(select === 1'b0);
`FAIL_UNLESS(data === 0);
// Make sure item_done is sent back
`FAIL_UNLESS(sequencer.check_item_done(req.get_transaction_id()));
// Stop driver
disable run;
`SVTEST_END
// Test that driver does not drive pins without a transaction
`SVTEST(no_packet)
// Run driver
fork: run
dut.run_phase(null);
join_none
// Make sure the pins stay at their default values.
repeat (10) begin
toggle_clock();
`FAIL_UNLESS(select === 1'b0);
`FAIL_UNLESS(data === 0);
end
// Set the pins to different values
my_interface.cb.select <= 1'bz;
my_interface.cb.data <= 4'hz;
// And make sure they stay that way
repeat (10) begin
toggle_clock();
`FAIL_UNLESS(select === 1'bz);
`FAIL_UNLESS(data === 4'hz);
end
// Stop driver
disable run;
`SVTEST_END
`SVUNIT_TESTS_END
task toggle_clock();
repeat (2) #5 clock = ~clock;
endtask // toggle_clock
initial begin
// Dump waves
$dumpvars(0, my_driver_unit_test);
end
endmodule