論理回路デザイン
ArchiTek home page
プロセッサのタネとしてのFPU

命令セットの定義

本体コード(RTL)

/* ****************************** MODULE PREAMBLE ******************************

        Copyright (c) 2012, ArchiTek
        This document constitutes confidential and proprietary information
        of ArchiTek. All rights reserved.
*/

// ******************************* MODULE HEADER *******************************

module fpu (
        iVld,
        iStall,
        iOut,
        iMCode,
        iMA,
        iMB,
        iACode,
        iAA,
        iAB,
        oVld,
        oStall,
        oMY,
        oAY,
        reset,
        clk
        );

// ************************ PARAMETER DECLARATIONS *****************************

        // レジスタファイルの数はパラメータで与える
        parameter               NR      = 1;            // Radix of register number
        parameter               N       = 1<<NR;

// *************************** I/O DECLARATIONS ********************************

        // Pipe Input
        input                   iVld;
        output                  iStall;
        // 出力タイミングを示し、これが伝搬してoVldになる
        input                   iOut;                   // Pipe out timing

        // ここがFMulのInstruction
        input   [3*NR+5:0]      iMCode;                 // Mul Op
                                                        // [3*NR+5]        Reserved
                                                        // [3*NR+4:2*NR+3] Operand0
                                                        // [2*NR+2:  NR+1] Operand1
                                                        //   MSB0: Imm Regsiter Sel
                                                        //   MSB1: Add Regsiter Sel
                                                        // [  NR  :   0  ] Dst
                                                        //   MSB : Write Enable (!NOP)
        // FMulのOperand A,Bに対する即値
        input   [15:0]          iMA;                    // Mul Operand0
        input   [15:0]          iMB;                    // Mul Operand1

        // ここがFAddのInstruction
        input   [3*NR+5:0]      iACode;                 // Add Op
                                                        // [3*NR+5]        Sub
                                                        // [3*NR+4:2*NR+3] Operand0
                                                        // [2*NR+2:  NR+1] Operand1
                                                        //   MSB0: Imm Regsiter Sel
                                                        //   MSB1: Mul Regsiter Sel
                                                        // [  NR  :   0  ] Dst
                                                        //   MSB : Write Enable (!NOP)
        // FAddのOperand A,Bに対する即値
        input   [15:0]          iAA;                    // Add Operand0
        input   [15:0]          iAB;                    // Add Operand1

        // Pipe Output
        // iVldに対して1対1ではなく、iVldとiOutが同時にアサートするものに対して
        output                  oVld;
        input                   oStall;
        // Mul/Addのレジスタ番号0の値をそれぞれ出力
        output  [15:0]          oMY;                    // Mul Result
        output  [15:0]          oAY;                    // Add Result

        // Utility
        input                   reset;
        input                   clk;

// ************************** LOCAL DECLARATIONS *******************************

        // 便利のためInstructionを分解しておく
        wire                    iMType          = iMCode[3*NR+5];
        wire                    iMImm0          = iMCode[3*NR+4];
        wire                    iMAlt0          = iMCode[3*NR+3];
        wire    [NR-1:0]        iMOp0           = iMCode[3*NR+2:2*NR+3];
        wire                    iMImm1          = iMCode[2*NR+2];
        wire                    iMAlt1          = iMCode[2*NR+1];
        wire    [NR-1:0]        iMOp1           = iMCode[2*NR:NR+1];
        wire                    iMEn            = iMCode[NR];
        wire    [NR-1:0]        iMDst           = iMCode[NR-1:0];

        wire                    iAType          = iACode[3*NR+5];
        wire                    iAImm0          = iACode[3*NR+4];
        wire                    iAAlt0          = iACode[3*NR+3];
        wire    [NR-1:0]        iAOp0           = iACode[3*NR+2:2*NR+3];
        wire                    iAImm1          = iACode[2*NR+2];
        wire                    iAAlt1          = iACode[2*NR+1];
        wire    [NR-1:0]        iAOp1           = iACode[2*NR:NR+1];
        wire                    iAEn            = iACode[NR];
        wire    [NR-1:0]        iADst           = iACode[NR-1:0];

        // Valid伝搬用のレジスタ(深いパイプ長の演算器を使うなら追加が必要)
        reg                     vld_0, vld_1;
        reg                     out_0;

        wire                    stall;          // 共通Stall

        // Instruction伝搬用のレジスタ(深いパイプ長の演算器を使うなら追加が必要)
        reg                     mEn_0;
        reg     [NR-1:0]        mDst_0;

        reg                     aEn_0;
        reg     [NR-1:0]        aDst_0;

        // それぞれの入力Operand
        reg     [15:0]          iMulOpA;
        reg     [15:0]          iMulOpB;

        reg     [15:0]          iAddOpA;
        reg     [15:0]          iAddOpB;
        wire    [15:0]          iAddNeg;

        // それぞれの出力結果
        wire    [15:0]          mulY;
        wire    [15:0]          addY;

        // 2次元配列でもいいが、後々alwaysのSensibility Listに入れる可能性を考慮
        // 簡単のためFFで構成(SRAMを採用するにはポート数や先行アクセスの問題が生じる)
        reg     [16*N-1:0]      mReg;
        reg     [16*N-1:0]      aReg;

