本篇是讨論SystemVerilog接口和接口參數化處理政策的三部分系列的第三部分。
在本系列的第一部分中,介紹了SystemVerilog接口的基本概念,并描述了這些接口的參數化會引入testbench代碼的問題。在第二部分中,描述了使用通路者類來屏蔽VIP代碼與參數化效果的方法,但是該解決方案對VIP通路該接口施加了新的限制。在本系列的最後一篇文章中,介紹了一個允許測試平台使用參數化接口的過程,而不對VIP可以通路其提供的接口的方式施加任何限制。
最大足迹:兩全其美
使用當今現有的SystemVerilog功能無法解決參數化接口引入動态測試平台代碼的問題。是以,我們必須設計一種方法來避免将這些參數暴露給VIP代碼。本系列的前一篇文章介紹了實作此目的的accessor類。另一種解決方案是定義VIP可以與之互動的最大占用空間樣式接口,以及一個參數化接口,它包裝最大占用空間接口并連接配接到最大占用空間接口所需的信号。
最大占用空間類型接口定義每個信号的最大寬度,并且可以配置各個VIP元件以利用來自這些信号的切片。這允許多個具有不同寬度的VIP執行個體,并且不需要參數化類來使用參數化接口。以下代碼段示範了這些概念。
首先,我們定義最大足迹樣式接口。請注意,此接口未參數化,因為這是VIP代碼将與之互動的接口:
// Redefinable max footprint
`ifndef MAX_DATA_WIDTH
`define MAX_DATA_WIDTH 32
`endif
interface max_footprint_if;
logic clk;
logic[`MAX_DATA_WIDTH-1:0] data_in;
logic[`MAX_DATA_WIDTH-1:0] data_out;
clocking active_cb @(posedge clk);
default input #1 output #1;
input data_in;
output data_out;
endclocking
modport active_mp (clocking active_cb);
endinterface
typedef virtual max_footprint_if max_footprint_vif;
接下來,定義參數化接口,用于包裝最大足迹接口:
interface param_if#(int width = 8);
logic clk;
logic[width-1:0] data_in;
logic[width-1:0] data_out;
max_footprint_if internal_if();
assign internal_if.clk = clk;
// Z values driven on unused inputs of the max footprint
assign internal_if.data_in = {`MAX_DATA_WIDTH'hz, data_in};
// Only selected output values used from the max footprint
assign data_out = internal_if.data_out[width-1:0];
endinterface
在此之後,實作VIP代碼以使用最大足迹接口而不是參數化接口。下面顯示的另一個類(未在前面的文章中顯示)是配置類,用于定義每個VIP執行個體的信号寬度。該解決方案産生的另一個複雜因素是VIP在采樣和驅動信号時必須使用比特技術。這很不幸,但SystemVerilog文法強大,可以解決這個問題。
//=======================================================================
class cust_cfg extends uvm_object;
rand int data_width;
constraint valid_data_width {
data_width inside {8, 16, 32};
}
…
//=======================================================================
class cust_driver extends uvm_driver#(cust_data);
max_footprint_vif vif;
cust_cfg cfg;
`uvm_component_utils(cust_driver)
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(max_footprint_vif)::get(this, "", "vif", vif))
`uvm_fatal("build", "A valid virtual interface was not received.");
if (!uvm_config_db#(cust_cfg)::get(this, "", "cfg", cfg))
`uvm_fatal("build", "A valid configuration was not received.");
…
task consume_from_seq_item_port();
seq_item_port.get_next_item(req);
vif.active_cb.prop_out <= ((req.prop <> (`MAX_DATA_WIDTH-cfg.data_width));
@(vif.active_cb);
…
task sample_signals();
bit[31:0] sampled_prop_in = ((vif.active_cb.prop_in <> (`MAX_DATA_WIDTH-cfg.data_width));
VM_LOW);
@(vif.active_cb);
…
//=======================================================================
class cust_agent extends uvm_agent;
`uvm_component_utils(cust_agent)
max_footprint_vif vif;
cust_driver driver;
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(max_footprint_vif)::get(this, "", "vif", vif))
`uvm_fatal("build", "A valid virtual interface was not received.");
if (!uvm_config_db#(cust_cfg)::get(this, "", "cfg", cfg))
`uvm_fatal("build", "A valid configuration was not received.");
uvm_config_db#(max_footprint_vif)::set(this, "driver", "vif", vif);
uvm_config_db#(cust_cfg)::set(this, "driver", "cfg", cfg);
driver = cust_driver::type_id::create("driver", this);
…
最後,介紹了測試平台代碼。測試用例可以在不參數化的情況下通路VIP,并且執行個體化接口的頂層子產品可以使用參數化接口。還顯示了為每個VIP執行個體建立配置對象的附加步驟(這不是一個額外的步驟,因為早期的解決方案也需要這樣做,但為了簡潔而省略了)。
利用最大足迹樣式接口進行VIP通路信号,可以建立VIP代碼,而無需參數化VIP代碼。定義參數化接口允許測試平台利用它們啟用的改進的內建功能。使用參數化接口來包裝最大足迹接口的政策可以實作兩種樣式的優勢。
//=======================================================================
class cust_test extends uvm_test;
cust_cfg cfg8;
cust_cfg cfg16;
cust_cfg cfg32;
cust_agent agent8;
cust_agent agent16;
cust_agent agent32;
virtual function void build_phase(uvm_phase phase);
cfg8 = new("cfg8");
cfg8.data_width = 8;
uvm_config_db#(cust_cfg)::set(this, "agent8", "cfg", cfg8);
agent8 = cust_agent::type_id::create("agent8", this);
cfg16 = new("cfg16");
cfg16.data_width = 16;
uvm_config_db#(cust_cfg)::set(this, "agent16", "cfg", cfg16);
agent16 = cust_agent::type_id::create("agent16", this);
cfg32 = new("cfg32");
cfg32.data_width = 32;
uvm_config_db#(cust_cfg)::set(this, "agent32", "cfg", cfg32);
agent32 = cust_agent::type_id::create("agent32", this);
endfunction
endclass
//=======================================================================
module test_top;
param_if#(8) if8();
param_if#(16) if16();
param_if#(32) if32();
initial begin
uvm_config_db#(max_footprint_vif)::set(uvm_root::get(), "uvm_test_top.agent8", "vif", if8.internal_if);
uvm_config_db#(max_footprint_vif)::set(uvm_root::get(), "uvm_test_top.agent16", "vif", if16.internal_if);
uvm_config_db#(max_footprint_vif)::set(uvm_root::get(), "uvm_test_top.agent32", "vif", if32.internal_if);
run_test("cust_test");
end
endmodule