2012年6月22日金曜日

FPGA FMトランスミッタ: 避けては通れぬ?2の補数(その2)

Verilog-2001から符号付き数値がサポートされましたが、Webの記事を見るとクセがあるようです。signedと宣言すれば安心、とは行かないところが中途半端な気がします。下記の例はISimを使って試してみた結果です。

(1)符号拡張
8ビットから15ビットへの変換例
左右のビット幅が異なってもVerilogではエラーになりません。例として良くないですが。

いずれもOK
input signed [7:0] a;
output signed [14:0] answer;
output [14:0] answer2, answer3, answer4;

wire [14:0] temp;

assign temp = a;
assign answer = a;
assign answer2 = a;

assign answer3 = temp;
assign answer4 = {{7{a[7]}}, a};

いずれもNG
input [7:0] a;
output signed [14:0] answer, answer2;
output [14:0] answer3;


wire signed [14:0] temp;

assign temp = a;
assign answer = a;
assign answer2 = temp;
assign answer3 = temp;


signed使わない例
input [7:0] a;
output [14:0] answer;

assign answer = {{7{a[7]}}, a};

(2)シフト演算
符号を保持してシフトする演算例
算術シフト演算子を使う場合
input signed [7:0] a;
output signed [14:0] answer;
output signed [14:0] answer2;

assign answer = a>>>2;
assign answer2 = a<<<2; // 右側は0詰めされる


自力で符号拡張する場合
input [7:0] a;
output [14:0] answer;

output [14:0] answer2;

assign answer = {{9{a[7]}}, a[7:2]};
assign answer2 = {{7{a[7]}}, a, 2'b0};

(3)正負の反転
input signed [7:0] a;
output signed [7:0] answer;

assign answer = - a;


(4)加算
input signed [7:0] a, b;
output [7:0] answer;

assign answer = a + b;


(5)減算
input signed [7:0] a, b;
output [7:0] answer;

assign answer = a - b;


(6)乗算
input signed [7:0] a, b;
output [14:0] answer;

assign answer = a * b;
ただし、負の最大値同士の乗算でビット溢れが出ます。これを避けるためには出力のビット幅を8+8=16ビットとします。


(7)signedとunsignedが混在する場合
Webの記事で、オペランドの両方がsignedでないとunsignedとして演算されてしまうと注意がありました。さらにこのページでは、シミュレータ目線で解説されています。
これらの記事を要約すると

・全てのオペランドがsignedでないとunsignedとして演算される
・ビットセレクトはunsigned (例) a[7:2]
・連接演算結果はunsigned
・比較演算結果は1ビットでunsigned
・複雑な式はsigned/unsignedが明示的になるように分解して記述した方がよい

unsignedをsignedに変換するには、1ビット符号拡張して符号を付ける。(MSBが1だった場合に負の数と誤認されてしまうため)
wire signed [8:0] temp;
assign temp = $signed({1'b0, a[7:0]});



参考資料

0 件のコメント:

コメントを投稿