verilog实例—sync_fifo


一、FIFO

  • 同步FIFO 即时钟同步
  • FIFO是什么,有什么用?
    First Input First Output的缩写,先入先出队列,这是一种传统的按序执行方法,先进入的指令先完成并引退,跟着才执行第二条指令。
  • 端口
    在这里插入图片描述
    在这里插入图片描述

二、skills

1、读写地址变化方式

1、关于写地址的变化,只需考虑we有效的情况:

只写不读时:若FIFO满,则写失败,写地址不变;若FIFO不满,则写一定成功,写地址加1。
又写又读时:若FIFO满,读写为同一单元,因读操作只需读取旧数据,所以读写都成功,写地址加1;若FIFO不满,则进行读写操作的是两个不同单元,所以写一定成功,所以写地址也加1。

总结,wr_en && (!full || (full && rd_en))时,写地址加1;其他情况,写地址不变。因为只有写成功(写地址加1)的情况,才能让RAM的写使能有效,所以RAM的写使能也为wr_en && (!full || (full && rd_en))。

2、关于读地址的变化,只需考虑re有效的情况:

只读不写时:若FIFO空,则读失败,读地址不变;若FIFO不空则读一定成功,读地址加1.。
又读又写时:若FIFO空,则读写为同一单元,由于单元内无旧数据,读失败,只有写成功,此时读地址不变;若FIFO不空,则进行读写操作的是两个不同单元,所以读一定成功,读地址加1。

总结,(re有效&&empty标志无效)时,读地址加1;其他情况,读地址不变。因为只有读成功(读地址加1)的情况,才能让RAM的读使能有效,所以RAM的读使能也为(re有效&&empty标志无效)。

2、notes

  • FIFO满时,和空时,读写指针指向同一地址
  • 满时,读写使能为1,可同时读写
  • 空时,读写使能为1,只能写

三、RTL design

module sync_fifo(
        clk,
        rst,    //async
        wr_data,
        wr_en,
        rd_data,
        rd_en,
        full,
        empty
        );
    
    parameter   DATA_WIDTH = 32,
                DATA_DEPTH = 8,
                ADD_WIDTH  = 3;

    input       clk;
    input       rst;
    input       wr_data;
    input       wr_en;
    input       rd_en;

    output      rd_data;
    output      full;
    output      empty;
    
    reg [DATA_WIDTH-1:0]    wr_data;
    reg [DATA_WIDTH-1:0]    rd_data;
    reg [DATA_WIDTH-1:0]    ram_32_8[DATA_DEPTH-1:0];
    reg [ADD_WIDTH-1:0]     wr_add;
    reg [ADD_WIDTH-1:0]     rd_add;
    reg [ADD_WIDTH-1+1:0]   data_count;
    
    wire         full;
    wire        empty;
    reg         wr_enbuf;
    reg         rd_enbuf;

    assign wr_enbuf = wr_en && (!full || (full && rd_en));
    assign rd_enbuf = rd_en && !empty;
    //写指针移动
    always@(posedge clk or negedge rst)begin
        if(!rst)
            wr_add <= 3'b0;
        else if(wr_enbuf)
            wr_add <= wr_add + 1'b1;
        end

    //读指针移动
    always@(posedge clk or negedge rst)begin
        if(!rst)
            rd_add <= 3'b0;
        else if(rd_enbuf)
            rd_add <= rd_add + 1'b1;
        end
    //数据计数器
    always@(posedge clk or negedge rst)begin//case is good
        if(!rst)
            data_count <= 4'b0;
        else begin 
            if(rd_enbuf && wr_enbuf) //writing while reading
                data_count <= data_count;
            else if(wr_enbuf)     //writing
                data_count <= data_count + 1'b1;
            else if(rd_enbuf)    //reading
                data_count <= data_count - 1'b1;
        end
    end

    //满空判断
//    always@(posedge clk or negedge rst)begin
//        if(!rst)
//            full <= 1'b0;
//        else 
//            //full <= (!rd_enbuf && data_count == 4'b1000)||(!rd_enbuf && data_count == 4'b0111 && wr_enbuf)||(rd_enbuf && wr_enbuf && data_count == 4'b1000);
//    end
    assign full = data_count == 4'b1000;


