27 |
BSVの問題点? (2) |
Uartをテストベンチに組み込み動作しました。次にFIFO付Uartに改造しようとしたところ、FIFOを接続すると最初に0xAAという未定義データが受信FIFOに入ることがわかりました。
そこでverilogコードを出力し波形観測したところ、確かにリセット直後に0xAAという未定義データがUartから出力され受信FIFOに入力されています。図805.1のようにリセット直後にRDY_readがアサートされていることが判明しました。
UartとFIFOを接続しているverilogコードを確認すると、uart$RDY_readはreadメソッドを呼ぶとアサートされ、それによりENQされることが判明しました。
assign rfifo$ENQ = uart$RDY_read && rfifo$FULL_N ;
最初のFIFO無しの場合に動作していたのは、ステートマシンの値がデコードされていたのでリセット直後の値は無視されていたからです。一方FIFOを接続するとリセット直後からの未定義データもFIFOに入るため、エラーが顕在化したわけです。その理由は、以下のように常にuartをreadしてenqしているためです。
/* receiver */
rule forever_rfeceiver_inside;
let rdata <- uart.read;
rfifo.enq(rdata);
endrule
リセット直後にRDY_readが誤って出ているのではないかと言う推測をしました。ここで、readメソッドは以下のようになっており、getfsmという受信fsmの完了信号であるgetfsm.doneによりreadを開始する論理となっています(下記)。
Uart.bsv(変更前):
method ActionValue#(Bit#(8)) read if (getfsm.done);
getfsmDone <= False;
return idata;
endmethod
getfsm.doneは直接観測できないものの、これがRDY_readとなっているだろうと推測し、getfsm.doneの代わりに相当するgetfsmDone信号に入れ替えてみます(下記)。getfsmDoneを作成しているgetfsmの部分も含めて示します。
Uart.bsv:(変更後)
Stmt getseq = seq
await(isdata == 1'h0);
repeat (8) action
idata <= {isdata, (idata >> 1)[6:0]};
endaction
getfsmDone <= True;
endseq;
FSM getfsm <- mkFSM(getseq);
method ActionValue#(Bit#(8)) read if (getfsmDone);
getfsmDone <= False;
return idata;
endmethod
この修正によりリセット直後のRDY_readは出力されなくなり、FIFOを接続しても正しく動作しました。
まとめるとRDY_readがおかしいというより、初期状態でgetfsm.doneがTrueになる点がおかしいと思われます。
本件についてフォーラムに問い合わせたところ、「mkFSMのdoneメソッドは、startのRDYと等価である。startはリセット後にレディになるので、doneメソッドも trueになる。startが呼び出された後にのみTrueとなる条件が必要な場合は、自分で実装する必要がある。」、つまり初期状態でgetfsm.doneがTrueなのは仕様とのことでした。