論理回路デザイン
ArchiTek home page
コーディング2

コード(LoadData RTL)

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

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

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

module fftLoadData (
        iVld, iStall, iRadix,

        oVld, oStall, oFlip,

        mStrb, mAck, mData,

        ram0WE, ram1WE, ram2WE, ram3WE,
        ram0WA, ram1WA, ram2WA, ram3WA,
        ram0WD, ram1WD, ram2WD, ram3WD,

        reset, clk

        );

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

        // 最大のポイント数の指数はカウンタ等のビット範囲を定める
        parameter               MRR     = 10;           // Max Radix Radix

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

        // Pipe Input
        // iRadixはiVldに同期していれば、タスクごとに値の変更が可能
        input                   iVld;
        output                  iStall;
        input   [3:0]           iRadix;

        // Pipe Output
        // oVldは処理の終了を伝達するために存在
        output                  oVld;
        input                   oStall;
        output  [1:0]           oFlip;

        // Memory Interface
        // メモリI/Fに接続してもよいし、データを供給するパイプにつなげてもよい
        output                  mStrb;
        input                   mAck;
        input   [127:0]         mData;

        // SRAMはトップモジュールで定義
        // SRAM
        output                  ram0WE, ram1WE, ram2WE, ram3WE;
        output  [MRR-3:0]       ram0WA, ram1WA, ram2WA, ram3WA;
        output  [31:0]          ram0WD, ram1WD, ram2WD, ram3WD;

        // Utility
        input                   reset;
        input                   clk;

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

        // Counter
        // Radix-4は4つ同時に処理するので、カウンタもN/4個数えればよい
        reg     [MRR-3:0]       cnt, iCnt;
        wire                    fin, iFin;

        // Pipeline (Valid Control)
        // パイプラインは0,1,2の3段、SuffixはパイプラインStageを示す
        reg                     vld_0, vld_1, vld_2;
        reg                     fin_0, fin_1, fin_2;
        reg     [MRR-3:0]       cnt_0, cnt_1;
        reg     [3:0]           radix_0, radix_1;
        // この信号(p)は分岐・結合のため別途定義している
        wire                    vld_0p;
        wire                    stall_0p;

        // Pipeline (Stall Control)
        wire                    stall_s, stall_0, stall_1, stall_2;

        // Pipeline (Data)
        reg     [127:0]         data_1, data_2;
        reg     [MRR-1:0]       addr0_2, addr1_2, addr2_2, addr3_2;

        // SRAM Flip
        reg                     flip;

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

// -----------------------------------------------------------------------------
// Control
// 最終カウントがパイプラインへ投入した後Stallを解放
// 終端からStallが伝搬しているので注意(トップモジュールのFIFOでタイミングアークは切断)
assign iStall           = iVld & (!iFin | stall_s);
assign iFin             = fin;

