#Float計算回路のVerilog実装
~ FPGA に載せたい ~
オレオレ実装なので間違っていても知りません
浮動小数点数の説明から
正の加算まで
目的
floatの勉強
float32のハードウェア実装
浮動小数点数について
単精度小数点数について
Wikipedia
左から
・符号
・指数部(8bit)
・仮数部(23bit)
となる.
値の計算方法はざっくり
\text{value} = 仮数部 \times 2^{指数部}
と表される.
Wikipediaでは
{\displaystyle {\text{value}}=(-1)^{\text{sign}}\left(1+\sum _{i=1}^{23}\ b_{-i}2^{-i}\right)\times 2^{e-127}}
と記述されている.
仮数部の表記法 (例:7.25)
7 = 111 \\
0.25 = 0.01\\
7.25 = 111.01
先にも記したように指数部によっていくらでも
記述方法ができてしまう.
したがって, 最上位ビットを1とし、
以下が小数となるように決定する.
7.25 = 111.01 = 1.1101 \times 2^2
上記の最上位が1という条件から最上位は省略する.
7.25 = 1101 \times 2^2
指数部の表記法 (例:7.25)
上記より
7.25 = 1101 \times 2^2
2という情報を入れる.
指数部は 8bit であるため、
アンサインドなら 0 ~ 255
サインドなら -128 ~ 127
の値を取ることができる.
浮動小数点数では
アンサインドなサインド表記となる.
0 を 8'b0111_1111 と表記する.
2 は 8'b1000_0000 である.
つまり、127のバイアス値を加えた値として表記する.
たとえば、-42 は
127 + (-42) = 85 = 8'\text{b}0101\_0101
となる.
###特別な表記(0)
0 は 指数部を -128とするようである.
つまり指数部は 8'b0 となる.
##浮動小数点数の加算
オレオレ浮動小数点加算回路のタイミングは下の図のように設計した.
0加算を行わない, 正の数のみ.
以下詳細
1. 値の比較
数値比較を行い, 大きい方を vb(value big), 小さい方を vs(value small)へ格納する.
//TIM1
reg [31:0] vb;
reg [31:0] vs;
always @(posedge clk) begin
if (v2[30:23] < v1[30:23]) begin
vb <= v1;
vs <= v2;
end else begin
vb <= v2;
vs <= v1;
end
end
2. 指数部距離の計算
シフト量を把握するために, 各数値の指数部距離を計算する.
他はパイプライン時に潰されないように保護する.
//TIM2
reg [7:0] dexp;
reg [7:0] vexp;
reg [22:0] vb2;
reg [22:0] vs2;
always @(posedge clk) begin
dexp <= vb[30:23] - vs[30:23];
vexp <= vb[30:23];
vb2 <= vb[22:0];
vs2 <= vs[22:0];
end
3. 値のシフト, 加算の準備
加算のために1を付け加えたり, 値をシフトして桁を合わせておく.
この際小さい方の数値はシフト時に切り捨てる(正しいかどうかは知らない).
//TIM3
reg [7:0] vexp2;
reg [24:0] vb3;
reg [24:0] vs3;
always @(posedge clk) begin
vexp2 <= vexp;
vb3 <= {2'b1, vb2};
vs3 <= {1'b0, vssf({1'b1, vs2}, dexp)};
end
シフト方法は頭いい方法がわからなかったので適当に作りました.
//Value Small Shift Function
function [23:0] vssf(input [23:0] v, input [7:0] num);
begin
case(num)
8'd0: vssf = v;
8'd1: vssf = {1'b0, v[23:1]};
8'd2: vssf = {2'b0, v[23:2]};
8'd3: vssf = {3'b0, v[23:3]};
8'd4: vssf = {4'b0, v[23:4]};
8'd5: vssf = {5'b0, v[23:5]};
8'd6: vssf = {6'b0, v[23:6]};
8'd7: vssf = {7'b0, v[23:7]};
8'd8: vssf = {8'b0, v[23:8]};
8'd9: vssf = {9'b0, v[23:9]};
8'd10: vssf = {10'b0, v[23:10]};
8'd11: vssf = {11'b0, v[23:11]};
8'd12: vssf = {12'b0, v[23:12]};
8'd13: vssf = {13'b0, v[23:13]};
8'd14: vssf = {14'b0, v[23:14]};
8'd15: vssf = {15'b0, v[23:15]};
8'd16: vssf = {16'b0, v[23:16]};
8'd17: vssf = {17'b0, v[23:17]};
8'd18: vssf = {18'b0, v[23:18]};
8'd19: vssf = {19'b0, v[23:19]};
8'd20: vssf = {20'b0, v[23:20]};
8'd21: vssf = {21'b0, v[23:21]};
8'd22: vssf = {22'b0, v[23:22]};
8'd23: vssf = {23'b0, v[23]};
default: vssf = 24'b0;
endcase
end
endfunction
4. 加算
桁は合わせているため,加算を行うのみ.
//TIM4
reg [7:0] vexp3;
reg [24:0] r;
always @(posedge clk) begin
vexp3 <= vexp2;
r <= vb3 + vs3;
end
5. 型の生成
桁上がりを考慮してfloat型を生成する.
//TIM5
reg [31:0] res;
always @(posedge clk) begin
res[31] <= 1'b0;
if (r[24]) begin
res[30:23] <= vexp3 + 8'b1;
res[22:0] <= r[23:1];
end else begin
res[30:23] <= vexp3;
res[22:0] <= r[22:0];
end
end
できたコード
github
シミュレーションではエラーが出なかったことまで確認.