/////////////////////////////////////////////////////////////////////
//   ,------.                    ,--.                ,--.          //
//   |  .--. ' ,---.  ,--,--.    |  |    ,---. ,---. `--' ,---.    //
//   |  '--'.'| .-. |' ,-.  |    |  |   | .-. | .-. |,--.| .--'    //
//   |  |\  \ ' '-' '\ '-'  |    |  '--.' '-' ' '-' ||  |\ `--.    //
//   `--' '--' `---'  `--`--'    `-----' `---' `-   /`--' `---'    //
//                                             `---'               //
//   Error Correction and Detection Encoder                        //
//   Parameterized Extended Hamming Code Encoder                   //
//                                                                 //
/////////////////////////////////////////////////////////////////////
//                                                                 //
//             Copyright (C) 2017 ROA Logic BV                     //
//             www.roalogic.com                                    //
//                                                                 //
//   This source file may be used and distributed without          //
//   restriction provided that this copyright statement is not     //
//   removed from the file and that any derivative work contains   //
//   the original copyright notice and the associated disclaimer.  //
//                                                                 //
//      THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY        //
//   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED     //
//   TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS     //
//   FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR OR     //
//   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  //
//   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  //
//   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  //
//   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      //
//   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN     //
//   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  //
//   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS          //
//   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  //
//                                                                 //
/////////////////////////////////////////////////////////////////////

// +FHDR -  Semiconductor Reuse Standard File Header Section  -------
// FILE NAME      : ecc_enc.sv
// DEPARTMENT     :
// AUTHOR         : rherveille
// AUTHOR'S EMAIL :
// ------------------------------------------------------------------
// RELEASE HISTORY
// VERSION DATE        AUTHOR      DESCRIPTION
// 1.0     2017-04-07  rherveille  initial release
// ------------------------------------------------------------------
// KEYWORDS : HAMMING ERROR CORRECTION ENCODER                 
// ------------------------------------------------------------------
// PURPOSE  : Adds ECC bits to incoming data
// ------------------------------------------------------------------
// PARAMETERS
//  PARAM NAME        RANGE  DESCRIPTION              DEFAULT UNITS
//  K                 1+     Information vector size  8
//  P0_LSB            0,1    0: p0 located at MSB     1
//                           1: p0 located at LSB
// ------------------------------------------------------------------
// REUSE ISSUES 
//   Reset Strategy      : none
//   Clock Domains       : none
//   Critical Timing     :
//   Test Features       : na
//   Asynchronous I/F    : yes
//   Scan Methodology    : na
//   Instantiations      : none
//   Synthesizable (y/n) : Yes
//   Other               :                                         
// -FHDR-------------------------------------------------------------


//-----------------------------------------------------------------------------
// Hamming codes can detect and correct a single bit error.
// An extended Hamming code allows detection of double bit errors and
// correction of single bit errors.
// This is called SECDED; Single Error Correction, Double Error Detection
//
// Number of bits required by a Hamming code: n = m + k
// n = code length
// m = number of check bits
// k = number of information bits
//
// Information, parity, and syndrome expressed as vectors:
// u = Information bit vector
// p = Parity check bit vector
// s = Syndrome vector
//
// The parity vector is encoded in 'n'.
// The information bit vector is part of 'p'
// The syndrome vector needs to be calculated.
//
// Bits required:
// p ranges from 0 to m+k; or p_range=m+k+1
// As a result 2^m >= m+k+1
//-----------------------------------------------------------------------------


module ecc_enc #(
  parameter K       = 8, //Information bit vector size
  parameter P0_LSB  = 1, //0: p0 is located at MSB
                         //1: p0 is located at LSB

  //these should be localparams
  parameter m = calculate_m(K),
  parameter n = m + K
)
(
  input  [K-1:0] d_i,      //information bit vector input
  output [n  :0] q_o,      //encoded data word output

  output [m  :1] p_o,      //parity vector output
  output         p0_o      //extended parity bit
);


//---------------------------------------------------------
// Functions
//---------------------------------------------------------
function integer calculate_m;
  input integer k;

  integer m_local;
begin
  m_local=1;
  while (2**m_local < m_local+k+1) m_local++;

  calculate_m = m_local;
end
endfunction //calculate_m


function [n:1] store_dbits_in_codeword;
  input [K-1:0] d;

  integer bit_idx, cw_idx;
begin
    //This function puts the information bits vector in the correct location
    //Information bits are stored in non-power-of-2 locations

    //clear all bits
    store_dbits_in_codeword = 0;

    bit_idx=0; //information vector bit index
    for (cw_idx=1; cw_idx<=n; cw_idx++)
      if (2**$clog2(cw_idx) != cw_idx) 
        /* verilator lint_off UNUSEDSIGNAL */
        store_dbits_in_codeword[cw_idx] = d[bit_idx++];
        /* verilator lint_on UNUSEDSIGNAL */
end
endfunction //store_dbits_in_codeword


function [m:1] calculate_p;
  input [n:1] cw;

  integer p_idx, cw_idx;
begin
    //clear p
    calculate_p = 0;

    for (p_idx =1; p_idx <=m; p_idx++)  //parity-index
    for (cw_idx=1; cw_idx<=n; cw_idx++) //codeword-index
      if (|(2**(p_idx-1) & cw_idx)) calculate_p[p_idx] = calculate_p[p_idx] ^ cw[cw_idx];
end
endfunction //calculate_p


function [n:1] store_p_in_codeword;
  input [n:1] cw;
  input [m:1] p;

  integer i;
begin
    //databits don't change ... copy into codeword
    store_p_in_codeword = cw;

    //put parity vector at power-of-2 locations
    for (i=1; i<=m; i=i+1)
      store_p_in_codeword[2**(i-1)] = p[i];
end
endfunction //store_p_in_codeword


//---------------------------------------------------------
// Variables
//---------------------------------------------------------
logic [n:1] cw_w_dbits; //codeword with loaded data bits
logic [n:1] cw;         //codeword with information + parity bits
  

//---------------------------------------------------------
// Module Body
//---------------------------------------------------------

/*
  Below diagram indicates the locations of the parity and data bits
  in the final 'p' vector.
  It also shows what databits each parity bit operates on

    1  2  3  4  5  6  7  8  9 10 11 12 13  14  15
   p1 p2 d1 p4 d2 d3 d4 p8 d5 d6 d7 d8 d9 d10 d11
p1  x     x     x     x     x     x     x       x
p2     x  x        x  x        x  x         x   x
p4           x  x  x  x              x  x   x   x
p8                       x  x  x  x  x  x   x   x
*/

//Step 1: Load all databits in codeword
assign cw_w_dbits = store_dbits_in_codeword(d_i);

//Step 2: Calculate p-vector
assign p_o = calculate_p(cw_w_dbits);

//Step 3: Store p-vector in codeword
assign cw = store_p_in_codeword(cw_w_dbits, p_o);

//Step 4: Calculate p0 (extended parity bit)
//        and store it in the codeword
assign p0_o = ^cw;
assign q_o  = P0_LSB ? {cw,p0_o} : {p0_o,cw};

endmodule
