Verification Engineerの戯言
その2のコードに対して、decrementメソッドを追加します。
まず、interface/endinterfaceにdecrementメソッドを追加します。
まず、interface/endinterfaceにdecrementメソッドを追加します。
interface Counter; method Bit#(8) read(); method Action load(Bit#(8) newval); method Action increment(); method Action decrement(); endinterface
次にmkCounterモジュールにdecrementメソッドを追加します。
テストベンチ側も変更します。
rule step1(state == 1); counter.increment(); counter.decrement(); state <= 2; endrule
ここでテストベンチ(tbCounter.bsv)をコンパイルします。すると、次のようなエラーが表示されます。
% bsc tbCounter.sv "TbCounter.bsv", line XX, column YY: (G0004) Error: Rule RL_step1 uses write methods that conflict in parallel: counter.increment and counter.decrement
エラーメッセージからcounter.incrementとcounter.decrementがコンフリクトしています。
そこでstep1ルールを次のように3つのルール(step1a/step1b/step1c)に分けます。
rule step1a(state == 1); counter.increment(); endrule rule step1b(state == 1); counter.decrement(); endrule rule step1c(state == 1); state <= 2; endrule
テストベンチ(tbCounter.bsv)をコンパイルしてみます。すると、今度はワーニングが表示されます。
% bsc tbCounter.sv "TbCounter1.bsv", line XXX, column YYY: (G0010) Warning: Rule "step1b" was treated as more urgent than "step1a". Conflicts: "step1b" vs. "step1a": calls to counter.decrement vs. counter.increment "step1a" vs. "step1b": calls to counter.increment vs. counter.decrement "TbCounter1.bsv", line 13, column 14: (G0021) Warning: According to the generated schedule, rule "step1a" can never fire.
step1bとstep1aがまだ、コンフリクトします。そして、step1aは呼ばれないようです。
そうですよね! counter.incrementとcounter.decrementが同じクロックで呼ばれることは無いので!
そうですよね! counter.incrementとcounter.decrementが同じクロックで呼ばれることは無いので!
そこで、PulseWireの登場です。
PulseWire increment_called <- mkPulseWire(); PulseWire decrement_called <- mkPulseWire(); method Action increment(); increment_called.send(); endmethod method Action decrement(); decrement_called.send(); endmethod rule do_increment(increment_called && !decrement_called); value <= value + 1; endrule rule do_decrement(!increment_called && decrement_called); value <= value - 1; endrule
リファレンスガイドによると、PulseWireインターフェースは、次のようなメソッドを持っています。
interface PulseWire; method Action send(); method Bool _read(); endinterface
sendメソッドは、ワイヤにシグナルを送ります。
_readメソッドは、PulseWireインターフェースのインスタンスの値をリードしたときに呼ばれ、
シグナルがあるかどうか、つまり、sendメソッドが呼ばれたかどうかを示します。
_readメソッドは、PulseWireインターフェースのインスタンスの値をリードしたときに呼ばれ、
シグナルがあるかどうか、つまり、sendメソッドが呼ばれたかどうかを示します。
このPulseWireインターフェースのsendメソッドがincrement/decrementメソッド内で使われています。
mkPulseWireモジュールは、リファレンスガイドによると、
The writing to this type of wire is used in rules and action methods to send a single bit to signal other methods or rules in the same clock cycle.
にようです。in the same clock cycleというところがミソのようです。
incrementメソッドとdecrementメソッドが同じクロックで呼ばれると、
increment_calledとdecrement_calledが共にTRUEになるので、
結果として、do_incrementルールとdo_decrementルールは同時には実行されません。
increment_calledとdecrement_calledが共にTRUEになるので、
結果として、do_incrementルールとdo_decrementルールは同時には実行されません。
検証、Verification、Bluespec SystemVerilog
P.S
夏休みが終わった。
夏休みが終わった。