論理回路デザイン |
|
/* **************************** 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 // *****************************************************************************
/* **************************** 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 ▲