同步FIFO与异步FIFO的Verilog实现
Posted pure-z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同步FIFO与异步FIFO的Verilog实现相关的知识,希望对你有一定的参考价值。
1 module sync_fifo( 2 input sys_clk, 3 input sys_rst_n, 4 input [7:0] wr_data, 5 input wr_en, 6 input rd_en, 7 8 output reg [7:0] rd_data, 9 output reg empty, 10 output reg full 11 ); 12 13 parameter WIDTH = 8 ; 14 parameter ADDRSIZE = 3; 15 parameter DEPTH = 1 << ADDRSIZE ; 16 17 reg [ADDRSIZE-1:0] wr_addr ; 18 reg [ADDRSIZE-1:0] rd_addr ; 19 reg [WIDTH-1:0] mem [DEPTH-1:0]; 20 reg [DEPTH-1:0] count; 21 22 //read 23 always @(posedge sys_clk or negedge sys_rst_n) begin 24 if (!sys_rst_n) 25 rd_data <= 0; 26 else if(rd_en && empty==0) 27 rd_data <= mem[rd_addr]; 28 end 29 30 //write 31 always @(posedge sys_clk ) begin 32 if(wr_en && full==0) 33 mem[wr_addr] <= wr_data; 34 end 35 36 //更新读地址 37 always @(posedge sys_clk or negedge sys_rst_n) begin 38 if(!sys_rst_n) 39 rd_addr <= 0; 40 else if (rd_en && empty == 0) 41 rd_addr <= rd_addr + 1 ; 42 end 43 44 //更新写地址 45 always@ (posedge sys_clk or negedge sys_rst_n) begin 46 if(!sys_rst_n) 47 wr_addr <= 0; 48 else if (wr_en && full == 0) 49 wr_addr <= wr_addr + 1 ; 50 end 51 52 //更新标志位 53 always @(posedge sys_clk or negedge sys_rst_n) begin 54 if(!sys_rst_n) 55 count <= 0; 56 else begin 57 case({wr_en,rd_en}) 58 2‘b00:count <= count; 59 2‘b01: 60 if (count != 0) 61 count <= count -1; 62 2‘b10: 63 if (count != (DEPTH-1)) 64 count <= count +1; 65 2‘b11:count <= count; 66 endcase 67 end 68 end 69 70 always@(count) begin 71 if (count == 0) 72 empty <= 1; 73 else 74 empty = 0; 75 end 76 77 always@(count) begin 78 if (count == (DEPTH -1)) 79 full <= 1; 80 else 81 full = 0; 82 end 83 84 endmodule
1 module async_fifo 2 #( 3 parameter WIDTH = 8, //数据位宽为8 4 parameter ADDRSIZE = 8 //地址位宽为8,则FIFO深度为2^8 5 ) 6 ( 7 input I_rst_n, //复位信号,低电平有效 8 input I_w_clk, //写时钟 9 input I_w_en, //写使能 10 input I_r_clk, //读时钟 11 input I_r_en, //读使能 12 input [WIDTH-1 : 0]I_data,//位宽为8的并行数据输入 13 output [WIDTH-1 : 0]O_data,//并行数据输出 14 output reg O_r_empty,//读空信号 15 output reg O_w_full //写满信号 16 ); 17 18 (*KEEP = "TRUE"*)wire [ADDRSIZE-1 : 0] waddr,raddr;//读写地址 19 reg [ADDRSIZE : 0] w_ptr,r_ptr;//读指针,写指针,格雷码(位宽为9,最高两位用来比较是否写了一圈) 20 reg [ADDRSIZE : 0] wp_to_rp1,wp_to_rp2;//写指针同步至读时钟域,格雷码,1与2指的是经过两级D触发器,消除亚稳态 21 reg [ADDRSIZE : 0] rp_to_wp1,rp_to_wp2;//读指针同步至写时钟域,格雷码,1与2指的是经过两级D触发器,消除亚稳态 22 23 //RAM模块----------------------------------------------------------------------------------------- 24 localparam RAM_DEPTH = 1 << ADDRSIZE; //RAM深度=2^ADDRSIZE, 深度=256 25 reg [WIDTH-1 : 0] mem[RAM_DEPTH-1 : 0]; //声明一个位宽为8,深度为256的RAM 26 27 always @(posedge I_w_clk) 28 begin 29 if(I_w_en) 30 mem[waddr] <= I_data; 31 end 32 assign O_data = mem[raddr]; 33 34 //同步模块,将读指针同步至写时钟域----------------------------------------------------------------------- 35 always @(posedge I_w_clk or negedge I_rst_n) 36 begin 37 if(!I_rst_n) 38 begin 39 rp_to_wp1 <= 0; 40 rp_to_wp2 <= 0; 41 end 42 else 43 begin 44 rp_to_wp1 <= r_ptr; 45 rp_to_wp2 <= rp_to_wp1; 46 end 47 end 48 49 //同步模块,将写指针同步至读时钟域-------------------------------------------------- 50 always @(posedge I_r_clk or negedge I_rst_n) 51 begin 52 if(!I_rst_n) 53 begin 54 wp_to_rp1 <= 0; 55 wp_to_rp2 <= 0; 56 end 57 else 58 begin 59 wp_to_rp1 <= w_ptr; 60 wp_to_rp2 <= wp_to_rp1; 61 end 62 end 63 64 //读空信号的产生------------------------------------------------------------------ 65 (*KEEP = "TRUE"*)reg [ADDRSIZE : 0] raddr_cnt; 66 (*KEEP = "TRUE"*)wire [ADDRSIZE : 0]raddr_cnt_next; 67 (*KEEP = "TRUE"*)wire [ADDRSIZE : 0] r_ptr_next; 68 (*KEEP = "TRUE"*)wire empty_val; 69 always @(posedge I_r_clk or negedge I_rst_n) 70 begin 71 if(!I_rst_n) 72 begin 73 raddr_cnt <= 0; 74 r_ptr <= 0; 75 end 76 else 77 begin 78 raddr_cnt <= raddr_cnt_next; 79 r_ptr <= r_ptr_next; 80 end 81 end 82 83 assign raddr_cnt_next = raddr_cnt + (I_r_en & ~O_r_empty);//读地址不断+1 84 assign r_ptr_next = (raddr_cnt_next >> 1) ^ raddr_cnt_next; //地址计数(二进制)=>地址指针(格雷码) 85 assign raddr = raddr_cnt[ADDRSIZE-1 : 0]; //实际地址比地址计数器少一位,最高位用来比较是否写了一圈 86 assign empty_val = (r_ptr_next == wp_to_rp2);//若读指针与同步过来的写指针相等,则读空信号产生 87 88 always @(posedge I_r_clk or negedge I_rst_n) 89 begin 90 if(!I_rst_n) 91 O_r_empty <= 1‘b1; 92 else 93 O_r_empty <= empty_val; 94 end 95 96 97 //写满信号的产生------------------------------------------------------------------ 98 (*KEEP = "TRUE"*)reg [ADDRSIZE : 0] waddr_cnt; 99 (*KEEP = "TRUE"*)wire [ADDRSIZE : 0]waddr_cnt_next; 100 wire [ADDRSIZE : 0]w_ptr_next; 101 wire full_val; 102 103 always @(posedge I_w_clk or negedge I_rst_n) 104 begin 105 if (!I_rst_n) 106 begin 107 waddr_cnt <= 0; 108 w_ptr <= 0; 109 end 110 else 111 begin 112 waddr_cnt <= waddr_cnt_next; 113 w_ptr <= w_ptr_next; 114 end 115 end 116 117 assign waddr_cnt_next = waddr_cnt + (I_w_en & ~O_w_full);//写地址不断+1 118 assign w_ptr_next = (waddr_cnt_next >> 1) ^ waddr_cnt_next; 119 assign waddr = waddr_cnt[ADDRSIZE-1 : 0];//实际地址比地址计数器少一位,最高位用来比较是否写了一圈 120 assign full_val = (w_ptr_next == {~rp_to_wp2[ADDRSIZE : ADDRSIZE-1],rp_to_wp2[ADDRSIZE-2 : 0]});//若写指针与同步过来的读指针最高两位不同,其他位都相等,则写满信号产生 121 122 always @(posedge I_w_clk or negedge I_rst_n) 123 begin 124 if(!I_rst_n) 125 O_w_full <= 1‘b0; 126 else 127 O_w_full <= full_val; 128 end 129 130 endmodule
以上是关于同步FIFO与异步FIFO的Verilog实现的主要内容,如果未能解决你的问题,请参考以下文章