
--! @file    : linear_block_decoder.vhd
--! @author  : Cesar Prados
--! @email   : c.prados@gsi.de
--  Company  : GSI
--  Created  : 2012 03
--  Update   : 2012 03
--  Platfrom : FPGA-generic
--  Standard : VHDL
-------------------------------------------------------------------------------
--! @brief   : Packet for the Golay family decoder. More information about Golay 
--             Code, "Error Correction Coding" Todd K. [1] The algorithm implemented
--             is the arithmetic decoding
-------------------------------------------------------------------------------
--  Copyright (c) 2012 Cesar Prados
-------------------------------------------------------------------------------
--! Revisions    :
--! Date     Version     Author      Description

-------------------------------------------------------------------------------
--! @todo   <next thing to do>
-------------------------------------------------------------------------------


--! Standard Library
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
--use ieee.std_logic_unsigned.all;

--! linear_block_package library
use work.linear_block_package.all;


--! The word, "word" is reserved for encoded data 24 bits
--! The word. "data" is reserved for non-encoded data 12 btis

----------------------------------------------------------------------------------
--! @brief Linear Block Decoder
----------------------------------------------------------------------------------
--! @details
--! The entity decodes data words encoded following the (24,12,8) Golay Code
--! It is systematic,first 12 bits [23,12] are the original information
--! last 12 bits [11,0] are the redundant bits
----------------------------------------------------------------------------------

entity linear_block_decoder is
    port(
            clk:         in  std_logic;
            reset:       in  std_logic;
            data_in:     in  word_vector;
            decoded_out: out data_vector;
            errorDecoded_out:out std_logic;
            succeedDeco_out:out  std_logic
        );
end linear_block_decoder;

--============================================================================
-- ! architecture of linear_block_decoder
--============================================================================
architecture behavioral of linear_block_decoder is
    -- vector correction
    signal vector_fixed : word_vector := zeros24;
    -- fms contral signals 
    type fms is (idle,step1,step2,step2_bis,step3,step4,step4_bis,deco,fail);
    signal deco_state: fms;
    signal errorDecoded: std_logic;
    signal succeedDeco : std_logic;
    signal errorVal			: errorValset;
    signal syndCal      : syndCalset;
    signal syndxBCal 		: syndxBCalset;
begin

    --============================================================================
    --! Process deco_logic
    --! @brief logic of the decoder, following the state machine defined in [1]
    --============================================================================
    deco_logic: process(clk,reset)

        variable syndCalTemp 	: syndCalset;
        variable syndxBCalTemp : syndxBCalset;
        variable errorValTemp	: errorValset;

    begin

        if(clk'event and clk='1') then
            if (reset = '1') then
                deco_state <= idle;
                syndCal  <= ((others=>'0'),0);
                errorVal <= ((others=>'0'),0);
                syndxBCal <= ((others=>'0'),0);
                vector_fixed <= (others=>'0');
                errorDecoded <= '0';
                succeedDeco <= '0';

            else

                case deco_state is
                    when idle => 		
                        if (data_in /= zeros24) then
                            deco_state <= step1;
                        else
                            deco_state <= idle;
                        end if;			
                    when step1 =>
                        syndCalTemp := syndromeCal(data_in);	 
                        syndCal <= syndCalTemp;

                        if (syndCalTemp.hammingW<=3) then 
                            deco_state <= deco;
                            vector_fixed <= (syndCalTemp.synd&zeros12) xor data_in;
                        else
                            vector_fixed <= zeros24;
                            deco_state <= step2;
                        end if;

                    when step2 =>
                     -- calc error vectors
                        errorValTemp := errorVectorCal(syndCal.synd);
                        errorVal <= errorValTemp;
                        deco_state <= step2_bis;		 

                    when step2_bis =>

                        if(errorVal.hammingW <= 2) then
                                                vector_fixed <= errorVal.errorVector xor data_in;
                                                deco_state <= deco;						     
                                            else
                                                vector_fixed <= zeros24;
                                                deco_state <= step3;	      
                                            end if;

                    when step3 =>
                    -- syndromexB and hammingW(syndromeB)
                        syndxBCalTemp := syndromexBCal(syndCal.synd);
                        syndxBCal <= syndxBCalTemp;

                        if (syndxBCalTemp.hammingW<=3) then 
                            vector_fixed <= (zeros12&syndxBCalTemp.syndxB) xor
                                            data_in;
                            deco_state <= deco;
                        else						        								  
                            vector_fixed <= zeros24;
                            deco_state <= step4;						 
                        end if;				 

                    when step4 =>
               -- (Beta*B+rowi) and hammingW					 
                        errorValTemp := errorVectorxBCal(syndxBCal.syndxB);
                        errorVal <= errorValTemp;
                        deco_state <= step4_bis;					

                    when step4_bis =>		  
                        if (errorVal.hammingW <= 2) then 
                            deco_state <= deco;
                            vector_fixed <= errorVal.errorVector xor
                                            data_in;						
                        else
                            vector_fixed <= zeros24;					 
                            deco_state <= fail;
                        end if;

                    when deco  =>
                        deco_state <= idle;			
                        errorDecoded <= '0';	
                        succeedDeco <= '1';
                    when fail  =>
                        deco_state <= idle;
                        errorDecoded <= '1';					
                        succeedDeco <= '0';
                    when others =>		
                        syndCal   <= ((others=>'0'),0);
                        syndxBCal <= ((others=>'0'),0);
                        vector_fixed <= zeros24;	
                    --					errorVal  <= ((others=>'0'),0);
                        syndCalTemp := ((others=>'0'),0);					
                end case;
            end if;
        end if;
    end process;

     -- output
    decoded_out <= vector_fixed(23 downto 12);
    succeedDeco_out <= succeedDeco;
    errorDecoded_out <= errorDecoded;

end behavioral;