// ****************************** MODULE BODY **********************************

// -----------------------------------------------------------------------------
// Valid & Parameter Path

// vld_1にはiOut(伝搬後のout_0)が織り込まれており、出力時にoStallがない限りiStallはデアサート
assign iStall           = vld_1 & oStall;

// ---- Stage 0
always @(posedge clk)
        if (reset) begin
                vld_0           <= #1 1'b0;
                out_0           <= #1 1'b0;
        end
        else if (!stall) begin
                vld_0           <= #1 iVld;
                out_0           <= #1 iOut;
        end

// 書き込みタイミングまで関係Instructionをパイプに流す(Enは上記説明のWEに相当)
always @(posedge clk)
        if (!stall) begin
                mEn_0           <= #1 iMEn;
                mDst_0          <= #1 iMDst;
                aEn_0           <= #1 iAEn;
                aDst_0          <= #1 iADst;
        end

// ---- Stage 1
always @(posedge clk)
        if (reset)
                vld_1           <= #1 1'b0;
        else if (!stall)
                vld_1           <= #1 vld_0 & out_0;

assign oVld             = iVld & vld_1;

// このモジュール全体のStall、iVldがなければStallさせる
assign stall            = !iVld | iStall;

// -----------------------------------------------------------------------------
// Multiplier Operand Sel
// FMulのOperandをInstructionにより選択
always @(
        iMImm0 or
        iMAlt0 or
        iMOp0 or
        iMA or
        mReg or
        aReg
        )
        casex ({iMImm0, iMAlt0})
                2'b1x:  iMulOpA         = iMA;
                2'b00:  iMulOpA         = selFunc(mReg, iMOp0);
                2'b01:  iMulOpA         = selFunc(aReg, iMOp0);
        endcase

always @(
        iMImm1 or
        iMAlt1 or
        iMOp1 or
        iMB or
        mReg or
        aReg
        )
        casex ({iMImm1, iMAlt1})
                2'b1x:  iMulOpB         = iMB;
                2'b00:  iMulOpB         = selFunc(mReg, iMOp1);
                2'b01:  iMulOpB         = selFunc(aReg, iMOp1);
        endcase

// -----------------------------------------------------------------------------
// Adder Operand Sel
// FAddのOperandをInstructionにより選択
always @(
        iAImm0 or
        iAAlt0 or
        iAOp0 or
        iAA or
        mReg or
        aReg
        )
        casex ({iAImm0, iAAlt0})
                2'b1x:  iAddOpA         = iAA;
                2'b00:  iAddOpA         = selFunc(aReg, iAOp0);
                2'b01:  iAddOpA         = selFunc(mReg, iAOp0);
        endcase

always @(
        iAImm1 or
        iAAlt1 or
        iAOp1 or
        iAB or
        mReg or
        aReg
        )
        casex ({iAImm1, iAAlt1})
                2'b1x:  iAddOpB         = iAB;
                2'b00:  iAddOpB         = selFunc(aReg, iAOp1);
                2'b01:  iAddOpB         = selFunc(mReg, iAOp1);
        endcase

// -----------------------------------------------------------------------------
// Multiplier
// 改変FMullをコール、結果mulYはMul用レジスタファイルに入る前の値
fmul_p mul_0 (
        .iA                     (iMulOpA),
        .iB                     (iMulOpB),
        .oStall                 (stall),
        .oY                     (mulY),
        .reset                  (reset),
        .clk                    (clk)
        );

// -----------------------------------------------------------------------------
// Adder
// 改変FAddlをコール、結果addYはAdd用レジスタファイルに入る前の値
fadd_p add_0 (
        .iA                     (iAddOpA),
        .iB                     (iAddOpB ^ iAddNeg),
        .oStall                 (stall),
        .oY                     (addY),
        .reset                  (reset),
        .clk                    (clk)
        );

// 演算オプションによりOperand Bの符号を反転(減算)
assign iAddNeg          = {iAType, 15'd0};

// -----------------------------------------------------------------------------
// Mul Register
// Mul InstructionでWEが'1'であった場合にのみMul用レジスタファイルに結果を格納
always @(posedge clk)
        if (!stall & mEn_0)
                mReg            <= #1 regFunc(mReg, mulY, mDst_0);

// R0を常に出力
assign oMY              = mReg[15:0];

// -----------------------------------------------------------------------------
// Add Register
// Add InstructionでWEが'1'であった場合にのみAdd用レジスタファイルに結果を格納
always @(posedge clk)
        if (!stall & aEn_0)
                aReg            <= #1 regFunc(aReg, addY, aDst_0);

// R0を常に出力
assign oAY              = aReg[15:0];

// ************************** FUNCTIONS and TASKS ******************************

// レジスタファイルからReg #で示されるレジスタを抽出
function [15:0] selFunc;
        input   [16*N-1:0]      plane;
        input   [NR-1:0]        ptr;
        reg     [15:0]          result;
        integer                 i;

        begin
                for (i=0; i<16; i=i+1)
                        result[i]       = plane[{ptr, i[3:0]}];

                selFunc         = result;
        end
endfunction

// レジスタファイルへReg #で示される値を上書き
function [16*N-1:0] regFunc;
        input   [16*N-1:0]      plane;
        input   [15:0]          data;
        input   [NR-1:0]        ptr;
        reg     [16*N-1:0]      result;
        integer                 i;
        integer                 j;

        begin
                for (i=0; i<N; i=i+1)
                        for (j=0; j<16; j=j+1)
                                result[{i[NR-1:0], j[3:0]}]
                                        // 該当レジスタへのみ入力値を代入
                                                = (i[NR-1:0] == ptr)
                                                        ? data[j]
                                                        : plane[{i[NR-1:0], j[3:0]}];

                regFunc         = result;
        end
endfunction

endmodule

// *****************************************************************************
        

改変FAddコード(RTL)

/* ****************************** MODULE PREAMBLE ******************************

        Copyright (c) 2011, ArchiTek
        This document constitutes confidential and proprietary information
        of ArchiTek. All rights reserved.
        faddに比べValid系統と最終段のLatch部を削除しているだけ
*/

// ******************************* MODULE HEADER *******************************

module fadd_p (
        iA,
        iB,

        oStall,
        oY,

        reset,
        clk

        );

// *************************** I/O DECLARATIONS ********************************

        // Pipe Input
        input   [15:0]          iA;                     // Operand A
        input   [15:0]          iB;                     // Operand B

        // Pipe Output
        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                    allDir          = ({aExp, aFrac} < {bExp, bFrac});
        wire                    expDir          = (aExp < bExp);

        wire    [4:0]           expAbs          = expDir ? bExp - aExp : aExp - bExp;
        wire    [3:0]           expSft;

        wire    [13:0]          fracFix;
        wire    [11:0]          fracTmp;

        reg                     ySign_0;
        reg                     ySign_0D;
        reg                     yInv_0;
        wire                    yInv_0D;
        reg                     aInv_0D;
        reg                     bInv_0D;

        reg     [4:0]           yExp_0;
        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_1D;
        reg     [1:0]           yFracRound_0;
        wire    [1:0]           yFracRound_0D;

// ****************************** MODULE BODY **********************************

// -----------------------------------------------------------------------------
// Sign Path

// ---- Stage 0 - Result
always @(posedge clk)
        if (!oStall) 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;

// ---- Alias
assign oY[15]           = ySign_0;

// -----------------------------------------------------------------------------
// Exp Path

// ---- Stage 0 - Put Large Exp
always @(posedge clk)
        if (!oStall)
                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
assign yExp_1D          = |fracTmp
                                ? yExp_0 - {1'd0, expSft} + 5'd1
                                : 5'h00;

assign expSft           = expShiftFunc(fracFix) - {3'd0, fracTmp[11]};

// ---- Alias
assign oY[14:10]        = yExp_1D;

// -----------------------------------------------------------------------------
// Frac Path

// ---- Stage0 - Fix Same Column
always @(posedge clk)
        if (!oStall) begin
                aFrac_0         <= #1 aFrac_0D;
                bFrac_0         <= #1 bFrac_0D;
                yFracRound_0    <= #1 yFracRound_0D;
        end

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

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);

assign aFrac_0D         = compFunc(aFracBar, aInv_0D);
assign bFrac_0D         = compFunc(bFracBar, bInv_0D);

assign yFracRound_0D    = {2{yInv_0D}} ^ roundFunc(pFrac, expAbs);

// ---- Stage1 - 2's Comlemet Add become always plus value
always @(
        fracTmp
        )
        yFrac_1D        = fracTmp[11]
                                ? fracTmp[10:1]
                                : fracTmp[9:0];

assign fracFix          = {1'd0, aFrac_0, 2'd0}
                        + {1'd0, bFrac_0, 2'd0}
                        + {12'd0, yFracRound_0}
                        + {yInv_0, 12'd0, yInv_0};

assign fracTmp          = fracShiftFunc(fracFix);

// ---- Alias
assign oY[9:0]          = yFrac_1D;

// ************************** FUNCTIONS and TASKS ******************************

function [10:0] compFunc;
        input   [10:0]          frac;
        input                   sign;

        begin
                compFunc        = sign ? ~frac : frac;
        end
endfunction

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

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

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

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

// *****************************************************************************
        

改変FMulコード(RTL)

/* ****************************** MODULE PREAMBLE ******************************

        Copyright (c) 2012, ArchiTek
        This document constitutes confidential and proprietary information
        of ArchiTek. All rights reserved.
        fmulに比べValid系統と最終段のLatch部を削除しているだけ
*/

// ******************************* MODULE HEADER *******************************

module fmul_p (
        iA,
        iB,

        oStall,
        oY,

        reset,
        clk

        );

// *************************** I/O DECLARATIONS ********************************

        // Pipe Input
        input   [15:0]          iA;                     // Operand A
        input   [15:0]          iB;                     // Operand B

        // Pipe Output
        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                    expSft;

        wire    [11:0]          fracSft;

        reg                     ySign_0;

        reg     [6:0]           yExp_0;
        reg     [4:0]           yExp_1D;

        reg     [12:0]          yFrac_0;
        wire    [21:0]          yFrac_0D;
        reg     [9:0]           yFrac_1D;

// ****************************** MODULE BODY **********************************

// -----------------------------------------------------------------------------
// Sign Path

// ---- Stage 0 - Result
always @(posedge clk)
        if (!oStall)
                ySign_0         <= #1 aSign ^ bSign;

// ---- Alias
assign oY[15]           = ySign_0;

// -----------------------------------------------------------------------------
// Exp Path

// ---- Stage 0 - Sum of Exp
always @(posedge clk)
        if (!oStall)
                yExp_0          <= #1 (aZero | bZero)
                                        ? 7'd0
                                        : {2'd0, aExp} + {2'd0, bExp} - 7'h0f;

// ---- Stage 1 - Carry Fix
always @(
        expTmp or
        expMin or
        fracSft
        )
        casex ({|fracSft, expMin})
                2'b0x,
                2'b11:  yExp_1D         = 5'h00;
                2'b10:  yExp_1D         = expTmp[4:0];
        endcase

assign expMin           = expTmp[6];

assign expTmp           = yExp_0 - {6'd0, expSft} + 7'd1;
assign expSft           = expShiftFunc(yFrac_0) - fracSft[11];

// ---- Alias
assign oY[14:10]        = yExp_1D;

// -----------------------------------------------------------------------------
// Frac Path

// ---- Stage0 - Separate Mul
always @(posedge clk)
        if (!oStall)
                yFrac_0         <= #1 yFrac_0D[21:9];

assign yFrac_0D         = aFrac * bFrac;

// ---- Stage1 - Carry Fix and Remove Hidden MSB
always @(
        fracSft
        )
        yFrac_1D        = fracSft[11]
                                ? fracSft[10:1]
                                : fracSft[9:0];

assign fracSft          = fracShiftFunc(yFrac_0);

// ---- Alias
assign oY[9:0]          = yFrac_1D;

// ************************** FUNCTIONS and TASKS ******************************

function expShiftFunc;
        input   [12:0]          frac;

        expShiftFunc    = !frac[12];
endfunction

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

// *****************************************************************************
        

回路デザイン > 設計例 [浮動小数点] > 応用FPUその1    次のページ(応用FPUその2)   このページのTOP ▲

[1]
フローを壊すと言うのは例えば、以下のようなことです。ハードウェアは最低限この回避に努める必要があります。

○早すぎる参照
・0番の演算結果R2を2番の演算で使用
・結果が後段Stallで書き込めない
・2番の命令で未書き込みR2を参照

○遅すぎる参照
・逆に、先ほどの書き込みは終了
・2番の命令が別の理由で発行できず
・発行済みの1番の命令でR2が上書き

    0: R0+R1->R2
    1: R2+R1->R2
    2: R2+R1->R3
    3: R2+R1->R4
      
[2]
昔の感覚で言うと、水平型 vs 垂直型はRISC vs CISCと言った感じでしょうか。RISCと言っても限られた命令長に収めるため垂直的な命令体系になる場合もあるのですが。

いずれにせよ、基本的に水平型は他の機能との依存関係がないのが前提なので、デコーダ・エンコーダ回路が無駄に加わることは少なくなります。その代わり命令を与える側に責任があります。

命令が変更できるのならいいのですが、LSI内で固定化されるとRISKは結局のところ同じ?(筆者はテストと思考ロジックが単純化するのでリスクは減るとの認識です)。
[3]
例はシンプルですが結構万能です。固定した計算式であれば大抵のことは対応できると思います。命令の分岐対応やフィールドの圧縮、依存関係の自動的な対処などやれることはあるのですが、GPUなど高級なものになればなるほど互換性等ややこしくなるのが常と言ったところでしょうか。