赞
踩
乒乓操作是FPGA开发中的一种数据缓冲优化设计技术,可以看成是另一种形式的流水线技术,具有节约缓冲空间、对数据流无缝处理等优点,其操作原理如图所示。
在输入数据流到达时,输入数据流选择单元对其流向进行控制,其执行流程:
①在第一个缓冲周期,输入数据流写入数据缓冲模块1,写完之后进入第二个缓冲周期。
②在第二个缓冲周期,输入数据流写入数据缓冲模块2,同时将数据缓冲模块1中的数据读出。
③在第三个缓冲周期,输入数据流写入数据缓冲模块1,同时将数据缓冲模块2中的数据读出。
如此反复循环地操作,即为乒乓操作。
乒乓操作特点:实现跨时钟域的数据传输,其基本原理:
输入数据流的 面积 × 速度 = 输出数据流的 面积 × 速度
面积:即数据传输线的位宽,bit。
速度:即数据传输的时钟频率,hz。
例:输入数据流为 50Mhz × 8bit,则输出数据流为 25Mhz × 16bit,这样就实现了跨时钟域的数据传输。
使用数据产生模块输出 50Mhz × 8bit 的数据 8'b0 ~ 8'b199,通过乒乓操作读取数据,对其缓存并输出为 25Mhz × 16bit 的数据 16'h0100、16'h0302 ... 16'h6362 ... 16'hc7c6、16'h0100...
将其划分为四个模块,如图所示。
模块框图如图所示。
执行流程:
①data_gen输出数据 0 ~ 199(50Mhz × 8bit) 。
②在第一个缓冲周期,ram_ctrl 将数据流接入 ram1,ram1存入 0 ~ 99。
③在第二个缓冲周期,ram_ctrl 将数据流接入 ram2,ram2存入 100 ~ 199,同时 ram_ctrl 将ram1中的数据输出,即16'h0100、16'h0302 ... 16'h6362(10'd99 10'd98)。
④在第三个缓冲周期,ram_ctrl 将数据流接入 ram1,ram1存入 0 ~ 99,同时 ram_ctrl 将ram2中的数据输出,即16'h6463、16'h6665 ... 16'hc7c6(10'd199 10'd198)。
用状态机来实现这个功能。
- module data_gen
- (
- input wire clk , //50MHZ
-
- input wire rst ,
-
- output wire data_en ,
-
- output reg [7:0] data
- );
-
-
-
- always@(posedge clk or negedge rst)
- if(!rst)
- data <= 8'b0;
- else if(data == 'd199)
- data <= 8'b0;
- else
- data <= data + 1'b1;
-
- assign data_en = (rst == 1'b1);
-
- endmodule
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- module ram_ctrl
- (
- input wire clk_25m ,
- input wire clk_50m ,
- input wire rst ,
- input wire [15:0] ram1_data ,
- input wire [15:0] ram2_data ,
- input wire data_en ,
- input wire [7:0] data_in ,
-
- output wire ram1_wr_en ,
- output reg [6:0] ram1_wr_addr ,
- output wire [7:0] ram1_wr_data ,
- output wire ram1_rd_en ,
- output reg [5:0] ram1_rd_addr ,
-
- output wire ram2_wr_en ,
- output reg [6:0] ram2_wr_addr ,
- output wire [7:0] ram2_wr_data ,
- output wire ram2_rd_en ,
- output reg [5:0] ram2_rd_addr ,
-
- output reg [7:0] data_in_reg ,
-
- output wire [15:0] data_out
- );
-
- parameter IDLE = 4'b0001,
- WRAM1 = 4'b0010,
- R1_W2 = 4'b0100,
- W1_R2 = 4'b1000;
-
- reg [3:0] state,next_state;
-
- //data_in_reg:读取数据并打拍
- always@(posedge clk_50m or negedge rst)
- if(!rst)
- data_in_reg <= 8'b0;
- else if(data_en == 1'b1)
- data_in_reg <= data_in;
-
- //state:现态转移
- always@(posedge clk_50m or negedge rst)
- if(!rst)
- state <= IDLE;
- else
- state <= next_state;
-
- //next_state:次态改变
- always@(*)
- case(state)
- IDLE : next_state = WRAM1;
- WRAM1 : next_state = (data_in_reg == 'd99 )?R1_W2:WRAM1;
- R1_W2 : next_state = (data_in_reg == 'd199)?W1_R2:R1_W2;
- W1_R2 : next_state = (data_in_reg == 'd99 )?R1_W2:W1_R2;
- default : next_state = IDLE;
- endcase
- //ram1、ram2读写使能
- assign ram1_wr_en = (state == WRAM1 || state == W1_R2);
- assign ram1_rd_en = (next_state == R1_W2 || state == R1_W2);
- assign ram2_wr_en = (state == R1_W2);
- assign ram2_rd_en = (next_state == W1_R2 || state == W1_R2);
- //ram1_wr_addr,ram2_wr_addr:写地址计数
- always@(posedge clk_50m or negedge rst)
- if(!rst)
- begin
- ram1_wr_addr <= 7'b0;
- ram2_wr_addr <= 7'b0;
- end
- else if(ram1_wr_addr == 'd99 || ram2_wr_addr == 'd99)
- begin
- ram1_wr_addr <= 7'b0;
- ram2_wr_addr <= 7'b0;
- end
- else
- case(state)
- WRAM1 : ram1_wr_addr <= ram1_wr_addr + 1'b1;
- R1_W2 : ram2_wr_addr <= ram2_wr_addr + 1'b1;
- W1_R2 : ram1_wr_addr <= ram1_wr_addr + 1'b1;
- default :
- begin
- ram1_wr_addr <= 7'b0;
- ram2_wr_addr <= 7'b0;
- end
- endcase
- //ram1_rd_addr,ram2_rd_addr:读地址计数
- always@(posedge clk_25m or negedge rst)
- if(!rst)
- begin
- ram1_rd_addr <= 6'b0;
- ram2_rd_addr <= 6'b0;
- end
- else if(ram1_rd_addr == 'd49 || ram2_rd_addr == 'd49)
- begin
- ram1_rd_addr <= 6'b0;
- ram2_rd_addr <= 6'b0;
- end
- else
- case(state)
- R1_W2 : ram1_rd_addr <= ram1_rd_addr + 1'b1;
- W1_R2 : ram2_rd_addr <= ram2_rd_addr + 1'b1;
- default :
- begin
- ram1_rd_addr <= 6'b0;
- ram2_rd_addr <= 6'b0;
- end
- endcase
-
- //ram1、ram2输入数据选择
- assign ram1_wr_data = (state == WRAM1 || state == W1_R2) ? data_in_reg:8'b0;
- assign ram2_wr_data = (state == R1_W2) ? data_in_reg:8'b0;
-
- //ram1、ram2输出数据选择
- assign data_out = (state == R1_W2) ? ram1_data:((state == W1_R2) ? ram2_data:16'b0);
-
-
- endmodule
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- module pingpang
- (
- input wire clk ,
- input wire rst ,
-
- output wire [15:0] data_out
- );
-
- wire clk_25m ;
- wire clk_50m ;
- wire locked ;
- wire rst_n ;
-
- wire [15:0] ram1_data ;
- wire [15:0] ram2_data ;
- wire data_en ;
- wire [7:0] data_in ;
-
- wire ram1_wr_en ;
- wire [6:0] ram1_wr_addr ;
- wire [7:0] ram1_wr_data ;
- wire ram1_rd_en ;
- wire [5:0] ram1_rd_addr ;
-
- wire ram2_wr_en ;
- wire [6:0] ram2_wr_addr ;
- wire [7:0] ram2_wr_data ;
- wire ram2_rd_en ;
- wire [5:0] ram2_rd_addr ;
-
- wire [7:0] data_in_reg ;
-
- assign rst_n = locked & rst;
-
- clk_gen clk_gen_inst
- (
- .areset (~rst ),
- .inclk0 (clk ),
- .c0 (clk_50m ),
- .c1 (clk_25m ),
- .locked (locked )
- );
- data_gen data_gen_inst
- (
- .clk (clk_50m ), //50MHZ
- .rst (rst_n ),
-
- .data_en (data_en ),
- .data (data_in )
- );
- ram_ctrl ram_ctrl_inst
- (
- .clk_25m (clk_25m ),
- .clk_50m (clk_50m ),
- .rst (rst_n ),
- .ram1_data (ram1_data ),
- .ram2_data (ram2_data ),
- .data_en (data_en ),
- .data_in (data_in ),
-
- .ram1_wr_en (ram1_wr_en ),
- .ram1_wr_addr (ram1_wr_addr ),
- .ram1_wr_data (ram1_wr_data ),
- .ram1_rd_en (ram1_rd_en ),
- .ram1_rd_addr (ram1_rd_addr ),
-
- .ram2_wr_en (ram2_wr_en ),
- .ram2_wr_addr (ram2_wr_addr ),
- .ram2_wr_data (ram2_wr_data ),
- .ram2_rd_en (ram2_rd_en ),
- .ram2_rd_addr (ram2_rd_addr ),
-
- .data_in_reg (data_in_reg ),
-
- .data_out (data_out )
- );
- ram ram1_inst
- (
- .data (ram1_wr_data ),
- .rdaddress (ram1_rd_addr ),
- .rdclock (~clk_25m ),
- .rden (ram1_rd_en ),
- .wraddress (ram1_wr_addr ),
- .wrclock (~clk_50m ),
- .wren (ram1_wr_en ),
- .q (ram1_data )
- );
- ram ram2_inst
- (
- .data (ram2_wr_data ),
- .rdaddress (ram2_rd_addr ),
- .rdclock (~clk_25m ),
- .rden (ram2_rd_en ),
- .wraddress (ram2_wr_addr ),
- .wrclock (~clk_50m ),
- .wren (ram2_wr_en ),
- .q (ram2_data )
- );
-
- endmodule
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
可以看到数据流实现了无缝衔接,达到预期的效果,实验成功。
参考资料:野火《FPGA Verilog开发实战指南——基于Altera EP4CE10》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。