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/] [tlm_rx_data_snk_mal.v] - Rev 42
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 : tlm_rx_data_snk_mal.v //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- /**************************************************************************** * Description : Rx Data Sink malformed packet detection * * Hierarchical : * * Functional : * Takes incoming packets, examines the packet for correct * construction and drops if it malformed. * ***************************************************************************/ `timescale 1ns/1ps `ifndef TCQ `define TCQ 1 `endif `ifndef PCIE `ifndef AS `define PCIE `endif `endif module tlm_rx_data_snk_mal #(parameter DW = 32, parameter FCW = 6, parameter LENW = 10, `ifdef PCIE parameter DOWNSTREAM_PORT = 0, `else // `ifdef AS parameter OVC = 0, parameter MVC = 0, `endif parameter MPS = 512, parameter TYPE1_UR = 0) ( input clk_i, input reset_i, // credit output output reg [FCW-1:0] data_credits_o, // data credits for the packet output data_credits_vld_o,// data credits valid // packet steering output reg cfg_o, // Packet is config `ifdef AS input oo_i, // Packet is OVC-bound input ts_i, // Packet is Bypassable in BVC `endif // errors `ifdef PCIE output reg malformed_o, // packet is badly constructed output reg tlp_ur_o, // unsupported request output reg tlp_ur_lock_o, // unsupported request due to MemRdLk output reg tlp_uc_o, // unexpected completion output reg tlp_filt_o, // filter this packet - not an // error, but handled @same time `else // `ifdef AS output reg bad_header_crc_o, output reg bad_pi_chain_o, output reg bad_credit_length_o, output reg invalid_credit_length_o, output reg non_zero_turn_pointer_o, output reg unsup_mvc_o, output reg unsup_ovc_o, `endif // For user/config steering input [3:0] aperture_i, // Config address ext. reg. number input load_aperture_i, `ifdef PCIE // for format calculations input eval_fulltype_i, // Latch fulltype_i input [6:0] fulltype_i, // Type valid on eval_fulltype_i input eval_msgcode_i, // Latch msgcode_i input [7:0] msgcode_i, // Msg code valid on eval_msgcode_i input tc0_i, // Are we traffic class 0? // for UC/UR determination input hit_src_rdy_i, // are the results ready input hit_ack_i, // did we request a check? input hit_lock_i, // was it for a locked Memrd? input hit_i, // is this our address? input hit_lat3_i, // is the hit latency 3 clocks? input pwr_mgmt_on_i, // are we in power mgmt mode? input legacy_mode_i, // core is in legacy mode // For user/config steering input legacy_cfg_access_i,//user implements legacy config input ext_cfg_access_i, // user implements extended config input [7:0] offset_i, // Config address offset // for (potential) packet drop output reg hp_msg_detect_o, // obsolete hot-plug msg detected `else // `ifdef AS // for PI calculations input [6:0] pi_1st_i, input [6:0] pi_2nd_i, input [6:0] pi_3rd_i, input [6:0] pi_4th_i, input load_pi_1st_i, input load_pi_2nd_i, input load_pi_3rd_i, input load_pi_4th_i, // for format calculations input [6:0] hcrc_i, // Header CRC input [50:0] route_header_i, // Route header covered by HCRC input [4:0] turn_pointer_i, // Pointer into the Turn Pool input dir_i, // Direction (1 = back-route) input switch_mode_i, // Are we in a Switch? // For user/config steering input [31:0] offset_i, // Config address offset input load_offset_i, input fabric_manager_mode_i, // Is core a Fabric Manager? input [31:0] cmm_ap0_space_end_i, // End of Aperture 0 range input [31:0] cmm_ap1_space_start_i, // Start of Aperture 1 range input [31:0] cmm_ap1_space_end_i, // End of Aperture 1 range // for packet drop input [1:0] lnk_state_i, // link state input lnk_state_src_rdy_i, // link state write enable output filter_drop_o, `endif // for length calculations input eval_formats_i, // latch the formatting check input [9:0] length_i, // supposed length of the packet `ifdef PCIE input length_1dw_i, // true if length_i == 1 `endif input sof_i, // beginning of header input eof_i, // end of packet `ifdef PCIE input rem_i, // rem at eof input td_i, // packet has digest input [2:0] max_payload_i // as cfg'd by the cmm `else // `ifdef AS input [3:0] max_payload_i // as cfg'd by the cmm `endif ); `ifdef PCIE //--------------------------------------------------------------------------- // PCI Express constants //--------------------------------------------------------------------------- // Full Type localparam MRD32 = 7'b00_00000; localparam MRD64 = 7'b01_00000; localparam MRD32LK = 7'b00_00001; localparam MRD64LK = 7'b01_00001; localparam MWR32 = 7'b10_00000; localparam MWR64 = 7'b11_00000; localparam IORD = 7'b00_00010; localparam IOWR = 7'b10_00010; localparam CFGRD0 = 7'b00_00100; localparam CFGWR0 = 7'b10_00100; localparam CFGRD1 = 7'b00_00101; localparam CFGWR1 = 7'b10_00101; localparam CFGANY = 7'bx0_0010x; localparam CFGANY0 = 7'bx0_00100; localparam CFGANY1 = 7'bx0_00101; localparam MSG = 7'b01_10xxx; localparam MSGD = 7'b11_10xxx; localparam CPL = 7'b00_01010; localparam CPLD = 7'b10_01010; localparam CPLLK = 7'b00_01011; localparam CPLDLK = 7'b10_01011; // Message code localparam UNLOCK = 8'b0000_0000; localparam PM_ACTIVE_STATE_NAK = 8'b0001_0100; localparam PM_PME = 8'b0001_1000; localparam PME_TURN_OFF = 8'b0001_1001; localparam PME_TO_ACK = 8'b0001_1011; localparam ATTENTION_INDICATOR_OFF = 8'b0100_0000; localparam ATTENTION_INDICATOR_ON = 8'b0100_0001; localparam ATTENTION_INDICATOR_BLINK = 8'b0100_0011; localparam POWER_INDICATOR_ON = 8'b0100_0101; localparam POWER_INDICATOR_BLINK = 8'b0100_0111; localparam POWER_INDICATOR_OFF = 8'b0100_0100; localparam ATTENTION_BUTTON_PRESSED = 8'b0100_1000; localparam SET_SLOT_POWER_LIMIT = 8'b0101_0000; localparam ASSERT_INTA = 8'b0010_0000; localparam ASSERT_INTB = 8'b0010_0001; localparam ASSERT_INTC = 8'b0010_0010; localparam ASSERT_INTD = 8'b0010_0011; localparam DEASSERT_INTA = 8'b0010_0100; localparam DEASSERT_INTB = 8'b0010_0101; localparam DEASSERT_INTC = 8'b0010_0110; localparam DEASSERT_INTD = 8'b0010_0111; localparam ERR_COR = 8'b0011_0000; localparam ERR_NONFATAL = 8'b0011_0001; localparam ERR_FATAL = 8'b0011_0011; localparam VENDOR_DEFINED_TYPE_0 = 8'b0111_1110; localparam VENDOR_DEFINED_TYPE_1 = 8'b0111_1111; // Route localparam ROUTE_TO_RC = 3'b000; localparam ROUTE_BY_AD = 3'b001; localparam ROUTE_BY_ID = 3'b010; localparam ROUTE_BROAD = 3'b011; localparam ROUTE_LOCAL = 3'b100; localparam ROUTE_GATHR = 3'b101; localparam ROUTE_RSRV0 = 3'b110; localparam ROUTE_RSRV1 = 3'b111; `endif // `ifdef PCIE //--------------------------------------------------------------------------- // Other constants //--------------------------------------------------------------------------- // Bus widths `ifdef PCIE localparam DCW = FCW + ((DW == 64) ? 1 : 2); // Data-count width localparam PLW = (FCW == 9) ? 10 : (FCW + 2); // Pertinent portion of the Length field `else // `ifdef AS localparam DCW = FCW + ((DW == 64) ? 3 : 4); // Data-count width localparam PLW = (FCW == 6) ? 5 : FCW; // Pertinent portion of the Credits Required field `endif // Port direction localparam UPSTREAM_PORT = !DOWNSTREAM_PORT; //--------------------------------------------------------------------------- // Internal signals //--------------------------------------------------------------------------- // delayed versions of signals reg eof_q1; `ifdef PCIE reg sof_q1, sof_q2, sof_q3, sof_q4; reg eof_q2, eof_q3; reg eval_formats_q, eval_formats_q2; wire eof_sync, bar_sync; reg load_aperture_q; `else // `ifdef AS reg load_offset_q; `endif // Length check reg [DCW-1:0] word_ct; reg [DCW-1:0] word_ct_d; reg malformed_maxsize; reg malformed_over; `ifdef AS reg malformed_byp_not_1; reg malformed_pi4_or_5_not_1; `endif reg [LENW-1:0] max_length; `ifdef PCIE reg [6:0] fulltype_in; reg [7:0] msgcode_in; wire has_data = fulltype_in[6]; wire header_4dw = fulltype_in[5]; wire length_odd = length_i[0] && has_data; reg type_1dw; reg malformed_eof; reg malformed_rem; reg malformed_len; reg malformed_min; wire malformed_1dw; wire word_ct_zero; wire word_ct_neg1; wire expected_rem; reg delay_ct; reg delay_ct_d; `endif `ifdef PCIE // URs and UCs reg malformed_fulltype; reg malformed_tc; reg malformed_message; reg malformed_fmt; reg ismsg, ismsgd, ismsgany; reg fulltype_tc0; wire msgcode_tc0; reg msgcode_legacy; reg msgcode_hotplug; reg msgcode_sigdef; reg msgcode_vendef; reg msgcode_dmatch; reg [2:0] msgcode_routing; wire [2:0] routing = fulltype_i[2:0]; wire [2:0] routing_in = fulltype_in[2:0]; reg routing_vendef; reg cpl_ip; reg filter_msgcode; reg filter_msgcode_q; reg ur_pwr_mgmt, uc_pwr_mgmt; reg ur_type1_cfg = 0; reg ur_mem_lk, uc_cpl_lk; reg ur_format, uc_format; reg ur_format_lock; // Packet steering reg cfg0_ip, cfg1_ip; reg is_usr_leg_ap, is_usr_ext_ap; `else // `ifdef AS // PI chain reg [7:0] pi_1st; reg [7:0] pi_2nd; reg [7:0] pi_3rd; reg [7:0] pi_4th; wire load_pi_1st; wire load_pi_2nd; wire load_pi_3rd; wire load_pi_4th; reg pi_1st_vld; reg pi_2nd_vld; reg pi_3rd_vld; reg pi_4th_vld; reg pi_2nd_seq_vld; reg pi_3rd_seq_vld; reg pi_4th_seq_vld; reg primary_pi0; reg primary_pi4; reg primary_pi5; // Config-packet detection reg pi4_ap0; reg pi4_ap1; reg in_ap0_range; reg in_ap1_range; reg secondary_pi0; // Link state and packet drop reg [1:0] lnk_state_d; reg [1:0] lnk_state; reg packet_ip; reg packet_keep; // Header CRC wire [6:0] header_crc_d; wire [6:0] header_crc_pb_d; reg [6:0] header_crc; reg [6:0] header_crc_pb; reg path_build; `endif `ifdef PCIE // Synchronize checks with BAR-hit latency assign eof_sync = hit_lat3_i ? eof_q3 : eof_q2; assign bar_sync = hit_lat3_i ? eval_formats_q2 : eval_formats_q; `endif `ifdef PCIE // Calculate data credits from Length field //==================================================================== // If the Length field is not correct, we'll signal Malformed for the // packet later, while freeing that same amount with unuse. //------------------------------------------------------------------- // Data credits are calculated on SOF q2 and provided to the top level // at SOF q4 for pipelining purposes. // 1 data credit = 4 dwords, round up partials always @(posedge clk_i) begin if (sof_q2) begin data_credits_o[PLW-3:0] <= #`TCQ has_data ? (length_i[PLW-1:2] + |length_i[1:0]): 0; end end generate if (FCW == 9) begin : max_data_credits always @(posedge clk_i) begin if (sof_q2) begin data_credits_o[FCW-1] <= #`TCQ ~|length_i && has_data; end end end endgenerate assign data_credits_vld_o = sof_q4; `else // `ifdef AS // Calculate data credits from actual length count //==================================================================== localparam WPC = 512/DW; // Words/credit (64 bytes = 512 bits/credit) localparam WPCW = (DW == 64) ? 3 : 4; // log2(WPC) // We pull off the upper portion of the word count to get the number // of credits. An illustration is how this works is given further // along. always @* data_credits_o = word_ct[DCW-1:WPCW]; assign data_credits_vld_o = eof_q1; `endif // Malformed length checks //==================================================================== //------------------------------------------------------------------------ // Convert the incoming CMM max-payload signal to a max length. //------------------------------------------------------------------------ // Optimize out any unsupported MPS settings. Note: 2176/4096 checked // differently. `ifdef PCIE localparam MAX_128 = 32; // 128B localparam MAX_256 = (MPS >= 256) ? 64 : MAX_128; // 256B localparam MAX_512 = (MPS >= 512) ? 128 : MAX_256; // 512B localparam MAX_1024 = (MPS >= 1024) ? 256 : MAX_512; // 1024B localparam MAX_2048 = (MPS >= 2048) ? 512 : MAX_1024; // 2048B localparam MAX_4096 = (MPS >= 4096) ? 0 : MAX_2048; // 4096B* always @(posedge clk_i) begin if (reset_i) begin max_length <= #`TCQ MAX_128; end else begin case (max_payload_i) 3'b000: max_length <= #`TCQ MAX_128; 3'b001: max_length <= #`TCQ MAX_256; 3'b010: max_length <= #`TCQ MAX_512; 3'b011: max_length <= #`TCQ MAX_1024; 3'b100: max_length <= #`TCQ MAX_2048; default: max_length <= #`TCQ MAX_4096; endcase end end `else // `ifdef AS localparam BVC = !OVC && !MVC; localparam MAX_64 = !BVC ? 1 : 3; localparam MAX_96 = (!BVC && (MPS >= 96)) ? 2 : 3; localparam MAX_128 = (!BVC && (MPS >= 128)) ? 2 : 3; localparam MAX_192 = (MPS >= 192) ? 3 : MAX_128; localparam MAX_320 = (MPS >= 320) ? 5 : MAX_192; localparam MAX_576 = (MPS >= 576) ? 9 : MAX_320; localparam MAX_1088 = (MPS >= 1088) ? 17: MAX_576; localparam MAX_2176 = (MPS >= 2176) ? 0 : MAX_1088; // Max length is MPS, except for PI-0:0, PI-4, PI-5 and Bypassable // packets, whose max length is 1. always @(posedge clk_i) begin if (reset_i) begin max_length <= #`TCQ MAX_192; end else begin casex (max_payload_i) 4'b000x: max_length <= #`TCQ MAX_64; 4'b0010: max_length <= #`TCQ MAX_96; 4'b0011: max_length <= #`TCQ MAX_128; 4'b0100: max_length <= #`TCQ MAX_192; 4'b0101: max_length <= #`TCQ MAX_320; 4'b0110: max_length <= #`TCQ MAX_576; 4'b0111: max_length <= #`TCQ MAX_1088; default: max_length <= #`TCQ MAX_2176; endcase end end `endif //-------------------------------------------------------------------- // This checks if the Length field is set too large for programmed // MPS. In PCIe, this only applies to packets with data; packets // without data can have length fields that exceed MPS (other length // requirements notwithstanding) since they don't have payloads. //-------------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin malformed_maxsize <= #`TCQ 0; end else if (eval_formats_i) begin `ifdef PCIE // If programmed MPS is not 4096, Length must be non-zero if ((max_payload_i < 3'b101) || (MPS < 4096)) begin malformed_maxsize <= #`TCQ ((length_i > max_length) || ~|length_i) && has_data; // If programmed MPS is 4096, any Length setting is legal end else begin malformed_maxsize <= #`TCQ 0; end `else // `ifdef AS // The Credits Required field must be 1 for Bypassable, PI-0:0, // PI-4 and PI-5. if ((!oo_i && ts_i) || (primary_pi0 && (pi_2nd_i == 0)) || primary_pi4 || primary_pi5) begin malformed_maxsize <= #`TCQ (length_i != 1); // If programmed MPS is not 2176, Credits Required must be non-zero end else if ((max_payload_i < 4'b1000) || (MPS < 2176)) begin malformed_maxsize <= #`TCQ (length_i > max_length) || ~|length_i; // If programmed MPS is 2176, any Credits Required setting is legal end else begin malformed_maxsize <= #`TCQ 0; end `endif end end //-------------------------------------------------------------------- // Payload count: DW count in 32-bit, QW count in 64-bit //-------------------------------------------------------------------- `ifdef PCIE //-------------------------------------------------------------------- // In PCIe, word_ct is loaded with the number of data beats following // assertion of eval_formats_q (on the 4th DW or 3rd QW), rem // notwithstanding. After eval_formats_i, word_ct decrements. This // causes word_ct to equal zero on the same clock cycle EOF is // expected. //-------------------------------------------------------------------- // The load value of word_ct is one of the following: // * Outside of eval_formats_i: current value of word_ct. We want to // decrement word_ct by 1; this will be done separately. // * If eval_formats_i is asserted, same as Length in 32-bit, or // Length right-shifted by 1 in 64-bit. The count is later delayed // based on header and TD. generate if (DW == 64) begin : word_ct_load_64 always @* begin if (!eval_formats_i) begin word_ct_d[PLW-2:0] = word_ct[PLW-2:0]; end else if (has_data) begin word_ct_d[PLW-2:0] = length_i[PLW-1:1]; end else begin word_ct_d[PLW-2:0] = 0; end end end else begin : word_ct_load_32 always @* begin if (!eval_formats_i) begin word_ct_d[PLW-1:0] = word_ct[PLW-1:0]; end else if (has_data) begin word_ct_d[PLW-1:0] = length_i[PLW-1:0]; end else begin word_ct_d[PLW-1:0] = 0; end end end endgenerate // If the data-count width supports 4096 bytes, we need to take care // of the all-zero case. generate if (FCW == 9) begin : word_ct_max_load always @* begin if (!eval_formats_i) begin word_ct_d[DCW-1] = word_ct[DCW-1]; end else begin word_ct_d[DCW-1] = ~|length_i && has_data; end end end endgenerate // Load or increment word_ct, using a mux-before-add strategy. This // saves us a level of logic over add-before-mux. always @(posedge clk_i) begin if (reset_i) begin word_ct <= #`TCQ 0; end else if (!delay_ct && !delay_ct_d) begin word_ct <= #`TCQ word_ct_d - 1; end end `else // `ifdef AS //-------------------------------------------------------------------- // In AS, word_ct is loaded upon sof_i with the number of data beats // per credit (16 in 32-bit, 8 in 64-bit). Unlike PCIe, word_ct counts // upward because the upper bits double as the data-credit quantity. // As such, the count is valid on the clock cycle after eof_i, as can // be seen in these 64-bit examples: // // 64 bytes => 8 words = 1 credit // clock 1: sof_i => load counter // clock 2: => length = 8 // clock 3: => length = 9 // clock 4: => length = 10 // clock 5: => length = 11 // clock 6: => length = 12 // clock 7: => length = 13 // clock 8: eof_i => length = 14 // clock 9: eof_q1 => length = 15 -> 01111b -> [01]111b -> 1 cred. // 72 bytes => 9 words = 2 credits // clock 1: sof_i => load counter // clock 2: => length = 8 // clock 3: => length = 9 // clock 4: => length = 10 // clock 5: => length = 11 // clock 6: => length = 12 // clock 7: => length = 13 // clock 8: => length = 14 // clock 9: eof_i => length = 15 // clock 10: eof_q1 => length = 16 -> 10000b -> [10]000b -> 2 cred. // // Note in the second case that if the // // To account for built-in incrementer in word_ct, we load // with the desired value minus one. //----------------------------------------------------------- always @* begin if (sof_i) begin word_ct_d = WPC - 1; end else begin word_ct_d = word_ct; end end // Load or increment word_ct, using a mux-before-add strategy. This // saves us a level of logic over add-before-mux. always @(posedge clk_i) begin if (reset_i) begin word_ct <= #`TCQ 0; end else begin word_ct <= #`TCQ word_ct_d + 1; end end `endif `ifdef PCIE // Delay the start of the word count based on header, TD and length // (in 64-bit, even or odd). Delaying the start of the counter rather // than adjusting the start value saves muxing logic into the word_ct // arithmetic. always @(posedge clk_i) begin if (reset_i) begin delay_ct <= #`TCQ 0; delay_ct_d <= #`TCQ 0; end else if (!eval_formats_i) begin delay_ct <= #`TCQ delay_ct_d; delay_ct_d <= #`TCQ 0; end else if (DW == 64) begin // In the 64-bit world, we want to count the number of data beats // following the 3rd QW. It's easiest to enumerate the possible // scenarios: // // 1. 3 DW header, no digest, even Length: The end of the packet // would be aligned if not for the 3 DW header. Thus the EOF // ends up at the same place as with a 4 DW, no-digest packet. // Beats after 3rd QW: Length/2 + 2 - 3 = Length/2 - 1. // 2. 3 DW header, no digest, odd Length: The odd DW at the end // fills out the last beat in case #1: floor(Length/2) - 1. // 3. 3 DW header, digest, even Length: Fills out the unaligned // end of case #1: Length/2 - 1. // 4. 3 DW header, digest, odd Length: Adds an unaligned beat to // case #2: floor(Length/2). // 5. 4 DW header, no digest, even Length: Additional header DW // fills out the unaligned end of case #1: Length/2 - 1. // 6. 4 DW header, no digest, odd Length: Adds an unaligned beat // to case #2: floor(Length/2). // 7. 4 DW header, digest, even Length: Adds an unaligned beat to // case #3: Length/2. // 8. 4 DW header, digest, odd Length: Fills out the unaligned end // of case #4: floor(Length/2). // // The decrementer in word_ct causes the load value to be // word_ct_d - 1 = (length_i >> 1) - 1 = floor(Length/2) - 1. We // distill these out to get the delay needed from the start of // the count: // // Case #1: (Length/2 - 1) - (floor(Length/2) - 1) = 0 delay // ... // Case #4: floor(Length/2) - (floor(Length/2) - 1) = 1 delay // ... case ({header_4dw,td_i,length_odd}) 3'b000: delay_ct <= #`TCQ 0; 3'b001: delay_ct <= #`TCQ 0; 3'b010: delay_ct <= #`TCQ 0; 3'b011: delay_ct <= #`TCQ 1; 3'b100: delay_ct <= #`TCQ 0; 3'b101: delay_ct <= #`TCQ 1; 3'b110: delay_ct <= #`TCQ 1; default: delay_ct <= #`TCQ 1; endcase delay_ct_d <= #`TCQ 0; // Only used in 32-bit, where two cycles // of delay may be necessary end else begin // In the 32-bit world, the number of data beats following the 4th // DW is equal to Length + Hdr_DW + TD - 4. The adjustment from // word_ct_d is thus Hdr_DW + TD - 4. Note that (Hdr_DW - 3) is // the same as header_4dw, so the delay is simply the sum of // header_4dw + td_i - 1, PLUS ONE to account for the built-in // word_ct decrementer. case ({header_4dw,td_i}) 2'b11: {delay_ct_d,delay_ct} <= #`TCQ 2'b10; // Two-cycle delay 2'b00: {delay_ct_d,delay_ct} <= #`TCQ 2'b00; // Zero-cycle delay default: {delay_ct_d,delay_ct} <= #`TCQ 2'b01; // One-cycle delay endcase end end // Flag a word count of zero. There are two ways to represent zero // word count: // // 1. If word_ct = 0 with no count delay (delay_ct = 0). // 2. If word_ct = -1 with count delay (delay_ct = 1). Count delay // represents a +1 adjustment to word_ct, so these two conditions // indicate that the true word count is zero. (See the delay_ct // comments below for more information.) This scenario occurs in // 64-bit when we have a packet of 1 DW payload that ends on the // 3rd QW: 3 DW header + TD, or 4 DW header w/o TD. (This case is // not covered by malformed_min, which only covers EOF on the 1st // or 2nd QW.) // // This logic also takes care of the case in 32-bit when Length = 1 // (causing word_ct = 0) but delay_ct/d is asserted due to a 4 DW // header or a TLP Digest. In this case, true word count is non-zero // even though word_ct = 0, because of the count delay. // // The lowest possible start value for word_ct is -1 (derived from a // payload length of 0 [or 1 in 64-bit]). This means that the true // word count will never be zero if delay_ct_d is asserted, because // this represents a two-cycle delay. assign word_ct_zero = (delay_ct ? &word_ct : ~|word_ct) && !delay_ct_d; // Flag a word count of -1. This occurs when word_ct = -1 with no // count delay. Needed to detect rollover. assign word_ct_neg1 = &word_ct && !delay_ct && !delay_ct_d; reg [4:0] test_temp; //------------------------------------------------------------------------ // Check length of short packets (1-4 DW in 32-bit, 1-2 DW in 64-bit). // Longer packets are checked against word_ct. //------------------------------------------------------------------------ always @(posedge clk_i) begin if (reset_i) begin malformed_min <= #`TCQ 0; end else begin if (DW == 64) begin // 2 words or less if (sof_i && eof_i) begin malformed_min <= #`TCQ 1; // Header fields too small check (3 or 4 words) // header words + digest <= 3 + rem end else if (sof_q1 && eof_i) begin casex ({header_4dw, rem_i, td_i, has_data, length_1dw_i}) // No-data checks // 3 DW header, 3 DW packet.. but digest is set! 5'b0010x: malformed_min <= #`TCQ 1; // 4 DW header, 3 DW packet (w/wo digest) 5'b10x0x: malformed_min <= #`TCQ 1; // 4 DW header, 4 DW packet.. but digest is set! 5'b1110x: malformed_min <= #`TCQ 1; // Has-data checks // 3 DW header, supposed to have data but doesn't 5'b00x1x: malformed_min <= #`TCQ 1; // 3 DW header, only 1 DW of data, but should have more 5'b0xx10: malformed_min <= #`TCQ 1; // 3 DW header w/TD, supposed to have data but doesn't 5'b0x11x: malformed_min <= #`TCQ 1; // 4 DW header, supposed to have data but doesn't 5'b1xx1x: malformed_min <= #`TCQ 1; // header-only (or header + 1DW data) packet is // correctly constructed default: malformed_min <= #`TCQ 0; endcase // There was data.. we'll catch these cases with the // word counter end else begin malformed_min <= #`TCQ 0; end // 32 bit checks end else begin // 1 or 2 dwords if ((sof_i || sof_q1) && eof_i) begin malformed_min <= #`TCQ 1; // 3 dword pkt, but w/ digest or data or 4 dw header end else if (sof_q2 && eof_i && (td_i || header_4dw || has_data)) begin malformed_min <= #`TCQ 1; // 4 word pkt && header, but with digest end else if (sof_q3 && eof_i && td_i && header_4dw) begin malformed_min <= #`TCQ 1; // we must be long enough end else begin malformed_min <= #`TCQ 0; end end end end //===================================================================== // Malformed TLP: incorrect length (valid at eof_o) // * length field != 0 while the TLP has no data // * length field doesn't match number of data dwords // * length field is not hardwired correctly (1 DW only for I/O & Cfg) //===================================================================== //-------------------------------------------------------------------- // This checks Config and I/O packets to make sure the Length field is // set to 1. //-------------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin type_1dw <= #`TCQ 0; end else if (eval_formats_i) begin casex (fulltype_in) CFGRD0, CFGWR0, CFGRD1, CFGWR1, IORD, IOWR: type_1dw <= #`TCQ 1; default: type_1dw <= #`TCQ 0; endcase end end assign malformed_1dw = type_1dw && !length_1dw_i; // Determine if the length of the packet is correct. Interpreted on // every clock, but only latched on eof_q1. //---------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin malformed_eof <= #`TCQ 0; end else begin malformed_eof <= #`TCQ !eval_formats_i && !word_ct_zero; end end `endif `ifdef PCIE // Flag when the counter rolls over. This covers the case in 32-bit // where a start value of -1 is loaded into word_ct on the 4th DW. // A -1 on the 4th DW means EOF should've been asserted on the 3rd DW; // but because word_ct cannot be valid on the 3rd DW, we can't flag a // zero count on that data beat. So we must flag when the count has // been allowed to load with a rollover value on or before EOF, so // that eof_q1 will detect the overflow condition. // // The rollover flag also ensures that the TLM doesn't mark as legal a // packet that overshoots Length by exactly MPS*2 (which would cause // the word counter to go down to zero a SECOND time). always @(posedge clk_i) begin if (reset_i) begin malformed_over <= #`TCQ 0; end else begin malformed_over <= #`TCQ (word_ct_neg1 || malformed_over) && !eval_formats_i; end end // Determine if REM is set incorrectly. Only matters on EOF. //---------------------------------------------------------- // The expected REM is determined by payload length (even vs. odd), // header size and and presence of the digest. The formula is: // // exp_rem = (!header_4dw + length_i[0] + td_i) % 2 == 0 -OR- // exp_rem = (header_4dw + length_i[0] + td_i) % 2 == 1 // // a.k.a. XOR. Length is qualified by has_data (embodied by the // length_odd signal) as it depends on the presence of the payload. assign expected_rem = header_4dw ^ length_odd ^ td_i; // The check for malformed REM is performed on each clock cycle but // only latched on the cycle after EOF. always @(posedge clk_i) begin if (reset_i) begin malformed_rem <= #`TCQ 0; end else if (DW == 32) begin malformed_rem <= #`TCQ 0; end else begin malformed_rem <= #`TCQ rem_i ^ expected_rem; end end // All our counting is complete on eof_i- latch on q1 // Our length is bad if the payload was bad, or if a header-only // packet was too short //------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin malformed_len <= #`TCQ 0; end else if (eof_q1) begin malformed_len <= #`TCQ malformed_eof || malformed_over || malformed_rem || malformed_min; end end always @(posedge clk_i) begin if (reset_i) begin malformed_o <= #`TCQ 0; end else if (eof_sync) begin malformed_o <= #`TCQ malformed_len || malformed_fmt; end end `else // `ifdef AS // Flag when the counter exceeds Credits Required. We trigger when // word_ct equals the maximum allowed for Credits Required. An // adjustment must be made for MPS = 96, since this represents an // overflow on a half-credit. Note that this is the only case where // we check the RUNNING word count against MPS. The malformed_maxsize // logic covers all other cases where the actual Credits Required // field exceeds MPS. // // We must adjust the incoming CR upwards for the all-zeroes case. reg [WPCW-1:0] word_ct_lo_limit; reg [FCW-1:0] word_ct_hi_limit; wire [DCW-1:0] word_ct_limit; reg [FCW-1:0] true_length; always @(posedge clk_i) begin if (reset_i) begin word_ct_lo_limit <= #`TCQ 0; end else if ((max_payload_i == 4'b0010) && !BVC && (MPS >= 96) && (length_i == 2)) begin word_ct_lo_limit <= #`TCQ WPC/2; end else begin word_ct_lo_limit <= #`TCQ 0; end end generate if (FCW == 6) begin : word_ct_limit_2176 always @* begin if (~|length_i) begin // All zeroes true_length = 34; end else begin true_length = {1'b0,length_i}; end end end else begin : word_ct_limit_below_2176 always @* true_length = length_i[FCW-1:0]; end endgenerate always @(posedge clk_i) begin if (reset_i) begin word_ct_hi_limit <= #`TCQ 1; end else begin word_ct_hi_limit <= #`TCQ true_length + 1; end end assign word_ct_limit = {word_ct_hi_limit,word_ct_lo_limit}; always @(posedge clk_i) begin if (reset_i) begin malformed_over <= #`TCQ 0; end else if (eval_formats_i) begin malformed_over <= #`TCQ 0; end else begin malformed_over <= #`TCQ (word_ct == word_ct_limit) || malformed_over; end end // Flag if Credits Required is not 1 for a bypassable, PI-4 or PI-5 // packet. always @(posedge clk_i) begin if (reset_i) begin malformed_byp_not_1 <= #`TCQ 0; end else if (eval_formats_i) begin malformed_byp_not_1 <= #`TCQ BVC && !oo_i && ts_i && (length_i != 1); end end always @(posedge clk_i) begin if (reset_i) begin malformed_pi4_or_5_not_1 <= #`TCQ 0; end else if (eval_formats_i) begin malformed_pi4_or_5_not_1 <= #`TCQ (primary_pi4 || primary_pi5) && (length_i != 1); end end // All our counting is complete on eof_i; latch on eof_q1. //------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin bad_credit_length_o <= #`TCQ 0; end else if (eof_q1) begin bad_credit_length_o <= #`TCQ malformed_over; end end always @(posedge clk_i) begin if (reset_i) begin invalid_credit_length_o <= #`TCQ 0; end else if (eof_q1) begin invalid_credit_length_o <= #`TCQ malformed_maxsize || malformed_byp_not_1 || malformed_pi4_or_5_not_1; end end `endif `ifdef PCIE //==================================================================== // Malformed format checks //==================================================================== // delay this one cycle more than is strictly necessary- otherwise // we might collide with another bad back-to-back packet always @(posedge clk_i) begin if (reset_i) begin malformed_fmt <= #`TCQ 0; // All type checks get triggered after we have latched // the inputs. OR together the checks afterwards. // ismsg* needs to be added into malformed_message even // though it is also included in some field checks // because completely specifying it in the case statement // absolutely kills timing end else if (bar_sync) begin malformed_fmt <= #`TCQ malformed_tc || malformed_fulltype || (malformed_message && ismsgany) || malformed_maxsize || malformed_1dw; end end //-------------------------------------------------------------------- // Traffic class determinations //-------------------------------------------------------------------- // Bad TC received if doesn't map to any enabled VC, meaning either: // * TC not mapped to any VC // * TC mapped to a VC not enabled ** FOR THIS VERSION ONLY 0 VALID!! ** // * TC other than TC0 on received: // * io and cfg // * CplDLk and I guess CplLk (MRdLk is UR and Unlock is dropped) // . Msg: power management (INT and errors are UR because routed to Root) // // Spec references on TC0 traffic restriction: // * "MRdLk, CplDLk and Unlock semantics are allowed only for (...) TC0" // * "all Assert_INTx and Deassert_INTx interrupts Requests must use TC0" // * "for legacy I/O, TC0 is used" // * "all power management system messages must use (...) TC0" // * "all Error Messages must use (...) TC0" // * "the Unlock Message must use (...) TC0" // * "MSIs are not restricted to TC0" // * cfg and io header shows a TC hardwired to 0 //-------------------------------------------------------------------- // Latch Type and Message code, should be removed as equivalent to // cur_fulltype and cur_msgcode on the upper level always @(posedge clk_i) begin if (eval_fulltype_i) begin fulltype_in <= #`TCQ fulltype_i; end end always @(posedge clk_i) begin if (eval_msgcode_i) begin msgcode_in <= #`TCQ msgcode_i; end end // Pre-calculate whether the Type is Msg or MsgD; ismsgany will be // removed during synthesis as equivalent to cur_fulltype_oh[MSG_BIT] // on the upper level. always @(posedge clk_i) begin if (eval_fulltype_i) begin casex (fulltype_i) MSG: begin ismsg <= #`TCQ 1; ismsgd <= #`TCQ 0; ismsgany <= #`TCQ 1; end MSGD: begin ismsg <= #`TCQ 0; ismsgd <= #`TCQ 1; ismsgany <= #`TCQ 1; end default: begin ismsg <= #`TCQ 0; ismsgd <= #`TCQ 0; ismsgany <= #`TCQ 0; end endcase end end // Pre-calculate whether the full type requires TC0 always @(posedge clk_i) begin if (eval_fulltype_i) begin casex (fulltype_i) // These Types require TC == 0 CFGANY, IORD, IOWR, CPLLK, CPLDLK, MRD32LK, MRD64LK: begin fulltype_tc0 <= #`TCQ 1; end default: begin fulltype_tc0 <= #`TCQ 0; end endcase end end // Pre-calculate whether the Message code requires TC0. All messages // other than Vendor_Defined_0/1 require TC0. assign msgcode_tc0 = msgcode_sigdef; // Check for Malformed TC always @(posedge clk_i) begin if (reset_i) begin malformed_tc <= #`TCQ 0; end else if (eval_formats_i) begin if (!tc0_i) begin malformed_tc <= #`TCQ fulltype_tc0 || (ismsgany && msgcode_tc0); end else begin // tc was 0, we must be good! malformed_tc <= #`TCQ 0; end end end // Check if type is valid based on allowable full types // (of spec, not what we actually support in our core) // Valid but unsupported types get turned into a UR/UC //------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin malformed_fulltype <= #`TCQ 0; end else if (eval_formats_i) begin casex (fulltype_in) MWR32, MWR64, MRD32, MRD64, MRD32LK, MRD64LK, CFGRD0, CFGWR0, CFGRD1, CFGWR1, CPL, CPLD, CPLLK, CPLDLK, MSG, MSGD, IORD, IOWR: malformed_fulltype <= #`TCQ 0; default: malformed_fulltype <= #`TCQ 1; endcase end end //==================================================================== // UR/UC checks //==================================================================== // Completions lead to Unexpected Completion, others lead to // Unsupported Request //-------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin cpl_ip <= #`TCQ 0; end else if (eval_formats_i) begin casex (fulltype_in) CPL, CPLD, CPLLK, CPLDLK: begin cpl_ip <= #`TCQ 1; end default: begin cpl_ip <= #`TCQ 0; end endcase end end // Grab some fields that are special cases in our UC/UR // determination // * We don't drop vendor messages on bar misses // * A locked mem access when not in legacy mode is unsupported // * A locked completion when not in legacy mode is unexpected // * We reject most types while in power management mode //------------------------------------------------------------- // We can receive the legacy UNLOCK message code if the user design is // a legacy device, or if this is a downstream port. wire allow_legacy = legacy_mode_i || DOWNSTREAM_PORT; always @(posedge clk_i) begin if (reset_i) begin ur_mem_lk <= #`TCQ 0; uc_cpl_lk <= #`TCQ 0; ur_pwr_mgmt <= #`TCQ 0; uc_pwr_mgmt <= #`TCQ 0; ur_type1_cfg <= #`TCQ 0; end else if (eval_formats_i) begin if (!allow_legacy) begin ur_mem_lk <= #`TCQ (fulltype_in == MRD32LK) || (fulltype_in == MRD64LK); uc_cpl_lk <= #`TCQ (fulltype_in == CPLLK) || (fulltype_in == CPLDLK); end else begin ur_mem_lk <= #`TCQ 0; uc_cpl_lk <= #`TCQ 0; end if (TYPE1_UR && (fulltype_in == CFGWR1 || fulltype_in == CFGRD1 || fulltype_in == CFGWR1)) begin // If TYPE1_UR is left as its default (0) all the ur_type1_cfg // logic should be optimized out ur_type1_cfg <= #`TCQ 1'b1; end else begin ur_type1_cfg <= #`TCQ 1'b0; end casex (fulltype_in) CPL, CPLD, CPLLK, CPLDLK: begin uc_pwr_mgmt <= #`TCQ pwr_mgmt_on_i; ur_pwr_mgmt <= #`TCQ 0; end MRD32, MRD64, MRD32LK, MRD64LK, MWR32, MWR64, IORD, IOWR: begin uc_pwr_mgmt <= #`TCQ 0; ur_pwr_mgmt <= #`TCQ pwr_mgmt_on_i; end CFGWR1, CFGRD1, CFGANY1: begin uc_pwr_mgmt <= #`TCQ 0; ur_pwr_mgmt <= #`TCQ 0; end default: begin uc_pwr_mgmt <= #`TCQ 0; ur_pwr_mgmt <= #`TCQ 0; end endcase end end // There are three components to a UR/UC... // 1. We're in power management mode, and this type is // not supported during power management // 2. There is a bad field determination.. we grab this // when the formats are ready, and if they are good, we // reset the register back to zero // 3. Our bar hit/miss information is available at hit_src_rdy.. // if we were a miss set the field // Otherwise, use the previous value //------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin ur_format <= #`TCQ 0; ur_format_lock <= #`TCQ 0; uc_format <= #`TCQ 0; filter_msgcode_q <= #`TCQ 0; end else if (bar_sync) begin // 1. In power management -OR- // 2. Our packet has a message or type we don't support -OR- // 3. Our packet is a type-1 config access and it's not allowed // Unsupported Request ur_format <= #`TCQ ur_pwr_mgmt || ur_mem_lk || ur_type1_cfg; ur_format_lock <= #`TCQ ur_mem_lk; //needed by errman to generate CplLk // Unexpected completion uc_format <= #`TCQ uc_pwr_mgmt || uc_cpl_lk; // Unpassed message (silently filtered in non-legacy mode) filter_msgcode_q <= #`TCQ filter_msgcode; end end // hits are ready, or & grab the format information always @(posedge clk_i) begin if (reset_i) begin tlp_ur_o <= #`TCQ 0; tlp_ur_lock_o <= #`TCQ 0; tlp_uc_o <= #`TCQ 0; tlp_filt_o <= #`TCQ 0; end else if (hit_src_rdy_i) begin if (ur_format) begin tlp_ur_o <= #`TCQ 1; tlp_ur_lock_o <= #`TCQ ur_format_lock; end else if (!cpl_ip && hit_ack_i && !hit_i && UPSTREAM_PORT) begin tlp_ur_o <= #`TCQ 1; tlp_ur_lock_o <= #`TCQ hit_lock_i; end else begin tlp_ur_o <= #`TCQ 0; tlp_ur_lock_o <= #`TCQ 0; end if (uc_format) begin tlp_uc_o <= #`TCQ 1; end else if (cpl_ip && hit_ack_i && !hit_i && UPSTREAM_PORT) begin tlp_uc_o <= #`TCQ 1; end else begin tlp_uc_o <= #`TCQ 0; end if (filter_msgcode_q) begin tlp_filt_o <= #`TCQ 1; end else begin tlp_filt_o <= #`TCQ 0; end end end //--------------------------------------------------------------------- // Check if the message is constructed properly according to the spec // * routing must be correct by spec // * routing must match our ability to route (endpoint/trunk) // * Msg/MsgD type must match message value //---------------------------------------------------------------------- // Check for valid message code, other than Vendor_Defined. The message // code is valid if it is both: // * Defined in the spec // * Legal for the port direction always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) UNLOCK, PME_TURN_OFF, PM_ACTIVE_STATE_NAK, SET_SLOT_POWER_LIMIT, ATTENTION_BUTTON_PRESSED, ATTENTION_INDICATOR_ON, ATTENTION_INDICATOR_OFF, ATTENTION_INDICATOR_BLINK, POWER_INDICATOR_ON, POWER_INDICATOR_OFF, POWER_INDICATOR_BLINK: msgcode_sigdef <= #`TCQ UPSTREAM_PORT; ASSERT_INTA, DEASSERT_INTA, ASSERT_INTB, DEASSERT_INTB, ASSERT_INTC, DEASSERT_INTC, ASSERT_INTD, DEASSERT_INTD, ERR_COR, ERR_NONFATAL, ERR_FATAL, PME_TO_ACK: msgcode_sigdef <= #`TCQ DOWNSTREAM_PORT; default: msgcode_sigdef <= #`TCQ 0; endcase end end // Check for Msg vs. MsgD. In 64-bit, fulltype_i and msgcode_i are // available on the same clock cycle. In 32-bit, ismsg and ismsgd are // calculated before msgcode_i is available. generate if (DW == 32) begin : msgd_check_32 always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) SET_SLOT_POWER_LIMIT: msgcode_dmatch <= #`TCQ ismsgd; default: msgcode_dmatch <= #`TCQ ismsg; endcase end end end else begin : msgd_check_64 always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (fulltype_i) MSG: msgcode_dmatch <= #`TCQ (msgcode_i != SET_SLOT_POWER_LIMIT); default: msgcode_dmatch <= #`TCQ (msgcode_i == SET_SLOT_POWER_LIMIT); endcase end end end endgenerate // Check the type of routing required by the Message code. Most codes // only take one routing type, but Vendor_Defined can take three types // (four if received on a downstream port) so it needs a special // register. always @(posedge clk_i) begin if (eval_fulltype_i) begin routing_vendef <= #`TCQ (routing == ROUTE_LOCAL) || (routing == ROUTE_BROAD) || (routing == ROUTE_BY_ID); end end // Create different casex blocks depending on whether // in downstream port mode or not. This is done so that when not in // downstream port mode, the interrupt-message checks will not be included. // Interrupts should not be received when in upstream mode so we // don't want to risk having their checks impact timing. generate if (DOWNSTREAM_PORT == 0) begin : dont_check_int always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) UNLOCK, PME_TURN_OFF: msgcode_routing <= #`TCQ ROUTE_BROAD; PME_TO_ACK: msgcode_routing <= #`TCQ ROUTE_GATHR; PM_ACTIVE_STATE_NAK, ATTENTION_BUTTON_PRESSED, ATTENTION_INDICATOR_ON, ATTENTION_INDICATOR_OFF, ATTENTION_INDICATOR_BLINK, POWER_INDICATOR_ON, POWER_INDICATOR_OFF, POWER_INDICATOR_BLINK, SET_SLOT_POWER_LIMIT: msgcode_routing <= #`TCQ ROUTE_LOCAL; // Vendor_Defined can take other values besides Route to RC; // these are covered by routing_vendef. default: msgcode_routing <= #`TCQ ROUTE_TO_RC; endcase end end end else begin : check_int always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) UNLOCK, PME_TURN_OFF: msgcode_routing <= #`TCQ ROUTE_BROAD; PME_TO_ACK: msgcode_routing <= #`TCQ ROUTE_GATHR; PM_ACTIVE_STATE_NAK, ATTENTION_BUTTON_PRESSED, ATTENTION_INDICATOR_ON, ATTENTION_INDICATOR_OFF, ATTENTION_INDICATOR_BLINK, POWER_INDICATOR_ON, POWER_INDICATOR_OFF, POWER_INDICATOR_BLINK, ASSERT_INTA, ASSERT_INTB, ASSERT_INTC, ASSERT_INTD, DEASSERT_INTA, DEASSERT_INTB, DEASSERT_INTC, DEASSERT_INTD, SET_SLOT_POWER_LIMIT: msgcode_routing <= #`TCQ ROUTE_LOCAL; // Vendor_Defined can take other values besides Route to RC; // these are covered by routing_vendef. default: msgcode_routing <= #`TCQ ROUTE_TO_RC; endcase end end end endgenerate // Make sure the Message parameters agree with each other: // // 1. Message code must be valid per spec // 2. Type (Msg or MsgD) must agree with the Message code // 3. If not Vendor_Defined, the Routing type must agree with the one // allowed by the Message code // 4. If Vendor_Defined, the Routing type must be: // a. Broadcast, Local or Route By ID (routing_vendef), or // b. Route to Root Complex if a downstream port // NOTE: Vendor_Defined does not care about Msg vs. MsgD. always @(posedge clk_i) begin if (reset_i) begin malformed_message <= #`TCQ 0; end else if (eval_formats_i) begin if (!msgcode_vendef) begin malformed_message <= #`TCQ !msgcode_sigdef || // #1 !msgcode_dmatch || // #2 (routing_in != msgcode_routing); // #3 end else begin malformed_message <= #`TCQ !routing_vendef && // #4 !(DOWNSTREAM_PORT && (routing_in == ROUTE_TO_RC)); end end end //--------------------------------------------------------------------- // Check if the message is supported by our core // * routing must match our ability to route (endpoint/trunk) //---------------------------------------------------------------------- always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) UNLOCK: msgcode_legacy <= #`TCQ 1; default: msgcode_legacy <= #`TCQ 0; endcase end end always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) POWER_INDICATOR_ON, POWER_INDICATOR_OFF, POWER_INDICATOR_BLINK, ATTENTION_INDICATOR_ON, ATTENTION_INDICATOR_OFF, ATTENTION_INDICATOR_BLINK, ATTENTION_BUTTON_PRESSED: msgcode_hotplug <= #`TCQ 1; default: msgcode_hotplug <= #`TCQ 0; endcase end end always @(posedge clk_i) begin if (eval_msgcode_i) begin casex (msgcode_i) VENDOR_DEFINED_TYPE_0, VENDOR_DEFINED_TYPE_1: msgcode_vendef <= #`TCQ 1; default: msgcode_vendef <= #`TCQ 0; endcase end end always @(posedge clk_i) begin if (reset_i) begin filter_msgcode <= #`TCQ 0; end else if (eval_formats_i) begin if (ismsgany) begin filter_msgcode <= #`TCQ !allow_legacy && msgcode_legacy; end else begin // not a Message filter_msgcode <= #`TCQ 0; end end end //==================================================================== // Steer packets to the CMM. always @(posedge clk_i) begin if (reset_i) begin cfg0_ip <= #`TCQ 0; cfg1_ip <= #`TCQ 0; end else if (eval_formats_i) begin casex (fulltype_in) CFGANY0: cfg0_ip <= #`TCQ 1; default: cfg0_ip <= #`TCQ 0; endcase casex (fulltype_in) CFGANY1: cfg1_ip <= #`TCQ 1; default: cfg1_ip <= #`TCQ 0; endcase end end // The user gets a Type 0 packet if: // // 1. The packet's address range is between 192 and 255 inclusive, and // the user implements legacy config space, or // 2. The packet's address range is at or above 1024 (4*256) and the // user implements extended config space. always @(posedge clk_i) begin if (reset_i) begin is_usr_leg_ap <= #`TCQ 0; end else if (load_aperture_i) begin is_usr_leg_ap <= #`TCQ (aperture_i == 0) && (offset_i[7:6] == 3) && legacy_cfg_access_i; end end always @(posedge clk_i) begin if (reset_i) begin is_usr_ext_ap <= #`TCQ 0; end else if (load_aperture_i) begin is_usr_ext_ap <= #`TCQ |aperture_i[3:2] && ext_cfg_access_i; end end always @(posedge clk_i) begin if (reset_i) begin load_aperture_q <= #`TCQ 0; end else begin load_aperture_q <= #`TCQ load_aperture_i; end end // The packet goes to the CMM if: // 1. It is Config Type 1, OR // 2. It is Config Type 0 and the packet doesn't fall into either of // the user categories above. always @(posedge clk_i) begin if (reset_i) begin cfg_o <= #`TCQ 0; end else if (load_aperture_q) begin cfg_o <= #`TCQ cfg1_ip || (cfg0_ip && !is_usr_leg_ap && !is_usr_ext_ap); end end // Signal receipt of a hot-plug Message. These have been obsoleted // starting with PCIe 1.1, so the user is given the option of dropping // them. always @(posedge clk_i) begin if (reset_i) begin hp_msg_detect_o <= #`TCQ 0; end else if (eval_formats_q) begin hp_msg_detect_o <= #`TCQ ismsgany && msgcode_hotplug; end end `else // `ifdef AS //==================================================================== // Check for valid PI and PI chain. //==================================================================== // Make sure that PIs are not latched past the end of the chain. Valid // chains are: // * 0 -> 0 // * 0 -> 1 -> PDU (8-126) // * 0 -> 1 -> 2 -> PDU // * 0 -> 2 -> PDU // * 1 -> PDU // * 1 -> 2 -> PDU // * 2 -> PDU // * 4 // * 5 // * PDU // The secondary and tertiary PIs appear on the same clock cycle in // 64-bit, which is why the equation for load_pi_3rd is more complex // than the other ones. assign load_pi_1st = load_pi_1st_i; assign load_pi_2nd = load_pi_2nd_i && (pi_1st <= 2); // In 64-bit, the secondary and tertiary PIs come on the same cycle, // so checks on the 3rd PI involve the live version of the 2nd PI. assign load_pi_3rd = load_pi_3rd_i && ((DW == 64) ? ((pi_2nd_i == 1) || (pi_2nd_i == 2)) : ((pi_2nd == 1) || (pi_2nd == 2))); assign load_pi_4th = load_pi_4th_i && (pi_3rd_i <= 2); // PIs 128-130 are "placeholders": If their corresponding registers // are not written into, they will still be greater than higher-order // PIs for the purposes of chain validation. always @(posedge clk_i) begin if (sof_i) begin pi_1st <= #`TCQ load_pi_1st ? pi_1st_i : 0; pi_2nd <= #`TCQ 128; pi_3rd <= #`TCQ 129; pi_4th <= #`TCQ 130; end else begin if (load_pi_2nd) begin pi_2nd[7] <= #`TCQ 0; pi_2nd[6:0] <= #`TCQ pi_2nd_i; end if (load_pi_3rd) begin pi_3rd[7] <= #`TCQ 0; pi_3rd[6:0] <= #`TCQ pi_3rd_i; end if (load_pi_4th) begin pi_4th[7] <= #`TCQ 0; pi_4th[6:0] <= #`TCQ pi_4th_i; end end end // Distill certain PIs into one-hot signals always @(posedge clk_i) begin if (reset_i) begin primary_pi0 <= #`TCQ 0; primary_pi4 <= #`TCQ 0; primary_pi5 <= #`TCQ 0; end else if (load_pi_1st) begin primary_pi0 <= #`TCQ (pi_1st_i == 0); primary_pi4 <= #`TCQ (pi_1st_i == 4); primary_pi5 <= #`TCQ (pi_1st_i == 5); end end always @(posedge clk_i) begin if (reset_i) begin secondary_pi0 <= #`TCQ 0; end else if (load_pi_2nd) begin secondary_pi0 <= #`TCQ (pi_2nd_i == 0); end end // Check for invalid PIs. Note that placeholder PIs (128+) which // represent "blanks" are always valid. //-------------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin pi_1st_vld <= #`TCQ 1; pi_2nd_vld <= #`TCQ 1; pi_3rd_vld <= #`TCQ 1; pi_4th_vld <= #`TCQ 1; end else begin // Primary PI: Legal values are 0-2, 4, 5, 8-126 pi_1st_vld <= #`TCQ (pi_1st != 3) && (pi_1st != 6) && (pi_1st != 7) && (pi_1st != 127); // Secondary PI: Legal values are 0-2, 8-126 pi_2nd_vld <= #`TCQ ((pi_2nd <= 2) || (pi_2nd >= 8)) && (pi_2nd != 127); // Tertiary PI: Legal values are 2, 8-126 pi_3rd_vld <= #`TCQ ((pi_2nd == 2) || (pi_2nd >= 8)) && (pi_3rd != 127); // Quaternary PI: Legal values are 8-126 pi_4th_vld <= #`TCQ (pi_4th >= 8) && (pi_4th != 127); end end // Check for invalid PI sequences. Note that the placeholder PIs will // always represent valid chains since they are greater than any legal // PI and are loaded in an increasing progression. In addition, //-------------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin pi_2nd_seq_vld <= #`TCQ 1; pi_3rd_seq_vld <= #`TCQ 1; pi_4th_seq_vld <= #`TCQ 1; end else begin // Secondary PI is sequence-valid if 1st PI = 0 or 2nd PI > 1st PI pi_2nd_seq_vld <= #`TCQ !((pi_1st < 4) && pi_2nd[7]) && (pi_2nd > pi_1st); // Tertiary PI is sequence-valid if 3rd PI > 2nd PI pi_3rd_seq_vld <= #`TCQ !(((pi_2nd > 0) || (pi_2nd < 4)) && pi_3rd[7]) && (pi_3rd > pi_2nd); // Quaternary PI is sequence-valid if 4th PI > 3rd PI pi_4th_seq_vld <= #`TCQ !(((pi_3rd > 0) || (pi_3rd < 4)) && pi_4th[7]) && (pi_4th > pi_3rd); end end // Latch any PI error condition. //-------------------------------------------------------------------- always @(posedge clk_i) begin if (reset_i) begin bad_pi_chain_o <= #`TCQ 1; end else if (eof_q1) begin bad_pi_chain_o <= #`TCQ !pi_1st_vld || !pi_2nd_vld || !pi_3rd_vld || !pi_4th_vld || !pi_2nd_seq_vld || !pi_3rd_seq_vld || !pi_4th_seq_vld; end end //==================================================================== // Check the Turn Pointer. Must be zero for any forward-routed packet // received by an Endpoint that is not PI-0. always @(posedge clk_i) begin if (reset_i) begin non_zero_turn_pointer_o <= #`TCQ 0; end else if (eval_formats_i) begin non_zero_turn_pointer_o <= #`TCQ !dir_i && !switch_mode_i && (pi_1st != 0) && (turn_pointer_i != 0); end end //==================================================================== // Check the Header CRC. Path-building and multicast packets (PI-0) // have a mutable Turn Pool which must be masked out when performing // the CRC calculation. For timing purposes, both the path-build and // non-path-build CRCs are calculated and the correct one is later // chosen for comparison. tlm_hcrc hcrc (.d_i (route_header_i[50:0]), .hcrc_o (header_crc_d)); tlm_hcrc hcrc_pb (.d_i ({route_header_i[50:32],32'b0}), .hcrc_o (header_crc_pb_d)); always @(posedge clk_i) begin if (reset_i) begin path_build <= #`TCQ 0; end else if (eval_formats_i) begin path_build <= #`TCQ (pi_1st == 0); end end always @(posedge clk_i) begin if (reset_i) begin header_crc <= #`TCQ 0; header_crc_pb <= #`TCQ 0; end else if (eval_formats_i) begin header_crc <= #`TCQ header_crc_d; header_crc_pb <= #`TCQ header_crc_pb_d; end end always @(posedge clk_i) begin if (reset_i) begin bad_header_crc_o <= #`TCQ 0; end else if (eof_q1) begin bad_header_crc_o <= #`TCQ (hcrc_i != (path_build ? header_crc_pb : header_crc)); end end //==================================================================== // Check whether we've received an packet intended for an unsupported // OVC or MVC. always @(posedge clk_i) begin if (reset_i) begin unsup_ovc_o <= #`TCQ 0; end else if (eval_formats_i) begin unsup_ovc_o <= #`TCQ oo_i && BVC; end end always @(posedge clk_i) begin if (reset_i) begin unsup_mvc_o <= #`TCQ 0; end else if (eof_q1) begin unsup_mvc_o <= #`TCQ primary_pi0 && (pi_2nd != 0) && !MVC; end end //==================================================================== // Drop packets depending on link state. In DL_Inactive or DL_init, // only PI-0:0 packets are allowed through. In DL_Protected, only // PI-0:0, PI-4 and PI-5 packets are allowed. localparam [1:0] DL_INACTIVE = 2'b00; localparam [1:0] DL_INIT = 2'b01; localparam [1:0] DL_PROTECTED = 2'b10; localparam [1:0] DL_ACTIVE = 2'b11; // Only change link state in between packets. always @(posedge clk_i) begin if (reset_i) begin packet_ip <= #`TCQ 0; end else if (sof_i) begin packet_ip <= #`TCQ 1; end else if (eof_i) begin packet_ip <= #`TCQ 0; end end always @(posedge clk_i) begin if (reset_i) begin lnk_state_d <= #`TCQ DL_INACTIVE; end else if (lnk_state_src_rdy_i) begin lnk_state_d <= #`TCQ lnk_state_i; end end always @(posedge clk_i) begin if (reset_i) begin lnk_state <= #`TCQ DL_INACTIVE; end else if (!packet_ip) begin lnk_state <= #`TCQ lnk_state_d; end end // Signal packet drop always @(posedge clk_i) begin if (reset_i) begin packet_keep <= #`TCQ 1'b1; end else if (eof_q1) begin case (lnk_state) DL_INACTIVE: packet_keep <= #`TCQ (pi_1st == 0) && (pi_2nd == 0); DL_INIT: packet_keep <= #`TCQ (pi_1st == 0) && (pi_2nd == 0); DL_PROTECTED: packet_keep <= #`TCQ ((pi_1st == 0) && (pi_2nd == 0)) || (pi_1st == 4) || (pi_1st == 5); DL_ACTIVE: packet_keep <= #`TCQ 1'b1; endcase end end assign filter_drop_o = !packet_keep; //==================================================================== // Flag PI-0:0 and PI-4 packets as config. For PI-4, make sure the // config address is in the CMM's range. always @(posedge clk_i) begin if (reset_i) begin pi4_ap0 <= #`TCQ 1'b0; pi4_ap1 <= #`TCQ 1'b0; end else if (load_aperture_i) begin pi4_ap0 <= #`TCQ primary_pi4 && (aperture_i == 0); pi4_ap1 <= #`TCQ primary_pi4 && (aperture_i == 1); end end always @(posedge clk_i) begin if (reset_i) begin in_ap0_range <= #`TCQ 0; in_ap1_range <= #`TCQ 0; end else if (load_offset_i) begin in_ap0_range <= #`TCQ (offset_i < cmm_ap0_space_end_i); in_ap1_range <= #`TCQ (offset_i >= cmm_ap1_space_start_i) && (offset_i < cmm_ap1_space_end_i); end end always @(posedge clk_i) begin if (reset_i) begin load_offset_q <= #`TCQ 0; end else begin load_offset_q <= #`TCQ load_offset_i; end end // The packet goes to the CMM if: // 1. It is PI-0:0 and we are not a Fabric Manager, OR // 2. It is PI-4 Aperture 0, and in the Aperture 0 address range, OR // 3. It is PI-4 Aperture 1, and in the Aperture 1 address range. always @(posedge clk_i) begin if (reset_i) begin cfg_o <= #`TCQ 0; end else if (load_offset_q) begin cfg_o <= #`TCQ (primary_pi0 && secondary_pi0 && !fabric_manager_mode_i) || (pi4_ap0 && in_ap0_range) || (pi4_ap1 && in_ap1_range); end end `endif //==================================================================== // delay of control signals always @(posedge clk_i) begin if (reset_i) begin `ifdef PCIE sof_q1 <= #`TCQ 0; sof_q2 <= #`TCQ 0; sof_q3 <= #`TCQ 0; sof_q4 <= #`TCQ 0; eof_q2 <= #`TCQ 0; eof_q3 <= #`TCQ 0; eval_formats_q <= #`TCQ 0; eval_formats_q2 <= #`TCQ 0; `endif eof_q1 <= #`TCQ 0; end else begin `ifdef PCIE sof_q1 <= #`TCQ sof_i; sof_q2 <= #`TCQ sof_q1; sof_q3 <= #`TCQ sof_q2; sof_q4 <= #`TCQ sof_q3; eof_q2 <= #`TCQ eof_q1; eof_q3 <= #`TCQ eof_q2; eval_formats_q <= #`TCQ eval_formats_i; eval_formats_q2 <= #`TCQ eval_formats_q; `endif eof_q1 <= #`TCQ eof_i; end end endmodule
Go to most recent revision | Compare with Previous | Blame | View Log