OpenCores
URL https://opencores.org/ocsvn/openhmc/openhmc/trunk

Subversion Repositories openhmc

[/] [openhmc/] [trunk/] [openHMC/] [rtl/] [hmc_controller/] [rx/] [rx_link.v] - Rev 11

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 *                              .--------------. .----------------. .------------.
 *                             | .------------. | .--------------. | .----------. |
 *                             | | ____  ____ | | | ____    ____ | | |   ______ | |
 *                             | ||_   ||   _|| | ||_   \  /   _|| | | .' ___  || |
 *       ___  _ __   ___ _ __  | |  | |__| |  | | |  |   \/   |  | | |/ .'   \_|| |
 *      / _ \| '_ \ / _ \ '_ \ | |  |  __  |  | | |  | |\  /| |  | | || |       | |
 *       (_) | |_) |  __/ | | || | _| |  | |_ | | | _| |_\/_| |_ | | |\ `.___.'\| |
 *      \___/| .__/ \___|_| |_|| ||____||____|| | ||_____||_____|| | | `._____.'| |
 *           | |               | |            | | |              | | |          | |
 *           |_|               | '------------' | '--------------' | '----------' |
 *                              '--------------' '----------------' '------------'
 *
 *  openHMC - An Open Source Hybrid Memory Cube Controller
 *  (C) Copyright 2014 Computer Architecture Group - University of Heidelberg
 *  www.ziti.uni-heidelberg.de
 *  B6, 26
 *  68159 Mannheim
 *  Germany
 *
 *  Contact: openhmc@ziti.uni-heidelberg.de
 *  http://ra.ziti.uni-heidelberg.de/openhmc
 *
 *   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 3 of the License, or
 *   (at your option) any later version.
 *
 *   This source file 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 file.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *  Module name: rx_link
 *
 */
 
`default_nettype none
 
module rx_link #(
    parameter LOG_FPW           = 2,
    parameter FPW               = 4,
    parameter DWIDTH            = FPW*128,
    parameter LOG_NUM_LANES     = 3,
    parameter NUM_LANES         = 2**LOG_NUM_LANES,
    parameter HMC_PTR_SIZE      = 8,
    parameter HMC_RF_RWIDTH     = 64,
    //Configure functionality
    parameter LOG_MAX_RTC        = 8,
    parameter CTRL_LANE_POLARITY = 1,
    parameter CTRL_LANE_REVERSAL = 1,
    parameter BITSLIP_SHIFT_RIGHT= 1
) (
 
    //----------------------------------
    //----SYSTEM INTERFACE
    //----------------------------------
    input   wire                        clk,
    input   wire                        res_n,
 
    //----------------------------------
    //----TO HMC PHY
    //----------------------------------
    input   wire    [DWIDTH-1:0]        phy_scrambled_data_in,
    output  reg     [NUM_LANES-1:0]     init_bit_slip,               //bit slip per lane
 
    //----------------------------------
    //----TO RX HTAX FIFO
    //----------------------------------
    output  reg     [DWIDTH-1:0]        d_out_fifo_data,
    input   wire                        d_out_fifo_full,
    input   wire                        d_out_fifo_a_full,
    output  reg                         d_out_fifo_shift_in,
    output  reg     [4*FPW-1:0]         d_out_fifo_ctrl,
 
 
    //----------------------------------
    //----TO TX Block
    //----------------------------------
    output  reg                         tx_link_retry,
    output  reg                         tx_error_abort_mode,
    output  reg                         tx_error_abort_mode_cleared,
    output  reg     [7:0]               tx_hmc_frp,
    output  reg     [7:0]               tx_rrp,
    output  reg     [7:0]               tx_returned_tokens,
    output  reg     [LOG_FPW:0]         tx_hmc_tokens_to_return,
    output  reg     [LOG_FPW:0]         tx_hmc_poisoned_tokens_to_return,
 
    //----------------------------------
    //----RF
    //----------------------------------
    //Monitoring    1-cycle set to increment
    output  reg     [HMC_RF_RWIDTH-1:0] rf_cnt_poisoned,
    output  reg     [HMC_RF_RWIDTH-1:0] rf_cnt_rsp,
    //Status
    output  reg     [1:0]               rf_link_status,
    output  reg     [2:0]               rf_hmc_init_status,
    input   wire                        rf_tx_sends_ts1,
    input   wire                        rf_hmc_sleep,
    //Init Status
    output  wire    [NUM_LANES-1:0]     rf_descrambler_part_aligned,
    output  wire    [NUM_LANES-1:0]     rf_descrambler_aligned,
    output  wire                        rf_all_descramblers_aligned,
    //Control
    input   wire    [5:0]               rf_bit_slip_time,
    input   wire                        rf_hmc_init_cont_set,
    output  reg     [NUM_LANES-1:0]     rf_lane_polarity,
    input   wire                        rf_scrambler_disable,
    output  reg                         rf_lane_reversal_detected,
    output  reg     [NUM_LANES-1:0]     rf_descramblers_locked,
    input   wire    [4:0]               rf_irtry_received_threshold
 
);
`include "hmc_field_functions.h"
 
//=====================================================================================================
//-----------------------------------------------------------------------------------------------------
//---------WIRING AND SIGNAL STUFF---------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//=====================================================================================================
 
//------------------------------------------------------------------------------------Some general things
//Link state
localparam              HMC_DOWN        = 3'b000;
localparam              HMC_NULL        = 3'b001;
localparam              HMC_TS1         = 3'b010;
localparam              HMC_UP          = 3'b100;
 
//Commands
localparam              CMD_IRTRY       = 3'b011;
localparam              CMD_FLOW        = 3'b000;
localparam              CMD_RSP         = 3'b111;
localparam              CMD_RSP_ERROR   = 6'b111110;
 
//Other helpful defines
localparam              WIDTH_PER_LANE          = (DWIDTH/NUM_LANES);
 
//16 bits is a ts1, so the init seq number is incremented according to the lane size
localparam              INIT_SEQ_INC_PER_CYCLE  = WIDTH_PER_LANE/16;
 
//MISC
integer i_f;    //counts to FPW
integer i_l;    //counts to NUM_LANES
integer i_c;    //counts to CYCLES_TO_COMPLETE_FULL_PACKET
 
genvar f;   //Counts to FPW
genvar n;   //Counts to NUM_LANES
genvar w;   //Counts to WIDTH_PER_LANE
 
//------------------------------------------------------------------------------------DESCRAMBLER AND DATA ORDERING
reg [NUM_LANES-1:0]     init_descrambler_part_aligned;
reg [NUM_LANES-1:0]     init_descrambler_aligned;
assign                  rf_descrambler_part_aligned = init_descrambler_part_aligned;
assign                  rf_descrambler_aligned      = init_descrambler_aligned;
 
//DATA and REORDERING
reg  [WIDTH_PER_LANE-1:0]   init_data_per_lane          [NUM_LANES-1:0];
wire [DWIDTH-1:0]           init_d_in;
wire [128-1:0]              init_d_in_flit              [FPW-1:0];
wire [WIDTH_PER_LANE-1:0]   descrambled_data_per_lane   [NUM_LANES-1:0];
wire [DWIDTH-1:0]           d_in;
wire [128-1:0]              d_in_flit                   [FPW-1:0];
 
//Valid FLIT sources. A FLIT is valid when it is not NULL
wire [FPW-1:0]              valid_flit_src;     //bit0 = flit0, ...
wire [FPW-1:0]              init_valid_flit_src;     //bit0 = flit0, ...
 
