URL
https://opencores.org/ocsvn/oms8051mini/oms8051mini/trunk
Subversion Repositories oms8051mini
[/] [oms8051mini/] [trunk/] [rtl/] [lib/] [async_fifo.v] - Rev 2
Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////////// //// //// //// OMS 8051 cores common library Module //// //// //// //// This file is part of the OMS 8051 cores project //// //// http://www.opencores.org/cores/oms8051mini/ //// //// //// //// Description //// //// OMS 8051 definitions. //// //// //// //// To Do: //// //// nothing //// //// //// //// Author(s): //// //// - Dinesh Annayya, dinesha@opencores.org //// //// //// //// Revision : Nov 26, 2016 //// //// //// ////////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2000 Authors and OPENCORES.ORG //// //// //// //// This source file may be used and distributed without //// //// restriction provided that this copyright statement is not //// //// removed from the file and that any derivative work contains //// //// the original copyright notice and the associated disclaimer. //// //// //// //// This source file is free software; you can redistribute it //// //// and/or modify it under the terms of the GNU Lesser General //// //// Public License as published by the Free Software Foundation; //// //// either version 2.1 of the License, or (at your option) any //// //// later version. //// //// //// //// This source is distributed in the hope that it will be //// //// useful, but WITHOUT ANY WARRANTY; without even the implied //// //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// //// PURPOSE. See the GNU Lesser General Public License for more //// //// details. //// //// //// //// You should have received a copy of the GNU Lesser General //// //// Public License along with this source; if not, download it //// //// from http://www.opencores.org/lgpl.shtml //// //// //// ////////////////////////////////////////////////////////////////////// //------------------------------------------- // async_fifo:: async FIFO // Following two ports are newly added // 1. At write clock domain: // wr_total_free_space --> Indicate total free transfer available // 2. At read clock domain: // rd_total_aval --> Indicate total no of transfer available //----------------------------------------------- module async_fifo (wr_clk, wr_reset_n, wr_en, wr_data, full, // sync'ed to wr_clk afull, // sync'ed to wr_clk wr_total_free_space, rd_clk, rd_reset_n, rd_en, empty, // sync'ed to rd_clk aempty, // sync'ed to rd_clk rd_total_aval, rd_data); parameter W = 4'd8; parameter DP = 3'd4; parameter WR_FAST = 1'b1; parameter RD_FAST = 1'b1; parameter FULL_DP = DP; parameter EMPTY_DP = 1'b0; parameter AW = (DP == 2) ? 1 : (DP == 4) ? 2 : (DP == 8) ? 3 : (DP == 16) ? 4 : (DP == 32) ? 5 : (DP == 64) ? 6 : (DP == 128) ? 7 : (DP == 256) ? 8 : 0; output [W-1 : 0] rd_data; input [W-1 : 0] wr_data; input wr_clk, wr_reset_n, wr_en, rd_clk, rd_reset_n, rd_en; output full, empty; output afull, aempty; // about full and about to empty output [AW:0] wr_total_free_space; // Total Number of free space aval // w.r.t write clk // note: Without accounting byte enables output [AW:0] rd_total_aval; // Total Number of words avaialble // w.r.t rd clock, // note: Without accounting byte enables // synopsys translate_off initial begin if (AW == 0) begin $display ("%m : ERROR!!! Fifo depth %d not in range 2 to 256", DP); end // if (AW == 0) end // initial begin // synopsys translate_on reg [W-1 : 0] mem[DP-1 : 0]; /*********************** write side ************************/ reg [AW:0] sync_rd_ptr_0, sync_rd_ptr_1; wire [AW:0] sync_rd_ptr; reg [AW:0] wr_ptr, grey_wr_ptr; reg [AW:0] grey_rd_ptr; reg full_q; wire full_c; wire afull_c; wire [AW:0] wr_ptr_inc = wr_ptr + 1'b1; wire [AW:0] wr_cnt = get_cnt(wr_ptr, sync_rd_ptr); assign full_c = (wr_cnt == FULL_DP) ? 1'b1 : 1'b0; assign afull_c = (wr_cnt == FULL_DP-1) ? 1'b1 : 1'b0; //-------------------------- // Shows total number of words // of free space available w.r.t write clock //--------------------------- assign wr_total_free_space = FULL_DP - wr_cnt; always @(posedge wr_clk or negedge wr_reset_n) begin if (!wr_reset_n) begin wr_ptr <= 0; grey_wr_ptr <= 0; full_q <= 0; end else if (wr_en) begin wr_ptr <= wr_ptr_inc; grey_wr_ptr <= bin2grey(wr_ptr_inc); if (wr_cnt == (FULL_DP-1)) begin full_q <= 1'b1; end end else begin if (full_q && (wr_cnt<FULL_DP)) begin full_q <= 1'b0; end end end assign full = (WR_FAST == 1) ? full_c : full_q; assign afull = afull_c; always @(posedge wr_clk) begin if (wr_en) begin mem[wr_ptr[AW-1:0]] <= wr_data; end end wire [AW:0] grey_rd_ptr_dly ; assign #1 grey_rd_ptr_dly = grey_rd_ptr; // read pointer synchronizer always @(posedge wr_clk or negedge wr_reset_n) begin if (!wr_reset_n) begin sync_rd_ptr_0 <= 0; sync_rd_ptr_1 <= 0; end else begin sync_rd_ptr_0 <= grey_rd_ptr_dly; sync_rd_ptr_1 <= sync_rd_ptr_0; end end assign sync_rd_ptr = grey2bin(sync_rd_ptr_1); /************************ read side *****************************/ reg [AW:0] sync_wr_ptr_0, sync_wr_ptr_1; wire [AW:0] sync_wr_ptr; reg [AW:0] rd_ptr; reg empty_q; wire empty_c; wire aempty_c; wire [AW:0] rd_ptr_inc = rd_ptr + 1'b1; wire [AW:0] sync_wr_ptr_dec = sync_wr_ptr - 1'b1; wire [AW:0] rd_cnt = get_cnt(sync_wr_ptr, rd_ptr); assign empty_c = (rd_cnt == 0) ? 1'b1 : 1'b0; assign aempty_c = (rd_cnt == 1) ? 1'b1 : 1'b0; //-------------------------- // Shows total number of words // space available w.r.t write clock //--------------------------- assign rd_total_aval = rd_cnt; always @(posedge rd_clk or negedge rd_reset_n) begin if (!rd_reset_n) begin rd_ptr <= 0; grey_rd_ptr <= 0; empty_q <= 1'b1; end else begin if (rd_en) begin rd_ptr <= rd_ptr_inc; grey_rd_ptr <= bin2grey(rd_ptr_inc); if (rd_cnt==(EMPTY_DP+1)) begin empty_q <= 1'b1; end end else begin if (empty_q && (rd_cnt!=EMPTY_DP)) begin empty_q <= 1'b0; end end end end assign empty = (RD_FAST == 1) ? empty_c : empty_q; assign aempty = aempty_c; assign rd_data = mem[rd_ptr[AW-1:0]]; wire [AW:0] grey_wr_ptr_dly ; assign #1 grey_wr_ptr_dly = grey_wr_ptr; // write pointer synchronizer always @(posedge rd_clk or negedge rd_reset_n) begin if (!rd_reset_n) begin sync_wr_ptr_0 <= 0; sync_wr_ptr_1 <= 0; end else begin sync_wr_ptr_0 <= grey_wr_ptr_dly; sync_wr_ptr_1 <= sync_wr_ptr_0; end end assign sync_wr_ptr = grey2bin(sync_wr_ptr_1); /************************ functions ******************************/ function [AW:0] bin2grey; input [AW:0] bin; reg [8:0] bin_8; reg [8:0] grey_8; begin bin_8 = bin; grey_8[1:0] = do_grey(bin_8[2:0]); grey_8[3:2] = do_grey(bin_8[4:2]); grey_8[5:4] = do_grey(bin_8[6:4]); grey_8[7:6] = do_grey(bin_8[8:6]); grey_8[8] = bin_8[8]; bin2grey = grey_8; end endfunction function [AW:0] grey2bin; input [AW:0] grey; reg [8:0] grey_8; reg [8:0] bin_8; begin grey_8 = grey; bin_8[8] = grey_8[8]; bin_8[7:6] = do_bin({bin_8[8], grey_8[7:6]}); bin_8[5:4] = do_bin({bin_8[6], grey_8[5:4]}); bin_8[3:2] = do_bin({bin_8[4], grey_8[3:2]}); bin_8[1:0] = do_bin({bin_8[2], grey_8[1:0]}); grey2bin = bin_8; end endfunction function [1:0] do_grey; input [2:0] bin; begin if (bin[2]) begin // do reverse grey case (bin[1:0]) 2'b00: do_grey = 2'b10; 2'b01: do_grey = 2'b11; 2'b10: do_grey = 2'b01; 2'b11: do_grey = 2'b00; endcase end else begin case (bin[1:0]) 2'b00: do_grey = 2'b00; 2'b01: do_grey = 2'b01; 2'b10: do_grey = 2'b11; 2'b11: do_grey = 2'b10; endcase end end endfunction function [1:0] do_bin; input [2:0] grey; begin if (grey[2]) begin // actually bin[2] case (grey[1:0]) 2'b10: do_bin = 2'b00; 2'b11: do_bin = 2'b01; 2'b01: do_bin = 2'b10; 2'b00: do_bin = 2'b11; endcase end else begin case (grey[1:0]) 2'b00: do_bin = 2'b00; 2'b01: do_bin = 2'b01; 2'b11: do_bin = 2'b10; 2'b10: do_bin = 2'b11; endcase end end endfunction function [AW:0] get_cnt; input [AW:0] wr_ptr, rd_ptr; begin if (wr_ptr >= rd_ptr) begin get_cnt = (wr_ptr - rd_ptr); end else begin get_cnt = DP*2 - (rd_ptr - wr_ptr); end end endfunction // synopsys translate_off always @(posedge wr_clk) begin if (wr_en && full) begin $display($time, "%m Error! afifo overflow!"); $stop; end end always @(posedge rd_clk) begin if (rd_en && empty) begin $display($time, "%m error! afifo underflow!"); $stop; end end // gray code monitor reg [AW:0] last_gwr_ptr; always @(posedge wr_clk or negedge wr_reset_n) begin if (!wr_reset_n) begin last_gwr_ptr <= #1 0; end else if (last_gwr_ptr !== grey_wr_ptr) begin check_ptr_chg(last_gwr_ptr, grey_wr_ptr); last_gwr_ptr <= #1 grey_wr_ptr; end end reg [AW:0] last_grd_ptr; always @(posedge rd_clk or negedge rd_reset_n) begin if (!rd_reset_n) begin last_grd_ptr <= #1 0; end else if (last_grd_ptr !== grey_rd_ptr) begin check_ptr_chg(last_grd_ptr, grey_rd_ptr); last_grd_ptr <= #1 grey_rd_ptr; end end task check_ptr_chg; input [AW:0] last_ptr; input [AW:0] cur_ptr; integer i; integer ptr_diff; begin ptr_diff = 0; for (i=0; i<= AW; i=i+ 1'b1) begin if (last_ptr[i] != cur_ptr[i]) begin ptr_diff = ptr_diff + 1'b1; end end if (ptr_diff !== 1) begin $display($time, "%m, ERROR! async fifo ptr has changed more than noe bit, last=%h, cur=%h", last_ptr, cur_ptr); $stop; end end endtask // synopsys translate_on endmodule