Mbitの信号をNbitに符号拡張したい、0fillしてビット長を変更したい場合、Verilogは書くのが面倒くさい。でも、SystemVerilogなら短く書けた。
結論
以下のコードで符号拡張、ビット長拡張が出来る。S,Dはパラメータでも、直値(数値)でも良い。
logic [S-1:0] src; logic [D-1:0] dst_unsigned , dst_signed; assign dst_unsigned = D'(unsigned'(src)); assign dst_signed = D'(signed'(src));
これ、assignで何やってるかというと、srcのキャストである。以下の様にキャストされてdstに接続される。
- unsigned'(src)、signed'(src) でsrcをunsigned型、signed型にキャスト
- D'(x)でxをDbitにサイズをキャスト
サイズをキャストする際には、符号が考慮される。unsignedは必要はないはずだが、明示した方がいいと思う。こう、暗黙って嫌いなんです。
詳細はSystemVerilog 3.1a Language Reference Manualを参照して欲しい。27p(PDFビューア上では43p)辺りである。
一応、Verilatorによるシミュレーション、Cadenceのツールによる合成で確認しています。あと、Quartus PrimeでElaborateは通った(ピンアサインとか面倒くさいし、合成はしてない)
Verilogでのよくある書き方
例えば、以下の記事の様に一般的な書き方をするとこうなる。
logic [S-1:0] src; logic [D-1:0] dst_unsigned,dst_signed; assign dst_unsigned = { {D-S{1'b0}} , src }; assign dst_signed = { {D-S{src[S-1]}} , src };
これ、問題があってD,Sがパラメタライズされていて、さらにD-S が0になるとき、処理系によってはエラーになるのだ。糞言語め。
先に示したキャストを使わずに、D=Sの問題を何とか回避しようとすると、以下の様にならざるを得ない。
always_comb begin dst_unsigned = {S{1'b0}}; dst_signed = {S{src[S-1]}}; dst_unsigned[S-1:0] = src; dst_signed[S-1:0] = src; end //もしくはfor文 always_comb begin int i; for(i = S; i < D ; i = i + 1)begin dst_unsigned[i] = 1'b0; dst_signed[i] = src[S-1]; end dst_unsigned[S-1:0] = src; dst_signed[S-1:0] = src; end
うーん、まぁ、合成は出来るだろうけど、綺麗じゃないよねぇ。
参考URL
- system verilog - How do I sign extend in SystemVerilog? - Stack Overflow:このベストアンサーが元ネタだけど、どういう意味なのか調べるのに苦労した
- Verilogの論理式の書き方
- ビット幅が異なる信号間のアサイン - Qiita