//
// Copyright 2017 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Generates an LFSR based on a given seed value
// Note that not all length LFSRs are supported in the file
// For xnor LSFR equations please refer to following link:
// https://www.xilinx.com/support/documentation/application_notes/xapp210.pdf

// All indexing will be from 1 to match indexing used in table from app note above


module crc_xnor #(
  parameter INPUT_WIDTH=64,
  parameter OUTPUT_WIDTH=8
) (
   input clk,
   input [INPUT_WIDTH:1] input_data,
   input rst,
   input hold,
   output [OUTPUT_WIDTH:1] crc_out
);

    wire [INPUT_WIDTH:1] current_lfsr;
    reg  [INPUT_WIDTH:1] current_lfsr_r;

    // LFSR based on table given by Xilinx
    generate if (INPUT_WIDTH == 64) begin
        assign current_lfsr[1] = current_lfsr_r[64] ^ current_lfsr_r[63] ^ current_lfsr_r[61] ^ current_lfsr_r[60];
        assign current_lfsr[INPUT_WIDTH:2] = current_lfsr_r[INPUT_WIDTH-1:1]; 
    end else begin
        fake_error_thrower invalid_width_parameter();
    end endgenerate

   always @(posedge clk) begin
      if (rst) begin
         current_lfsr_r <= input_data;
      end else if(~hold) begin
         current_lfsr_r <= current_lfsr ^ input_data;
      end
   end

    // Sum reduce based on output width
    generate if(INPUT_WIDTH == 64 && OUTPUT_WIDTH == 16) begin
        assign crc_out =    current_lfsr_r[INPUT_WIDTH:INPUT_WIDTH/4*3+1]+current_lfsr_r[INPUT_WIDTH/4*3:INPUT_WIDTH/4*2+1]+
                            current_lfsr_r[INPUT_WIDTH/4*2:INPUT_WIDTH/4+1]+current_lfsr_r[INPUT_WIDTH/4:1];
    end else if(INPUT_WIDTH == 64 && OUTPUT_WIDTH == 32) begin
        assign crc_out =    current_lfsr_r[INPUT_WIDTH:INPUT_WIDTH/2+1]+current_lfsr_r[INPUT_WIDTH/2:1];
    end else begin
        fake_error_thrower invalid_width_parameter();
    end endgenerate
      
   

endmodule