----------------------------------------------------------------------------------------------
--
-- Generated by X-HDL Verilog Translator - Version 4.0.0 Apr. 30, 2006
-- Wed Jun 17 2009 01:03:24
--
--      Input file      : /home/samsonn/SandBox_LBranch_11.2/env/Databases/ip/src2/L/mig_v3_2/data/dlib/virtex6/ddr3_sdram/verilog/rtl/ecc/ecc_gen.v
--      Component name  : ecc_gen
--      Author          : 
--      Company         : 
--
--      Description     : 
--
--
----------------------------------------------------------------------------------------------

library ieee;
   use ieee.std_logic_1164.all;
   use ieee.std_logic_unsigned.all;
   use ieee.std_logic_arith.all;


-- Generate the ecc code.  Note that the synthesizer should
-- generate this as a static logic.  Code in this block should
-- never run during simulation phase, or directly impact timing.
--
-- The code generated is a single correct, double detect code.
-- It is the classic Hamming code.  Instead, the code is
-- optimized for minimal/balanced tree depth and size.  See
-- Hsiao IBM Technial Journal 1970.
--
-- The code is returned as a single bit vector, h_rows.  This was
-- the only way to "subroutinize" this with the restrictions of
-- disallowed include files and that matrices cannot be passed
-- in ports.
--
-- Factorial and the combos functions are defined.  Combos
-- simply computes the number of combinations from the set
-- size and elements at a time.
--
-- The function next_combo computes the next combination in
-- lexicographical order given the "current" combination.  Its
-- output is undefined if given the last combination in the 
-- lexicographical order. 
-- 
-- next_combo is insensitive to the number of elements in the
-- combinations.
--
-- An H transpose matrix is generated because that's the easiest
-- way to do it. The H transpose matrix is generated by taking
-- the one at a time combinations, then the 3 at a time, then
-- the 5 at a time.  The number combinations used is equal to
-- the width of the code (CODE_WIDTH).  The boundaries between
-- the 1, 3 and 5 groups are hardcoded in the for loop.
--
-- At the same time the h_rows vector is generated from the
-- H transpose matrix.

entity ecc_gen is
   generic (
      CODE_WIDTH                 : integer := 72;
      ECC_WIDTH                  : integer := 8;
      DATA_WIDTH                 : integer := 64
   );
   port (
      -- Outputs
      
      -- function next_combo
      -- Given a combination, return the next combo in lexicographical
      -- order.  Scans from right to left.  Assumes the first combination
      -- is k ones all of the way to the left.
      --
      -- Upon entry, initialize seen0, trig1, and ones.  "seen0" means
      -- that a zero has been observed while scanning from right to left.
      -- "trig1" means that a one have been observed _after_ seen0 is set.
      -- "ones" counts the number of ones observed while scanning the input.
      --
      -- If trig1 is one, just copy the input bit to the output and increment
      -- to the next bit.  Otherwise  set the the output bit to zero, if the 
      -- input is a one, increment ones.  If the input bit is a one and seen0
      -- is true, dump out the accumulated ones.  Set seen0 to the complement
      -- of the input bit.  Note that seen0 is not used subsequent to trig1 
      -- getting set.
      
      -- The stuff above leads to excessive XST execution times.  For now, hardwire to 72/64 bit.
      
      h_rows                     : out std_logic_vector(CODE_WIDTH * ECC_WIDTH - 1 downto 0)
   );
end entity ecc_gen;

