Float計算回路のVerilog-HDL実装について -その2.1(加算回路の共通化とタイミング調整)

#Float計算回路のVerilog実装
~ FPGA に載せたい ~
オレオレ実装なので間違っていても知りません

加算回路編
[Float計算回路のVerilog-HDL実装について -その１](https://qiita.com/Soleiyu/items/5bbb991de443e61e318e)

デバッグツール作成編
[Float計算回路の(ry-その１.１(float値の16進数表記)](https://qiita.com/Soleiyu/items/1fbdc78c68ad69a6d34d)

補足とLeadingZeros編
[Float計算回路のVerilog-HDL実装について -その1.5 (LeadingZeros)](https://qiita.com/Soleiyu/items/2fbd44883cfb1cdd253d)

減算回路編
[Float計算回路のVerilog-HDL実装について -その2(減算編)](https://qiita.com/Soleiyu/items/b56d3db666bd93f9ef75)

## 目的
floatの勉強
float32のハードウェア実装

その１で作成した加算回路とその２で作成した減算回路を共通化するため、
加算回路（のタイミングなどを）を調整する。

仕様はその１に準拠

## 仕様
下図右が前回作成した減算回路
下図左が今回作成した加算回路

4クロック目の符号のみ異なる

![addsub_timing2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253609/19c84ecb-2e37-d7f2-8337-707c05f511a8.png)

## 略コード

```float_add2.sv
module float_add(
	input wire clk,
	input wire [31:0] v1,
	input wire [31:0] v2,

	output wire [31:0] vres
);

	assign vres = res;

	//TIM1
	reg [31:0] vb;
	reg [31:0] vs;

	//TIM2
	reg [7:0] dexp;
	reg [7:0] vexp;
	reg [22:0] vb2;
	reg [22:0] vs2;
	
	//TIM3
	reg [7:0] vexp2;
	reg [24:0] vb3;
	reg [24:0] vs3;
	
	//TIM4
	reg [7:0] vexp3;
	reg [24:0] r;

	//TIM5,6
	reg [7:0] vexp4;
	reg [7:0] vexp5;
	reg [23:0] lzr;
	wire [7:0] lznum;
	wire [23:0] lzres;

	lzsv lzm(
		.clk(clk),
		.v(r),
		.num(lznum),
		.res(lzres)
	);

	//TIM7
	reg [31:0] res;

	always @(posedge clk) begin
		
		// TIM1 //
		if (v2[30:23] < v1[30:23]) begin
			vb <= v1;
			vs <= v2;
		end else if (v1[30:23] < v2[30:23]) begin
			vb <= v2;
			vs <= v1;
		end else if (v2[22:0] < v1[22:0]) begin
			vb <= v1;
			vs <= v2;
		end else begin
			vb <= v2;
			vs <= v1;
		end

		// TIM2 //
		dexp <= vb[30:23] - vs[30:23];
		vexp <= vb[30:23];

		vb2 <= vb;
		vs2 <= vs;

		// TIM3 //
		vexp2 <= vexp;
		
		vb3 <= {2'b1, vb2};
		vs3 <= {1'b0, vssf({1'b1, vs2}, dexp)};

		// TIM4 //
		vexp3 <= vexp2;

		r <= vb3 + vs3;
    //	r <= vb3 - vs3;

		// TIM5 //
		vexp4 <= vexp3;
		vexp5 <= vexp4 - lznum;
		
		lzr <= lzres;

		// TIM6 //
		res[31] <= 1'b0;
		res[30:23] <= vexp5;
		res[22:0] <= lzr[22:0];
	
	end

//Value Small Shift Function
function [23:0] vssf(input [23:0] v, input [7:0] num);
(略)
endfunction

endmodule
```

TIM4 のコメントアウトを逆にすることで、減算できることも確認できている

## 新しい LeadingZeros 用モジュール
加算回路でもLeadingZerosモジュールを使用するため、
桁下がりだけでなく、桁上がりにもこのLeadingZerosモジュールを対応させる必要がある

``` leadingzeros2.sv
module lzsv(
	input wire clk,
	input wire [24:0] v,

	output wire [7:0] num,
	output wire [23:0] res
);

// {num8, res24}
 reg [31:0] cnum;
 assign num = cnum[31:24];
 assign res = cnum[23:0];

always @(posedge clk) begin
	if (v[24]) cnum <= {8'hFF, v[24:1]};
	else if (v[23]) cnum <= {8'd0, v[23:0]};
	else if (v[22]) cnum <= {8'd1, v[22:0],  1'b0};
	else if (v[21]) cnum <= {8'd2, v[21:0],  2'b0};
	else if (v[20]) cnum <= {8'd3, v[20:0],  3'b0};
	else if (v[19]) cnum <= {8'd4, v[19:0],  4'b0};

    (略)

	else if (v[ 1]) cnum <= {8'd22, v[ 1:0], 22'b0};
	else if (v[ 0]) cnum <= {8'd23, 24'h800_000};
	else cnum <= {8'd24, 24'd0};
end

endmodule
```
桁計算時に-1を引くように仕向けるべく 24bit 目が 1 のとき FF(-1) を返す

## シミュレーション結果
```math
123.4 + 7.25 = 130.65\\
=> 42F6\_CCCD + 40E8\_0000 = 4302\_A666
```
![Screenshot from 2020-05-16 20-46-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253609/34778e11-480d-40e8-ee0d-3523ae152df4.png)


```math
123.4 - 7.25 = 116.15\\
=> 42F6\_CCCD - 40E8\_0000 = 42E8\_4CCD
```

![Screenshot from 2020-05-16 20-53-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253609/fa2df3fa-cde7-2e3c-9ce8-0a6b4ed19779.png)