プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

SystemVerilog: ビット長拡張(符号拡張)の書き方

 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に接続される。

  1. unsigned'(src)、signed'(src) でsrcをunsigned型、signed型にキャスト
  2. 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