04FIFO

题目:同步FIFO

FIFO:同步FIFO是读时钟与写时钟为同一时钟,在时钟上升沿同时发生读写操作。异步FIFO是读写时钟为不同时钟,读写时钟彼此相互独立。

module Ip_Fifo
    #(
    	parameter 	DATA_WIDTH 	= 8,
        parameter 	DATA_DEPTH 	= 8,
        parameter	RAM_DEPTH	= (1 << DATA_DEPTH)
    )
    (
    	input	wire					clk		,
        input	wire					rst_n	,
        input	wire	[DATA_WIDTH: 1]	data_in	,
        input	wire					wr_req	,
        input	wire					rd_req	,
        output	reg		[DATA_WIDTH: 1]	data_out,
        output	wire					empty	,
        output	wire					full        
    );
    
    reg	[DATA_DEPTH-1: 0]	data_cnt;
    reg	[DATA_DEPTH-1: 0]	wr_addr, rd_addr;
    wire					wren_wire, rden_wire;
    
    assign full = (data_cnt == RAM_DEPTH-1)? 1'b1: 1'b0;
    assign empty = (data_cnt == 1'b0)?1'b1:1'b0;
    
    assign wren_wire = (wr_req && !full);
    assign rden_wire = (rd_req && !empty);
    
    // 写计数
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            wr_addr <= 1'b0;
        else if(wr_req && !full)
            wr_addr <= wr_addr + 1'b1;
        else
            wr_addr <= wr_addr;
    end
    
    // 读计数
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            rd_addr <= 1'b0;
        else if(rd_req && !empty)
            rd_addr <= rd_addr + 1'b1;
        else
            rd_addr <= rd_addr;
    end
    
    // data_cnt 计数
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            data_cnt <= 1'b0;
        else begin
            case({rd_req, wr_req})
            	2'b00: data_cnt <= data_cnt;
                2'b01: begin
                    if(!full)
                    	data_cnt <= data_cnt + 1'b1;
                    else
                        data_cnt <= data_cnt;
                end
                2'b10: begin
                    if(!empty)
                    	data_cnt <= dat_cnt - 1'b1;
                    else
                        data_cnt <= data_cnt;
                end
                2'b11: data_cnt <= data_cnt;
                default: data_cnt <= data_cnt;
            endcase
        end
    end
    
    // -----------------Syn_Dual_Port_Ram----------------------// 
    Dual_Ram_Port Dual_Ram_Port_Init
    (
        .wr_data	(data_in	),
        .rd_data	(data_out	),
        .clk		(clk		),
        .rst		(rst_n		),
        .wren		(wren_wire	),
        .rden		(rden_wire	),
        .wraddr		(wr_addr	),
        .rdaddr		(rd_addr	)
    );
    
    
endmodule

#仿真代码

`timescale 1ps/1ps
module Ip_Fifo_tb();
    
    reg	clk, rst_n;
    reg	[ 7: 0]	data_in;
    reg	wr_req, rd_req;
    
    wire	[ 7: 0] data_out;
    wire	empty, full;
    wire	[ 7: 0] usedw;
    
    initial clk = 0;
    always #10 clk = ~clk;
    
    integer i;
    initial begin
    	rst_n = 0;
        wr_req = 0;
        rd_req = 0;
        data_in = 'd0;
        
    	# 100
        rst_n = 1;
        
        for(i=0; i<255; i=i+1) begin
        	wr_req = 1;
            data_in = i; 
        end
        wr_req = 0;
        
        for(i=0;i<255;i=i+1) begin
        	rd_req = 1;
            #20;
        end
        rd_req = 0;
        # 200
        $stop;
    end
    
    Ip_Fifo Ip_Fifo_Init
    (
        .clk		(clk		),
        .rst_n		(rst_n		),
        .data_in	(data_in	),
        .wr_req		(wr_reg		),
        .rd_req		(rd_req		),
        .data_out	(data_out	),
        .empty		(empty		),
        .full    	(full		)    
    );
    
endmodule

题目:设计异步FIFO

将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。

module Ip_Fifo_k(
	input	wire			Rclk	,
    input	wire			Wclk	,
    input	wire			rst_n	,
    input	wire			wr_req	,
    input	wire			rd_req	,
    input	wire	[ 7: 0]	data_in	,
    output	reg				empty	,
    output	reg				full	,
    output	reg		[ 7: 0]	data_out
);
    
    // --内部寄存器声明-------------------------------- // 
    
    parameter	ADDR_WIDTH = 10;
    
    reg	[ADDR_WIDTH-1: 0]	wr_addr_bin;
    reg	[ADDR_WIDTH-1: 0]	rd_addr_bin;
    
    reg	[ADDR_WIDTH-1: 0]	wr_addr_gray;
    reg	[ADDR_WIDTH-1: 0]	wr_addr_gray;
    
    reg	[ADDR_WIDTH-1: 0]	wr_addr_bin_n;
    reg	[ADDR_WIDTH-1: 0]	rd_addr_bin_n;
    
    reg	[ADDR_WIDTH-1: 0]	wr_addr_gray_n;
    reg	[ADDR_WIDTH-1: 0]	wr_addr_gray_n;
    
    reg	[ADDR_WIDTH-1: 0]	wclk_raddr_gray_r0;
    reg	[ADDR_WIDTH-1: 0]	wclk_raddr_gray_r1;
    reg	[ADDR_WIDTH-1: 0]	rclk_waddr_gray_r0;
    reg	[ADDR_WIDTH-1: 0]	rclk_waddr_gray_r1;
    
    wire	wren_wire, rden_wire;
    
    // - 写地址更新(二进制和格雷码)
    always @(posedge Wclk or negedge rst_n) begin
        if(!rst_n)
            wr_addr_bin <= 10'b0;
        else if(wr_req && !full)
            wr_addr_bin <= wr_addr_bin_n;
        else 
            wr_addr_bin <= wr_addr_bin;
    end
    
    always @(posedge Wclk or negedge rst_n) begin
        if(!rst_n)
            wr_addr_gray <= 10'b0;
        else if(wr_req && !full)
            wr_addr_gray <= wr_addr_gray_n;
        else 
            wr_addr_gray <= wr_addr_gray;    
    end
    
    assign wr_addr_bin_n = wr_addr_bin + 1'b1;
    // 二进制转格雷码相当于高位不变,其余每一位和左位异或。
    assign wr_addr_gray_n = wr_addr_bin_n ^ {1'b0, wr_addr_bin_n[ADDR_WIDTH-1: 1]};
    
     // - 读地址更新(二进制和格雷码)
    always @(posedge Rclk or negedge rst_n) begin
        if(!rst_n)
            rd_addr_bin <= 10'b0;
        else if(rd_req && !empty)
            rd_addr_bin <= rd_addr_bin_n;
        else 
            rd_addr_bin <= rd_addr_bin;
    end
    
    always @(posedge Rclk or negedge rst_n) begin
        if(!rst_n)
            rd_addr_gray <= 10'b0;
        else if(rd_req && !empty)
            rd_addr_gray <= rd_addr_gray_n;
        else 
            rd_addr_gray <= rd_addr_gray;    
    end
    
    assign rd_addr_bin_n = rd_addr_bin + 1'b1;
    assign rd_addr_gray_n = rd_addr_bin_n ^ {1'b0, rd_addr_bin_n[ADDR_WIDTH-1: 1]};
    
    // - 同步写地址到读时钟
    always @(posedge Rclk) begin
		rclk_waddr_gray_r0 <= wr_addr_gray;
		rclk_waddr_gray_r1 <= rclk_waddr_gray_r0;            
    end
    
    // - 同步读地址到写时钟
    always @(posedge Wclk) begin
		wclk_raddr_gray_r0 <= rd_addr_gray;
		wclk_raddr_gray_r1 <= wclk_raddr_gray_r0;            
    end
    
    always @(posedge Wclk or negedge rst_n) begin
        if(!rst_n)
            full <= 1'b0;
        else if(wr_addr_gray_n == wclk_raddr_gray_r1 && wr_req)
            full <= 1'b1;
        else if(wr_addr_gray_n != wclk_raddr_gray_r1)
            full <= 1'b0;
        else
            full <= full;
    end
    
    always @(posedge Rclk or negedge rst_n) begin
        if(!rst_n)
            empty <= 1'b0;
        else if(rd_addr_gray_n == rclk_waddr_gray_r1 && rd_req)
            empty <= 1'b1;
        else if(rd_addr_gray_n != rclk_waddr_gray_r1)
            empty <= 1'b0;
        else
            empty <= empty;
    end
    
    assign wren_wire = (full == 1'b1) ? 1'b1 : wr_req;
    assign rden_wire = (empty == 1'b1) ? 1'b1: rd_req;
    
    
    // -----------------Syn_Dual_Port_Ram----------------------// 
    
    Dual_Ram_Port Dual_Ram_Port_Init
    (
        .wr_data	(data_in	),
        .rd_data	(data_out	),
        .wclk		(Wclk		),
        .rclk		(Rclk		),
        .rst		(rst_n		),
        .wren		(wren_wire	),
        .rden		(rden_wire	),
        .wraddr		(wr_addr	),
        .rdaddr		(rd_addr	)
    );
    
endmodule
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值