generate
 
    //-- Apply lane reversal if detected
    for(n = 0; n < NUM_LANES; n = n + 1) begin : apply_lane_reversal
        for(w = 0; w < WIDTH_PER_LANE; w = w + 1) begin
            if(CTRL_LANE_REVERSAL==1)begin
                assign d_in[w*NUM_LANES+n]      = rf_lane_reversal_detected ? descrambled_data_per_lane[NUM_LANES-1-n][w] : descrambled_data_per_lane[n][w];
                assign init_d_in[w*NUM_LANES+n] = rf_lane_reversal_detected ? init_data_per_lane[NUM_LANES-1-n][w] : init_data_per_lane[n][w];
            end else begin
                assign d_in[w*NUM_LANES+n]      = descrambled_data_per_lane[n][w];
                assign init_d_in[w*NUM_LANES+n] = init_data_per_lane[n][w];
            end
        end
    end
 
 
    for(f = 0; f < FPW; f = f + 1) begin : reorder_input_data
        //-- Reorder the descrambled data to FLITs
        assign d_in_flit[f]       = d_in[128-1+(f*128):f*128];
        assign init_d_in_flit[f]  = init_d_in[128-1+(f*128):f*128];
        //-- Generate valid flit positions for the init sequence
        assign valid_flit_src[f]        = (|d_in_flit[f] == 1'b0) ? 1'b0 : 1'b1;
        assign init_valid_flit_src[f]   = (|init_d_in_flit[f] == 1'b0) ? 1'b0 : 1'b1;
    end
 
endgenerate
 
 
//------------------------------------------------------------------------------------INIT
localparam                  LINK_DOWN   = 2'b00;
localparam                  LINK_INIT   = 2'b01;
localparam                  LINK_UP     = 2'b10;
 
reg     [5:0]               init_bit_slip_cnt;
reg     [4:0]               init_wait_time;
wire    [NUM_LANES-1:0]     init_descrambler_locked;           //locked from the descrambler
wire                        link_is_up;
reg     [3:0]               init_tmp_seq;
reg                         init_prbs_seen;
 
assign                      link_is_up                  = rf_link_status[1];
assign                      rf_all_descramblers_aligned = &init_descrambler_aligned;
 
//--------------TS1 recognition
localparam                  ts1_independent_portion = {4'hF,4'h0};
localparam                  ts1_lanex_portion       = {4'h5};
localparam                  ts1_lane7or15_portion   = 4'hc;
localparam                  ts1_lane0_portion       = 4'h3;
 
localparam                  ts1_per_cycle_and_lane = DWIDTH/NUM_LANES/16;
 
wire    [NUM_LANES-1:0]     init_lane_has_correct_ts1;
wire    [ts1_per_cycle_and_lane-1:0]     init_lane_has_correct_ts1_vec   [NUM_LANES-1:0];
 
genvar t;
generate
    //Make sure that the lanes have valid ts1 sequences throughout the entire data stream
    for(n=0;n<NUM_LANES;n=n+1) begin : lane_has_correct_ts1_gen
 
        assign init_lane_has_correct_ts1[n] = &init_lane_has_correct_ts1_vec[n];
 
        for(t=0;t<ts1_per_cycle_and_lane;t=t+1) begin
            if(n==0 || n==NUM_LANES-1) begin
                assign init_lane_has_correct_ts1_vec[n][t] = (init_data_per_lane[n][(t*16)+16-1:(t*16)+4] == {ts1_independent_portion,ts1_lane7or15_portion})
                                                             ||
                                                             (init_data_per_lane[n][(t*16)+16-1:(t*16)+4] == {ts1_independent_portion,ts1_lane0_portion});            
            end else begin
                assign init_lane_has_correct_ts1_vec[n][t] = (init_data_per_lane[n][(t*16)+16-1:(t*16)+4] == {ts1_independent_portion,ts1_lanex_portion});
            end
        end
    end
endgenerate
 
//--------------Align the lanes, scan for the ts1 seq
reg  [LOG_NUM_LANES-1:0]    init_lane_cnt;
wire [3:0]                  init_seq_diff;
 
//If one of the descramblers is already partially aligned search for other lanes with their ts1 sequence number close this lane. 
assign                      init_seq_diff = |init_descrambler_part_aligned ? 
                                                (BITSLIP_SHIFT_RIGHT==1 ? (init_data_per_lane[init_lane_cnt][3:0] - init_tmp_seq) 
                                                : init_tmp_seq - init_data_per_lane[init_lane_cnt][3:0])
                                            : 0;
 
//------------------------------------------------------------------------------------Input Stage: Scan for Packets, Headers, Tails ...
reg  [DWIDTH-1:0]       data2crc;
reg  [FPW-1:0]          data2crc_hdr;
reg  [FPW-1:0]          data2crc_tail;
reg  [FPW-1:0]          data2crc_valid;
wire [(FPW*4)-1:0]      data2crc_lng;
reg  [3:0]              data2crc_lng_per_flit [FPW-1:0];
reg  [3:0]              data2crc_payload_remain;
 
reg  [FPW-1:0]          data2crc_hdr_comb;
reg  [FPW-1:0]          data2crc_tail_comb;
reg  [FPW-1:0]          data2crc_valid_comb;
reg  [3:0]              data2crc_lng_per_flit_comb [FPW-1:0];
reg  [3:0]              data2crc_payload_remain_comb;
 
generate
        for(f = 0; f < (FPW); f = f + 1) begin
            assign data2crc_lng[(f*4)+4-1:(f*4)] = data2crc_lng_per_flit[f];
        end
endgenerate
 
//------------------------------------------------------------------------------------CRC
wire [DWIDTH-1:0]       crc_d_out_data;
wire [128-1:0]          crc_d_out_flit              [FPW-1:0];
wire [FPW-1:0]          crc_d_out_flit_is_hdr;
wire [FPW-1:0]          crc_d_out_flit_is_tail;
wire [FPW-1:0]          crc_d_out_flit_is_valid;
wire [FPW-1:0]          crc_d_out_flit_is_error;
wire [FPW-1:0]          crc_d_out_flit_is_poisoned;
wire [FPW-1:0]          crc_d_out_flit_has_rtc;
wire [FPW-1:0]          crc_d_out_flit_is_flow;
 
generate
        for(f=0;f<FPW;f=f+1) begin : reorder_crc_output
            assign crc_d_out_flit[f] = crc_d_out_data[128-1+(f*128):f*128];
        end
endgenerate
 
//------------------------------------------------------------------------------------LNG and DLN stage
reg     [128-1:0]       flit_after_lng_check                   [FPW-1:0];
reg     [FPW-1:0]       flit_after_lng_check_is_hdr;
reg     [FPW-1:0]       flit_after_lng_check_is_tail;
reg     [FPW-1:0]       flit_after_lng_check_is_valid;
reg     [FPW-1:0]       flit_after_lng_check_is_error;
reg     [FPW-1:0]       flit_after_lng_check_is_poisoned;
reg     [FPW-1:0]       flit_after_lng_check_is_flow;
reg     [FPW-1:0]       flit_after_lng_check_has_rtc;
 
//------------------------------------------------------------------------------------Start TX retry Stage
reg     [128-1:0]       flit_after_retry_stage                   [FPW-1:0];
reg     [FPW-1:0]       flit_after_retry_stage_is_hdr;
reg     [FPW-1:0]       flit_after_retry_stage_is_tail;
reg     [FPW-1:0]       flit_after_retry_stage_is_valid;
reg     [FPW-1:0]       flit_after_retry_stage_is_valid_mask_msb;
reg     [FPW-1:0]       flit_after_retry_stage_is_valid_mask_lsb;
reg     [FPW-1:0]       flit_after_retry_stage_is_error;
reg     [FPW-1:0]       flit_after_retry_stage_is_poisoned;
reg     [FPW-1:0]       flit_after_retry_stage_is_flow;
reg     [FPW-1:0]       flit_after_retry_stage_has_rtc;
reg     [FPW-1:0]       flit_after_retry_stage_is_start_retry;
reg     [FPW-1:0]       flit_after_retry_stage_is_start_retry_comb;
 
//------------------------------------------------------------------------------------SeqStage and Seqnum
reg     [128-1:0]       flit_after_seq_check                   [FPW-1:0];
reg     [FPW-1:0]       flit_after_seq_check_is_hdr;
reg     [FPW-1:0]       flit_after_seq_check_is_tail;
reg     [FPW-1:0]       flit_after_seq_check_is_valid;
reg     [FPW-1:0]       flit_after_seq_check_is_error;
reg     [FPW-1:0]       flit_after_seq_check_is_error_comb;
reg     [FPW-1:0]       flit_after_seq_check_is_poisoned;
reg     [FPW-1:0]       flit_after_seq_check_is_flow;
reg     [FPW-1:0]       flit_after_seq_check_has_rtc;
reg     [FPW-1:0]       flit_after_seq_check_is_start_retry;
 
reg     [2:0]           next_seqnum;
reg     [2:0]           next_seqnum_comb; //use param instead
reg     [2:0]           first_seq_after_error;
 
//------------------------------------------------------------------------------------Invalidation Stage
localparam CYCLES_TO_COMPLETE_FULL_PACKET   =   (FPW == 2) ? 5 :
                                                (FPW == 4) ? 3 : //Assuming Max Pkt size = 9 FLITs
                                                (FPW == 6) ? 3 :
                                                (FPW == 8) ? 2 :
                                                1;
 
//Regs to retrieve the pkt length, assign the length to correspoding tail. The packet will be invalidated then
reg     [3:0]        lng_per_tail      [FPW-1:0] ;
reg     [3:0]        lng_per_tail_comb [FPW-1:0] ;
reg     [3:0]        lng_temp;
reg     [3:0]        lng_comb;
//Signal that an error was detected. Invalid all FLITs after
reg                  error_detected;
 
//Assign FLITs to word, necessary for the invalidation stage pipeline
wire   [DWIDTH-1:0]            flit_after_seq_check_word;
generate
        for(f = 0; f < (FPW); f = f + 1) begin : reorder_flits_after_seq_to_word
            assign flit_after_seq_check_word[(f*128)+128-1:(f*128)] = flit_after_seq_check[f];
        end
endgenerate
 
reg     [DWIDTH-1:0]    flit_in_invalidation_data          [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation_is_hdr        [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation_is_tail       [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation_is_valid      [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation_mask_error;
reg     [FPW-1:0]       flit_in_invalidation_is_poisoned   [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation0_is_poisoned_comb;
reg     [FPW-1:0]       flit_in_invalidation_is_flow       [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation_has_rtc       [CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
reg     [FPW-1:0]       flit_in_invalidation_is_start_retry[CYCLES_TO_COMPLETE_FULL_PACKET-1:0];
 
//------------------------------------------------------------------------------------Checked FLITs
wire     [128-1:0]      checked_flit             [FPW-1:0];
wire     [FPW-1:0]      checked_flit_is_poisoned;
wire     [FPW-1:0]      checked_flit_is_valid;
wire     [FPW-1:0]      checked_flit_is_hdr;
wire     [FPW-1:0]      checked_flit_is_tail;
wire     [FPW-1:0]      checked_flit_has_rtc;
wire     [FPW-1:0]      checked_flit_is_flow;
wire     [FPW-1:0]      checked_flit_is_start_retry;
 
assign checked_flit_is_hdr         = flit_in_invalidation_is_hdr       [CYCLES_TO_COMPLETE_FULL_PACKET-1] & flit_in_invalidation_is_valid     [CYCLES_TO_COMPLETE_FULL_PACKET-1];
assign checked_flit_is_tail        = flit_in_invalidation_is_tail      [CYCLES_TO_COMPLETE_FULL_PACKET-1] & flit_in_invalidation_is_valid     [CYCLES_TO_COMPLETE_FULL_PACKET-1];
assign checked_flit_is_valid       = flit_in_invalidation_is_valid     [CYCLES_TO_COMPLETE_FULL_PACKET-1] ;
assign checked_flit_is_poisoned    = flit_in_invalidation_is_poisoned  [CYCLES_TO_COMPLETE_FULL_PACKET-1] & flit_in_invalidation_is_valid     [CYCLES_TO_COMPLETE_FULL_PACKET-1];
assign checked_flit_is_flow        = flit_in_invalidation_is_flow      [CYCLES_TO_COMPLETE_FULL_PACKET-1] & flit_in_invalidation_is_valid     [CYCLES_TO_COMPLETE_FULL_PACKET-1];
assign checked_flit_has_rtc        = flit_in_invalidation_has_rtc      [CYCLES_TO_COMPLETE_FULL_PACKET-1] & flit_in_invalidation_is_valid     [CYCLES_TO_COMPLETE_FULL_PACKET-1];
assign checked_flit_is_start_retry = flit_in_invalidation_is_start_retry[CYCLES_TO_COMPLETE_FULL_PACKET-1];
 
generate
        for(f = 0; f < (FPW); f = f + 1) begin : reorder_invalidation_word_back_to_flits
            assign checked_flit[f] = flit_in_invalidation_data[CYCLES_TO_COMPLETE_FULL_PACKET-1][128-1+(f*128):f*128];
        end
endgenerate
 
//------------------------------------------------------------------------------------Counter
reg [LOG_FPW:0]         rf_cnt_poisoned_comb;
reg [LOG_FPW:0]         rf_cnt_rsp_comb;
 
//------------------------------------------------------------------------------------Input Buffer
reg     [LOG_FPW:0]          tokens_out_of_fifo_sum_comb;
reg     [LOG_FPW:0]          tokens_poisoned;
reg     [7:0]                rtc_sum_comb; //for 8 FLIT config, maximum 8*31 tokens will be returned per cycle
 
reg     [128-1:0]            input_buffer_d_in_flit    [FPW-1:0];
reg     [FPW-1:0]            input_buffer_valid;
reg     [FPW-1:0]            input_buffer_is_hdr;
reg     [FPW-1:0]            input_buffer_is_tail;
reg     [FPW-1:0]            input_buffer_is_error_rsp;
wire    [DWIDTH+(4*FPW)-1:0] input_buffer_d_in;
wire    [DWIDTH+(4*FPW)-1:0] input_buffer_d_out;
wire                         input_buffer_empty;
reg                          input_buffer_shift_in;
wire                         input_buffer_shift_out;
assign                       input_buffer_shift_out    =   ~(input_buffer_empty || d_out_fifo_a_full);
 
generate
        for(f = 0; f < (FPW); f = f + 1) begin : assign_flits_to_input_buffer_to_a_single_reg
            assign input_buffer_d_in[f*128+128-1:f*128] = input_buffer_d_in_flit[f];
            assign input_buffer_d_in[DWIDTH+f]          = input_buffer_valid[f];
            assign input_buffer_d_in[DWIDTH+f+FPW]      = input_buffer_is_hdr[f];
            assign input_buffer_d_in[DWIDTH+f+(2*FPW)]  = input_buffer_is_tail[f];
            assign input_buffer_d_in[DWIDTH+f+(3*FPW)]  = input_buffer_is_error_rsp[f];
        end
endgenerate
 
//------------------------------------------------------------------------------------LINK RETRY
reg  [5:0]     irtry_start_retry_cnt;
reg  [5:0]     irtry_clear_error_cnt;
reg  [5:0]     irtry_start_retry_cnt_comb;
reg  [5:0]     irtry_clear_error_cnt_comb;
reg            irtry_clear_trig;
reg            irtry_clear_trig_comb;
 
//=====================================================================================================
//-----------------------------------------------------------------------------------------------------
//---------ACTUAL LOGIC STARTS HERE--------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//=====================================================================================================
 
//========================================================================================================================================
//------------------------------------------------------------------INIT
//========================================================================================================================================
always @(posedge clk)  begin
    for(i_l = 0;i_l<NUM_LANES;i_l=i_l+1)begin
        init_data_per_lane[i_l] <= descrambled_data_per_lane[i_l];
    end
end
 
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    //----Misc
    init_descrambler_aligned         <= {NUM_LANES{1'b0}};
    init_descrambler_part_aligned    <= {NUM_LANES{1'b0}};
    init_bit_slip               <= {NUM_LANES{1'b0}};
    init_bit_slip_cnt           <= 6'h0;
    init_wait_time              <= 5'h0;
    init_tmp_seq                <= 4'h0;
    init_lane_cnt               <= {LOG_NUM_LANES{1'b0}};
    init_prbs_seen              <= 1'b0;
    rf_hmc_init_status          <= HMC_DOWN;
    rf_link_status              <= LINK_DOWN;
    rf_lane_polarity            <= {NUM_LANES{1'b0}};
    rf_lane_reversal_detected   <= 1'b0;
    rf_descramblers_locked      <= {NUM_LANES{1'b0}};
end
else begin
 
    rf_descramblers_locked  <= init_descrambler_locked;
    init_bit_slip           <= {NUM_LANES{1'b0}};
 
 
    if(rf_hmc_sleep || !rf_hmc_init_cont_set) begin
        rf_link_status <= LINK_DOWN;
    end else if(rf_link_status == LINK_DOWN) begin
        //Begin (Re-)Init
        init_descrambler_aligned         <= {NUM_LANES{1'b0}};
        init_descrambler_part_aligned    <= {NUM_LANES{1'b0}};
        init_wait_time              <= 5'h1f;
        init_tmp_seq                <= 4'h0;
        init_lane_cnt               <= {LOG_NUM_LANES{1'b0}};
        init_prbs_seen              <= 1'b0;
        rf_hmc_init_status          <= HMC_DOWN;
        rf_link_status              <= LINK_INIT;
        rf_lane_polarity            <= {NUM_LANES{1'b0}};
        rf_lane_reversal_detected   <= 1'b0;
        rf_descramblers_locked      <= {NUM_LANES{1'b0}};
    end
 
    //Detect Lane polarity when HMC is sending first NULLs
    if(&rf_descramblers_locked && rf_link_status == LINK_INIT) begin
        for(i_l = 0;i_l<NUM_LANES;i_l=i_l+1)begin
            if(init_data_per_lane[i_l] == {WIDTH_PER_LANE{1'b1}})begin
                rf_lane_polarity[i_l] <=  1'b1;
            end
        end
    end
 
    if(rf_hmc_init_status == HMC_DOWN) begin
        if(|init_valid_flit_src) begin
            init_prbs_seen <= 1'b1;
        end 
        if(!init_valid_flit_src && init_prbs_seen && &rf_descramblers_locked) begin
            rf_hmc_init_status <= HMC_NULL;
        end
    end
 
    //When TX block sends ts1, start init process
    if(rf_tx_sends_ts1 && &init_valid_flit_src) begin
        rf_hmc_init_status      <= HMC_TS1;
    end
 
    if(rf_hmc_init_status==HMC_TS1) begin
        // -------------------------------------------------------------------------TS1 AND DESCRAMBLER SYNCHRONIZATION
        if(!rf_all_descramblers_aligned) begin      // repeat this until all descramblers are aligned !!
 
            if(|init_wait_time == 1'b0)begin
 
                init_tmp_seq    <= init_tmp_seq + INIT_SEQ_INC_PER_CYCLE;
 
                if(|init_bit_slip_cnt == 1'b0)begin
 
                    init_lane_cnt        <= init_lane_cnt + 1;
 
                    if(!init_descrambler_part_aligned[init_lane_cnt])begin     
                        init_bit_slip[init_lane_cnt]                     <= ~init_lane_has_correct_ts1[init_lane_cnt];
                        //if the current lane is more advanced than the current reference lane, set this lane as new reference
                        if(init_seq_diff < 2 && init_lane_has_correct_ts1[init_lane_cnt]) begin
                            init_tmp_seq                            <= init_data_per_lane[init_lane_cnt][3:0] + INIT_SEQ_INC_PER_CYCLE;
                        end
                    end
 
                    if(&init_descrambler_part_aligned) begin
                        if(|init_seq_diff==1'b0 && init_lane_has_correct_ts1[init_lane_cnt])begin
                            init_descrambler_aligned[init_lane_cnt] <= 1'b1;
                        end else begin
                            init_bit_slip[init_lane_cnt] <= 1'b1;
                        end
                    end else begin
                        init_descrambler_part_aligned[init_lane_cnt]          <= init_lane_has_correct_ts1[init_lane_cnt];
                    end
 
                    if(init_lane_cnt == NUM_LANES-1)begin
                        init_bit_slip_cnt <= rf_bit_slip_time;
                    end
 
                end else begin
                    init_bit_slip_cnt <= init_bit_slip_cnt -1;
                end
 
            end else begin
                init_wait_time <= init_wait_time -1;
            end
        // -------------------------------------------------------------------------SECOND NULL SEQUENCE
        end else begin  // now that all is synchronized continue with NULL and TRET
 
            //lane reversal detected, reverse the input stream lane by lane
            if(init_data_per_lane[0][7:4] ==  ts1_lane7or15_portion)begin
                rf_lane_reversal_detected   <= 1'b1;
            end
 
            //when received NULLs again, init done (initial TRETs are treated as normal packets)
            if(|init_valid_flit_src == 1'b0)begin
                rf_link_status      <= LINK_UP;
                rf_hmc_init_status  <= HMC_UP;
            end
        end
    end
end
end
 
//========================================================================================================================================
//------------------------------------------------------------------Packet Processing
//========================================================================================================================================
//==================================================================================
//---------------------------------Detect HDR,Tail,Valid Flits and provide to CRC logic
//==================================================================================
always @(*)  begin
    //Use the remaining payload from last cycle
    data2crc_payload_remain_comb = data2crc_payload_remain;
 
    data2crc_hdr_comb    = {FPW{1'b0}};
    data2crc_tail_comb   = {FPW{1'b0}};
    data2crc_valid_comb  = {FPW{1'b0}};
 
    for(i_f=0;i_f<FPW;i_f=i_f+1) begin
 
        data2crc_lng_per_flit_comb[i_f] = {128{1'b0}};
 
        if(data2crc_payload_remain_comb ==4'h1) begin
            data2crc_tail_comb[i_f]  = 1'b1;
        end
 
        if(data2crc_payload_remain_comb) begin
            data2crc_valid_comb[i_f]     = 1'b1;
            data2crc_payload_remain_comb = data2crc_payload_remain_comb - 1;
        end else if(valid_flit_src[i_f])begin
 
            data2crc_hdr_comb[i_f]   = 1'b1;
            data2crc_valid_comb[i_f] = 1'b1;
 
            if(lng(d_in_flit[i_f]) < 2 || lng(d_in_flit[i_f]) > 9) begin
                //Treat false lng values as single FLIT packets which will force error abort mode
                data2crc_tail_comb[i_f]         = 1'b1;
                data2crc_lng_per_flit_comb[i_f] = 1;
            end else begin
                data2crc_payload_remain_comb    = lng(d_in_flit[i_f]) -1;
                data2crc_lng_per_flit_comb[i_f] = lng(d_in_flit[i_f]);
            end
        end
 
    end
end
 
//Register the combinational logic from previous stage
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    data2crc_hdr    <= {FPW{1'b0}};
    data2crc_tail   <= {FPW{1'b0}};
    data2crc_valid  <= {FPW{1'b0}};
 
    data2crc_payload_remain  <= {4{1'b0}};
 
    for(i_f=0;i_f<FPW;i_f=i_f+1) begin
        data2crc_lng_per_flit[i_f] <= {128{1'b0}};
    end
 
    data2crc <= {DWIDTH{1'b0}};
 
end else begin
    if(link_is_up) begin
        data2crc_hdr    <= data2crc_hdr_comb;
        data2crc_tail   <= data2crc_tail_comb;
        data2crc_valid  <= data2crc_valid_comb;
    end
 
    data2crc_payload_remain  <= data2crc_payload_remain_comb;
 
    for(i_f=0;i_f<FPW;i_f=i_f+1) begin
        data2crc_lng_per_flit[i_f] <= data2crc_lng_per_flit_comb[i_f];
    end
 
    data2crc  <= d_in;
 
end
end
 
//==================================================================================
//---------------------------------LNG/DLN check
//==================================================================================
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    flit_after_lng_check_is_hdr       <= {FPW{1'b0}};
    flit_after_lng_check_is_tail      <= {FPW{1'b0}};
    flit_after_lng_check_is_valid     <= {FPW{1'b0}};
    flit_after_lng_check_is_poisoned  <= {FPW{1'b0}};
    flit_after_lng_check_is_flow      <= {FPW{1'b0}};
    flit_after_lng_check_has_rtc      <= {FPW{1'b0}};
    flit_after_lng_check_is_error     <= {FPW{1'b0}};
 
    for(i_f = 0; i_f < FPW; i_f = i_f + 1) begin
        flit_after_lng_check[i_f]     <= {128{1'b0}};
    end
 
end else begin
    flit_after_lng_check_is_hdr       <= crc_d_out_flit_is_hdr;
    flit_after_lng_check_is_tail      <= crc_d_out_flit_is_tail;
    flit_after_lng_check_is_valid     <= crc_d_out_flit_is_valid;
    flit_after_lng_check_is_poisoned  <= crc_d_out_flit_is_poisoned;
    flit_after_lng_check_is_flow      <= crc_d_out_flit_is_flow;
    flit_after_lng_check_has_rtc      <= crc_d_out_flit_has_rtc;
    flit_after_lng_check_is_error     <= crc_d_out_flit_is_error;
 
    for(i_f = 0; i_f < FPW; i_f = i_f + 1) begin
        flit_after_lng_check[i_f]     <= crc_d_out_flit[i_f];
    end
 
    //perform lng/dln check
    for(i_f = 0; i_f < FPW; i_f = i_f + 1) begin
        if(crc_d_out_flit_is_hdr[i_f] && (lng(crc_d_out_flit[i_f]) != dln(crc_d_out_flit[i_f]))) begin
            flit_after_lng_check_is_error[i_f]  <= 1'b1;
        end
    end
end
end
 
//====================================================================
//---------------------------------Start Retry Stage
//====================================================================
//-- Count all types of IRTRY packets
always @(*)  begin
 
    //Set the lower bit mask for the next stage: Mask out all error FLITs
    flit_after_retry_stage_is_valid_mask_lsb   = {FPW{1'b1}};
    for(i_f = FPW-1; i_f >=0; i_f = i_f - 1) begin
        if(flit_after_lng_check_is_error[i_f])begin
            //Pass the tail in case it is an crc error so that the corresponding FLITs of the packet can be invalidated
            //but mask out single flit packets!
            flit_after_retry_stage_is_valid_mask_lsb = {FPW{1'b1}} >> (FPW-i_f-(flit_after_lng_check_is_tail[i_f] & !flit_after_lng_check_is_hdr[i_f]));
        end
    end
 
    //Next up, count both types of irtry packets and set the mask accordingly for irtry start packets in error abort mode and the
    //final clear abort FLIT that reaches the threshold
 
    flit_after_retry_stage_is_start_retry_comb = {FPW{1'b0}};
 
    if( (tx_error_abort_mode && !irtry_clear_trig) ||
        |(flit_after_retry_stage_is_error) ||
        |(flit_after_seq_check_is_error)
    )begin
        flit_after_retry_stage_is_valid_mask_msb = {FPW{1'b0}};
    end else begin
        flit_after_retry_stage_is_valid_mask_msb = {FPW{1'b1}};
    end
 
    irtry_clear_trig_comb      = 1'b0;
 
    irtry_clear_error_cnt_comb = irtry_clear_error_cnt;
    irtry_start_retry_cnt_comb = irtry_start_retry_cnt;
 
 
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
 
        if( flit_after_lng_check_is_flow[i_f] &&
            cmd(flit_after_lng_check[i_f]) == {CMD_FLOW,CMD_IRTRY} &&
            !flit_after_lng_check_is_error[i_f]
        ) begin
 
            if(irtry_start_retry_flag(flit_after_lng_check[i_f])) begin
                //it's a start tx retry pkt
                irtry_start_retry_cnt_comb   = irtry_start_retry_cnt_comb + 6'h1;
                irtry_clear_error_cnt_comb   = 6'h0;
            end else begin
                //must be clear error pkt
                irtry_clear_error_cnt_comb   = irtry_clear_error_cnt_comb + 6'h1;
                irtry_start_retry_cnt_comb   = 6'h0;
            end
 
            if(irtry_start_retry_cnt_comb == rf_irtry_received_threshold) begin
                //The start retry packet that reaches the trehold is treated as valid and will trigger tx retry
                flit_after_retry_stage_is_valid_mask_msb[i_f]   = 1'b1;
                flit_after_retry_stage_is_start_retry_comb[i_f] = 1'b1;
            end
 
            //Clear error abort when threshold reached, allow following FLITs to be valid
            if(irtry_clear_error_cnt_comb == rf_irtry_received_threshold) begin
                irtry_clear_trig_comb                    = 1'b1;
                flit_after_retry_stage_is_valid_mask_msb = {FPW{1'b1}} << (i_f);
            end
 
        end else begin
            //Reset both counters when received a non-irtry packet
            irtry_start_retry_cnt_comb = 6'h0;
            irtry_clear_error_cnt_comb = 6'h0;
        end
    end
end
 
//Save the temporary counts to be re-used in the next cycle and register the clear trigger
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    irtry_clear_trig      <= 1'b0;
 
    irtry_clear_error_cnt <= {6{1'b0}};
    irtry_start_retry_cnt <= {6{1'b0}};
 
end else begin
    irtry_clear_trig      <= irtry_clear_trig_comb;
 
    irtry_clear_error_cnt <= irtry_clear_error_cnt_comb;
    irtry_start_retry_cnt <= irtry_start_retry_cnt_comb;
end
end
 
//Propagate data and apply the valid masks
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    for(i_f = 0;i_f<(FPW);i_f=i_f+1) begin
        flit_after_retry_stage[i_f]       <= {128{1'b0}};
    end
    flit_after_retry_stage_is_hdr         <= {FPW{1'b0}};
    flit_after_retry_stage_is_tail        <= {FPW{1'b0}};
    flit_after_retry_stage_is_poisoned    <= {FPW{1'b0}};
    flit_after_retry_stage_is_flow        <= {FPW{1'b0}};
    flit_after_retry_stage_has_rtc        <= {FPW{1'b0}};
    flit_after_retry_stage_is_error       <= {FPW{1'b0}};
    flit_after_retry_stage_is_valid       <= {FPW{1'b0}};
    flit_after_retry_stage_is_start_retry <= 1'b0;
end else begin
 
    for(i_f = 0;i_f<(FPW);i_f=i_f+1) begin
        flit_after_retry_stage[i_f] <= flit_after_lng_check[i_f];
    end
    flit_after_retry_stage_is_hdr         <= flit_after_lng_check_is_hdr;
    flit_after_retry_stage_is_tail        <= flit_after_lng_check_is_tail;
    flit_after_retry_stage_is_poisoned    <= flit_after_lng_check_is_poisoned &
                                             flit_after_retry_stage_is_valid_mask_msb &
                                             flit_after_retry_stage_is_valid_mask_lsb;
    flit_after_retry_stage_is_flow        <= flit_after_lng_check_is_flow;
    flit_after_retry_stage_has_rtc        <= flit_after_lng_check_has_rtc;
    flit_after_retry_stage_is_error       <= flit_after_lng_check_is_error;
    flit_after_retry_stage_is_valid       <= flit_after_lng_check_is_valid &
                                             flit_after_retry_stage_is_valid_mask_msb &
                                             flit_after_retry_stage_is_valid_mask_lsb;
    flit_after_retry_stage_is_start_retry <= flit_after_retry_stage_is_start_retry_comb;
end
end
 
//-------------------------------------------Error abort mode
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    //TX signaling
    tx_error_abort_mode             <= 1'b0;
    tx_error_abort_mode_cleared     <= 1'b0;
 
end else begin
 
    tx_error_abort_mode_cleared <= 1'b0;
 
    if(irtry_clear_trig) begin
        tx_error_abort_mode         <= 1'b0;
        tx_error_abort_mode_cleared <= 1'b1;
    end
 
    //Set error abort mode again if error detected
    if(|flit_after_lng_check_is_error || flit_after_seq_check_is_error)begin
        tx_error_abort_mode <= 1'b1;
    end
 
end
end
 
//==================================================================================
//---------------------------------SEQ check
//==================================================================================
//Check the seqnum FLIT by FLIT. Assign the last received seqnum when error abort mode is cleared
//!Lots of logic levels for 8FLIT config
always @(*)  begin
 
    next_seqnum_comb                    = 3'h0;
    flit_after_seq_check_is_error_comb  = {FPW{1'b0}};
 
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        if(flit_after_retry_stage_has_rtc[i_f]) begin
        //All packets that have an RTC also have a valid seqnum
            if(seq(flit_after_retry_stage[i_f]) == next_seqnum + next_seqnum_comb) begin
                next_seqnum_comb = next_seqnum_comb + 3'h1;
            end else begin
                flit_after_seq_check_is_error_comb[i_f]  = 1'b1;
            end
        end
    end
end
 
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    //We expect the first packet to have the seqnum 1
    next_seqnum                         <= 3'h1;
 
    flit_after_seq_check_is_hdr         <= {FPW{1'b0}};
    flit_after_seq_check_is_tail        <= {FPW{1'b0}};
    flit_after_seq_check_is_valid       <= {FPW{1'b0}};
    flit_after_seq_check_is_poisoned    <= {FPW{1'b0}};
    flit_after_seq_check_is_flow        <= {FPW{1'b0}};
    flit_after_seq_check_has_rtc        <= {FPW{1'b0}};
    flit_after_seq_check_is_error       <= {FPW{1'b0}};
    flit_after_seq_check_is_start_retry <= {FPW{1'b0}};
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        flit_after_seq_check[i_f]     <= {128{1'b0}};
    end
 
end else begin
 
    //Set the expected sequence number to the first one after error abort mode was cleared
    //otherwise apply the last seqnum + combinatioanl offset
    if(irtry_clear_trig_comb) begin
        next_seqnum     <= first_seq_after_error + next_seqnum_comb;
    end else begin
        next_seqnum     <= next_seqnum + next_seqnum_comb;
    end
 
    //propage data to next stage and include any error bits that were detected during sequence number check
    flit_after_seq_check_is_hdr         <= flit_after_retry_stage_is_hdr;
    flit_after_seq_check_is_tail        <= flit_after_retry_stage_is_tail;
    flit_after_seq_check_is_valid       <= flit_after_retry_stage_is_valid;
    flit_after_seq_check_is_poisoned    <= flit_after_retry_stage_is_poisoned;
    flit_after_seq_check_is_flow        <= flit_after_retry_stage_is_flow;
    flit_after_seq_check_has_rtc        <= flit_after_retry_stage_has_rtc;
    flit_after_seq_check_is_error       <= flit_after_retry_stage_is_error |
                                           flit_after_seq_check_is_error_comb;
    flit_after_seq_check_is_start_retry <= flit_after_retry_stage_is_start_retry;
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        flit_after_seq_check[i_f]     <= flit_after_retry_stage[i_f];
    end
 
end
end
 
//==================================================================================
//---------------------------------Retrieve the lengths to invalide FLITs
//==================================================================================
always @(*)  begin
//Retrieve the length from the header and assign it to the tail. This information will be used in the
//invalidation stage to mask out FLITs that belong to the faulty packet
 
    lng_comb = lng_temp;
 
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
 
        if(flit_after_retry_stage_is_hdr[i_f]) begin
            if( lng(flit_after_retry_stage[i_f]) < 2 ||
                lng(flit_after_retry_stage[i_f]) > 9
            ) begin
                lng_comb = 1;
            end else begin
                lng_comb = lng(flit_after_retry_stage[i_f]);
            end
        end
 
        if(flit_after_retry_stage_is_tail[i_f]) begin
            lng_per_tail_comb[i_f] = lng_comb;
        end else begin
            lng_per_tail_comb[i_f] = {4{1'b0}};
        end
 
    end
end
 
//Register combinational values
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        lng_per_tail[i_f] <= 0;
    end
    lng_temp    <= {4{1'b0}};
end else begin
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        lng_per_tail[i_f] <= lng_per_tail_comb[i_f];
    end
    lng_temp    <= lng_comb;
end
end
 
//==================================================================================
//---------------------------------FLIT Invalidation Stage
//==================================================================================
//Constant propagation for some parts of the invalidation stage
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    for(i_c=0; i_c<(CYCLES_TO_COMPLETE_FULL_PACKET); i_c=i_c+1) begin
        flit_in_invalidation_data[i_c]            <= {DWIDTH{1'b0}};
        flit_in_invalidation_is_hdr[i_c]          <= {FPW{1'b0}};
        flit_in_invalidation_is_tail[i_c]         <= {FPW{1'b0}};
        flit_in_invalidation_is_flow[i_c]         <= {FPW{1'b0}};
        flit_in_invalidation_has_rtc[i_c]         <= {FPW{1'b0}};
        flit_in_invalidation_is_start_retry[i_c]  <= {FPW{1'b0}};
    end
end else begin
    flit_in_invalidation_data[0]            <= flit_after_seq_check_word;
    flit_in_invalidation_is_hdr[0]          <= flit_after_seq_check_is_hdr;
    flit_in_invalidation_is_tail[0]         <= flit_after_seq_check_is_tail;
    flit_in_invalidation_is_flow[0]         <= flit_after_seq_check_is_flow;
    flit_in_invalidation_has_rtc[0]         <= flit_after_seq_check_has_rtc;
    flit_in_invalidation_is_start_retry[0]  <= flit_after_seq_check_is_start_retry;
 
    for(i_c=0; i_c<(CYCLES_TO_COMPLETE_FULL_PACKET-1); i_c=i_c+1) begin
        flit_in_invalidation_data[i_c+1]            <= flit_in_invalidation_data[i_c];
        flit_in_invalidation_is_hdr[i_c+1]          <= flit_in_invalidation_is_hdr[i_c];
        flit_in_invalidation_is_tail[i_c+1]         <= flit_in_invalidation_is_tail[i_c];
        flit_in_invalidation_is_flow[i_c+1]         <= flit_in_invalidation_is_flow[i_c];
        flit_in_invalidation_has_rtc[i_c+1]         <= flit_in_invalidation_has_rtc[i_c];
        flit_in_invalidation_is_start_retry[i_c+1]  <= flit_in_invalidation_is_start_retry[i_c];
    end
end
end
 
//Mark all poisoned FLITs
always @(*)  begin
    flit_in_invalidation0_is_poisoned_comb  = {FPW{1'b0}};
    for(i_f = FPW-1; i_f>=0; i_f = i_f-1) begin
        if(flit_after_seq_check_is_poisoned[i_f])begin
            flit_in_invalidation0_is_poisoned_comb =flit_in_invalidation0_is_poisoned_comb | 
                                                    (({FPW{1'b1}} >> (FPW-i_f-1)) & ~({FPW{1'b1}} >> lng_per_tail[i_f]+(FPW-i_f-1)));
        end
    end
end
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    for(i_c = 0; i_c < (CYCLES_TO_COMPLETE_FULL_PACKET); i_c = i_c + 1) begin
        flit_in_invalidation_is_poisoned[i_c]  <= 0;
    end
 
end else begin
    flit_in_invalidation_is_poisoned[0]     <= flit_in_invalidation0_is_poisoned_comb;
 
    for(i_c = 0; i_c < (CYCLES_TO_COMPLETE_FULL_PACKET-1); i_c = i_c + 1) begin
        flit_in_invalidation_is_poisoned[i_c+1] <= flit_in_invalidation_is_poisoned[i_c];
    end
 
    //If there is a poisoned packet mark all FLITs as such
    for(i_f = FPW-1; i_f>=0; i_f = i_f-1) begin
        if(flit_after_seq_check_is_poisoned[i_f]) begin
 
            // flit_in_invalidation_is_poisoned[0] <= ({FPW{1'b1}} >> (FPW-i_f-1)) & ~({FPW{1'b1}} >> lng_per_tail[i_f]+(FPW-i_f-1));
 
            for(i_c = 0; i_c < (CYCLES_TO_COMPLETE_FULL_PACKET-1); i_c = i_c + 1) begin
                if(lng_per_tail[i_f] > ((i_c)*FPW)+i_f+1) begin
                    flit_in_invalidation_is_poisoned[i_c+1] <= flit_in_invalidation_is_poisoned[i_c] | ~({FPW{1'b1}} >> lng_per_tail[i_f]-(i_c*FPW)-i_f-1);
                end
            end
 
        end
    end
end
end
 
 
//Invalidate FLITs that belong to errorenous packets
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    for(i_c = 0; i_c < (CYCLES_TO_COMPLETE_FULL_PACKET); i_c = i_c + 1) begin
        flit_in_invalidation_is_valid[i_c]     <= 0;
    end
    error_detected                  <= 0;
    flit_in_invalidation_mask_error <= {FPW{1'b1}};
 
end else begin
 
    //Reset the masks for invalidation stages
    flit_in_invalidation_mask_error         <= {FPW{1'b1}};
 
    if(irtry_clear_trig) begin
        error_detected <= 0;
    end
 
    //Propate invalidation stages but apply error and poisoned masks to the second stage
    for(i_c = 1; i_c < (CYCLES_TO_COMPLETE_FULL_PACKET-1); i_c = i_c + 1) begin
        flit_in_invalidation_is_valid[i_c+1] <= flit_in_invalidation_is_valid[i_c];
    end
    flit_in_invalidation_is_valid[1] <= flit_in_invalidation_is_valid[0] & flit_in_invalidation_mask_error;
 
    if(error_detected) begin
        //There is no valid FLIT when an error was detected
        flit_in_invalidation_is_valid[0] <= {FPW{1'b0}};
    end else begin
        //First apply valids from previous stage
        flit_in_invalidation_is_valid[0] <= flit_after_seq_check_is_valid;
 
        //At least one FLIT contained an error in its tail. Leave all FLITs before the error untouched
        for(i_f = FPW-1; i_f>=0; i_f = i_f-1) begin
            if(flit_after_seq_check_is_error[i_f] && flit_after_seq_check_is_tail[i_f]) begin
                error_detected <= 1'b1;
                flit_in_invalidation_mask_error <= {FPW{1'b1}} >> (FPW-i_f-1+lng_per_tail[i_f]);
            end
        end
 
        //Now use the length of the packet to invalidate FLITs that may reside in the next stages already
        for(i_f = FPW-1; i_f>=0; i_f = i_f-1) begin
            if(flit_after_seq_check_is_error[i_f] && flit_after_seq_check_is_tail[i_f]) begin
                for(i_c = 0; i_c < (CYCLES_TO_COMPLETE_FULL_PACKET-1); i_c = i_c + 1) begin
                    if(lng_per_tail[i_f] > ((i_c)*FPW)+i_f+1) begin
                        flit_in_invalidation_is_valid[i_c+1] <= flit_in_invalidation_is_valid[i_c] &
                                                                ({FPW{1'b1}} >> lng_per_tail[i_f]-(i_c*FPW)-i_f-1);
                    end
                end
            end
        end
    end
 
end
end
 
//====================================================================
//---------------------------------FRP/RRP/RTC
//====================================================================
//Count Tokens that were returned
always @(*)  begin
    rtc_sum_comb                  = {8{1'b0}};
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        if(checked_flit_has_rtc[i_f])begin
            rtc_sum_comb                  =  rtc_sum_comb + rtc(checked_flit[i_f]);
        end
    end
end
 
//Extract FRP/RRP + last seq (which is necessary to check packets after error_abort_mode is cleared)
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    tx_hmc_frp                      <= {8{1'b0}};
    tx_rrp                          <= {8{1'b0}};
    tx_returned_tokens              <= {8{1'b0}};
    first_seq_after_error           <= 3'h1;
 
    tx_link_retry                   <= 1'b0;
 
end else begin
    //Return tokens
    tx_returned_tokens              <= rtc_sum_comb;
 
    //Process FLITs and extract frp/seq/rrp if applicable
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
 
        if(checked_flit_is_tail[i_f] || checked_flit_is_start_retry[i_f]) begin
            tx_rrp                  <=  rrp(checked_flit[i_f]);
 
            if(checked_flit_has_rtc[i_f])begin
                tx_hmc_frp                      <= frp(checked_flit[i_f]);
                first_seq_after_error           <= seq(checked_flit[i_f]) + 3'h1;
            end
        end
    end
 
    //-------------------------------------------TX retry
    tx_link_retry   <= 1'b0;
 
    if(|checked_flit_is_start_retry)begin
        tx_link_retry              <= 1'b1;
    end
 
end
end
 
//==================================================================================
//---------------------------------Fill the input buffer with all response packets
//==================================================================================
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
 
    input_buffer_shift_in     <= 1'b0;
    input_buffer_valid        <= {FPW{1'b0}};
    input_buffer_is_hdr       <= {FPW{1'b0}};
    input_buffer_is_tail      <= {FPW{1'b0}};
    input_buffer_is_error_rsp <= {FPW{1'b0}};
 
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        input_buffer_d_in_flit[i_f]     <= {128{1'b0}};
    end
 
end else begin
 
    input_buffer_shift_in       <= 1'b0;
    input_buffer_is_error_rsp   <= {FPW{1'b0}};
 
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        input_buffer_d_in_flit[i_f]        <= {128{1'b0}};
 
        //Flow and poisoned packets are not forwarded
        if(checked_flit_is_valid[i_f]) begin
            if(!checked_flit_is_flow[i_f] && !checked_flit_is_poisoned[i_f])begin
                input_buffer_d_in_flit[i_f]           <= checked_flit[i_f];
            end
            if(checked_flit_is_hdr[i_f] && (cmd(checked_flit[i_f])==CMD_RSP_ERROR)) begin
                input_buffer_is_error_rsp[i_f]  <= 1'b1;
            end
        end
    end
 
    //Mask out any flow or poisoned packets
    input_buffer_valid      <=  checked_flit_is_valid &
                                ~checked_flit_is_flow &
                                ~checked_flit_is_poisoned;
    input_buffer_is_hdr     <=  checked_flit_is_hdr   &
                                ~checked_flit_is_flow &
                                ~checked_flit_is_poisoned;
    input_buffer_is_tail    <=  checked_flit_is_tail  &
                                ~checked_flit_is_flow &
                                ~checked_flit_is_poisoned;
 
    //If there is still a valid packet remaining after applying the mask
    if(|(checked_flit_is_valid  & ~checked_flit_is_flow & ~checked_flit_is_poisoned))begin
       input_buffer_shift_in    <= 1'b1;
    end
 
end
end
 
always @(*)  begin
    tokens_poisoned          = {LOG_FPW+1{1'b0}};
 
    for(i_f=0; i_f<FPW; i_f=i_f+1) begin
        tokens_poisoned  =   tokens_poisoned + checked_flit_is_poisoned[i_f];
    end
end
 
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    tx_hmc_poisoned_tokens_to_return    <= {LOG_FPW+1{1'b0}};
end else begin
    tx_hmc_poisoned_tokens_to_return    <= tokens_poisoned;
end
end
 
//==================================================================================
//---------------------------------Count responses and poisoned packets
//==================================================================================
always @(*)  begin
    rf_cnt_poisoned_comb = {LOG_FPW+1{1'b0}};
    rf_cnt_rsp_comb      = {LOG_FPW+1{1'b0}};
 
    for(i_f = 0; i_f < (FPW); i_f = i_f + 1) begin
        if(checked_flit_is_poisoned[i_f] && checked_flit_is_hdr[i_f])begin
            rf_cnt_poisoned_comb = rf_cnt_poisoned_comb + {{LOG_FPW{1'b0}},1'b1};
        end
        if(input_buffer_is_tail[i_f] && !input_buffer_is_error_rsp[i_f])begin
            //if its a tail but not error response
            rf_cnt_rsp_comb = rf_cnt_rsp_comb + {{LOG_FPW{1'b0}},1'b1};
        end
    end
end
 
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    rf_cnt_poisoned <= {HMC_RF_RWIDTH{1'b0}};
    rf_cnt_rsp      <= {HMC_RF_RWIDTH{1'b0}};
end else begin
    rf_cnt_poisoned <= rf_cnt_poisoned + {{HMC_RF_RWIDTH-LOG_FPW-1{1'b0}},rf_cnt_poisoned_comb};
    rf_cnt_rsp      <= rf_cnt_rsp + {{HMC_RF_RWIDTH-LOG_FPW-1{1'b0}},rf_cnt_rsp_comb};
end
end
 
//==================================================================================
//---------------------------------Shift response packets into the output fifo, return a token for each processed FLIT
//==================================================================================
always @(*)  begin
    tokens_out_of_fifo_sum_comb          = {LOG_FPW+1{1'b0}};
 
    if(input_buffer_shift_out)begin
        for(i_f=0; i_f<FPW; i_f=i_f+1) begin
            tokens_out_of_fifo_sum_comb  =   tokens_out_of_fifo_sum_comb + 
                                             (input_buffer_d_out[DWIDTH+i_f] && 
                                             !input_buffer_d_out[DWIDTH+i_f+(3*FPW)]);    //increment if there's a valid FLIT, but not an error response
        end
    end
end
 
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    tx_hmc_tokens_to_return    <= {LOG_FPW+1{1'b0}};
end else begin
    tx_hmc_tokens_to_return    <= tokens_out_of_fifo_sum_comb;
end
end
 
`ifdef ASYNC_RES
always @(posedge clk or negedge res_n)  begin `else
always @(posedge clk)  begin `endif
if(!res_n) begin
    //----FIFO
    d_out_fifo_shift_in          <= 1'b0;
    d_out_fifo_ctrl              <= {4*FPW{1'b0}};
    d_out_fifo_data              <= {DWIDTH{1'b0}};
 
end else begin
    d_out_fifo_shift_in          <= 1'b0;
    d_out_fifo_ctrl              <= {4*FPW{1'b0}};
 
 
    if(input_buffer_shift_out)begin
        d_out_fifo_data             <= input_buffer_d_out[DWIDTH-1:0];
        d_out_fifo_shift_in         <= 1'b1;
        d_out_fifo_ctrl             <= input_buffer_d_out[DWIDTH+(4*FPW)-1:DWIDTH];
    end
end
end
 
 
 
//=====================================================================================================
//-----------------------------------------------------------------------------------------------------
//---------INSTANTIATIONS HERE-------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//=====================================================================================================
 
wire   res_n_lanes;
assign res_n_lanes = ((rf_link_status == LINK_DOWN) || !rf_hmc_init_cont_set) ? 1'b0 : 1'b1;
 
//Lane Init
genvar i;
generate
for(i=0;i<NUM_LANES;i=i+1)begin : lane_gen
    rx_lane_logic #(
        .DWIDTH(DWIDTH),
        .NUM_LANES(NUM_LANES),
        .CTRL_LANE_POLARITY(CTRL_LANE_POLARITY),
        .BITSLIP_SHIFT_RIGHT(BITSLIP_SHIFT_RIGHT)
    ) rx_lane_I (
        .clk(clk),
        .res_n(res_n_lanes),
        .bit_slip(init_bit_slip[i]),
        .descrambler_locked(init_descrambler_locked[i]),
        .descrambler_disable(rf_scrambler_disable),
        .lane_polarity(rf_lane_polarity[i]),
        .scrambled_data_in(phy_scrambled_data_in[i*WIDTH_PER_LANE+WIDTH_PER_LANE-1:i*WIDTH_PER_LANE]),
        .descrambled_data_out(descrambled_data_per_lane[i])
    );
end
endgenerate
 
//HMC CRC Logic
rx_crc_compare #(
    .DWIDTH(DWIDTH),
    .FPW(FPW),
    .LOG_FPW(LOG_FPW)
)
rx_crc_compare
(
    .clk(clk),
    .res_n(res_n),
    //input
    .d_in_data(data2crc),
    .d_in_hdr(data2crc_hdr),
    .d_in_tail(data2crc_tail),
    .d_in_valid(data2crc_valid),
    .d_in_lng(data2crc_lng),
    //output
    .d_out_data(crc_d_out_data),
    .d_out_hdr(crc_d_out_flit_is_hdr),
    .d_out_tail(crc_d_out_flit_is_tail),
    .d_out_valid(crc_d_out_flit_is_valid),
    .d_out_error(crc_d_out_flit_is_error),
    .d_out_poisoned(crc_d_out_flit_is_poisoned),
    .d_out_rtc(crc_d_out_flit_has_rtc),
    .d_out_flow(crc_d_out_flit_is_flow)
);
 
//Buffer Fifo - Depth = Max Tokens
openhmc_sync_fifo #(
        .DATASIZE(DWIDTH+(4*FPW)),   //+4*FPW for header/tail/valid/error response information -> AXI-4 TUSER signal
        .ADDRSIZE(LOG_MAX_RTC)
    ) input_buffer_I(
        .clk(clk),
        .res_n(res_n),
        .d_in(input_buffer_d_in),
        .shift_in(input_buffer_shift_in),
        .d_out(input_buffer_d_out),
        .shift_out(input_buffer_shift_out),
        .next_stage_full(1'b1), // Dont touch!
        .empty(input_buffer_empty)
    );
 
endmodule
`default_nettype wire
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.