FIFO三项求和

概述

FIFO 的英文全称是 First In First Out,即先进先出。 FPGA 使用的 FIFO 一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存,或者高速异步数据的交互即所谓的跨时钟域信号传递。它与 FPGA 内部的 RAM 和 ROM 的区别是没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像 RAM 和 ROM 那样可以由地址线决定读取或写入某个指定的地址。
根据 FIFO 工作的时钟域,可以将 FIFO 分为同步 FIFO 和异步 FIFO。同步 FIFO 是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步 FIFO 是指读写时钟不一致,读写时钟是互相独立的。 Xilinx 的 FIFO IP 核可以被配置为同步 FIFO 或异步 FIFO,其信号框图如下图所示。从图中可以了解到,当被配置为同步 FIFO 时,只使用 wr_clk,所有的输入输出信号都同步于 wr_clk 信号。而当被配置为异步FIFO 时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟 wr_clk,所有与读相关的信号都是同步于读时钟 rd_clk。 异步 FIFO 能够将不同时钟域中的数据同步到所需的时钟域中

image.png
FIFO 的宽度: FIFO 一次读写操作的数据位 N;
FIFO 的深度: FIFO 可以存储多少个宽度为 N 位的数据。
空标志: empty。 FIFO 已空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO中读出数据而造成无效数据的读出。
将空标志: almost_ empty。 FIFO 即将被读空。满标志: full。 FIFO 已满时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成溢出。
将满标志: almost_full。 FIFO 即将被写满。
读时钟:读 FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
这里请注意,“almost_ empty”和“almost_full”这两个信号分别被看作“empty”和“full”的警告信号,他们距离真正的空(empty)和满(full)都一个时钟的延时。
写时钟:写 FIFO 时所遵循的时钟,在每个时钟的上升沿触发。

FIFO求和

串口每次输入一个数据,要对多组数据求和,则利用FIFO进行缓存。
要完成 3 行数据的 SUM 求和,需要调用 2 个 FIFO IP 核,当数据开始输入时,将数据的第 0 行数据存储到 fifo1 中,将第 1 行数据存储到 fifo2 中,当数据的第 2 行的第 0 个数据输入的同时,读取写入 fifo1 中的的第 0 个数据和写入 fifo2 中的第 0 个数据,将三个数据求和,求和结果实时输出,在完成求和的同时,将读取的 fifo2 中的第 0 个数据写入 fifo1中, fifo1 读出的数据弃之不用,将输入的第 2 行的数据写入 fifo2 中,当第 2 行的最后一个数据输入,完成前三行的最后一个求和运算后,第 0 行的数据已读取完成,第 1 行的数据重新写入 fifo1,第 2 行的数据写入 fifo2,当第 3 行数据开始传入时,开始进行第 1 行、第2 行和第 3 行的数据求和运算,如此循环,直到最后一个数据输入,完成求和运算。流程示意图具体见图 。
image.png

image.png

程序框图

image.png

程序

fifo_sum_ctrl

