📄 fifo_generator_v2_0.v
字号:
input [C_WR_PNTR_WIDTH-1:0] PROG_FULL_THRESH_NEGATE; input RD_CLK; input RD_EN; input RST; input WR_CLK; input WR_EN; output ALMOST_EMPTY; output ALMOST_FULL; output [C_DOUT_WIDTH-1:0] DOUT; output EMPTY; output FULL; output OVERFLOW; output PROG_EMPTY; output PROG_FULL; output VALID; output [C_RD_DATA_COUNT_WIDTH-1:0] RD_DATA_COUNT; output UNDERFLOW; output WR_ACK; output [C_WR_DATA_COUNT_WIDTH-1:0] WR_DATA_COUNT; /******************************************************************************* * Input and output register declarations ******************************************************************************//******************************************************************************* * Parameters used as constants ******************************************************************************/ parameter C_FULL_RESET_VAL = 1; parameter C_ALMOST_FULL_RESET_VAL = 1; parameter C_PROG_FULL_RESET_VAL = 1; parameter C_HAS_FAST_FIFO = 0; parameter C_RATIO_W = (C_WR_DEPTH>C_RD_DEPTH) ? (C_WR_DEPTH/C_RD_DEPTH) : 1; parameter C_RATIO_R = (C_RD_DEPTH>C_WR_DEPTH) ? (C_RD_DEPTH/C_WR_DEPTH) : 1; parameter C_FIFO_WR_DEPTH = (C_HAS_FAST_FIFO || (C_PRELOAD_REGS && C_PRELOAD_LATENCY) || C_COMMON_CLOCK) ? C_WR_DEPTH : C_WR_DEPTH - 1; parameter C_FIFO_RD_DEPTH = (C_HAS_FAST_FIFO || (C_PRELOAD_REGS && C_PRELOAD_LATENCY) || C_COMMON_CLOCK) ? C_RD_DEPTH : C_RD_DEPTH - 1; parameter C_PROG_FULL_REG = 1; parameter C_PROG_EMPTY_REG = 1; //Memory which will be used to simulate a FIFO reg [C_DIN_WIDTH-1:0] memory[C_WR_DEPTH-1:0]; reg [31:0] num_wr_bits; reg [31:0] num_rd_bits; reg [31:0] next_num_wr_bits; reg [31:0] next_num_rd_bits; reg [31:0] wr_ptr; reg [31:0] rd_ptr; reg [31:0] wr_ptr_rdclk; reg [31:0] wr_ptr_rdclk_q; reg [31:0] wr_ptr_rdclk_next; reg [31:0] rd_ptr_wrclk; reg [31:0] rd_ptr_wrclk_q; reg [31:0] rd_ptr_wrclk_next; wire [31:0] num_read_words = num_rd_bits/C_DOUT_WIDTH; wire [31:0] num_write_words = num_wr_bits/C_DIN_WIDTH; wire [31:0] reads_per_write = C_DIN_WIDTH/C_DOUT_WIDTH; wire [31:0] log2_reads_per_write = log2_val(reads_per_write); wire [31:0] writes_per_read = C_DOUT_WIDTH/C_DIN_WIDTH; wire [31:0] log2_writes_per_read = log2_val(writes_per_read); /******************************************************************************* * Internal Registers and wires ******************************************************************************/ wire wr_ack_i; wire overflow_i; wire underflow_i; wire valid_i; //Special ideal FIFO signals reg [C_DOUT_WIDTH-1:0] ideal_dout; reg ideal_wr_ack; reg ideal_valid; reg ideal_overflow; reg ideal_underflow; reg ideal_full; reg ideal_empty; reg ideal_almost_full; reg ideal_almost_empty; reg ideal_prog_full; reg ideal_prog_empty; //MSBs of the counts reg [C_WR_DATA_COUNT_WIDTH-1 : 0] ideal_wr_count; reg [C_WR_DATA_COUNT_WIDTH-1 : 0] ideal_wr_count_q; reg [C_RD_DATA_COUNT_WIDTH-1 : 0] ideal_rd_count; reg [C_RD_DATA_COUNT_WIDTH-1 : 0] ideal_rd_count_q; //user specified value for reseting the size of the fifo reg [C_DOUT_WIDTH-1:0] dout_reset_val; //temporary registers for WR_RESPONSE_LATENCY feature reg ideal_wr_ack_q; reg ideal_overflow_q; integer tmp_wr_listsize; integer tmp_rd_listsize; //Signal for registered version of prog full and empty reg prog_full_d; reg prog_empty_d; /**************************************************************************** * Function Declarations ***************************************************************************/ task write_fifo; begin memory[wr_ptr] <= DIN; if (wr_ptr == 0) begin wr_ptr <= C_WR_DEPTH - 1; end else begin wr_ptr <= wr_ptr - 1; end end endtask // write_fifo task read_fifo; integer i; reg [C_DOUT_WIDTH-1:0] tmp_dout; reg [C_DIN_WIDTH-1:0] memory_read; reg [31:0] tmp_rd_ptr; reg [31:0] rd_ptr_high; reg [31:0] rd_ptr_low; begin // output is wider than input if (reads_per_write == 0) begin tmp_dout = 0; tmp_rd_ptr = (rd_ptr << log2_writes_per_read)+(writes_per_read-1); for (i = writes_per_read - 1; i >= 0; i = i - 1) begin tmp_dout = tmp_dout << C_DIN_WIDTH; tmp_dout = tmp_dout | memory[tmp_rd_ptr]; if (tmp_rd_ptr == 0) begin tmp_rd_ptr = C_WR_DEPTH - 1; end else begin tmp_rd_ptr = tmp_rd_ptr - 1; end end // output is symmetric end else if (reads_per_write == 1) begin tmp_dout = memory[rd_ptr]; // input is wider than output end else begin rd_ptr_high = rd_ptr >> log2_reads_per_write; rd_ptr_low = rd_ptr & (reads_per_write - 1); memory_read = memory[rd_ptr_high]; tmp_dout = memory_read >> (rd_ptr_low*C_DOUT_WIDTH); end ideal_dout <= tmp_dout; if (rd_ptr == 0) begin rd_ptr <= C_RD_DEPTH - 1; end else begin rd_ptr <= rd_ptr - 1; end end endtask /**************************************************************************** * log2_va * Returns the 'log2' value for the input value for the supported ratios ***************************************************************************/ function [31:0] log2_val; input [31:0] binary_val; begin if (binary_val == 8) begin log2_val = 3; end else if (binary_val == 4) begin log2_val = 2; end else begin log2_val = 1; end end endfunction /************************************************************************* * hexstr_conv * Converts a string of type hex to a binary value (for C_DOUT_RST_VAL) ***********************************************************************/ function [C_DOUT_WIDTH-1:0] hexstr_conv; input [(C_DOUT_WIDTH*8)-1:0] def_data; integer index,i,j; reg [3:0] bin; begin index = 0; hexstr_conv = 'b0; for( i=C_DOUT_WIDTH-1; i>=0; i=i-1 ) begin case (def_data[7:0]) 8'b00000000 : begin bin = 4'b0000; i = -1; end 8'b00110000 : bin = 4'b0000; 8'b00110001 : bin = 4'b0001; 8'b00110010 : bin = 4'b0010; 8'b00110011 : bin = 4'b0011; 8'b00110100 : bin = 4'b0100; 8'b00110101 : bin = 4'b0101; 8'b00110110 : bin = 4'b0110; 8'b00110111 : bin = 4'b0111; 8'b00111000 : bin = 4'b1000; 8'b00111001 : bin = 4'b1001; 8'b01000001 : bin = 4'b1010; 8'b01000010 : bin = 4'b1011; 8'b01000011 : bin = 4'b1100; 8'b01000100 : bin = 4'b1101; 8'b01000101 : bin = 4'b1110; 8'b01000110 : bin = 4'b1111; 8'b01100001 : bin = 4'b1010; 8'b01100010 : bin = 4'b1011; 8'b01100011 : bin = 4'b1100; 8'b01100100 : bin = 4'b1101; 8'b01100101 : bin = 4'b1110; 8'b01100110 : bin = 4'b1111; default : begin bin = 4'bx; end endcase for( j=0; j<4; j=j+1) begin if ((index*4)+j < C_DOUT_WIDTH) begin hexstr_conv[(index*4)+j] = bin[j]; end end index = index + 1; def_data = def_data >> 8; end end endfunction /************************************************************************* * Initialize Signals *************************************************************************/ initial begin num_wr_bits = 0; num_rd_bits = 0; next_num_wr_bits = 0; next_num_rd_bits = 0; rd_ptr = C_RD_DEPTH - 1; wr_ptr = C_WR_DEPTH - 1; rd_ptr_wrclk = rd_ptr; rd_ptr_wrclk_q = rd_ptr; wr_ptr_rdclk = wr_ptr; wr_ptr_rdclk_q = wr_ptr; dout_reset_val = hexstr_conv(C_DOUT_RST_VAL); ideal_dout = dout_reset_val; ideal_wr_ack = 1'b0; ideal_valid = 1'b0; ideal_overflow = 1'b0; ideal_underflow = 1'b0; ideal_full = 1'b1; ideal_empty = 1'b1; ideal_almost_full = 1'b1; ideal_almost_empty = 1'b1; ideal_wr_count = 0; ideal_rd_count = 0; ideal_prog_full = 1'b1; ideal_prog_empty = 1'b1; prog_full_d = 1'b1; prog_empty_d = 1'b1; end /************************************************************************* * Assign Internal ideal signals to output ports *************************************************************************/ assign DOUT = ideal_dout; assign FULL = ideal_full; assign EMPTY = ideal_empty; assign ALMOST_FULL = ideal_almost_full; assign ALMOST_EMPTY = ideal_almost_empty; assign WR_DATA_COUNT= ideal_wr_count; assign RD_DATA_COUNT= ideal_rd_count_q; assign PROG_FULL = (C_PROG_FULL_REG==1) ? ideal_prog_full : prog_full_d; assign PROG_EMPTY = (C_PROG_EMPTY_REG==1) ? ideal_prog_empty : prog_empty_d; //Handshaking signals can be active low, depending on _LOW parameters assign valid_i = (C_PRELOAD_LATENCY==0) ? (RD_EN & ~EMPTY) : ideal_valid; assign VALID = valid_i ? !C_VALID_LOW : C_VALID_LOW; assign underflow_i = (C_PRELOAD_LATENCY==0) ? (RD_EN & EMPTY) : ideal_underflow; assign UNDERFLOW = underflow_i ? !C_UNDERFLOW_LOW : C_UNDERFLOW_LOW; assign WR_ACK = wr_ack_i ? !C_WR_ACK_LOW : C_WR_ACK_LOW; assign wr_ack_i = (C_WR_RESPONSE_LATENCY==2) ? ideal_wr_ack_q : (C_WR_RESPONSE_LATENCY==1) ? ideal_wr_ack : (WR_EN & !FULL); assign OVERFLOW = overflow_i ? !C_OVERFLOW_LOW : C_OVERFLOW_LOW; assign overflow_i = (C_WR_RESPONSE_LATENCY==2) ? ideal_overflow_q : (C_WR_RESPONSE_LATENCY==1) ? ideal_overflow : (WR_EN & FULL); always @(posedge WR_CLK or posedge RST ) begin : gen_fifo_w /****** Reset fifo (case 1)***************************************/ if (RST == 1'b1) begin num_wr_bits <= 0; next_num_wr_bits <= 0; wr_ptr <= C_WR_DEPTH - 1; rd_ptr_wrclk <= C_RD_DEPTH - 1; rd_ptr_wrclk_q <= C_RD_DEPTH - 1; ideal_wr_ack <= 0; ideal_overflow <= 0; ideal_full <= C_FULL_RESET_VAL; //1'b1; ideal_almost_full <= C_ALMOST_FULL_RESET_VAL; //1'b1; ideal_wr_count <= 0; ideal_wr_count_q <= 0; ideal_prog_full <= C_PROG_FULL_RESET_VAL; //1'b1; end else begin //Determine the current number of words in the FIFO tmp_wr_listsize = (C_RATIO_R > 1) ? num_wr_bits/C_DOUT_WIDTH : num_wr_bits/C_DIN_WIDTH; rd_ptr_wrclk_next = rd_ptr; if (rd_ptr_wrclk < rd_ptr_wrclk_next) begin next_num_wr_bits = num_wr_bits - C_DOUT_WIDTH*(rd_ptr_wrclk + C_RD_DEPTH - rd_ptr_wrclk_next); end else begin next_num_wr_bits = num_wr_bits - C_DOUT_WIDTH*(rd_ptr_wrclk - rd_ptr_wrclk_next); end //If this is a write, handle the write by adding the value // to the linked list, and updating all outputs appropriately if (WR_EN == 1'b1) begin if (ideal_full == 1'b1) begin //If the FIFO is full, do NOT perform the write, // update flags accordingly if ((tmp_wr_listsize + C_RATIO_R - 1)/C_RATIO_R >= C_FIFO_WR_DEPTH) begin //write unsuccessful - do not change contents //Do not acknowledge the write ideal_wr_ack <= 0; //throw an overflow error ideal_overflow <= 1; //Reminder that FIFO is still full ideal_full <= 1'b1; ideal_almost_full <= 1'b1; ideal_wr_count <= num_write_words[C_WR_PNTR_WIDTH-1:C_WR_PNTR_WIDTH-C_WR_DATA_COUNT_WIDTH]; //If the FIFO is one from full, but reporting full end else if ((tmp_wr_listsize + C_RATIO_R - 1)/C_RATIO_R == C_FIFO_WR_DEPTH-1) begin //No change to FIFO //Write not successful ideal_wr_ack <= 0; ideal_overflow <= 1; //With DEPTH-1 words in the FIFO, it is almost_full ideal_full <= 1'b0; ideal_almost_full <= 1'b1; ideal_wr_count <= num_write_words[C_WR_PNTR_WIDTH-1:C_WR_PNTR_WIDTH-C_WR_DATA_COUNT_WIDTH]; //If the FIFO is completely empty, but it is // reporting FULL for some reason (like reset) end else if ((tmp_wr_listsize + C_RATIO_R - 1)/C_RATIO_R <= C_FIFO_WR_DEPTH-2) begin //No change to FIFO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -