mirror of https://github.com/XS-MLVP/picker.git
230 lines
8.1 KiB
Systemverilog
230 lines
8.1 KiB
Systemverilog
//==============================================================================
|
|
// File : example-uvm.sv
|
|
// Description: UVM testbench for Adder DUT with Python integration
|
|
// - UVM environment drives Adder DUT
|
|
// - Python can monitor/drive through Adder transaction
|
|
//==============================================================================
|
|
import uvm_pkg::*;
|
|
import uvmc_pkg::*;
|
|
|
|
// Include common utility package before agents
|
|
`include "RandomGenerator/utils_pkg.sv"
|
|
|
|
// Multi-transaction mode: include all transaction definitions and agents
|
|
`include "RandomGenerator_trans.sv"
|
|
`include "RandomGenerator/xagent.sv"
|
|
interface example_interface(input clk, input rst_n);
|
|
// RTL DUT signals
|
|
logic reset;
|
|
logic [15:0] seed;
|
|
logic [15:0] random_number;
|
|
endinterface //example_interface
|
|
|
|
// RTL Driver: drives the actual DUT based on transactions from Python
|
|
class rtl_driver extends uvm_component;
|
|
`uvm_component_utils(rtl_driver)
|
|
virtual example_interface vif;
|
|
uvm_blocking_put_imp#(RandomGenerator_trans, rtl_driver) put_export;
|
|
|
|
function new(string name = "rtl_driver", uvm_component parent = null);
|
|
super.new(name, parent);
|
|
put_export = new("put_export", this);
|
|
endfunction
|
|
|
|
virtual function void build_phase(uvm_phase phase);
|
|
super.build_phase(phase);
|
|
if(!uvm_config_db#(virtual example_interface)::get(this, "", "vif", vif))
|
|
`uvm_fatal("rtl_driver", "virtual interface must be set")
|
|
endfunction
|
|
|
|
virtual task put(RandomGenerator_trans tr);
|
|
drive_rtl(tr);
|
|
endtask
|
|
|
|
virtual task drive_rtl(RandomGenerator_trans tr);
|
|
// Drive RTL signals from transaction
|
|
vif.reset <= tr.reset;
|
|
vif.seed <= tr.seed;
|
|
@(posedge vif.clk); // Wait for clock edge
|
|
endtask
|
|
endclass
|
|
|
|
// RTL Monitor: samples RTL outputs and sends back to Python
|
|
// Inherits from generated xmonitor to directly use sequence_send
|
|
class example_monitor extends RandomGenerator_xmonitor;
|
|
`uvm_component_utils(example_monitor)
|
|
virtual example_interface vif;
|
|
|
|
function new(string name = "example_monitor", uvm_component parent = null);
|
|
super.new(name, parent);
|
|
endfunction
|
|
|
|
virtual function void build_phase(uvm_phase phase);
|
|
super.build_phase(phase);
|
|
if(!uvm_config_db#(virtual example_interface)::get(this, "", "vif", vif))
|
|
`uvm_fatal("example_monitor", "virtual interface must be set")
|
|
endfunction
|
|
|
|
virtual task run_phase(uvm_phase phase);
|
|
RandomGenerator_trans tr;
|
|
forever begin
|
|
@(posedge vif.clk);
|
|
tr = RandomGenerator_trans::type_id::create("tr");
|
|
// Sample RTL outputs
|
|
tr.random_number = vif.random_number;
|
|
tr.reset = vif.reset;
|
|
tr.seed = vif.seed;
|
|
tr.clk = 0; // Not relevant for output
|
|
|
|
// Directly send to Python using parent's method
|
|
sequence_send(tr);
|
|
end
|
|
endtask
|
|
endclass
|
|
|
|
// Multi-transaction mode: create drivers for each transaction type
|
|
class example_driver extends RandomGenerator_xdriver;
|
|
`uvm_component_utils(example_driver);
|
|
int transaction_count;
|
|
uvm_blocking_put_port#(RandomGenerator_trans) rtl_driver_port;
|
|
|
|
function new (string name = "example_driver", uvm_component parent = null);
|
|
super.new(name,parent);
|
|
transaction_count = 0;
|
|
rtl_driver_port = new("rtl_driver_port", this);
|
|
endfunction
|
|
|
|
virtual function void build_phase(uvm_phase phase);
|
|
super.build_phase(phase);
|
|
endfunction
|
|
|
|
virtual task sequence_receive(RandomGenerator_trans tr);
|
|
transaction_count++;
|
|
`uvm_info("example_driver", $sformatf("Received transaction #%0d from Python:\n%s",
|
|
transaction_count, tr.sprint()), UVM_LOW)
|
|
|
|
// Forward transaction to RTL driver
|
|
rtl_driver_port.put(tr);
|
|
endtask
|
|
|
|
function void report_phase(uvm_phase phase);
|
|
super.report_phase(phase);
|
|
`uvm_info("example_driver", $sformatf("Total transactions received: %0d", transaction_count), UVM_LOW)
|
|
endfunction
|
|
endclass
|
|
|
|
class example_env extends uvm_env;
|
|
`uvm_component_utils(example_env)
|
|
// Multi-transaction mode: one agent per transaction type
|
|
RandomGenerator_xagent RandomGenerator_agent;
|
|
RandomGenerator_xagent_config RandomGenerator_config;
|
|
example_driver RandomGenerator_drv;
|
|
|
|
// RTL components
|
|
rtl_driver rtl_drv;
|
|
// rtl_monitor removed, replaced by overridden RandomGenerator_xmonitor
|
|
|
|
virtual example_interface vif;
|
|
|
|
function new (string name = "example_env", uvm_component parent = null);
|
|
super.new(name,parent);
|
|
// Multi-transaction configs - use factory override for custom driver types
|
|
RandomGenerator_config = new("RandomGenerator_config");
|
|
// Set to UVM_ACTIVE for both monitor and driver (default behavior)
|
|
RandomGenerator_config.is_active = UVM_ACTIVE;
|
|
uvm_config_db#(RandomGenerator_xagent_config)::set(this,"RandomGenerator_agent", "RandomGenerator_xagent_config", RandomGenerator_config);
|
|
|
|
// Use factory override to replace default driver with example driver
|
|
set_type_override_by_type(RandomGenerator_xdriver::get_type(), example_driver::get_type());
|
|
// Use factory override to replace default monitor with example monitor
|
|
set_type_override_by_type(RandomGenerator_xmonitor::get_type(), example_monitor::get_type());
|
|
endfunction
|
|
|
|
function void build_phase(uvm_phase phase);
|
|
super.build_phase(phase);
|
|
// Build multi-transaction agents
|
|
RandomGenerator_agent = RandomGenerator_xagent::type_id::create("RandomGenerator_agent",this);
|
|
|
|
// Build RTL driver
|
|
rtl_drv = rtl_driver::type_id::create("rtl_drv", this);
|
|
|
|
if(!uvm_config_db#(virtual example_interface)::get(this,"","vif",vif))
|
|
`uvm_fatal("example_env","virtual interface must be set for vif")
|
|
|
|
// Set vif for RTL components
|
|
uvm_config_db#(virtual example_interface)::set(this, "rtl_drv", "vif", vif);
|
|
// Set vif for the overridden monitor inside the agent
|
|
// The monitor is created with name "{channel_name}_sub", typically "RandomGenerator_sub"
|
|
uvm_config_db#(virtual example_interface)::set(this, "RandomGenerator_agent.*", "vif", vif);
|
|
endfunction
|
|
|
|
function void connect_phase(uvm_phase phase);
|
|
super.connect_phase(phase);
|
|
|
|
// Connect Python driver to RTL driver
|
|
if (RandomGenerator_agent.RandomGenerator_xdrv != null) begin
|
|
if ($cast(RandomGenerator_drv, RandomGenerator_agent.RandomGenerator_xdrv)) begin
|
|
RandomGenerator_drv.rtl_driver_port.connect(rtl_drv.put_export);
|
|
end
|
|
end
|
|
endfunction
|
|
|
|
virtual task main_phase(uvm_phase phase);
|
|
phase.raise_objection(this);
|
|
// Just wait for Python to send transactions
|
|
// Python controls the simulation time via Step() calls
|
|
#10000; // Wait long enough for Python to complete
|
|
phase.drop_objection(this);
|
|
endtask
|
|
|
|
endclass
|
|
|
|
|
|
class example_test extends uvm_test;
|
|
`uvm_component_utils(example_test)
|
|
example_env env;
|
|
|
|
function new (string name = "example_test", uvm_component parent = null);
|
|
super.new(name,parent);
|
|
endfunction
|
|
|
|
function void build_phase(uvm_phase phase);
|
|
super.build_phase(phase);
|
|
env = example_env::type_id::create("example_env",this);
|
|
endfunction
|
|
endclass
|
|
|
|
|
|
module sv_main;
|
|
logic clk;
|
|
logic rst_n;
|
|
example_interface vif(clk,rst_n);
|
|
|
|
// Instantiate RandomGenerator RTL
|
|
RandomGenerator dut (
|
|
.clk(clk),
|
|
.reset(vif.reset),
|
|
.seed(vif.seed),
|
|
.random_number(vif.random_number)
|
|
);
|
|
|
|
initial begin
|
|
clk = 0;
|
|
forever begin
|
|
#2
|
|
clk <= ~clk;
|
|
end
|
|
end
|
|
|
|
initial begin
|
|
rst_n <= 1'b0;
|
|
#10
|
|
rst_n <= 1'b1;
|
|
end
|
|
|
|
initial begin
|
|
uvm_config_db #(virtual example_interface)::set(null,"uvm_test_top.example_env","vif",vif);
|
|
run_test("example_test");
|
|
end
|
|
endmodule
|