1. 程式人生 > 實用技巧 >同步FIFO與非同步FIFO的Verilog實現

同步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
sync_fifo
  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
async_fifo