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
夏休みが終わった。
夏休みが終わった。