UVMに入門したくて、簡単な例を用いて試してみることにした。以下のようなシンプルなデザインをテストしたい。
次にMonitorとScoreboardについてみていこうと思う。
monitorについては、駆動側と同様にseq_item mon_item
を用意し、そこに工藤側から生成された入力値を入れておく。
そしてこのadder
は計算結果を出力するのに1サイクル必要なため、@(posedge vif.clk)
だけ待ってから、DUTの計算結果を格納する。
そして、その結果をitem_collect_port
に格納する。item_collect_port
はseq_item
を含んだuvm_analysis_port
で、これの詳細は正直よくわからない。
task run_phase (uvm_phase phase); forever begin wait(!vif.reset); @(posedge vif.clk); mon_item.ip1 = vif.ip1; mon_item.ip2 = vif.ip2; `uvm_info(get_type_name, $sformatf("ip1 = %0d, ip2 = %0d", mon_item.ip1, mon_item.ip2), UVM_HIGH); @(posedge vif.clk); mon_item.out = vif.out; item_collect_port.write(mon_item); end endtask
とにかく、このrun_phase
によって、item_collect_port.write()
が実行されすべての情報が格納されるというわけだ。
そして、scoreboard
によって検証が行われる。scoreboard
のrun_phase
はでは、item_q
の中から1つの要素が取り出され、計算結果があっているかの検証が行われる。
上記のmonitor
が、item_collect_port.write()
を呼び出したのは、下記のwrite()
と同一なのだろうか?この辺の詳細もよくわからない。
function void write(seq_item req); item_q.push_back(req); endfunction task run_phase (uvm_phase phase); seq_item sb_item; forever begin wait(item_q.size > 0); if(item_q.size > 0) begin sb_item = item_q.pop_front(); $display("----------------------------------------------------------------------------------------------------------"); if(sb_item.ip1 + sb_item.ip2 == sb_item.out) begin `uvm_info(get_type_name, $sformatf("Matched: ip1 = %0d, ip2 = %0d, out = %0d", sb_item.ip1, sb_item.ip2, sb_item.out),UVM_LOW); end else begin `uvm_error(get_name, $sformatf("NOT matched: ip1 = %0d, ip2 = %0d, out = %0d", sb_item.ip1, sb_item.ip2, sb_item.out)); end $display("----------------------------------------------------------------------------------------------------------"); end end endtask
つまり、UVMの検証環境は、スコアボードによってうまく一致が検出できるようにテストを構成できるか、というのが肝になるのではなかろうか。 つまり、一致比較が可能なようにテストを構成し、Scoreboardでうまく一致比較することがポイントとなる。