使用两个FIFO完成流水操作
一、设计目标
写一个FIFO控制器,控制器里有两个FIFO,输入的数据由串行接收模块(uart_rx_module)送来,一共有86行86列的数据,按0、1、2行,1、2、3行,直到最后83、84、85行,每3行为一组进行加操作,即每一组的每一列三个数进行相加,每一组要加86次。传过来的第一行数据先暂存在FIFO1中,第二行数据先暂存在FIFO2中,从第三行数据开始流水操作,即取出第一、二行的数据,与输入的新数据相加,将结果通过串行发送模块(uart_tx_module)发送出去,在相加的同时,将新数据存在FIFO2中,将FIFO2中读出的数据重新存在FIFO1中,这一组的加操作完成后,FIFO1中为第1行的数据,FIFO2中为第二行的数据,以此操作不断循环,直到最后一组。
二、设计思路
2.1 设计先知
- 串口传输过来的86×86的数据是每十个波特时间才传输一次,每一个数据传送过来的同时会有标志位拉高,只需要判断该标志位即可进行读写操作。
- 因为是三行数据相加,所以先要把前两行的数据先存到fifo1和fifo2,当第三行数据传输过来的时候,再把三个数据(两个fifo输出端和rx输出)相加。
- 第0、1、2行加完后,需要把第1、2、3行数据相加,这时第0、1、2行的数据已经全部读出来了,所以需要在相加的时候把后面两行(第1、2行)数据存到fifo里面,即相加的同时需要将fifo2的数据存入fifo1,pi_data的数据存入fifo2。
- 最后三行相加,即第83、84、85行相加,不需要写数据了,写使能可以关闭了,只需要读使能,将fifo1里面的83行读出来和将fifo2里面的84行读出来,然后与新传送过来的85行进行相加。
2.2 设计结构图
2.3 fifo核的读写时序
2.4 fifo控制模块的时序图
接口传输方向 |
接口名称 |
位宽 |
功能 |
输入 |
Pi_flag |
1 |
输入数据有效标志位,为高代表有数据输入 |
输入 |
Pi_data |
8 |
输入的一个8位数据 |
中间变量 |
Cnt_col |
8 |
列计数器,用于统计每一行写入的数据个数 |
中间变量 |
Cnt_row |
8 |
行计数器,用于统计输入数据的行数 |
中间变量 |
Wr_en_1 |
1 |
Fifo1的写使能,控制fifo数据的写入 |
中间变量 |
Wr_en_2 |
1 |
Fifo2的写使能,控制fifo数据的写入 |
中间变量 |
Data_in_1 |
8 |
Fifo1写入数据的端口 |
中间变量 |
Data_in_2 |
8 |
Fifo2写入数据的端口 |
中间变量 |
Data_out_1 |
8 |
Fifo1读出数据的端口 |
中间变量 |
Data_out_2 |
8 |
Fifo2读出数据的端口 |
中间变量 |
Rd_en |
1 |
Fifo1和Fifo2读使能,控制两个Fifo数据的读出 |
中间变量 |
Flag_add |
1 |
加操作使能信号,为高时控制三个数据相加 |
输出 |
Po_sum |
8 |
存放每一组,每列三个数据相加的结果 |
输出 |
Po_flag |
1 |
输出数据有效标志位 |
三、关键代码
3.1串口接受模块
module uart_rx_moudule( input wire Clk, input wire Rst_n, input wire rx, output reg po_flag, output reg [7:0] po_data ); wire Rst; assign Rst=~Rst_n; reg rx1; reg rx2; reg rx2_reg; reg [12:0] cnt_baud; parameter CNT_BAUD_MAX = 13'd5207; parameter HALF_CNT_BAUD_MAX = 13'd2603; reg rx_flag; reg [3:0] bit_cnt; reg bit_flag; //打第一拍 always@(posedge Clk or posedge Rst) if(Rst) begin rx1<=1'd0; end else begin rx1<=rx; end //打第二拍 always@(posedge Clk or posedge Rst) if(Rst) begin rx2<=1'd0; end else begin rx2<=rx1; end //打第三拍 always@(posedge Clk or posedge Rst) if(Rst) begin rx2_reg<=1'd0; end else begin rx2_reg<=rx2; end //rx_flag always@(posedge Clk or posedge Rst) if(Rst) begin rx_flag<=1'b0; end else if((!rx2)&&(rx2_reg)) begin rx_flag<=1'b1; end else if((bit_cnt=='d8)&&(bit_flag)) begin rx_flag<=1'b0; end //cnt_baud always@(posedge Clk or posedge Rst) if(Rst) begin cnt_baud<='d0; end else if((cnt_baud==CNT_BAUD_MAX)||(!rx_flag)) begin cnt_baud<='d0; end else begin cnt_baud<=cnt_baud+1'b1; end //bit_flag always@(posedge Clk or posedge Rst) if(Rst) begin bit_flag<=1'b0; end else if(cnt_baud==HALF_CNT_BAUD_MAX) begin bit_flag<=1'b1; end else begin bit_flag<=1'b0; end //bit_cnt always@(posedge Clk or posedge Rst) if(Rst) begin bit_cnt<='b0; end else if((bit_cnt=='d8)&&(bit_flag)) begin bit_cnt<='b0; end else if(bit_flag) begin bit_cnt<=bit_cnt+1'b1; end //po_data always@(posedge Clk or posedge Rst) if(Rst) begin po_data<='d0; end else if((bit_flag)&&(bit_cnt>='d1)) begin po_data[bit_cnt-1'b1]<=rx2; end //po_flag always@(posedge Clk or posedge Rst) if(Rst) begin po_flag<=1'b0; end else if((bit_flag)&&(bit_cnt=='d8)) begin po_flag<=1'b1; end else begin po_flag<=1'b0; end endmodule
3.2串口发送模块
module uart_tx_module( input wire Clk, input wire Rst_n, input wire [7:0] pi_data, input wire pi_flag, output reg tx ); wire Rst; assign Rst=~Rst_n; reg [7:0] data_temp;//数据暂存 reg tx_flag;//控制发送定时器 reg [3:0] bit_cnt;//控制发送位数 reg bit_flag; reg [12:0] cnt_baud; parameter CNT_BAUD_MAX = 13'd5207; //data_temp always@(posedge Clk or posedge Rst) if(Rst) begin data_temp<='d0; end else if(pi_flag) begin data_temp<=pi_data; end //tx_flag always@(posedge Clk or posedge Rst) if(Rst) begin tx_flag<=1'b0; end else if(pi_flag) begin tx_flag<=1'b1; end else if((bit_cnt=='d8)&&(bit_flag)) begin tx_flag<=1'b0; end //cnt_baud always@(posedge Clk or posedge Rst) if(Rst) begin cnt_baud<='d0; end else if((cnt_baud==CNT_BAUD_MAX)||(!tx_flag)) begin cnt_baud<='d0; end else begin cnt_baud<=cnt_baud+1'b1; end //bit_flag always@(posedge Clk or posedge Rst) if(Rst) begin bit_flag<=1'b0; end else if(cnt_baud==CNT_BAUD_MAX-1'b1) begin bit_flag<=1'b1; end else begin bit_flag<=1'b0; end //bit_cnt always@(posedge Clk or posedge Rst) if(Rst) begin bit_cnt<='d0; end else if((bit_cnt=='d8)&&(bit_flag)) begin bit_cnt<='d0; end else if(bit_flag) begin bit_cnt<=bit_cnt+1'b1; end //tx always@(posedge Clk or posedge Rst) if(Rst) begin tx<='d1; end else if(pi_flag) begin tx<=1'b0; end else if((bit_flag)&&(bit_cnt<='d7)) begin tx<=data_temp[bit_cnt]; end else if((bit_flag)&&(bit_cnt=='d8)) begin tx<=1'b1; end endmodule
3.3 fifo控制模块
//============================================================= // ---名 称:fifo_ctrl // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-31 // ---描 述:控制两个fifo核完成读写流水操作 //============================================================= module fifo_ctrl( input wire Clk, input wire Rst_n, input wire pi_flag, input wire [7:0] pi_data, output reg po_flag, output reg [7:0] po_sum ); wire Rst; assign Rst=~Rst_n; reg [7:0]cnt_col; reg [7:0]cnt_row; reg wr_en_1; reg wr_en_2; reg rd_en; wire [7:0]data_in_1; wire [7:0]data_in_2; wire [7:0]data_out_1; wire [7:0]data_out_2; reg flag_add; //cnt_col always@(posedge Clk or posedge Rst) if(Rst) begin cnt_col<='d0; end else if((cnt_col=='d85)&&(pi_flag)) begin cnt_col<='d0; end else if(pi_flag) begin cnt_col<=cnt_col+1'b1; end //cnt_row always@(posedge Clk or posedge Rst) if(Rst) begin cnt_row<='d0; end else if((cnt_col=='d85)&&(cnt_row=='d85)&&(pi_flag)) begin cnt_row<='d0; end else if((cnt_col=='d85)&&(pi_flag)) begin cnt_row<=cnt_row+1'b1; end //wr_en_1 always@(posedge Clk or posedge Rst) if(Rst) begin wr_en_1<=1'd0; end else if(((pi_flag)&&(cnt_row=='d0))||((cnt_row>='d2)&&(cnt_row<='d84)&&(rd_en))||((cnt_row=='d85)&&(cnt_col=='d0)&&(rd_en))) begin wr_en_1<=1'b1; end else begin wr_en_1<=1'b0; end //wr_en_2 always@(posedge Clk or posedge Rst) if(Rst) begin wr_en_2<=1'b0; end else if(((pi_flag)&&(cnt_row=='d1))||((cnt_row>='d2)&&(cnt_row<='d84)&&(rd_en))||((cnt_row=='d85)&&(cnt_col=='d0)&&(rd_en))) begin wr_en_2<=1'b1; end else begin wr_en_2<=1'b0; end //rd_en always@(posedge Clk or posedge Rst) if(Rst) begin rd_en<=1'b0; end else if((cnt_row>='d2)&&(cnt_row<='d85)&&(pi_flag)) begin rd_en<=1'b1; end else begin rd_en<=1'b0; end //flag_add always@(posedge Clk or posedge Rst) if(Rst) begin flag_add<=1'b0; end else if(rd_en) begin flag_add<=1'b1; end else begin flag_add<=1'b0; end //po_sum always@(posedge Clk or posedge Rst) if(Rst) begin po_sum<='d0; end else if(flag_add) begin po_sum<=data_out_1+data_out_2+pi_data; end //po_flag always@(posedge Clk or posedge Rst) if(Rst) begin po_flag<='d0; end else if(flag_add) begin po_flag<='d1; end else begin po_flag<='d0; end //data_in_1 assign data_in_1=(cnt_row<='d1)?pi_data:data_out_2; //data_in2 assign data_in_2=pi_data; fifo fifo_inst1( .wr_clk(Clk), // input wr_clk .rd_clk(Clk), // input rd_clk .din(data_in_1), // input [7 : 0] din .wr_en(wr_en_1), // input wr_en .rd_en(rd_en), // input rd_en .dout(data_out_1), // output [7 : 0] dout .full(), // output full .empty() // output empty ); fifo fifo_inst2 ( .wr_clk(Clk), // input wr_clk .rd_clk(Clk), // input rd_clk .din(data_in_2), // input [7 : 0] din .wr_en(wr_en_2), // input wr_en .rd_en(rd_en), // input rd_en .dout(data_out_2), // output [7 : 0] dout .full(), // output full .empty() // output empty ); endmodule
3.4顶层模块
//============================================================= // ---名 称:top_double_fifo // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-31 // ---描 述:双流水fifo顶层模块 //============================================================= module top_double_fifo( input wire Clk, input wire Rst_n, input wire rx, output wire tx ); wire flag1,flag2; wire [7:0] data1,data2; uart_rx_moudule uart_rx_moudule_inst( .Clk(Clk), .Rst_n(Rst_n), .rx(rx), .po_data(data1), .po_flag(flag1) ); fifo_ctrl fifo_ctrl_inst( .Clk(Clk), .Rst_n(Rst_n), .pi_flag(flag1), .pi_data(data1), .po_flag(flag2), .po_sum(data2) ); uart_tx_module uart_tx_module_inst( .Clk(Clk), .Rst_n(Rst_n), .pi_flag(flag2), .pi_data(data2), .tx(tx) ); endmodule
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步