以下の文章は、読み物として読むには悪くないと思う(自分で書いていてなんですが)のですが、「要はどのサンプルを見ればいいか」が自分で読んでもわかりづらい気がしましたので、サンプルとして見ても らうコードを別出ししました。サンプルだけ見たい方は、基本スコアボードのサンプルを御覧ください。
期待値と観測値をインプットして、自動比較を行うコンポーネント、それがスコアボードなわけですが…ここでは、
を比べて遊んでみようと思います。クラスライブラリ未使用のスコアボードです。
まずmoduleで簡単に作ってみました。
`timescale 1ps/1psmodule m_scrbd; string name = "m_scrbd"; logic [7:0] exp_q[$]; logic [7:0] obs_q[$]; function void set_name(string _name); name = _name; endfunction function void write_exp(logic [7:0] data); exp_q.push_back(data); endfunction function void write_obs(logic [7:0] data); obs_q.push_back(data); endfunction initial begin forever begin wait(obs_q.size()!=0); if(exp_q[0]===obs_q[0]) $display("%0t [SCRBD] %s compare OK. data=%02xh", $time, name, exp_q[0]); else $display("%0t [SCRBD] %s compare NG. EXP=%02xh, OBS=%02xh", $time, name, exp_q[0], obs_q[0]); exp_q.delete(0); obs_q.delete(0); end endendmoduleさてここで問題です。このスコアボードは、データの型がlogic [7:0]です。32bitのデータ比較したければ、
まあ当然、後者の方が利便性が高いですね。だって、元の記述を直す必要がありませんから。
それでは次の問題です。スコアボードで、2種類のデータを比較しなければなりません。上記モデルでは1種類のデータしか比較できません。どうしますか?
さて、次の問題です。比較データを格納するclassを作ったとして、class定義が変わったらどうしますか?
では、このように作り変えたスコアボードを掲載します。
`timescale 1ps/1psmodule m_scrbd;`include "data_item.sv" string name = "m_scrbd"; //logic [7:0] exp_q[$]; //logic [7:0] obs_q[$]; data_item exp_q[$]; data_item obs_q[$]; data_item for_handle; function data_item get_handle(); for_handle = new(); return for_handle; endfunction function void set_name(string _name); name = _name; endfunction //function void write_exp(logic [7:0] data); function void write_exp(data_item item); exp_q.push_back(item); endfunction //function void write_obs(logic [7:0] data); function void write_obs(data_item item); obs_q.push_back(item); endfunction initial begin forever begin wait(obs_q.size()!=0); //if(exp_q[0]===obs_q[0]) if(exp_q[0].compare(obs_q[0]))begin $display("%0t [SCRBD] %s compare OK ===================================", $time, name); exp_q[0].print; end else begin $display("%0t [SCRBD] %s compare NG ===================================", $time, name); exp_q[0].print; obs_q[0].print; end exp_q.delete(0); obs_q.delete(0); end endendmoduledata_itemはこんな感じで。
class data_item; string name; logic [7:0] data0; logic [7:0] data1; function new (string name="data_item"); this.name = name; endfunction function bit compare(data_item item); if(data0===item.data0 && data1===item.data1)begin return 1; end else begin return 0; end endfunction function void set_data(logic [7:0] data0, data1); this.data0 = data0; this.data1 = data1; endfunction function void print; $display("----------------------------------------------------------"); $display("%0t [%s] data0 : %02xh", $time, name, data0); $display("%0t [%s] data1 : %02xh", $time, name, data1); $display("----------------------------------------------------------"); endfunctionendclass…って作ったら動かないですね。何がダメだったかというと、write_expとwrite_obsのfunctionが動かせない。どうやらclass周りの問題のようです。検証の方法は、tb_topからm_scrbdのdata_itemを、functionで returnし、tb_topのdata_itemと$castでcastingできるか否かで判断することにしました。
の3つの定義があります。で、ですね、以下を試行しました。
tb_top.sv
if($cast(item, _scrbd.get_handle()))m_scrbd.sv (instance is _scrbd)
function data_item get_handle(); for_handle = new(); return for_handle; endfunction以上のことより、1番のファイル構成でなければうまくいかない(modelsim ASEにて)ようです。面倒ですねー。1番の手法で実行した結果を掲載します。
# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 01h# 0 [EXP] data1 : 2bh# ----------------------------------------------------------# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 02h# 0 [EXP] data1 : 56h# ----------------------------------------------------------# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 03h# 0 [EXP] data1 : 01h# ----------------------------------------------------------# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 04h# 0 [EXP] data1 : 81h# ----------------------------------------------------------# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 05h# 0 [EXP] data1 : c4h# ----------------------------------------------------------# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 06h# 0 [EXP] data1 : 53h# ----------------------------------------------------------# 0 [SCRBD] m_scrbd compare OK ===================================# ----------------------------------------------------------# 0 [EXP] data0 : 07h# 0 [EXP] data1 : deh# ----------------------------------------------------------# ** Note: $finish : tb_top.sv(33)では次の問題です。moduleで定義したスコアボードをclass定義したらどんなメリットがあるでしょう?ぼくの答えは
説明していきます。
下記の太字のところ。moduleでは「値」をパラメータ化できましたが、classではそれだけでなく「型」もパラメータ化できます。ついでに、classではinitial文を使えないので、task文に変えています。
//module m_scrbd;class c_scrbd #(type T = int); string name = "m_scrbd"; //data_item exp_q[$]; //data_item obs_q[$]; T exp_q[$]; T obs_q[$]; function void set_name(string _name); name = _name; endfunction function void write_exp(T item); exp_q.push_back(item); endfunction function void write_obs(T item); obs_q.push_back(item); endfunction //initial begin virtual task run; forever begin wait(obs_q.size()!=0); //if(exp_q[0]===obs_q[0]) if(exp_q[0].compare(obs_q[0]))begin $display("%0t [SCRBD] %s compare OK ===================================", $time, name); exp_q[0].print; end else begin $display("%0t [SCRBD] %s compare NG ===================================", $time, name); exp_q[0].print; obs_q[0].print; end exp_q.delete(0); obs_q.delete(0); end //end endtaskendclassdata_itemの定義は変わりません。
tb_topはこんな感じで。太字のところはポイントです。
`timescale 1ps/1psmodule tb_top; `include "data_item.sv" `include "c_scrbd.sv" c_scrbd #(data_item) _scrbd; initial begin int i; data_item item; logic [7:0] data_q[$]; _scrbd = new(); fork _scrbd.run(); join_none // データ生成 for(i=0; i<8; i=i+1)begin data_q.push_back($urandom_range(255,0)); end for(i=0; i<8; i=i+1)begin item = new("EXP"); item.set_data(i, data_q[i]); _scrbd.write_exp(item); end for(i=0; i<8; i=i+1)begin item = new("OBS"); item.set_data(i, data_q[i]); _scrbd.write_obs(item); end #100 $finish; endendmodule