// -----------------------------------------------------------------------------
// Counter
// iCntのデフォルト設定はポイント数2^10、MRRを増やす場合は隙間(10,12,14,,,)を積み増して行く
// case()文でiRadix依存しない記述方法があればそれを採用すべき
always @(posedge clk)
        if (reset)
                cnt             <= #1 {MRR-2{1'b0}};
        else if (!stall_s)
                cnt             <= #1 fin
                                        ? {MRR-2{1'b0}}
                                        : cnt + {{MRR-3{1'b0}}, iVld};

always @(
        iRadix
        )
        case (iRadix)
                4'h4:   iCnt            = {{MRR-4{1'b0}}, 2'h3};
                4'h6:   iCnt            = {{MRR-6{1'b0}}, 4'hf};
                4'h8:   iCnt            = {{MRR-8{1'b0}}, 6'h3f};
                default:
                        iCnt            = {MRR-2{1'b1}};
        endcase

assign fin              = (cnt == iCnt);

// -----------------------------------------------------------------------------
// Pipeline (Valid Control)
// 3段パイプラインのうち、vld_0とvld_1の間にデータパイプが合流
always @(posedge clk)
        if (reset)
                {vld_0, fin_0, radix_0, cnt_0}
                                <= #1 {MRR+4{1'b0}};
        else if (!stall_s)
                {vld_0, fin_0, radix_0, cnt_0}
                                <= #1 {iVld, iFin, iRadix, cnt};

always @(posedge clk)
        if (reset)
                {vld_1, fin_1, radix_1, cnt_1}
                                <= #1 {MRR+4{1'b0}};
        else if (!stall_0p)
                {vld_1, fin_1, radix_1, cnt_1}
                                <= #1 {vld_0p, fin_0, radix_0, cnt_0};

always @(posedge clk)
        if (reset)
                {vld_2, fin_2}  <= #1 2'b00;
        else if (!stall_1)
                {vld_2, fin_2}  <= #1 {vld_1, fin_1};

// 左辺と右辺の制御信号の合計が3を確認(3つのパイプの結合)、以下stall_0p, mStrbも同じ
assign vld_0p           = vld_0 & mAck;

// -----------------------------------------------------------------------------
// Pipeline (Stall Control)
// バッファ型のパイプライン記述
// パイプラインの最終出力oVldは終了を示すfin_2信号が結合しているので、stall_2も同様の処理を施す
assign stall_s          = vld_0 & stall_0;
assign stall_0          = stall_0p | !mAck;
assign stall_0p         = vld_1 & stall_1;
assign stall_1          = vld_2 & stall_2;
assign stall_2          = oStall & fin_2;

// -----------------------------------------------------------------------------
// Pipeline (Data)
// データバッファ1段目、バス幅が異なればサイジング回路を挿入(64bitバス→2回のAckで1回のパイプ結合)
always @(posedge clk)
        if (mStrb & mAck)
                data_1          <= #1 mData;

// データバッファ2段目、無駄に思えるが実はここにフォーマット変換を挟む余地を作るため
always @(posedge clk)
        if (!stall_1)
                data_2          <= #1 data_1;

// データアドレスに対するBit Reverseを4ポートに対して実施
always @(posedge clk)
        if (!stall_1) begin
                addr0_2         <= #1 reverseFunc({cnt_1, 2'h0}, radix_1);
                addr1_2         <= #1 reverseFunc({cnt_1, 2'h1}, radix_1);
                addr2_2         <= #1 reverseFunc({cnt_1, 2'h2}, radix_1);
                addr3_2         <= #1 reverseFunc({cnt_1, 2'h3}, radix_1);
        end

// -----------------------------------------------------------------------------
// Output
assign oVld             = vld_2 & fin_2;

// パイプライン準備が整っていなければ入力データを拒否
assign mStrb            = vld_0 & !stall_0p;

// -----------------------------------------------------------------------------
// SRAM Flip
// FFTの実行の度にFlipすることで、使用するSRAMセットを選択する
// また、SRAMを使用する状態(vld=1)を組み合わせて出力(トップモジュールはこの信号でデータをブレンド)
always @(posedge clk)
        if (reset)
                flip            <= #1 1'b0;
        else if (oVld & !oStall)
                flip            <= #1 ~flip;

assign oFlip            = {1'b0, vld_2 & !stall_2} << flip;

// -----------------------------------------------------------------------------
// SRAM Write
// SRAMにStallを効かす、また未使用時はWE(Write Enable)をActiveにしないことで低消費電力化を考慮する
assign ram0WE           = vld_2 & !stall_2;
assign ram1WE           = vld_2 & !stall_2;
assign ram2WE           = vld_2 & !stall_2;
assign ram3WE           = vld_2 & !stall_2;

// 4つのSRAMアドレスLSB2ビットは必ず排他的になり、これによりSRAM Bankに配分する
assign ram0WA           = addr0_2[MRR-1:2] & {MRR-2{addr0_2[1:0] == 2'h0}}
                        | addr1_2[MRR-1:2] & {MRR-2{addr1_2[1:0] == 2'h0}}
                        | addr2_2[MRR-1:2] & {MRR-2{addr2_2[1:0] == 2'h0}}
                        | addr3_2[MRR-1:2] & {MRR-2{addr3_2[1:0] == 2'h0}};

assign ram1WA           = addr0_2[MRR-1:2] & {MRR-2{addr0_2[1:0] == 2'h1}}
                        | addr1_2[MRR-1:2] & {MRR-2{addr1_2[1:0] == 2'h1}}
                        | addr2_2[MRR-1:2] & {MRR-2{addr2_2[1:0] == 2'h1}}
                        | addr3_2[MRR-1:2] & {MRR-2{addr3_2[1:0] == 2'h1}};

assign ram2WA           = addr0_2[MRR-1:2] & {MRR-2{addr0_2[1:0] == 2'h2}}
                        | addr1_2[MRR-1:2] & {MRR-2{addr1_2[1:0] == 2'h2}}
                        | addr2_2[MRR-1:2] & {MRR-2{addr2_2[1:0] == 2'h2}}
                        | addr3_2[MRR-1:2] & {MRR-2{addr3_2[1:0] == 2'h2}};

assign ram3WA           = addr0_2[MRR-1:2] & {MRR-2{addr0_2[1:0] == 2'h3}}
                        | addr1_2[MRR-1:2] & {MRR-2{addr1_2[1:0] == 2'h3}}
                        | addr2_2[MRR-1:2] & {MRR-2{addr2_2[1:0] == 2'h3}}
                        | addr3_2[MRR-1:2] & {MRR-2{addr3_2[1:0] == 2'h3}};

assign ram0WD           = data_2[31:0]   & {32{addr0_2[1:0] == 2'h0}}
                        | data_2[63:32]  & {32{addr1_2[1:0] == 2'h0}}
                        | data_2[95:64]  & {32{addr2_2[1:0] == 2'h0}}
                        | data_2[127:96] & {32{addr3_2[1:0] == 2'h0}};

assign ram1WD           = data_2[31:0]   & {32{addr0_2[1:0] == 2'h1}}
                        | data_2[63:32]  & {32{addr1_2[1:0] == 2'h1}}
                        | data_2[95:64]  & {32{addr2_2[1:0] == 2'h1}}
                        | data_2[127:96] & {32{addr3_2[1:0] == 2'h1}};

assign ram2WD           = data_2[31:0]   & {32{addr0_2[1:0] == 2'h2}}
                        | data_2[63:32]  & {32{addr1_2[1:0] == 2'h2}}
                        | data_2[95:64]  & {32{addr2_2[1:0] == 2'h2}}
                        | data_2[127:96] & {32{addr3_2[1:0] == 2'h2}};

assign ram3WD           = data_2[31:0]   & {32{addr0_2[1:0] == 2'h3}}
                        | data_2[63:32]  & {32{addr1_2[1:0] == 2'h3}}
                        | data_2[95:64]  & {32{addr2_2[1:0] == 2'h3}}
                        | data_2[127:96] & {32{addr3_2[1:0] == 2'h3}};

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

// Bit ReverseとSRAM Bank配分のためのアドレス攪乱を行う
function [MRR-1:0] reverseFunc;
        input   [MRR-1:0]       cnt;
        input   [3:0]           radix;
        reg     [MRR-1:0]       result;
        reg     [MRR-1:0]       twid;

        begin
                // Reverse
                // Radixの範囲でLSBとMSBが対象になるようビット配置を交換する
                // Radixが増える場合はcase()の条件も増やす
                case (radix)
                        4'h4:   result          = {{MRR-4{1'b0}},
                                                        cnt[0], cnt[1], cnt[2], cnt[3]
                                                        };
                        4'h6:   result          = {{MRR-6{1'b0}},
                                                        cnt[0], cnt[1], cnt[2], cnt[3],
                                                        cnt[4], cnt[5]
                                                        };
                        4'h8:   result          = {{MRR-8{1'b0}},
                                                        cnt[0], cnt[1], cnt[2], cnt[3],
                                                        cnt[4], cnt[5], cnt[6], cnt[7]
                                                        };
                        default:
                                result          = {
                                                        cnt[0], cnt[1], cnt[2], cnt[3],
                                                        cnt[4], cnt[5], cnt[6], cnt[7],
                                                        cnt[8], cnt[9]
                                                        };
                endcase

                // 上位2ビットをLSB2ビットに排他的論理和を行いアドレス攪乱を行う
                // この攪乱はBfCalcの初段の入力時に引き継がれる
                // Twiddle Factor
                case (radix)
                        4'h4:   twid            = {{MRR-2{1'b0}}, result[3:2]};
                        4'h6:   twid            = {{MRR-2{1'b0}}, result[5:4]};
                        4'h8:   twid            = {{MRR-2{1'b0}}, result[7:6]};
                        default:
                                twid            = {{MRR-2{1'b0}}, result[MRR-1:MRR-2]};
                endcase

                // Result
                reverseFunc     = result ^ twid;
        end
endfunction

endmodule       // loadData

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

コード(StoreData RTL)

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

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

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

module fftStoreData (
        iVld, iStall, iRadix,

        oVld, oStall, oFlip,

        mStrb, mAck, mData,

        ram0RE, ram1RE, ram2RE, ram3RE,
        ram0RA, ram1RA, ram2RA, ram3RA,
        ram0RD, ram1RD, ram2RD, ram3RD,

        reset, clk

        );

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

        // 最大のポイント数の指数はカウンタ等のビット範囲を定める
        parameter               MRR     = 10;           // Max Radix Radix

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

        // Pipe Input
        // iRadixはiVldに同期していれば、タスクごとに値の変更が可能
        input                   iVld;
        output                  iStall;
        input   [3:0]           iRadix;

        // Pipe Output
        // oVldは処理の終了を伝達するために存在
        output                  oVld;
        input                   oStall;
        output  [1:0]           oFlip;

        // Memory Interface
        // メモリI/Fに接続してもよいし、データを受け取るパイプにつなげてもよい
        output                  mStrb;
        input                   mAck;
        output  [127:0]         mData;

        // SRAM
        // SRAMはトップモジュールで定義
        output                  ram0RE, ram1RE, ram2RE, ram3RE;
        output  [MRR-3:0]       ram0RA, ram1RA, ram2RA, ram3RA;
        input   [31:0]          ram0RD, ram1RD, ram2RD, ram3RD;

        // Utility
        input                   reset;
        input                   clk;

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

        // Counter
        // Radix-4は4つ同時に処理するので、カウンタもN/4個数えればよい
        reg     [MRR-3:0]       cnt, iCnt;
        wire                    fin, iFin;

        // Pipeline (Valid Control)
        // パイプラインは0,1,2の3段、SuffixはパイプラインStageを示す
        reg                     vld_0, vld_1, vld_2;
        reg                     fin_0, fin_1, fin_2;
        // この信号(p)は分岐・結合のため別途定義している
        wire                    vld_2p;
        wire                    stall_2p;

        // Pipeline (Stall Control)
        wire                    stall_s, stall_0, stall_1, stall_2;

        // Pipeline (Data)
        reg     [MRR-1:0]       addr0_0, addr1_0, addr2_0, addr3_0;
        reg     [1:0]           addr0_1, addr1_1, addr2_1, addr3_1;
        reg     [127:0]         data_2;

        // SRAM Flip
        reg                     flip;

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

// -----------------------------------------------------------------------------
// Control
// 最終カウントがパイプラインへ投入した後Stallを解放
// 終端からStallが伝搬しているので注意(トップモジュールのFIFOでタイミングアークは切断)
assign iStall           = iVld & (!iFin | stall_s);
assign iFin             = fin;

// -----------------------------------------------------------------------------
// Counter
// iCntのデフォルト設定はポイント数2^10、MRRを増やす場合は隙間(10,12,14,,,)を積み増して行く
// case()文でiRadix依存しない記述方法があればそれを採用すべき
always @(posedge clk)
        if (reset)
                cnt             <= #1 {MRR-2{1'b0}};
        else if (!stall_s)
                cnt             <= #1 fin
                                        ? {MRR-2{1'b0}}
                                        : cnt + {{MRR-3{1'b0}}, iVld};

always @(
        iRadix
        )
        case (iRadix)
                4'h4:   iCnt            = {{MRR-4{1'b0}}, 2'h3};
                4'h6:   iCnt            = {{MRR-6{1'b0}}, 4'hf};
                4'h8:   iCnt            = {{MRR-8{1'b0}}, 6'h3f};
                default:
                        iCnt            = {MRR-2{1'b1}};
        endcase

assign fin              = (cnt == iCnt);

// -----------------------------------------------------------------------------
// Pipeline (Valid Control)
// 3段パイプラインのうち、vld_2と出力の間にデータパイプが分岐
always @(posedge clk)
        if (reset)
                {vld_0, fin_0}  <= #1 2'b00;
        else if (!stall_s)
                {vld_0, fin_0}  <= #1 {iVld, iFin};

always @(posedge clk)
        if (reset)
                {vld_1, fin_1}  <= #1 2'b00;
        else if (!stall_0)
                {vld_1, fin_1}  <= #1 {vld_0, fin_0};

always @(posedge clk)
        if (reset)
                {vld_2, fin_2}  <= #1 2'b00;
        else if (!stall_1)
                {vld_2, fin_2}  <= #1 {vld_1, fin_1};

assign vld_2p           = vld_2 & mAck;

// -----------------------------------------------------------------------------
// Pipeline (Stall Control)
// バッファ型のパイプライン記述
// パイプラインの最終出力oVldは終了を示すfin_2信号が結合しているので、stall_2も同様の処理を施す
assign stall_s          = vld_0 & stall_0;
assign stall_0          = vld_1 & stall_1;
assign stall_1          = vld_2 & stall_2;
assign stall_2          = stall_2p | !mAck;
assign stall_2p         = oStall & fin_2;

// -----------------------------------------------------------------------------
// Pipeline (Data)
// データアドレスに対するアドレス攪乱を4ポートに対して実施
always @(posedge clk)
        if (!stall_s) begin
                addr0_0         <= #1 twidFunc({cnt, 2'h0}, iRadix);
                addr1_0         <= #1 twidFunc({cnt, 2'h1}, iRadix);
                addr2_0         <= #1 twidFunc({cnt, 2'h2}, iRadix);
                addr3_0         <= #1 twidFunc({cnt, 2'h3}, iRadix);
        end

always @(posedge clk)
        if (!stall_0) begin
                addr0_1         <= #1 addr0_0[1:0];
                addr1_1         <= #1 addr1_0[1:0];
                addr2_1         <= #1 addr2_0[1:0];
                addr3_1         <= #1 addr3_0[1:0];
        end

// Readデータを受け取るタイミングはREアサート(vld_0)から2サイクル後(vld_2)
always @(posedge clk)
        if (!stall_1) begin
                data_2[127:96]  <= #1   ram0RD & {32{addr3_1 == 2'h0}} |
                                        ram1RD & {32{addr3_1 == 2'h1}} |
                                        ram2RD & {32{addr3_1 == 2'h2}} |
                                        ram3RD & {32{addr3_1 == 2'h3}};

                data_2[95:64]   <= #1   ram0RD & {32{addr2_1 == 2'h0}} |
                                        ram1RD & {32{addr2_1 == 2'h1}} |
                                        ram2RD & {32{addr2_1 == 2'h2}} |
                                        ram3RD & {32{addr2_1 == 2'h3}};

                data_2[63:32]   <= #1   ram0RD & {32{addr1_1 == 2'h0}} |
                                        ram1RD & {32{addr1_1 == 2'h1}} |
                                        ram2RD & {32{addr1_1 == 2'h2}} |
                                        ram3RD & {32{addr1_1 == 2'h3}};

                data_2[31:0]    <= #1   ram0RD & {32{addr0_1 == 2'h0}} |
                                        ram1RD & {32{addr0_1 == 2'h1}} |
                                        ram2RD & {32{addr0_1 == 2'h2}} |
                                        ram3RD & {32{addr0_1 == 2'h3}};
        end

// -----------------------------------------------------------------------------
// Output
assign oVld             = vld_2p & fin_2;

// パイプライン準備が整っていなければ出力データなしをアサート
assign mStrb            = vld_2 & !stall_2p;
assign mData            = data_2;

// -----------------------------------------------------------------------------
// SRAM Flip
// FFTの実行の度にFlipすることで、使用するSRAMセットを選択する
// また、SRAMを使用する状態(vld=1)を組み合わせて出力(トップモジュールはこの信号でデータをブレンド)
always @(posedge clk)
        if (reset)
                flip            <= #1 1'b0;
        else if (oVld & !oStall)
                flip            <= #1 ~flip;

assign oFlip            = {1'b0, vld_0 & !stall_0} << flip;

// -----------------------------------------------------------------------------
// SRAM
// SRAMにStallを効かす、また未使用時はRE(Read Enable)をActiveにしないことで低消費電力化を考慮する
assign ram0RE           = vld_0 & !stall_0;
assign ram1RE           = vld_0 & !stall_0;
assign ram2RE           = vld_0 & !stall_0;
assign ram3RE           = vld_0 & !stall_0;

assign ram0RA           = {
                                addr0_0[MRR-1:2] & {8{addr0_0[1:0] == 2'h0}} |
                                addr1_0[MRR-1:2] & {8{addr1_0[1:0] == 2'h0}} |
                                addr2_0[MRR-1:2] & {8{addr2_0[1:0] == 2'h0}} |
                                addr3_0[MRR-1:2] & {8{addr3_0[1:0] == 2'h0}}
                                };

assign ram1RA           = {
                                addr0_0[MRR-1:2] & {8{addr0_0[1:0] == 2'h1}} |
                                addr1_0[MRR-1:2] & {8{addr1_0[1:0] == 2'h1}} |
                                addr2_0[MRR-1:2] & {8{addr2_0[1:0] == 2'h1}} |
                                addr3_0[MRR-1:2] & {8{addr3_0[1:0] == 2'h1}}
                                };

assign ram2RA           = {
                                addr0_0[MRR-1:2] & {8{addr0_0[1:0] == 2'h2}} |
                                addr1_0[MRR-1:2] & {8{addr1_0[1:0] == 2'h2}} |
                                addr2_0[MRR-1:2] & {8{addr2_0[1:0] == 2'h2}} |
                                addr3_0[MRR-1:2] & {8{addr3_0[1:0] == 2'h2}}
                                };

assign ram3RA           = {
                                addr0_0[MRR-1:2] & {8{addr0_0[1:0] == 2'h3}} |
                                addr1_0[MRR-1:2] & {8{addr1_0[1:0] == 2'h3}} |
                                addr2_0[MRR-1:2] & {8{addr2_0[1:0] == 2'h3}} |
                                addr3_0[MRR-1:2] & {8{addr3_0[1:0] == 2'h3}}
                                };

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

// 上位2ビットをLSB2ビットに排他的論理和を行いアドレス攪乱を行う
// この攪乱はBfCalcの最終段の出力時を引き継ぐ
function [MRR-1:0] twidFunc;
        input   [MRR-1:0]       cnt;
        input   [3:0]           radix;
        reg     [MRR-1:0]       twid;

        begin
                // Twiddle Factor
                case (radix)
                        4'h4:   twid            = {{MRR-2{1'b0}}, cnt[3:2]};
                        4'h6:   twid            = {{MRR-2{1'b0}}, cnt[5:4]};
                        4'h8:   twid            = {{MRR-2{1'b0}}, cnt[7:6]};
                        default:
                                twid            = {{MRR-2{1'b0}}, cnt[MRR-1:MRR-2]};
                endcase

                // Result
                twidFunc        = cnt ^ twid;
        end
endfunction

endmodule       // storeData

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

回路デザイン > 設計例 [FFT] > コーディング2    次のページ(コーディング3)   このページのTOP ▲

[1]
上位のトップモジュールでiRadixの供給をiVldに同期させる必要があります。
[2]
あいまいな表現ですが、DCTの前処理アルゴリズム(入出力データの並び替え)に依存するためです。