architecture trans of ecc_gen is

  function factorial (ivar: integer) return integer is
    variable tmp   : integer;
  begin
    if (ivar = 1) then 
        return 1;
    else 
      tmp := 1;
      for i in ivar downto 2 loop
        tmp := tmp * i;
      end loop;
    end if;
    return tmp;
  end function factorial;

  function combos ( n, k: integer) return integer is
  begin
    return factorial(n)/(factorial(k)*factorial(n-k));
  end function combos;

  
  function next_combo (i: std_logic_vector) return std_logic_vector is
    variable seen0: std_logic;
    variable trig1: std_logic;
    variable ones: std_logic_vector (ECC_WIDTH-1 downto 0);
    variable tmp: std_logic_vector (ECC_WIDTH-1 downto 0);
    variable tmp_index : integer;
    begin
      seen0 := '0';
      trig1 := '0';
      ones := (others => '0');
      for index in ECC_WIDTH -1 downto 0 loop
          tmp_index := ECC_WIDTH -1 - index;
          if (trig1 = '1') then 
            tmp(tmp_index) := i(tmp_index);
          else
            tmp(tmp_index) := '0';
            ones := ones + i(tmp_index);
            if ((i(tmp_index) = '1') and (seen0 = '1')) then
              trig1 := '1';
              for dump_index in tmp_index-1 downto 0 loop
                if (dump_index >= (tmp_index- conv_integer(ones)) ) then
                    tmp(dump_index) := '1';  
                end if;
              end loop;
            end if;              
            seen0 := not(i(tmp_index));
          end if;
      end loop;
      return tmp;
  end function next_combo;
  
  constant COMBOS_3 : integer := combos(ECC_WIDTH, 3);
  constant COMBOS_5 : integer := combos(ECC_WIDTH, 5);

   type twoDarray is array (CODE_WIDTH -1 downto 0) of std_logic_vector (ECC_WIDTH-1 downto 0);
   signal ht_matrix               : twoDarray;
begin

   columns: for n in CODE_WIDTH - 1 downto 0 generate
   
      column0: if (n = 0) generate
         ht_matrix(n) <= "111" & conv_std_logic_vector(0,ECC_WIDTH-3);
      end generate;
      
      column_combos3: if ((n = COMBOS_3) and ( n < DATA_WIDTH) ) generate
         ht_matrix(n) <= "11111" & conv_std_logic_vector(0,ECC_WIDTH-5);
      end generate;
      
      column_combos5: if ((n = COMBOS_3 + COMBOS_5) and ( n < DATA_WIDTH) ) generate
         ht_matrix(n) <= "1111111" & conv_std_logic_vector(0,ECC_WIDTH-7);
      end generate;
      
      column_datawidth: if (n = DATA_WIDTH) generate
         ht_matrix(n) <= "1" & conv_std_logic_vector(0,ECC_WIDTH-1);
      end generate;
      
      column_gen: if ( (n /= 0 ) and ((n /= COMBOS_3) or (n > DATA_WIDTH)) and ((n /= COMBOS_3+COMBOS_5) or (n > DATA_WIDTH)) and (n /= DATA_WIDTH) ) generate
        ht_matrix(n) <= next_combo(ht_matrix(n-1));
      end generate;
      
      out_assign: for s in ECC_WIDTH-1 downto 0 generate
        h_rows(s*CODE_WIDTH+n) <= ht_matrix(n)(s);
      end generate;
      
   end generate;
   --h_row0 <= "100000000100100011101101001101001000110100100010000110100100010000100000";
   --h_row1 <= "010000001010010011011010101010100100101010010001000101010010001000010000";
   --h_row2 <= "001000001001001010110110010110010010011001001000100011001001000100001000";
   --h_row3 <= "000100000111000101110001110001110001000111000100010000111000100010000100";
   --h_row4 <= "000010000000111100001111110000001111000000111100001000000111100001000010";
   --h_row5 <= "000001001111111100000000001111111111000000000011111000000000011111000001";
   --h_row6 <= "000000101111111100000000000000000000111111111111111000000000000000111111";
   --h_row7 <= "000000011111111100000000000000000000000000000000000111111111111111111111";
   --h_rows <= (h_row7 & h_row6 & h_row5 & h_row4 & h_row3 & h_row2 & h_row1 & h_row0);
end architecture trans;