//    always@(posedge clk or negedge rst)begin
//        if(!rst)
//            empty <= 1'b1;
//        else 
//            //empty <= (!wr_enbuf && data_count == 3'b000)||(!wr_enbuf && data_count ==3'b001 && rd_enbuf);
//        end
    assign empty = data_count == 0;

    //ram写读数据
    always@(posedge clk or negedge rst)begin
        if(!rst)begin
            integer i ;
            for(i=0;i < DATA_DEPTH;i=i+1)
                begin
                ram_32_8[i] <= 32'b0;
                end
        end
        else if(wr_enbuf)begin
                ram_32_8[wr_add] <= wr_data;
        end
    end


    always@(posedge clk or negedge rst)begin
        if(!rst)begin
            rd_data <= 32'b0;
        end
        else if(rd_enbuf)begin
            rd_data <= ram_32_8[rd_add];
        end
    end

endmodule

  • tb
`timescale 1ps/1ps
module test;
    //data type spicifiction
    reg         clk;
    reg         rst;
    reg [31:0]  wr_data;
    reg         wr_en;
    reg         rd_en;

    wire [31:0] rd_data;
    wire        full;
    wire        empty;

    //reset all
    initial begin
        clk   = 0;
        rst   = 1;

        wr_en = 0;
        rd_en = 0;

        wr_data = 32'b0;

     #2 rst   = 0;
     #5 rst   = 1;

    end
    
    //clock genarating
    always #0.5 clk = ~clk;
        
    //stimulate
    initial begin
        #10 wr_en = 1;
            rd_en = 0;
        #10 wr_en = 0;
            rd_en = 1;
        #10 wr_en = 1;
            rd_en = 0;
        #3  rd_en = 1;
        #10 
        repeat(100) begin
            #5 wr_en = {$random}%2;
               rd_en = {$random}%2;
        end
    end
    
    always #1 wr_data = {$random}%10;
    
    //module instantiation
     sync_fifo u_sync_fifo(
        .clk            (clk    ),
        .rst            (rst    ),    
        .wr_data        (wr_data),
        .wr_en          (wr_en  ),
        .rd_data        (rd_data),
        .rd_en          (rd_en  ),
        .full           (full   ),
        .empty          (empty  ) 
        );

    //stop
    initial begin
        forever begin
            #100
            //$display("---gyc---:%d",$time);
            if($time >= 2000)begin
                $finish;
            end
        end
    end
endmodule

4、veidi graph

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vivado中使用Sync_fifo实现时间同步需要以下步骤: 1. 打开Vivado并创建一个新工程,选择你的FPGA开发板型号。 2. 在设计界面中,选择“IP Integrator”选项卡,然后单击“Create Block Design”。 3. 在“Diagram”选项卡中,右键单击并选择“Add IP”选项,然后搜索“Sync_fifo”并添加到设计中。 4. 双击Sync_fifo模块,以调整它的配置。你需要调整以下三个参数: a. Sync_fifo深度:设置为20秒对应的时钟周期数,即20秒*1MHz=20000000个时钟周期。 b. 同步脉冲输出频率:设置为每20秒发出一个脉冲信号。 c. 同步脉冲输出宽度:根据需要设置脉冲宽度。 5. 确认完Sync_fifo的配置后,单击“Run Connection Automation”按钮来自动连接Sync_fifo模块到FPGA开发板的时钟信号。 6. 在“Sources”选项卡中,单击“Create HDL Wrapper”以生成VHDL或Verilog代码。 7. 在生成的代码中,你可以找到Sync_fifo模块的实例化代码,并将它添加到你的设计中。 8. 最后,你需要将Sync_fifo的输出信号与其他系统的时钟同步信号进行比较,以实现时间同步。具体方法可以根据系统的具体情况而定,例如可以使用PLL锁相环等技术将Sync_fifo的输出信号与系统时钟同步。 以上就是在Vivado中使用Sync_fifo实现时间同步的步骤。需要注意的是,具体的配置和连接方式可能会因开发板型号、时钟频率等因素而有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值