論理回路デザイン |
|
/* ****************************** MODULE PREAMBLE ****************************** Copyright (c) 2012, ArchiTek This document constitutes confidential and proprietary information of ArchiTek. All rights reserved. */ // ******************************* MODULE HEADER ******************************* module fmul ( iVld, iStall, iA, iB, oVld, oStall, oY, reset, clk ); // *************************** I/O DECLARATIONS ******************************** // Pipe Input input iVld; output iStall; input [15:0] iA; // Operand A input [15:0] iB; // Operand B // Pipe Output output oVld; input oStall; output [15:0] oY; // Result // Utility input reset; input clk; // ************************** LOCAL DECLARATIONS ******************************* // 便利信号の定義と同時に値を代入 wire aSign = iA[15]; wire [4:0] aExpo = iA[14:10]; wire [4:0] aExp = |aExpo ? aExpo : 5'h0f; wire [10:0] aFrac = {|aExpo, iA[9:0]}; wire aZero = ~|iA[14:0]; wire bSign = iB[15]; wire [4:0] bExpo = iB[14:10]; wire [4:0] bExp = |bExpo ? bExpo : 5'h0f; wire [10:0] bFrac = {|bExpo, iB[9:0]}; wire bZero = ~|iB[14:0]; wire expMin; wire [6:0] expTmp; wire expShift; // 2ステージ分の信号を定義、末尾DはFFのD端子信号(確定ではない) reg vld_0; reg vld_1; wire stall_0; wire stall_1; reg ySign_0; reg ySign_1; reg [6:0] yExp_0; reg [4:0] yExp_1; reg [4:0] yExp_1D; reg [12:0] yFrac_0; wire [21:0] yFrac_0D; reg [9:0] yFrac_1; wire [11:0] yFrac_1D; // ****************************** MODULE BODY ********************************** // ----------------------------------------------------------------------------- // Valid Path // ---- Input // 後方のStallを論理に加えバッファ型のステージに(以下同じ) // 添え字の番号は、0をスタートに番号付けしたステージ後方の境界を示す assign iStall = vld_0 & stall_0; // ---- Stage 0 always @(posedge clk) if (reset) vld_0 <= #1 1'b0; else if (!iStall) vld_0 <= #1 iVld; assign stall_0 = vld_1 & stall_1; // ---- Stage 1 always @(posedge clk) if (reset) vld_1 <= #1 1'b0; else if (!stall_0) vld_1 <= #1 vld_0; assign stall_1 = oStall; // ---- Alias // ステージの結果を出力信号にマッピング assign oVld = vld_1; // ----------------------------------------------------------------------------- // Sign Path // ---- Stage 0 - Result // 符号は単純な排他的論理和 always @(posedge clk) if (!iStall) ySign_0 <= #1 aSign ^ bSign; // ---- Stage 1 - Delay // 単にパイプするだけ always @(posedge clk) if (!stall_0) ySign_1 <= #1 ySign_0; // ---- Alias // ステージの結果を出力信号にマッピング assign oY[15] = ySign_1; // ----------------------------------------------------------------------------- // Exp Path // ---- Stage 0 - Sum of Exp // オペランドのいずれかが0なら指数も0、それ以外はBias分を引いた合計に // 合計結果を2ビット拡張し、アンダーフローはMSB、オーバーフローはMSBの次のビットが表現 always @(posedge clk) if (!iStall) yExp_0 <= #1 (aZero | bZero) ? 7'd0 : {2'd0, aExp} + {2'd0, bExp} - 7'h0f; // ---- Stage 1 - Carry Fix // 仮数部の計算結果が0およびアンダーフローの場合指数は0、計算結果ラッチ always @(posedge clk) if (!stall_0) yExp_1 <= #1 yExp_1D; always @( expTmp or expMin or yFrac_1D ) casex ({|yFrac_1D, expMin}) 2'b0x, 2'b11: yExp_1D = 5'h00; 2'b10: yExp_1D = expTmp[4:0]; endcase // アンダーフロー assign expMin = expTmp[6]; // 仮数部どうしの1.xxxと1.xxxを掛けると指数はデフォルトで1加算(結果のMSBは2の位なので) // 仮数部のMSBが0なら仮数部は左寄せするため、桁上がり分を補正(-1) // ただし、仮数部のMSBが0でもまるめで桁上がりの可能性を仮数部の左寄せの結果のMSBを見て判断 assign expTmp = yExp_0 - {6'd0, expShift} + 7'd1; assign expShift = expShiftFunc(yFrac_0) - yFrac_1D[11]; // ---- Alias // ステージの結果を出力信号にマッピング assign oY[14:10] = yExp_1; // ----------------------------------------------------------------------------- // Frac Path // ---- Stage0 - Separate Mul // 仮数部の乗算結果22ビットのうち上位13ビットをラッチ always @(posedge clk) if (!iStall) yFrac_0 <= #1 yFrac_0D[21:9]; // 高速化のためEDAベンダーの用意する掛け算ライブラリを使う場合もある assign yFrac_0D = aFrac * bFrac; // ---- Stage1 - Carry Fix and Remove Hidden MSB // ラッチ時は最終的な左寄せを行う(左寄せ2回目) always @(posedge clk) if (!stall_0) yFrac_1 <= #1 yFrac_1D[11] ? yFrac_1D[10:1] : yFrac_1D[9:0]; // 左寄せを行う(左寄せ1回目) // MSBは指数の補正に利用する(これがなければFunction内で左寄せの処理は閉じれる) assign yFrac_1D = fracShiftFunc(yFrac_0); // ---- Alias // ステージの結果を出力信号にマッピング assign oY[9:0] = yFrac_1; // ************************** FUNCTIONS and TASKS ****************************** // 仮数部のMSBをチェック、非正規化仮数部対応時は全ビットのチェックが必要 function expShiftFunc; input [12:0] frac; expShiftFunc = !frac[12]; endfunction // 左寄せの1回目とまるめ、まるめは左寄せ数により参照ビットが異なる // 入力MSBが1ならまるめてもオーバーフローしない(carry信号は0) // 入力MSBが0ならまるめるとオーバーフローする可能性がある(その場合carry信号は1) // 非正規化仮数部対応時は全ビットのチェックと左寄せが必要で論理が深い function [11:0] fracShiftFunc; input [12:0] frac; reg carry; reg [10:0] result; reg [10:0] adder0; reg [10:0] adder1; begin adder0 = {10'd0, frac[1]}; adder1 = {10'd0, frac[0]}; carry = (frac[12] == 1'b0) & (&frac[11:0]); casex (frac[12]) 1'h1: result = frac[12:2] + adder0; 1'h0: result = frac[11:1] + adder1; endcase fracShiftFunc = {carry, result}; end endfunction endmodule // *****************************************************************************
/* ****************************** MODULE PREAMBLE ****************************** Copyright (c) 2011, ArchiTek This document constitutes confidential and proprietary information of ArchiTek. All rights reserved. // 指数シフトが2以上あれば正規化が簡単になり、1以下であれば最初の桁合わせが簡単になる // 前者は最終段の正規化を前段に入れ込むことができ、後者は初段で桁合わせと加算を実行できる // それぞれ専用パスで回路を作れば、演算器は倍になるがレイテンシは2から1にすることができる // ここではその手法を採用していない */ // ******************************* MODULE HEADER ******************************* module fadd ( iVld, iStall, iA, iB, oVld, oStall, oY, reset, clk ); // *************************** I/O DECLARATIONS ******************************** // Pipe Input input iVld; output iStall; input [15:0] iA; // Operand A input [15:0] iB; // Operand B // Pipe Output output oVld; input oStall; output [15:0] oY; // Result // Utility input reset; input clk; // ************************** LOCAL DECLARATIONS ******************************* // 便利信号の定義と同時に値を代入 // allDirはオペランドの大きい方から小さい方を引くための判断に使う // expDirはオペランドどうしの指数を合わせるため、指数の大小の判断に使う wire aSign = iA[15]; wire [4:0] aExpo = iA[14:10]; wire [4:0] aExp = |aExpo ? aExpo : 5'h0f; wire [10:0] aFrac = {|aExpo, iA[9:0]}; wire aZero = ~|iA[14:0]; wire bSign = iB[15]; wire [4:0] bExpo = iB[14:10]; wire [4:0] bExp = |bExpo ? bExpo : 5'h0f; wire [10:0] bFrac = {|bExpo, iB[9:0]}; wire bZero = ~|iB[14:0]; wire allDir = ({aExp, aFrac} < {bExp, bFrac}); wire expDir = (aExp < bExp); wire [4:0] expAbs = expDir ? bExp - aExp : aExp - bExp; wire [3:0] expShift; // 2ステージ分の信号を定義、末尾DはFFのD端子信号(確定ではない) reg vld_0; reg vld_1; wire stall_0; wire stall_1; reg ySign_0; reg ySign_0D; reg ySign_1; reg yInv_0; wire yInv_0D; reg aInv_0D; reg bInv_0D; reg [4:0] yExp_0; reg [4:0] yExp_1; reg [4:0] yExp_0D; wire [4:0] yExp_1D; reg [10:0] aFrac_0; reg [10:0] bFrac_0; wire [10:0] aFrac_0D; wire [10:0] bFrac_0D; reg [10:0] aFracBar; reg [10:0] bFracBar; reg [10:0] pFrac; wire [10:0] qFrac; reg [9:0] yFrac_1; wire [11:0] yFrac_1D; wire [13:0] yFracTmp; reg [1:0] yFracRound_0; wire [1:0] yFracRound_0D; // ****************************** MODULE BODY ********************************** // ----------------------------------------------------------------------------- // Valid Path // ---- Input // 後方のStallを論理に加えバッファ型のステージに(以下同じ) // 添え字の番号は、0をスタートに番号付けしたステージ後方の境界を示す assign iStall = vld_0 & stall_0; // ---- Stage 0 always @(posedge clk) if (reset) vld_0 <= #1 1'b0; else if (!iStall) vld_0 <= #1 iVld; assign stall_0 = vld_1 & stall_1; // ---- Stage 1 always @(posedge clk) if (reset) vld_1 <= #1 1'b0; else if (!stall_0) vld_1 <= #1 vld_0; assign stall_1 = oStall; // ---- Alias // ステージの結果を出力信号にマッピング assign oVld = vld_1; // ----------------------------------------------------------------------------- // Sign Path // ---- Stage 0 - Result // オペランドの符号、0、大小関係から結果の符号を判断 // 特に減算の場合(符号が排他的)、いずれのオペランドの補数をとるかも決定 always @(posedge clk) if (!iStall) begin ySign_0 <= #1 ySign_0D; yInv_0 <= #1 yInv_0D; end always @( allDir or aSign or bSign or aZero or bZero ) casex ({aZero, bZero, aSign, bSign, allDir}) 5'b1xx0x: // B's Sign {ySign_0D, bInv_0D, aInv_0D} = 3'b000; 5'b1xx1x: // B's Sign {ySign_0D, bInv_0D, aInv_0D} = 3'b100; 5'b010xx: // A's Sign {ySign_0D, bInv_0D, aInv_0D} = 3'b000; 5'b011xx: // A's Sign {ySign_0D, bInv_0D, aInv_0D} = 3'b100; 5'b0000x: // + (|A|+|B|) {ySign_0D, bInv_0D, aInv_0D} = 3'b000; 5'b0011x: // - (|A|+|B|) {ySign_0D, bInv_0D, aInv_0D} = 3'b100; 5'b00010: // + (|A|-|B|) {ySign_0D, bInv_0D, aInv_0D} = 3'b010; 5'b00011: // - (|B|-|A|) {ySign_0D, bInv_0D, aInv_0D} = 3'b101; 5'b00100: // - (|A|-|B|) {ySign_0D, bInv_0D, aInv_0D} = 3'b110; 5'b00101: // + (|B|-|A|) {ySign_0D, bInv_0D, aInv_0D} = 3'b001; endcase assign yInv_0D = aInv_0D | bInv_0D; // ---- Stage 1 - Delay always @(posedge clk) if (!stall_0) ySign_1 <= #1 ySign_0; // ---- Alias // ステージの結果を出力信号にマッピング assign oY[15] = ySign_1; // ----------------------------------------------------------------------------- // Exp Path // ---- Stage 0 - Put Large Exp // 指数の大小関係から大きい方をラッチ、0の場合は他方をラッチ always @(posedge clk) if (!iStall) yExp_0 <= #1 yExp_0D; always @( expDir or aExp or bExp or aZero or bZero ) casex ({aZero, bZero, expDir}) 3'b1xx: yExp_0D = bExp; // B's Exp 3'b01x: yExp_0D = aExp; // A's Exp 3'b000: yExp_0D = aExp; // A's Exp 3'b001: yExp_0D = bExp; // B's Exp endcase // ---- Stage 1 - Normalize always @(posedge clk) if (!stall_0) yExp_1 <= #1 yExp_1D; // 仮数部どうしの1.xxxと1.xxxを足すと指数はデフォルトで1加算(結果のMSBは2の位なので) // 仮数部の左寄せ数はFunctionでチェック、その分の桁上がり分を補正 // ただし、仮数部のMSBが0でもまるめで桁上がりの可能性を仮数部の左寄せの結果のMSBを見て判断 assign yExp_1D = |yFrac_1D ? yExp_0 - {1'd0, expShift} + 5'd1 : 5'h00; assign expShift = expShiftFunc(yFracTmp) - {3'd0, yFrac_1D[11]}; // ---- Alias // ステージの結果を出力信号にマッピング assign oY[14:10] = yExp_1; // ----------------------------------------------------------------------------- // Frac Path // ---- Stage0 - Fix Same Column // 指数部の桁合わせをした仮数部とまるめ情報をラッチ always @(posedge clk) if (!iStall) begin aFrac_0 <= #1 aFrac_0D; bFrac_0 <= #1 bFrac_0D; yFracRound_0 <= #1 yFracRound_0D; end // 指数の大小関係からオペランドAが小さいなら下記の右寄せした結果を代入 always @( expDir or aZero or bZero or aFrac or qFrac ) casex ({bZero, aZero, expDir}) 3'bx1x: aFracBar = 11'h000; 3'b001: aFracBar = qFrac; default: aFracBar = aFrac; endcase // 指数の大小関係からオペランドBが小さいなら下記の右寄せした結果を代入 always @( expDir or aZero or bZero or bFrac or qFrac ) casex ({bZero, aZero, expDir}) 3'b1xx: bFracBar = 11'h000; 3'b000: bFracBar = qFrac; default: bFracBar = bFrac; endcase // 指数の小さい方を大きい方に合わせるため、仮数部を右寄せ always @( expDir or aZero or bZero or aFrac or bFrac ) casex ({bZero, aZero, expDir}) 3'bx1x: pFrac = aFrac; 3'b10x: pFrac = bFrac; 3'b001: pFrac = aFrac; 3'b000: pFrac = bFrac; endcase assign qFrac = bsftFunc(pFrac, expAbs); // 符号のところで求めた仮数部の補数の必要性から、先ずは1の補数を計算 // 補数を取るのはどちらか一方で、2つ同時はない assign aFrac_0D = compFunc(aFracBar, aInv_0D); assign bFrac_0D = compFunc(bFracBar, bInv_0D); // 下記の右寄せで捨てられるビットのMSBの2ビットをまるめ情報として取得 // 同時に補数の必要性を見て1の補数を実行(減算時は引く方が小さくなっている) assign yFracRound_0D = {2{yInv_0D}} ^ roundFunc(pFrac, expAbs); // ---- Stage1 - 2's Comlemet Add become always plus value // ラッチ時は最終的な左寄せを行う(左寄せ2回目) always @(posedge clk) if (!stall_1) yFrac_1 <= #1 yFrac_1D[11] ? yFrac_1D[10:1] : yFrac_1D[9:0]; // 左寄せを行う(左寄せ1回目) // MSBは指数の補正に利用する(これがなければFunction内で左寄せの処理は閉じれる) assign yFrac_1D = fracShiftFunc(yFracTmp); // 加算の本体、まるめと2の補数の+1をまとめて計算 assign yFracTmp = {1'd0, aFrac_0, 2'd0} + {1'd0, bFrac_0, 2'd0} + {12'd0, yFracRound_0} + {yInv_0, 12'd0, yInv_0}; // ---- Alias // ステージの結果を出力信号にマッピング assign oY[9:0] = yFrac_1; // ************************** FUNCTIONS and TASKS ****************************** // 1の補数 function [10:0] compFunc; input [10:0] frac; input sign; begin compFunc = sign ? ~frac : frac; end endfunction // 指数に従ったバレルシフト、指数はオペランドの指数の差分の絶対値(Priority encoder) function [10:0] bsftFunc; input [10:0] frac; input [4:0] exp; reg [5:0] idx; reg [10:0] result; integer i; begin for (i=0; i<11; i=i+1) begin idx = {1'b0, exp} + i[5:0]; if (idx > 6'd10) result[i] = 1'b0; else result[i] = frac[idx]; end bsftFunc = result; end endfunction // 上記バレルシフトで捨てるビットの上位2ビットを選択(Priority encoder) function [1:0] roundFunc; input [10:0] frac; input [4:0] exp; reg [5:0] idx; reg [10:0] result; integer i; begin for (i=0; i<11; i=i+1) begin idx = {1'b0, exp} + i[5:0] - 6'd11; if (idx[5] | (idx[4:0] > 5'd10)) result[i] = 1'b0; else result[i] = frac[idx]; end roundFunc = result[10:9]; end endfunction // 仮数部の有効桁をチェック、全ビットのチェックを実施(Priority encoder) function [3:0] expShiftFunc; input [13:0] frac; reg [3:0] idx; integer i; begin idx = 4'd10; for (i=0; i<12; i=i+1) if (frac[i+2]) idx = i[3:0]; expShiftFunc = 4'd11 - idx; end endfunction // 左寄せの1回目とまるめ、まるめは左寄せ数により参照ビットが異なる // 入力MSBが1ならまるめてもオーバーフローしない(carry信号は0) // 入力MSBが0ならまるめるとオーバーフローする可能性がある(その場合carry信号は1) // 減算の結果、上位のビットの多くが0に連なる場合があるので、全ビットのチェックが必要 // このあたりを工夫すれば偶数丸め可能 function [11:0] fracShiftFunc; input [13:0] frac; reg [11:0] result; reg [11:0] adder0; reg [11:0] adder1; reg [11:0] adder2; begin adder0 = {11'd0, frac[2]}; adder1 = {11'd0, frac[1]}; adder2 = {11'd0, frac[0]}; casex (frac) { 1'h1, 13'hxxxx}: result = {1'd0, frac[13:3]} + adder0; { 2'h1, 12'hxxx}: result = {1'd0, frac[12:2]} + adder1; { 3'h1, 11'hxxx}: result = {1'd0, frac[11:1]} + adder2; { 4'h1, 10'hxxx}: result = {1'd0, frac[10:0] }; { 5'h01, 9'hxxx}: result = {1'd0, frac[9:0], 1'd0}; { 6'h01, 8'hxx}: result = {1'd0, frac[8:0], 2'd0}; { 7'h01, 7'hxx}: result = {1'd0, frac[7:0], 3'd0}; { 8'h01, 6'hxx}: result = {1'd0, frac[6:0], 4'd0}; { 9'h001, 5'hxx}: result = {1'd0, frac[5:0], 5'd0}; {10'h001, 4'hx}: result = {1'd0, frac[4:0], 6'd0}; {11'h001, 3'hx}: result = {1'd0, frac[3:0], 7'd0}; {12'h001, 2'hx}: result = {1'd0, frac[2:0], 8'd0}; {13'h001, 1'hx}: result = {1'd0, frac[1:0], 9'd0}; default: result = {1'd0, 11'd0}; endcase fracShiftFunc = result; end endfunction endmodule // *****************************************************************************
回路デザイン > 設計例 [浮動小数点] > コーディング 次のページ(テスト) このページのTOP ▲