URL
https://opencores.org/ocsvn/pcie_ds_dma/pcie_ds_dma/trunk
Subversion Repositories pcie_ds_dma
[/] [pcie_ds_dma/] [trunk/] [core/] [ds_dma64/] [pcie_src/] [pcie_core64_m1/] [source/] [pcie_blk_ll_oqbqfifo.v] - Rev 15
Go to most recent revision | Compare with Previous | Blame | View Log
//----------------------------------------------------------------------------- // // (c) Copyright 2009-2010 Xilinx, Inc. All rights reserved. // // This file contains confidential and proprietary information // of Xilinx, Inc. and is protected under U.S. and // international copyright and other intellectual property // laws. // // DISCLAIMER // This disclaimer is not a license and does not grant any // rights to the materials distributed herewith. Except as // otherwise provided in a valid license issued to you by // Xilinx, and to the maximum extent permitted by applicable // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and // (2) Xilinx shall not be liable (whether in contract or tort, // including negligence, or under any other theory of // liability) for any loss or damage of any kind or nature // related to, arising under or in connection with these // materials, including for any direct, or any indirect, // special, incidental, or consequential loss or damage // (including loss of data, profits, goodwill, or any type of // loss or damage suffered as a result of any action brought // by a third party) even if such damage or loss was // reasonably foreseeable or Xilinx had been advised of the // possibility of the same. // // CRITICAL APPLICATIONS // Xilinx products are not designed or intended to be fail- // safe, or for use in any application requiring fail-safe // performance, such as life-support or safety devices or // systems, Class III medical devices, nuclear facilities, // applications related to the deployment of airbags, or any // other applications that could lead to death, personal // injury, or severe property or environmental damage // (individually and collectively, "Critical // Applications"). Customer assumes the sole risk and // liability of any use of Xilinx products in Critical // Applications, subject only to applicable laws and // regulations governing limitations on product liability. // // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS // PART OF THIS FILE AT ALL TIMES. // //----------------------------------------------------------------------------- // Project : V5-Block Plus for PCI Express // File : pcie_blk_ll_oqbqfifo.v //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- //-- //-- Description: First word Fall-Thru FIFO with separate storage areas //-- for Non-posted and posted/completion TLPs //-- //-------------------------------------------------------------------------------- `timescale 1ns/1ns `ifndef TCQ `define TCQ 1 `endif module pcie_blk_ll_oqbqfifo //{{{ Port List ( // Clock and reset input wire clk, input wire rst_n, // Outputs output reg trn_rsrc_rdy = 0, output reg [63:0] trn_rd = 0, output reg [7:0] trn_rrem = 0, output reg trn_rsof = 0, output reg trn_reof = 0, output reg trn_rerrfwd = 0, output reg [6:0] trn_rbar_hit = 0, output reg fifo_np_ok = 1, output reg fifo_pcpl_ok = 1, // Inputs input trn_rdst_rdy, input trn_rnp_ok, input fifo_wren, input [63:0] fifo_data, input fifo_rem, input fifo_sof, input fifo_preeof, input fifo_eof, input fifo_dsc, input fifo_np, input [3:0] fifo_barenc, // Encoded BAR hit input fifo_np_req, input fifo_pcpl_req, input fifo_np_abort, input fifo_pcpl_abort ); //}}} //{{{ Wire/Reg declarations wire [71:0] oq_din, bq_din; wire [71:0] oq_dout, bq_dout; wire [63:0] oq_dataout, bq_dataout; wire oq_sofout, bq_sofout; wire oq_preeofout, bq_preeofout; wire oq_remout, bq_remout; wire oq_errout, bq_errout; wire [3:0] oq_barout, bq_barout; wire oq_wren, bq_wren; wire oq_rden, bq_rden; wire oq_full, bq_full; wire oq_afull, bq_afull; wire oq_rdy, bq_rdy; wire oq_valid, bq_valid; wire oq_empty, bq_empty; wire oq_trn_in_progress, bq_trn_in_progress; wire trigger_oq_trn, trigger_bq_trn; wire oq_memrd; wire poisoned; reg poisoned_reg = 0; reg packet_in_progress = 0; reg packet_in_progress_bq = 0; reg packet_in_progress_oq = 0; wire trigger_bypass; wire oq_byp_in_progress; reg oq_byp_in_progress_reg; reg [3:0] np_count = 0; reg trn_np = 0; reg trn_drain_np = 0; reg fifo_discard_np = 0; reg trn_rnp_ok_d = 1; reg [8:0] oq_pktcnt = 0; reg [3:0] bq_pktcnt = 0; reg oq_pkt_avail = 0; reg bq_pkt_avail = 0; reg oq_write_pkt_in_progress_reg = 0; reg new_oq_pkt_wr =0; reg new_oq_pkt_wr_d =0; reg new_oq_pkt_wr_d2 =0; integer i; //}}} //{{{ Functions function [6:0] barhit; input [3:0] selector; begin casex (selector) 4'b0000: barhit = 7'b0000001; 4'b0001: barhit = 7'b0000010; 4'b0010: barhit = 7'b0000100; 4'b0011: barhit = 7'b0001000; 4'b0100: barhit = 7'b0010000; 4'b0101: barhit = 7'b0100000; 4'b0110: barhit = 7'b1000000; 4'b0111: barhit = 7'b0000011; 4'b1000: barhit = 7'b0000110; 4'b1001: barhit = 7'b0001100; 4'b1010: barhit = 7'b0011000; 4'b1011: barhit = 7'b0110000; default: barhit = 7'b0000000; // No BAR hit (cpl) endcase end endfunction function nonposted; input [7:0] header; begin casex (header[6:0]) 7'b0x0000x: nonposted = 1'b1; //MRd, MRdLk 7'bx000010: nonposted = 1'b1; //IO 7'bx00010x: nonposted = 1'b1; //Cfg default: nonposted = 1'b0; endcase end endfunction //}}} //{{{ Ordered Queue (OQ) FIFO // Map module inputs and internal signals to BRAM inputs wire nonposted_or_rem = fifo_sof ? nonposted(fifo_data[63:56]) : fifo_rem; // 71 70 69 68 67:64 63:0 assign oq_din = {fifo_sof, fifo_eof, nonposted_or_rem, poisoned, fifo_barenc, fifo_data}; assign oq_sofout = oq_dout[71]; assign oq_eofout = oq_dout[70]; assign oq_remout = oq_eofout ? oq_dout[69] : 1'b1; assign oq_errout = oq_dout[68]; assign oq_barout = oq_dout[67:64]; assign oq_dataout = oq_dout[63:0]; assign oq_valid = !oq_empty; assign oq_memrd = oq_sofout && oq_valid && oq_dout[69]; //bit69 indicates nonposted during SOF assign oq_wren = (oq_write_pkt_in_progress_reg || fifo_sof) && fifo_wren; assign oq_rden = ((oq_trn_in_progress && (trn_rdst_rdy || !trn_rsrc_rdy)) || oq_byp_in_progress); always @(posedge clk) begin if (!rst_n) oq_write_pkt_in_progress_reg <= #`TCQ 1'b0; else if (fifo_wren && fifo_sof) oq_write_pkt_in_progress_reg <= #`TCQ 1'b1; else if (fifo_wren && (fifo_eof || fifo_dsc)) oq_write_pkt_in_progress_reg <= #`TCQ 1'b0; end sync_fifo #( .WIDTH (72), .DEPTH (512), .STYLE ("BRAM"), .AFASSERT (512 - 66 - 14), .FWFT (1), .SUP_REWIND (1) ) oq_fifo ( .clk ( clk ), .rst_n ( rst_n ), .din ( oq_din ), .dout ( oq_dout ), .wr_en ( oq_wren ), .rd_en ( oq_rden ), .full ( oq_full ), .afull ( oq_afull ), .empty ( oq_empty ), .aempty ( ), .data_count ( ), .mark_addr ( fifo_sof && oq_wren ), .clear_addr ( fifo_eof && oq_wren ), .rewind ( fifo_dsc && oq_wren ) ); //}}} //{{{ Bypass Queue (BQ) FIFO // Instantiate SRLFIFO for storing BQ data. assign bq_din = oq_dout; assign bq_sofout = bq_dout[71]; assign bq_eofout = bq_dout[70]; assign bq_remout = bq_dout[69]; assign bq_errout = bq_dout[68]; assign bq_barout = bq_dout[67:64]; assign bq_dataout = bq_dout[63:0]; assign bq_valid = !bq_empty; assign bq_wren = oq_valid && oq_byp_in_progress; assign bq_rden = bq_valid && bq_trn_in_progress && (trn_rdst_rdy || !trn_rsrc_rdy); sync_fifo #( .WIDTH (72), .DEPTH (16), .FWFT (1), .STYLE ("SRL") ) bq_fifo ( .din ( bq_din ), .dout ( bq_dout ), .wr_en ( bq_wren ), .rd_en ( bq_rden ), .full ( bq_full ), .afull ( bq_afull ), .empty ( bq_empty ), .aempty ( ), .data_count ( ), .clk ( clk ), .rst_n ( rst_n ) ); //}}} //{{{ OQ/BQ Arbitration Logic; Bypass assign trigger_bypass = (oq_memrd && !bq_afull && !trn_rnp_ok_d); assign oq_byp_in_progress = oq_byp_in_progress_reg || trigger_bypass; assign bq_rdy = bq_pkt_avail; assign oq_rdy = !bq_rdy && oq_pkt_avail && !oq_byp_in_progress; assign trigger_bq_trn = bq_rdy && !trn_rsrc_rdy && !packet_in_progress; assign bq_trn_in_progress = packet_in_progress_bq || trigger_bq_trn; assign trigger_oq_trn = oq_rdy && !trn_rsrc_rdy && !packet_in_progress; assign oq_trn_in_progress = packet_in_progress_oq || trigger_oq_trn; always @(posedge clk) begin if (!rst_n) oq_byp_in_progress_reg <= #`TCQ 1'b0; else if (trigger_bypass) oq_byp_in_progress_reg <= #`TCQ 1'b1; else if (oq_eofout && oq_valid) oq_byp_in_progress_reg <= #`TCQ 1'b0; end //}}} //{{{ TRN Interface always @(posedge clk) begin if (!rst_n) begin trn_rd <= #`TCQ 'h0; trn_rsof <= #`TCQ 1'b0; trn_reof <= #`TCQ 1'b0; trn_rrem <= #`TCQ 8'hFF; trn_rbar_hit <= #`TCQ 'h0; trn_rsrc_rdy <= #`TCQ 1'b0; trn_rerrfwd <= #`TCQ 1'b0; packet_in_progress <= #`TCQ 1'b0; packet_in_progress_bq <= #`TCQ 1'b0; packet_in_progress_oq <= #`TCQ 1'b0; end else begin //Case 1: Waiting for EOF to be accepted (stalled with DST RDY) if (trn_rsrc_rdy && trn_reof && !trn_rdst_rdy) begin packet_in_progress <= #`TCQ 1'b0; packet_in_progress_bq <= #`TCQ 1'b0; packet_in_progress_oq <= #`TCQ 1'b0; trn_rd <= #`TCQ trn_rd; trn_rsof <= #`TCQ trn_rsof; trn_reof <= #`TCQ trn_reof; trn_rrem <= #`TCQ trn_rrem; trn_rsrc_rdy <= #`TCQ trn_rsrc_rdy && !trn_rdst_rdy; trn_rbar_hit <= #`TCQ trn_rbar_hit; trn_rerrfwd <= #`TCQ trn_rerrfwd; end //Case 2: Packet in progress from BQ queue, or starting new one from idle else if (bq_trn_in_progress) begin // Filling accepted data if ((trn_rdst_rdy || !trn_rsrc_rdy) && bq_valid) begin packet_in_progress <= #`TCQ (!bq_eofout || bq_rdy) || (bq_eofout && oq_rdy); packet_in_progress_bq <= #`TCQ !bq_eofout || bq_rdy; packet_in_progress_oq <= #`TCQ bq_eofout && oq_rdy && !oq_byp_in_progress; trn_rd <= #`TCQ bq_dataout; trn_rsof <= #`TCQ bq_sofout; trn_rrem <= #`TCQ {4'hF, { 4{bq_remout} }}; trn_rbar_hit <= #`TCQ barhit(bq_barout); trn_rerrfwd <= #`TCQ bq_errout; end if ((trn_rdst_rdy || !trn_rsrc_rdy) && bq_valid) begin trn_rsrc_rdy <= #`TCQ 1'b1; trn_reof <= #`TCQ bq_eofout; // Packet in progress from BQ queue; queue pauses end else if (!bq_valid) begin trn_rsrc_rdy <= #`TCQ trn_rsrc_rdy && !trn_rdst_rdy; trn_reof <= #`TCQ bq_eofout && !trn_rdst_rdy; end end //Case 3: Packet in progress from OQ queue, or starting new one from idle else if (oq_trn_in_progress && !oq_byp_in_progress) begin //packet_in_progress_oq || (oq_rdy && !trn_rsrc_rdy && !packet_in_progress)) begin if ((trn_rdst_rdy || !trn_rsrc_rdy) && oq_valid) begin packet_in_progress <= #`TCQ (!oq_eofout || oq_rdy) || (oq_eofout && bq_rdy); packet_in_progress_bq <= #`TCQ oq_eofout && bq_rdy; packet_in_progress_oq <= #`TCQ !oq_eofout || oq_rdy; trn_rd <= #`TCQ oq_dataout; trn_rsof <= #`TCQ oq_sofout; trn_rrem <= #`TCQ {4'hF, { 4{oq_remout} }}; trn_rbar_hit <= #`TCQ barhit(oq_barout); trn_rerrfwd <= #`TCQ oq_errout; trn_rsrc_rdy <= #`TCQ 1'b1; trn_reof <= #`TCQ oq_eofout; // Packet in progress from OQ queue; queue pauses end else if (!oq_valid) begin trn_rsrc_rdy <= #`TCQ trn_rsrc_rdy && !trn_rdst_rdy; trn_reof <= #`TCQ oq_eofout && !trn_rdst_rdy; end end //Case 4: Idle else begin packet_in_progress <= #`TCQ 1'b0; packet_in_progress_bq <= #`TCQ 1'b0; packet_in_progress_oq <= #`TCQ 1'b0; trn_rd <= #`TCQ trn_rd; trn_rsof <= #`TCQ 1'b0; trn_reof <= #`TCQ 1'b0; trn_rrem <= #`TCQ 8'hFF; trn_rsrc_rdy <= #`TCQ 1'b0; trn_rbar_hit <= #`TCQ 'h0; trn_rerrfwd <= #`TCQ 1'b0; end end end //}}} //{{{ ASSERTIONS: LocalLink and TRN `ifdef SV //synthesis translate_off ASSERT_LL_DOUBLESOF: assert property (@(posedge clk) (trn_rsof && trn_rdst_rdy && trn_rsrc_rdy) |-> ##1 !(trn_rsof && trn_rdst_rdy && trn_rsrc_rdy) ) else $fatal; ASSERT_LL_DOUBLEEOF: assert property (@(posedge clk) (trn_reof && trn_rdst_rdy && trn_rsrc_rdy) |-> ##1 !(trn_reof && trn_rdst_rdy && trn_rsrc_rdy) ) else $fatal; ASSERT_RDST_HOLDS_OUTPUT: assert property (@(posedge clk) !trn_rdst_rdy && trn_rsrc_rdy |-> ##1 $stable(trn_rd) && $stable(trn_rsof) && $stable(trn_reof) && $stable(trn_rrem) && $stable(trn_rbar_hit) && $stable(trn_rerrfwd) ) else $fatal; //TLPs s/b back2back if possible, if there is a valid dword in OQ or BQ after //a non-stalled EOF, unless: //a) OQ->BQ bypass is occurring, and BQ output is empty or stalled due to RNP_OK deassertion //b) RNP_OK is deasserted, and either OQ not available or it is a NP ASSERT_RX_TRN_BACK2BACK_NP: assert property (@(posedge clk) !(!trn_rdst_rdy && trn_rsrc_rdy && trn_reof) && (bq_valid && (bq_pktcnt>0) && trn_rnp_ok_d) ##1 trn_rdst_rdy && trn_rsrc_rdy && trn_reof |-> ##1 (trn_rsof && trn_rsrc_rdy && nonposted(trn_rd[63:56])) ) else $fatal; ASSERT_RX_TRN_BACK2BACK_PCPL:assert property (@(posedge clk) !(!trn_rdst_rdy && trn_rsrc_rdy && trn_reof) && !(bq_valid && (bq_pktcnt>0) && trn_rnp_ok_d) && (oq_valid && (oq_pktcnt>0) && !oq_byp_in_progress && !(!trn_rnp_ok_d && oq_memrd)) ##1 trn_rdst_rdy && trn_rsrc_rdy && trn_reof |-> ##1 (trn_rsof && trn_rsrc_rdy) || oq_byp_in_progress ) else $fatal; ASSERT_PROGRESS_MUTEX1: assert property (@(posedge clk) bq_trn_in_progress |-> !oq_trn_in_progress ) else $fatal; ASSERT_PROGRESS_MUTEX2: assert property (@(posedge clk) oq_trn_in_progress |-> !bq_trn_in_progress && (!oq_byp_in_progress || (trn_reof && trn_rsrc_rdy)) ) else $fatal; ASSERT_PROGRESS_MUTEX3: assert property (@(posedge clk) oq_byp_in_progress && !(trn_reof && trn_rsrc_rdy) |-> !oq_trn_in_progress ) else $fatal; ASSERT_PACKETINPROGRESS2: assert property (@(posedge clk) packet_in_progress_oq |-> !packet_in_progress_bq && packet_in_progress ) else $fatal; ASSERT_PACKETINPROGRESS3: assert property (@(posedge clk) packet_in_progress |-> packet_in_progress_bq || packet_in_progress_oq ) else $fatal; ASSERT_BYPASS_OQ_MUTEX: assert property (@(posedge clk) !(bq_wren && oq_trn_in_progress && !(trn_reof && trn_rsrc_rdy)) ) else $fatal; ASSERT_BQ_WRITE_BYP_ONLY: assert property (@(posedge clk) !(bq_wren && !oq_byp_in_progress) ) else $fatal; ASSERT_RNPOK_STOPS_NP: assert property (@(posedge clk) !trn_rnp_ok ##1 !trn_rnp_ok ##1 !trn_rnp_ok |-> ##1 !(trn_rsof && trn_rsrc_rdy && nonposted(trn_rd[64:56])) ) else $fatal; //synthesis translate_on `endif //}}} //{{{ Poisoned bit logic // Assert poisoned when starting or continuing a poisoned TLP assign poisoned = poisoned_reg || (fifo_data[46] && fifo_sof); // Continue wrtrans* and poisoned signals after SOF until EOF always @(posedge clk) begin if (!rst_n) begin poisoned_reg <= #`TCQ 0; end else if (fifo_sof && !fifo_eof && fifo_wren) begin poisoned_reg <= #`TCQ fifo_data[46]; end else if (fifo_eof && fifo_wren) begin poisoned_reg <= #`TCQ 0; end end //}}} //{{{ FIFO-fullness counting logic always @(posedge clk) begin if (!rst_n) begin fifo_np_ok <= #`TCQ 1'b1; fifo_pcpl_ok <= #`TCQ 1'b1; trn_np <= #`TCQ 1'b0; trn_drain_np <= #`TCQ 1'b0; fifo_discard_np <= #`TCQ 1'b0; np_count <= #`TCQ 'h0; trn_rnp_ok_d <= #`TCQ 1'b1; new_oq_pkt_wr <= #`TCQ 1'b0; new_oq_pkt_wr_d <= #`TCQ 1'b0; new_oq_pkt_wr_d2 <= #`TCQ 1'b0; oq_pktcnt <= #`TCQ 'h0; bq_pktcnt <= #`TCQ 'h0; oq_pkt_avail <= #`TCQ 'b0; bq_pkt_avail <= #`TCQ 'b0; end else begin fifo_np_ok <= #`TCQ (np_count<8) && !oq_afull; fifo_pcpl_ok <= #`TCQ !oq_afull; if (trn_rsof && nonposted(trn_rd[63:56]) && trn_rsrc_rdy) trn_np <= #`TCQ 1'b1; else if (trn_rsof && trn_rsrc_rdy) trn_np <= #`TCQ 1'b0; trn_drain_np <= #`TCQ trn_np && trn_reof && trn_rsrc_rdy && trn_rdst_rdy; fifo_discard_np <= #`TCQ fifo_np && fifo_wren && fifo_dsc; case ({fifo_np_req,trn_drain_np,fifo_discard_np}) 3'b000 : np_count <= #`TCQ np_count; 3'b001 : np_count <= #`TCQ np_count - 1; 3'b010 : np_count <= #`TCQ np_count - 1; 3'b011 : np_count <= #`TCQ np_count - 2; 3'b100 : np_count <= #`TCQ np_count + 1; 3'b101 : np_count <= #`TCQ np_count; 3'b110 : np_count <= #`TCQ np_count; 3'b111 : np_count <= #`TCQ np_count - 1; default: np_count <= #`TCQ np_count; endcase trn_rnp_ok_d <= #`TCQ trn_rnp_ok; new_oq_pkt_wr <= #`TCQ oq_wren && fifo_eof && !fifo_dsc; new_oq_pkt_wr_d <= #`TCQ new_oq_pkt_wr; new_oq_pkt_wr_d2 <= #`TCQ new_oq_pkt_wr_d; if (new_oq_pkt_wr_d2 && !(oq_rden && oq_sofout && oq_valid)) begin oq_pktcnt <= #`TCQ oq_pktcnt + 1; oq_pkt_avail <= #`TCQ 1'b1; end else if (!new_oq_pkt_wr_d2 && (oq_rden && oq_sofout && oq_valid)) begin oq_pktcnt <= #`TCQ oq_pktcnt - 1; oq_pkt_avail <= #`TCQ (oq_pktcnt>1); end else begin oq_pkt_avail <= #`TCQ (oq_pktcnt>0); end if ( (bq_wren && oq_eofout) && !(bq_rden && bq_sofout && bq_valid)) begin bq_pktcnt <= #`TCQ bq_pktcnt + 1; bq_pkt_avail <= #`TCQ trn_rnp_ok_d; end else if (!(bq_wren && oq_eofout) && (bq_rden && bq_sofout && bq_valid)) begin bq_pktcnt <= #`TCQ bq_pktcnt - 1; bq_pkt_avail <= #`TCQ (bq_pktcnt>1) && trn_rnp_ok_d; end else begin bq_pkt_avail <= #`TCQ (bq_pktcnt>0) && trn_rnp_ok_d; end end end //}}} //{{{ ASSERTIONS: npcount `ifdef SV //synthesis translate_off ASSERT_NPCOUNT_IS_0_WHEN_IDLE: assert property (@(posedge clk) (!oq_valid && !bq_valid && !trn_rsrc_rdy && !fifo_np_req)[*20] |-> (np_count == 0) ) else $fatal; ASSERT_NPCOUNT_IS_8_OR_LESS: assert property (@(posedge clk) !(np_count > 8 ) ) else $fatal; //synthesis translate_on `endif //}}} endmodule
Go to most recent revision | Compare with Previous | Blame | View Log