論理回路デザイン
ArchiTek home page
FPUの組み込みテスト

予め与える命令の設定

テストモジュールサンプル(RTL)

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

        Copyright (c) 2011, ArchiTek
        This document constitutes confidential and proprietary information
        of ArchiTek. All rights reserved.
        // このコードと前ページのコード、およびfifoのコードをコンパイルすれば結果が出る
        // なお、命令列はオーバーラップを考慮しないものである
*/

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

`timescale 1ps / 1ps

module test;

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

        parameter       D       = 1;
        parameter       DCLK    = 5000;
        parameter       DCLK2   = DCLK/2;

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

        reg             clk;

        reg             reset_n;

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

// -----------------------------------------------------------------------------
initial begin clk=0; forever begin #(DCLK2) clk=~clk; end end

// -----------------------------------------------------------------------------
initial begin reset_n=0; #D reset_n=0; #(DCLK*3.5) reset_n=1; end

// -----------------------------------------------------------------------------
top top_0 (
        clk, reset_n
        );

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

endmodule

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

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

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

module top (
        clk,
        reset_n
        );

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

        input           clk;
        input           reset_n;

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

        reg                     iVld;
        wire                    iStall;
        wire                    iOut;
        wire    [11:0]          iMCode;
        wire    [15:0]          iMA;
        wire    [15:0]          iMB;
        wire    [11:0]          iACode;
        wire    [15:0]          iAA;
        wire    [15:0]          iAB;

        wire                    oVld;
        reg                     oStall;
        wire    [15:0]          oMY;
        wire    [15:0]          oAY;
        reg     [7:0]           oCnt;

        reg     [1:0]           rst;
        reg                     reset;

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

// -----------------------------------------------------------------------------
// Pipeline drive
always @(posedge clk)
        if (reset)
                iVld    <= #1 1'b0;
        else if (!iStall)
                iVld    <= #1 $random;

always @(posedge clk)
        if (reset)
                oStall  <= #1 1'b0;
        else
                oStall  <= #1 $random;

always @(posedge clk)
        if (reset)
                oCnt    <= #1 8'd0;
        else
                oCnt    <= #1 oCnt + (oVld & !oStall);

// -----------------------------------------------------------------------------
// Clock & Reset
// Generate a synchronized reset
always @(posedge clk or negedge reset_n)
        if (!reset_n)
                rst     <= #1 2'b11;
        else
                rst     <= #1 {rst[0], 1'b0};

always @(posedge clk or negedge reset_n)
        if (!reset_n)
                reset   <= #1 1'b1;
        else
                reset   <= #1 rst[1];

// -----------------------------------------------------------------------------
// FPU
// 22個のレジスタを持つFPUとして設定
fpu #(2) fpu_0 (
        .iVld                   (iVld),
        .iStall                 (iStall),
        .iOut                   (iOut),
        .iMCode                 (iMCode),
        .iMA                    (iMA),
        .iMB                    (iMB),
        .iACode                 (iACode),
        .iAA                    (iAA),
        .iAB                    (iAB),
        .oVld                   (oVld),
        .oStall                 (oStall),
        .oMY                    (oMY),
        .oAY                    (oAY),
        .reset                  (reset),
        .clk                    (clk)
        );

// -----------------------------------------------------------------------------
// Sequencer
ts ts_0 (
        .iVld                   (iVld),
        .iStall                 (iStall),
        .iOut                   (iOut),
        .iMCode                 (iMCode),
        .iMA                    (iMA),
        .iMB                    (iMB),
        .iACode                 (iACode),
        .iAA                    (iAA),
        .iAB                    (iAB),
        .oVld                   (oVld),
        .oStall                 (oStall),
        .oMY                    (oMY),
        .oAY                    (oAY),
        .reset                  (reset),
        .clk                    (clk)
        );

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

endmodule

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

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

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

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

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

        input                    iVld;
        input                    iStall;
        output                   iOut;
        output  [11:0]           iMCode;
        output  [15:0]           iMA;
        output  [15:0]           iMB;
        output  [11:0]           iACode;
        output  [15:0]           iAA;
        output  [15:0]           iAB;
        input                    oVld;
        input                    oStall;
        input   [15:0]           oMY;
        input   [15:0]           oAY;
        input                    clk;
        input                    reset;

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

        reg                     iOut;
        reg     [11:0]          iMCode;
        reg     [15:0]          iMA;
        reg     [15:0]          iMB;
        reg     [11:0]          iACode;
        reg     [15:0]          iAA;
        reg     [15:0]          iAB;
        reg     [15:0]          expM;
        reg     [15:0]          expA;
        wire    [15:0]          resultM;
        wire    [15:0]          resultA;

        reg     [9:0]           iSc;
        reg     [9:0]           oSc;

        reg                     simEnd;
        wire                    doEnd;

        wire                    errY;

        wire                    iAlloc          = iVld & !iStall;
        wire                    oAlloc          = oVld & !oStall;

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

// Timing synchronizer for expectation
// iOutがアサートされるもののみFIFOに入れる、乗算器の結果は見なくてもいいが、参考のため記述
fifo #(33, 8) fifo_0 (
        .iVld                   (iAlloc & iOut),
        .iStall                 (),
        .iData                  ({simEnd, expM, expA}),
        .oVld                   (),
        .oStall                 (!oAlloc),
        .oData                  ({doEnd, resultM, resultA}),
        .reset                  (reset),
        .clk                    (clk)
        );

always @(posedge clk)
        if (oAlloc) begin
                case (errY)
                        1'b0:   $display(" OK : oMY=%4h\texpM=%4h\t\t
                                                oAY=%4h\texpA=%4h\t@%d",
                                                oMY, resultM, oAY, resultA, oSc);

                        1'b1:   $display(" NG : oMY=%4h\texpM=%4h\t\t
                                                oAY=%4h\texpA=%4h\t@%d",
                                                oMY, resultM, oAY, resultA, oSc);
                endcase

                if (doEnd)
                        $finish;
        end

assign errY             = (resultM != oMY) | (resultA != oAY);

// Test in counter
always @(posedge clk)
        if (reset)
                iSc     <= #1 10'd0;
        else
                iSc     <= #1 iSc + iAlloc;

// Test out counter
always @(posedge clk)
        if (reset)
                oSc     <= #1 10'd0;
        else
                oSc     <= #1 oSc + oAlloc;

// Test sequence
// iScをPCとして、Instructionと演算器の入力値を生成する
always @(
        iSc
        ) begin

        simEnd          = 1'b0;

        case (iSc)

        // Option___Imm_Alt_Reg#___Imm_Alt_Reg#___WE_Reg#
        // Result(R0a) <- (A0B0+C0C0)D0+(A1B1+C1C1)D1
        // Reg #のフィールド長はレジスタ数が4なので2
        // ここでは減算を使用しないので、Codeの先頭は常に0
        // NOPはWEを0にするだけで十分だが、全フィールド0にしている

        10'd0:          begin
                                iOut    = 1'b0;
                                // 2.5 x 0.375 -> R0m
                                iMCode  = 12'b0___10_00___10_00___1_00;
                                iMA     = 16'h4100;
                                iMB     = 16'h3600;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd1:          begin
                                iOut    = 1'b0;
                                // 1.5 x 1.5 -> R1m
                                iMCode  = 12'b0___10_00___10_00___1_01;
                                iMA     = 16'h3e00;
                                iMB     = 16'h3e00;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd2:          begin
                                iOut    = 1'b0;
                                // 0.625 x 0.5 -> R0m
                                iMCode  = 12'b0___10_00___10_00___1_00;
                                iMA     = 16'h3900;
                                iMB     = 16'h3800;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd3:          begin
                                iOut    = 1'b0;
                                // 1.0 x 1.0 -> R1m
                                iMCode  = 12'b0___10_00___10_00___1_01;
                                iMA     = 16'h3c00;
                                iMB     = 16'h3c00;
                                // R0m(2.5x0.375) + R1m(1.5x1.5) -> R0a
                                iACode  = 12'b0___01_00___01_01___1_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd4:          begin
                                iOut    = 1'b0;
                                // NOP
                                iMCode  = 12'b0___00_00___00_00___0_00;
                                iMA     = 16'h0000;
                                iMB     = 16'h0000;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd5:          begin
                                iOut    = 1'b0;
                                // 0.75 x R0a(2.5x0.375+1.5x1.5) -> R0m
                                iMCode  = 12'b0___10_00___01_00___1_00;
                                iMA     = 16'h3a00;
                                iMB     = 16'h0000;
                                // R0m(0.625x0.5) + R1m(1.0x1.0) -> R0a
                                iACode  = 12'b0___01_00___01_01___1_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd6:          begin
                                iOut    = 1'b0;
                                // NOP
                                iMCode  = 12'b0___00_00___00_00___0_00;
                                iMA     = 16'h0000;
                                iMB     = 16'h0000;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd7:          begin
                                iOut    = 1'b0;
                                // 0.125 x R0a(0.625x0.5+1.0x1.0) -> R1m
                                iMCode  = 12'b0___10_00___01_00___1_01;
                                iMA     = 16'h3000;
                                iMB     = 16'h0000;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd8:          begin
                                iOut    = 1'b0;
                                // NOP
                                iMCode  = 12'b0___00_00___00_00___0_00;
                                iMA     = 16'h0000;
                                iMB     = 16'h0000;
                                // NOP
                                iACode  = 12'b0___00_00___00_00___0_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h0000;
                                expA    = 16'h0000;
                        end

        10'd9:          begin
                                iOut    = 1'b1;
                                // NOP
                                iMCode  = 12'b0___00_00___00_00___0_00;
                                iMA     = 16'h0000;
                                iMB     = 16'h0000;
                                // R0m(0.75x(2.5x0.375+1.5x1.5)) +
                                // R1m(0.125x(0.625x0.5+1.0x1.0))
                                iACode  = 12'b0___01_00___01_01___1_00;
                                iAA     = 16'h0000;
                                iAB     = 16'h0000;
                                expM    = 16'h40c8;
                                expA    = 16'h411c;        // この値が最終的に出れば結果OK

                                // Simulation Terminate
                                simEnd  = 1'b1;
                        end
        endcase
end

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

endmodule

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

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

[1]
命令と入力値をPCに応じて主記憶などから読み出す細工をすれば、立派なプロセッサになります。ただし、メモリ語長と命令フィールド長のギャップが生じるかもしれません。その場合、命令の圧縮等を別途考える必要があります。
[2]
VLIW(Very Long Instruction Word)であってもコンパイラがあれば楽なのですが、独自のFPUに対するコンパイラをわざわざ作ることはまれです。従って、独自に記述することが多いと思います。

如何に空白区間をなくしコードを短くする(結果を速く出す)かは一種のパズルのようで、面白い人にとっては面白いようです。むしろ、無駄な空白(バブル)部分が多いのは許せないと言うこともあります。
[3]
単精度や倍精度になるとレイテンシが増える方向にあるため、フロー制御も複雑になってきます。演算器が仕事をしないバブルの期間も増えるので、せっかくなら異なるタスク(さまざまな計算)を間に入れ込んで機能を充実させることも一つの解だと思います。
[4]
さらなる性能が必要なら演算器を増やすことを考えます。水平構造なのでコストを考えなければ簡単に増設できます。ここの例で、FMulを1つではなく2つ実装すればコードがぐんと短くなることは容易に推察できることと思います。

ただし、必要に応じて入力値も同時に増やすことも考えねばなりません(ここが結構面倒だったりします)。