`timescale  1ns/1ns
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/01/14 18:36:46
// Design Name: 
// Module Name: fifo_sum_ctrl
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: FIFO三列求和实验
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module  fifo_sum_ctrl
(
    input   wire          sys_clk     ,   
    input   wire          sys_rst_n   ,   
    input   wire  [7:0]   pi_data     ,   
    input   wire          pi_flag     ,   

    output  reg   [7:0]   po_sum      ,   
    output  reg           po_flag         
);

//parameter define
parameter   CNT_ROW_MAX = 7'd49 ,   //行计数最大值
            CNT_COL_MAX = 7'd49 ;   //列计数最大值

//wire  define
wire  [7:0]   data_out1   ;   //fifo1数据输出
wire  [7:0]   data_out2   ;   //fifo2数据输出

//reg   define 
reg   [6:0]   cnt_row     ;   //行计数,计数一行数据个数
reg   [6:0]   cnt_col     ;   //场计数,计数数据行数
reg           wr_en1      ;   //fifo1写使能
reg           wr_en2      ;   //fifo2写使能
reg   [7:0]   data_in1    ;   //fifo1写数据输入  
reg   [7:0]   data_in2    ;   //fifo2写数据输入
reg           rd_en       ;   //fifo1、fifo2共用的读使能
reg           dout_flag   ;   //控制fifo1,2~84行的写使能
reg           po_flag_reg ;   //输出标志位缓存,rd_en延后一拍得到,控制计算po_sum


//cnt_row:行计数器,计数一行数据个数
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        cnt_row <=  7'd0;
    else if((cnt_row == CNT_ROW_MAX) && (pi_flag == 1'b1))
        cnt_row <=  7'd0;
    else if(pi_flag == 1'b1)
        cnt_row <=  cnt_row + 1'b1;
end

//cnt_col:列计数器,计数数据行数
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        cnt_col <=  7'd0;
    else if((cnt_col == CNT_COL_MAX) && (pi_flag == 1'b1) && (cnt_row == CNT_ROW_MAX))
        cnt_col <=  7'd0;
    else if((cnt_row == CNT_ROW_MAX) && (pi_flag == 1'b1))
        cnt_col <=  cnt_col + 1'b1;
end

//wr_en1:fifo1写使能信号,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        wr_en1  <=  1'b0;
    else if((cnt_col == 7'd0) && (pi_flag == 1'b1))
        wr_en1  <=  1'b1;          //第0行写入fifo1
    else
        wr_en1  <=  dout_flag;  //2-84行写入fifo1
end

//dout_flag:控制2-CNT_COL_MAX-1行wr_en1信号
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        dout_flag <=  0;
    else if((wr_en2 == 1'b1) && (rd_en == 1'b1))
        dout_flag <=  1'b1;
    else
        dout_flag <=  1'b0;
end

//wr_en2:fifo2写使能信号,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        wr_en2  <=  1'b0;
    else if((cnt_col >= 7'd1) && (cnt_col <= CNT_COL_MAX - 1'b1) && (pi_flag == 1'b1))
        wr_en2  <=  1'b1;          //2-CNT_COL_MAX行写入fifo2
    else
      wr_en2  <=  1'b0;
end

//data_in1:fifo1数据输入
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        data_in1  <=  8'b0;
    else if((pi_flag == 1'b1) && (cnt_col == 7'd0))
        data_in1  <=  pi_data;  //第0行数据暂存fifo1中
    else if(dout_flag == 1'b1)
      data_in1  <=  data_out2;//第2-CNT_COL_MAX-1行时,fifo2读出数据存入fifo1
    else
        data_in1  <=  data_in1;
end

//data_in2:fifo2数据输入
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        data_in2  <=  8'b0;
    else    if((pi_flag == 1'b1)&&(cnt_col >= 7'd1)&&(cnt_col <= (CNT_COL_MAX - 1'b1)))
        data_in2  <=  pi_data;
    else
        data_in2  <=  data_in2;
end

//rd_en:fifo1和fifo2的共用读使能信号
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        rd_en <=  1'b0;
    else    if((pi_flag == 1'b1)&&(cnt_col >= 7'd2)&&(cnt_col <= CNT_COL_MAX))
        rd_en <=  1'b1;
    else
        rd_en <=  1'b0;
end

//po_flag_reg:输出标志位缓存,延后rd_en一拍,控制po_sum信号
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        po_flag_reg <=  1'b0;
    else    if(rd_en == 1'b1)
        po_flag_reg <=  1'b1;
    else
        po_flag_reg <=  1'b0;
end

//po_flag:输出标志信号,延后输出标志位缓存一拍,与po_sum同步输出
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        po_flag <=  1'b0;
    else
        po_flag <=  po_flag_reg;
end

//po_sum:求和数据输出
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        po_sum  <=  8'b0;
    else    if(po_flag_reg == 1'b1)
        po_sum  <=  data_out1 + data_out2 + pi_data;
    else
        po_sum  <=  po_sum;
end



//------------- fifo_data_inst1 --------------
fifo1   fifo_data_inst1
(
    .clk    (sys_clk    ),  //input clk
    .din    (data_in1   ),  //input [7:0] din
    .wr_en  (wr_en1     ),  //input wr_en
    .rd_en  (rd_en      ),  //input rd_en
    .full   ( ),            // output full
    .empty  ( ),            // output empty
    .dout   (data_out1   )   //output [7:0] dout
);

//------------- fifo_data_inst2 --------------
fifo2   fifo_data_inst2
(
    .clk    (sys_clk    ),  //input clk
    .din    (data_in2   ),  //input [7:0] din
    .wr_en  (wr_en2     ),  //input wr_en
    .rd_en  (rd_en      ),  //input rd_en
    .full   ( ),            // output full
    .empty  ( ),            // output empty
    .dout   (data_out2   )   //output [7:0] dout
);

endmodule

uart_rx

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/27 13:27:27
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_rx
#(
    parameter UART_BPS = 'd9600, //串口波特率
    parameter CLK_FREQ = 'd50_000_000 //时钟频率
 )
 (
    input   wire    sys_clk,
    input   wire    sys_rst_n,
    input   wire    rx,

    output  reg [7:0]   po_data,
    output  reg         po_flag 
 );

    localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;

    reg         rx_reg1 ;
    reg         rx_reg2 ;
    reg         rx_reg3 ;
    reg         start_nedge;
    reg         work_en;
    reg [12:0]  baud_cnt;
    reg         bit_flag;
    reg [3:0]   bit_cnt;
    reg [7:0]   rx_data;
    reg         rx_flag;

    //将接收的rx信号打两拍,消除亚稳态。再打一拍用消除亚稳态后的rx_reg2、rx_reg3进行下降沿判断
//rx_reg1
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0) 
            rx_reg1 <= 1'b1;
        else 
            rx_reg1 <= rx;
    end
//rx_reg2
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0) 
            rx_reg2 <= 1'b1;
        else 
            rx_reg2 <= rx_reg1;
    end
//rx_reg2
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0) 
            rx_reg3 <= 1'b1;
        else 
            rx_reg3 <= rx_reg2;
    end
//start_nedge
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0) 
            start_nedge <= 1'b0;
        else if (rx_reg3 && (~rx_reg2))
            start_nedge <= 1'b1;
        else
            start_nedge <= 1'b0;
        end
//work_en
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else if(start_nedge == 1'b1)
            work_en <= 1'b1; 
        else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            work_en <= 1'b0;
    end
//baud_cnt
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;
      //  
        
        
    end
//bit_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else if(baud_cnt ==  BAUD_CNT_MAX/2 - 1)
            bit_flag <= 1'b1;
        else    
            bit_flag <= 1'b0;
    end
//bit_cnt
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            bit_cnt <= 4'b0;
        else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            bit_cnt <=  4'b0;
        else if(bit_flag == 1'b1)
            bit_cnt <= bit_cnt + 1'b1;
    end
//rx_data
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            rx_data <= 8'b0;
        else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
            rx_data <= {rx_reg3, rx_data[7:1]};
    end
//rx_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            rx_flag <= 1'b0;
        else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            rx_flag <= 1'b1;
        else 
            rx_flag <= 1'b0;
    end
//po_data
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            po_data <= 8'b0;
        else if(rx_flag == 1'b1)
            po_data <= rx_data;
    end
//po_data_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (sys_rst_n == 1'b0)
            po_flag <= 1'b0;
        else 
            po_flag <= rx_flag;
    end
    
endmodule

uart_tx

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/27 18:45:39
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_tx
#(
    parameter UART_BPS = 'd9600, //串口波特率
    parameter CLK_FREQ = 'd50_000_000 //时钟频率
 )
 (
    input   wire        sys_clk,
    input   wire        sys_rst_n,
    input   wire        pi_flag,
    input   wire[7:0]   pi_data,

    output  reg         tx
  
 );

    localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
    reg         work_en;
    reg [12:0]  baud_cnt;
    reg         bit_flag;
    reg [3:0]   bit_cnt;
//work_en
        always @(posedge sys_clk or negedge sys_rst_n) begin
            if(sys_rst_n == 1'b0)
                work_en <= 1'b0;
            else if(pi_flag == 1'b1)
                work_en <= 1'b1;
            else if((bit_flag ==1'b1) && (bit_cnt == 4'd9))
                work_en <= 1'b0;
        end
//baud_cnt
        always @(posedge sys_clk or negedge sys_rst_n) begin
            if(sys_rst_n == 1'b0)
                baud_cnt <= 13'b0;
            else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
                baud_cnt <= 13'b0;
            else if(work_en == 1'b1)
                baud_cnt <= baud_cnt + 1'b1;
        end
//bit_flag
        always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                bit_flag <= 1'b0;
            else if(baud_cnt == 13'd1)
                bit_flag <= 1'b1;
            else
                bit_flag <= 1'b0;
 //bit_cnt
        always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                bit_cnt <= 4'b0;
            else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
                bit_cnt <= 4'b0;
            else if((bit_flag == 1'b1) && (work_en == 1'b1))
                bit_cnt <= bit_cnt + 1'b1;  
//tx
        always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                tx <= 1'b1; //空闲状态时为高电平
            else if(bit_flag == 1'b1)
                case(bit_cnt)
                    0 : tx <= 1'b0;
                    1 : tx <= pi_data[0];
                    2 : tx <= pi_data[1];
                    3 : tx <= pi_data[2];
                    4 : tx <= pi_data[3];
                    5 : tx <= pi_data[4];
                    6 : tx <= pi_data[5];
                    7 : tx <= pi_data[6];
                    8 : tx <= pi_data[7];
                    9 : tx <= 1'b1;
                    default : tx <= 1'b1;
                endcase      
endmodule

top_fifo_sum

`timescale  1ns/1ns
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/01/14 18:36:46
// Design Name: 
// Module Name: fifo_sum_ctrl
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module  top_fifo_sum
(
    input     wire    sys_clk       ,   //输入系统时钟,50MHz
    input     wire    sys_rst_n     ,   //复位信号,低电平有效
    input     wire    rx            ,   //串口数据接收

    output    wire    tx                //串口数据发送
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   UART_BPS    =   14'd9600        ,   //比特率
            CLK_FREQ    =   26'd50_000_000  ;   //时钟频率

//wire define
wire    [7:0]   pi_data ;   //输入待求和数据
wire            pi_flag ;   //输入数据标志信号
wire    [7:0]   po_sum  ;   //输出求和后数据
wire            po_flag ;   //输出数据标志信号

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- uart_rx_inst --------------
uart_rx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_rx_inst
(
    .sys_clk    (sys_clk    ),  //系统时钟50Mhz
    .sys_rst_n  (sys_rst_n  ),  //全局复位
    .rx         (rx         ),  //串口接收数据

    .po_data    (pi_data    ),  //串转并后的数据
    .po_flag    (pi_flag    )   //串转并后的数据有效标志信号
);

//------------- fifo_sum_ctrl_inst --------------
fifo_sum_ctrl  fifo_sum_ctrl_inst
(
    .sys_clk    (sys_clk    ),  //频率为50MHz
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低有效
    .pi_data    (pi_data    ),  //rx传入的数据信号
    .pi_flag    (pi_flag    ),  //rx传入的标志信号

    .po_sum     (po_sum     ),  //求和运算后的信号
    .po_flag    (po_flag    )   //输出数据标志信号
);

//------------- uart_tx_inst --------------
uart_tx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_tx_inst
(
    .sys_clk    (sys_clk    ),  //系统时钟50Mhz
    .sys_rst_n  (sys_rst_n  ),  //全局复位
    .pi_data    (po_sum     ),  //并行数据
    .pi_flag    (po_flag    ),  //并行数据有效标志信号

    .tx         (tx         )   //串口发送数据
);

endmodule
  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值