1. 程式人生 > 實用技巧 >每日一摘:乒乓操作

每日一摘:乒乓操作

FPGA設計的四種常用思想與技巧:乒乓操作、串並轉換、流水線操作、資料介面同步化。

其中乒乓操作是一個常應用於資料流控制的處理技巧,典型的乒乓操作方法如圖:

乒乓操作的處理流程為:輸入資料流通過“輸入資料選擇單元”將資料流分配到兩個資料緩衝區,資料緩衝模組可以為任何儲存模組,比較常用的儲存單元為雙埠RAM(DPRAM)、單口RAM(SPRAM)、FIFO等。

在第一個緩衝週期,將輸入的資料流快取到“資料緩衝模組1”;

在第二個緩衝週期,通過“輸入資料選擇單元”的切換,將輸入的資料流快取到“資料快取模組2”,同時將“資料快取模組1”快取的第一個緩衝週期的資料通過“輸出資料流選擇單元”的選擇,送到“資料流運算處理模組”進行運算處理。

在第三個緩衝週期,通過“輸入資料選擇單元”的再次切換,將輸入的資料流快取到“資料緩衝模組1”,同時將“資料緩衝模組2”快取的第二個緩衝週期的資料通過“輸出資料選擇單元”的選擇,送到“資料流運算處理模組”進行運算處理。如此迴圈。

程式碼示範:

module ping_pong
    (
    input            sys_clk,
    input            sys_rst_n,
    input      [7:0] data_in,   // 輸入資料
    output reg [7:0] data_out   // 輸出資料
    );
