UVMのさらなるテストベンチを試行するために、以下のウェブサイトのサンプルを試してみることにした。
このページでは、別ページで作ったSystemVerilogのレジスタコントローラ(レジスタファイルみたいなもの)を検証するためのUVM環境を作り上げていくものになっている。
インタフェースとしてはこんな感じのデザイン:
module reg_ctrl #( parameter ADDR_WIDTH = 8, parameter DATA_WIDTH = 16, parameter DEPTH = 256, parameter RESET_VAL = 16'h1234 ) ( input logic clk, input logic rstn, input logic [ADDR_WIDTH-1: 0] addr, input logic sel, input logic wr, input logic [DATA_WIDTH-1: 0] wdata, output logic [DATA_WIDTH-1: 0] rdata, output logic ready );
UVMのインタフェースとして作っていくのは以下のようなクラス:
- Sequence Item (
reg_item.sv
) : ドライバに渡す前に入力アドレスと書き込みデータをランダム化するためのデータクラスを定義する。
class reg_item extends uvm_sequence_item; rand bit [`ADDR_WIDTH-1: 0] addr; rand bit [`DATA_WIDTH-1: 0] wdata; rand bit wr; bit [`DATA_WIDTH-1: 0] rdata;
- Driver (
driver.sv
) : このクラスは、reg_item
クラスをパラメータとして渡している。DUTのピンを駆動するためにvirtual
インタフェースを定義しおり、get_next_item
とitem_done
を使ってテスト値を受け取り、DUTのインタフェースを駆動する。
class driver extends uvm_driver #(reg_item); `uvm_component_utils (driver) function new (string name = "driver", uvm_component parent=null); super.new(name, parent); endfunction // new virtual reg_if vif; ... virtual task drive_item (reg_item m_item); vif.sel <= 1; vif.addr <= m_item.addr; vif.wr <= m_item.wr; vif.wdata <= m_item.wdata; @(posedge vif.clk); while (!vif.ready) begin `uvm_info ("DRV", "Wait until ready is high", UVM_LOW); @(posedge vif.clk); end vif.sel <= 0; endtask // drive_item
- Monitor (
monitor.sv
): virtualインタフェースを持っており、インタフェースの動作を監視する。ピンの動作を監視・デコードし、テストベンチのコンポーネントに渡す。この例では、DUTのインタフェースを監視しreg_item
インスタンスを作成し、analysis
ポートに渡している。
class monitor extends uvm_monitor; `uvm_component_utils(monitor) function new(string name="monitor", uvm_component parent=null); super.new(name, parent); endfunction // new ... virtual task run_phase (uvm_phase phase); super.run_phase (phase); // This task monitors the interface for a complete // translactions and writes into analysis port when complete `uvm_info (get_type_name(), $sformatf("Monitor found packet %s", item.convert2str()), UVM_LOW) mon_analysis_port.write(item); end // if (vif.sel) end // forever begin endtask // run_phase endclass // monitor
- Agent (
agent.sv
): Sequencer, Driver, Monitorを1つのコンテナに包含する。sequencerはシーケンスをドライバに渡す責任を持つ。
class agent extends uvm_agent; `uvm_component_utils(agent); function new(string name="agent", uvm_component parent=null); super.new(name, parent); endfunction // new driver d0; // Driver handle monitor m0; // Monitor handle uvm_sequencer #(reg_item) s0; // Sequencer Handle
スコアボードから先は、これから実装していく。