今回は、
1)符号付き2進数の加算方法
2)verilog code
3)膨らんだbit幅を削減する方法
を説明します.
1)符号付き2進数の加算方法
符号なしの加算はたとえばこんなです.そんなに困ったことはないです.(0.6.0)+(0.4.0)=(0.7.0)となりますのは前回で解説したとおりです.
36+13 = 49 100100 + 1101 = 0110001
ところが、つぎのような符号付きの加算は注意が必要です.
(-36)+(-13)=(-49)
やってみます.
まず、-36を符号付き2進数に変換します.関数電卓で変換すりゃ簡単ですが、ここでは手でやってみます.
①+36の2進数100100に符号bitを追加する.0100100 ←(1.6.0)になった
②各bitを反転させた1011011に+1して、1011100 を得る ←これが-36
つぎに、-13を符号付き2進数に変換します.
①+13の2進数1101に符号bitを追加する.01101 ←(1.4.0)になった
②各bitを反転させた10010に+1して、10011 を得る ←これが-13
では加算します.
1011100 + 10011 = 1101111
この右辺が-49になっているのかを確かめます.
③1101111の各bitを反転して、 0010000を得る
④0010000に+1して、0010001 を得る
⑤0010001を10進数に変換すると17です.つまり、上記の計算は-17という間違った答えを導き出してしまっています.
ムムッこれはイカン! どこで間違ったんだ?
その答えは、
符号付き2進数を加算するときには、符号拡張をしなくちゃいけない
という法則があります.
式: (-36)+(-13)=(-49) bit構成: (1.6.0) + (1.4.0) = (1.7.0)
符号付き加算回路を構成するには、出力のbit幅で入力を統一しなくちゃいけません.そういう操作を符号拡張と呼びます.つまりこうゆうbit構成にて計算します.
式: (-36)+(-13)=(-49) bit構成: (1.7.0) + (1.7.0) = (1.7.0)
-36の符号拡張のしかたはこうです.
-36=1011100=(1.6.0) → -36=11011100=(1.7.0)
-13の符号拡張のしかたはこうです.
-13=10011=(1.4.0) → -13=11110011=(1.7.0)
符号拡張でやることは、符号bitを必要なだけMSB側に並べることです.憶えましょう.
そして計算します.
11011100 + 11110011 = 11001111 bit構成: (1.7.0) + (1.7.0) = (1.7.0)
この右辺が-49になっているのかを確かめます.
③ 11001111 の各bitを反転して、 00110000を得る
④ 00110000 に+1して、 00110001 を得る
⑤ 00110001 を10進数に変換すると49です. やったー正答を得た!
ここまでの知見を元に verilog codeを書きますと、実は意外に簡単です.
変数にS36+S13=A49と名付けしますと、
// S36 (1.6.0) + S13 (1.4.0) = A49 (1.7.0)
wire [6:0] S36; // (1.6.0) -36
wire [4:0] S13; // (1.4.0) -13
wire [7:0] A49 = {S36[6],S36[6:0]} + {S13[4],S13[4],S13[4],S13[4:0]}; // (1.7.0) -49
赤いところが符号拡張です.符号付き加算にはこの操作が必ず必要です.かったるいですねー.
符号付き数値であっても、必ず正数だと判っているなら符号拡張は不要です.ゼロを符号拡張してもゼロですから.
2)verilog code
前回の例題であったこの回路をverilog codeで書いてみます.赤が符号拡張です.
wire [13:0] A1; // (1.7.6)
wire [14:0] A2; // (1.7.7)
wire [15:0] A = {A1[13],A1[13],A1} + {A2[14],A2}; // (1.8.7)
reg [15:0] B1; // (1.8.7)
always @(posedge clk or negedge xrst) if(!xrst) B1<=0; else B1<=A;
wire [14:0] B2; // (1.7.7)
wire [16:0] B = {B1[15],B1[15:0]} + {B2[14],B2[14],B2[14:0]}; // (1.9.7)
reg [16:0] C1; // (1.9.7)
always @(posedge clk or negedge xrst) if(!xrst) C1<=0; else C1<=B;
wire [14:0] C2; // (1.7.7)
wire [16:0] C = {C1[15],C1[15:0]} + {C2[14],C2[14],C2[14:0]}; // (1.9.7)
reg [16:0] D1; // (1.9.7)
always @(posedge clk or negedge xrst) if(!xrst) D1<=0; else D1<=C;
wire [13:0] D2; // (1.7.6)
wire [17:0] D = {D1[16],D1[16:0]} + {D2[13],D2[13],D2[13],D2[13],D2[13:0]}; // (1.10.7)
↑どうですか? 意外に簡単なcodeでホッとしたんじゃないかと思います.でも、目がチカチカして間違いやすいです.固定小数点演算回路はこのようにかったるい設計なんです.
3)膨らんだbit幅を削減する方法
すまんが長くなってしまったのでこれは次回にさしてくれ. つぎへ 前へ
人気ブログランキングへ
0 件のコメント:
コメントを投稿