// ------------------------------------------------------ 
// reg [7:0] buffer1; // 快取1 reg [7:0] buffer2; // 快取2 reg wr_flag; // 寫標誌,wr_flag=0,寫buffer1,wr_flag=1,寫buffer2 reg rd_flag; // 讀標誌,rd_flag=0,讀buffer2,rd_flag=1,讀buffer1 reg state; // 狀態機,0:寫1讀2,1:寫2讀1,狀態轉移和輸出分開編碼 // ------------------------------------------------------ // //
狀態轉移 always @ (posedge sys_clk or negedge sys_rst_n) begin if(sys_rst_n == 1'b0) begin state <= 1'b0; end else begin case(state) 1'b0 : state <= 1'b1; // 寫1讀2->寫2讀1 1'b1 : state <= 1'b0; // 寫2讀1->寫1讀2 default : state <= 1'b0; endcase end end // ------------------------------------------------------ // // 狀態輸出 always @ (state) begin case(state) 1'b0: begin wr_flag = 1'b0; // 寫1 rd_flag = 1'b0; // 讀2 end 1'b1: begin wr_flag = 1'b1; // 寫2 rd_flag = 1'b1; // 讀1 end default: begin wr_flag = 1'b0; rd_flag = 1'b0; end endcase end // ------------------------------------------------------ // // 寫buffer資料 always @ (posedge sys_clk or negedge sys_rst_n) begin if(sys_rst_n == 1'b0) begin buffer1 <= 8'b0; buffer2 <= 8'b0; end else begin case(wr_flag) 1'b0 : buffer1 <= data_in; // wr_flag = 0,寫buffer1 1'b1 : buffer2 <= data_in; // wr_flag = 1,寫buffer2 default: begin buffer1 <= 8'b0; buffer2 <= 8'b0; end endcase end end // ------------------------------------------------------ // // 讀buffer資料 always @ (posedge sys_clk or negedge sys_rst_n) begin if(sys_rst_n == 1'b0) begin data_out <= 8'b0; end else begin case(rd_flag) 1'b0 : data_out <= buffer2; // rd_flag=0,讀buffer2 1'b1 : data_out <= buffer1; // rd_flag=1,讀buffer1 default : data_out <= 8'b0; endcase end end // ------------------------------------------------------ // endmodule
綜合程式碼
`timescale 1ns/1ns
module ping_pong_tb();
// ------------------------------------------------------ //
    // Inputs
    reg       sys_clk;
    reg       sys_rst_n;
    reg [7:0] data_in;
    // Outputs
    wire [7:0] data_out;
// ------------------------------------------------------ //
ping_pong u_ping_pong
    (
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    .data_in(data_in),   // ????
    .data_out(data_out)   // ????
    );
// ------------------------------------------------------ //
    initial
    begin
        sys_clk = 0;
        sys_rst_n = 0;
        data_in = 0;
        #100;
        sys_rst_n = 1;
    end
// ------------------------------------------------------ //
    always #10 sys_clk = ~sys_clk;
// ------------------------------------------------------ //
    always @ (posedge sys_clk or negedge sys_rst_n)
    begin
        if(sys_rst_n == 1'b0)
        begin
            data_in <= 8'b0;
        end
        else
        begin
            data_in <= data_in + 1'b1;
        end
    end
// ------------------------------------------------------ //
endmodule
模擬程式碼

程式碼結果:

結果分析:從模擬波形中可以看出按照0、1、2、3......遞增的方式輸入資料,兩個快取區交替儲存資料,最後依次輸出資料,不過輸出資料會有兩個時鐘的延遲。

乒乓操作的最大特點是通過“輸入資料選擇單元”和“輸出資料選擇單元”按節拍、相互配合的切換,將經過緩衝的資料流沒有停頓地送到“資料流運算處理模組”進行運算處理。

把乒乓操作模組當作一個整體,站在這個模組的兩端看資料,輸入資料流和輸出資料流都是連續不斷的,沒有任何停頓,因此非常適合對資料流進行流水線式處理。所以乒乓操作常常應用於流水線式演算法,完成資料的無縫緩衝與處理。

乒乓操作的第二個優點是可以節約緩衝區空間。比如在WCDMA基帶應用中,1個幀是由15個時隙組成的,有時需要將1整幀的資料延時一個時隙後處理,比較直接的辦法是將這幀資料快取起來,然後延時1個時隙進行處理。這時緩衝區的長度是1整幀資料長,假設資料速率是3.84Mbps,1幀長10ms,則此時需要緩衝區長度是38400位。如果採用乒乓操作,只需定義兩個能緩衝1個時隙資料的RAM(單口RAM即可)。當向一塊RAM寫資料的時候,從另一塊RAM讀資料,然後送到處理單元處理,此時每塊RAM的容量僅需2560位即可,2塊RAM加起來也只有5120位的容量。

另外, 巧妙運用乒乓操作還可以達到用低速模組處理高速資料流的效果。 如圖2所示, 資料緩衝模組採用了雙口RAM, 並在DPRAM後引入了一級資料預處理模組, 這個資料預處理可以根據需要的各種資料運算, 比如在WCDMA設計中, 對輸入資料流的解擴、 解擾、去旋轉等。 假設埠A的輸入資料流的速率為100Mbps, 乒乓操作的緩衝週期是10ms。 以下分析各個節點埠的資料速率。

A埠處輸入資料流速率為100Mbps, 在第1個緩衝週期10ms內, 通過“ 輸入資料選擇單元” , 從B1到達DPRAM1。B1的資料速率也是100Mbps,DPRAM1要在10ms內寫入1Mb資料。同理, 在第2個10ms, 資料流被切換到DPRAM2, 埠B2的資料速率也是100Mbps,DPRAM2在第2個10ms被寫入1Mb資料。 在第3個10ms, 資料流又切換到DPRAM1,DPRAM1被寫入1Mb資料。仔細分析就會發現到第3個緩衝週期時,留給DPRAM1讀取資料並送到“ 資料預處理模組1”的時間一共是20ms。 有的工程師困惑於DPRAM1的讀數時間為什麼是20ms, 這個時間是這樣得來的: 首先, 在在第2個緩衝週期向DPRAM2寫資料的10ms內,DPRAM1可以進行讀操作;

另外, 在第1個緩衝週期的第5ms起(絕對時間為5ms時刻),DPRAM1就可以一邊向500K以後的地址寫資料, 一邊從地址0讀數, 到達10ms時,DPRAM1剛好寫完了1Mb資料, 並且讀了500K資料, 這個緩衝時間內DPRAM1讀了5ms; 在第3個緩衝週期的第5ms起(絕對時間為35ms時刻), 同理可以一邊向500K以後的地址寫資料一邊從地址0讀數, 又讀取了5個ms, 所以截止DPRAM1第一個週期存入的資料被完全覆蓋以前,DPRAM1最多可以讀取20ms時間, 而所需讀取的資料為1Mb, 所以埠C1的資料速率為:1Mb/20ms=50Mbps。 因此, “ 資料預處理模組1” 的最低資料吞吐能力也僅僅要求為50Mbps。 同理, “ 資料預處理模組2”的最低資料吞吐能力也僅僅要求為50Mbps。 換言之, 通過乒乓操作, “ 資料預處理模組”的時序壓力減輕了, 所要求的資料處理速率僅僅為輸入資料速率的1/2。

通過乒乓操作實現低速模組處理高速資料的實質是:通過DPRAM這種快取單元實現了資料流的串並轉換, 並行用“ 資料預處理模組1” 和“ 資料預處理模組2” 處理分流的資料, 是面積與速度互換原則的體現!