-------------------------------------------------------------------------------
-- Title      : FLAC_DECODER
-------------------------------------------------------------------------------
-- File       : FLAC_DECODER.vhd
-- Author     : Sathishkumar Donthu
--              Sathish.Donthu@microsemi.com
-- Company    : Microsemi Corporation
-- Device     : SmartFusion 
-- Standard   : VHDL
-------------------------------------------------------------------------------
-- Description: RICE decoder with a custom-made APB3 interface.
--The parameters required to send from Cortex-M3 are:
--address of residual
--address of a buffer for writing return values
--rice parameter
--number of words available
--number of samples required to decode
--consumed bits and address of status
--address of status array
-------------------------------------------------------------------------------
-- Copyright (c) 2011   Actel Corporation
--                      All rights reserved.
-------------------------------------------------------------------------------
library   IEEE;
use       IEEE.std_logic_1164.all;
use       IEEE.std_logic_unsigned.all;

entity RICE is
port ( 
       PCLK                    : in  std_logic;
       PRESET                  : in  std_logic;
       P_VALID                 : in  std_logic;       
       
       --APB3 slave signals 
       
       SPENABLE                : in  std_logic;
       SPSEL                   : in  std_logic;
       SPWRITE                 : in  std_logic;
       SPWDATA                 : in  std_logic_vector(31 downto 0);
       SPADDR                  : in  std_logic_vector(19 downto 0);
       SPRDATA                 : out std_logic_vector(31 downto 0);
       SPREADY,SPSLVERR        : out std_logic;

       --APB3 master signals

       MPENABLE                : out std_logic;
       MPSEL                   : out std_logic;
       MPWRITE                 : out std_logic;
       MPWDATA                 : out std_logic_vector(31 downto 0);
       MPADDR                  : out std_logic_vector(31 downto 0);
       MPRDATA                 : in  std_logic_vector(31 downto 0);
       MPREADY,PSLVERR         : in  std_logic;

       --Signals for conncting to GPIO's of MSS

       START                   : in  std_logic;
       STOP                    : out std_logic
       );
      end RICE;

architecture beh of RICE is

component shifter 
 port(
      INPUT     :   in  std_logic_vector(15 downto 0);
      CLK       :   in  std_logic;
      SHIFT     :   in  std_logic_vector(3 downto 0);
      OUTPUT    :   out std_logic_vector(31 downto 0));
end component;

type array3         is array (3  downto  0) of std_logic_vector(11  downto   0 ) ;
type array6         is array (6  downto  0) of std_logic_vector(31  downto   0 ) ;
type state_type     is (start_rice,zeroparm,wsetup,waccess,idle,ssetup,saccess,                        
                        msetup,maccess,cmsb,remainder,addsign,ret);
signal state        : state_type;
signal rx_data      : array6;
signal tx_data      : array3;
signal read         : std_logic;
signal signbit      : std_logic;
signal calrem       : std_logic;
signal cbits        : std_logic_vector(7 downto 0);
signal acbits       : std_logic_vector(7 downto 0);
signal word         : std_logic_vector(31 downto 0);
signal residue      : std_logic_vector(31 downto 0);
signal residua1     : std_logic_vector(31 downto 0);
signal length       : std_logic_vector(11 downto 0);
signal nwords       : std_logic_vector(11 downto 0);
signal product      : std_logic_vector(31 downto 0);
signal nmsbs        : std_logic_vector(15 downto 0);
signal r            : std_logic_vector(15 downto 0);
signal rparam       : std_logic_vector(3 downto 0);
signal counts       : std_logic_vector(3 downto 0);
constant one        : std_logic_vector(31 downto 0):=x"00000004";

begin

process(PCLK,PRESET,START)
variable args_read      :   integer range 6 downto 0;
variable args_write     :   integer range 3 downto 0;
variable msbcount       :   integer range 31 downto 0;
begin
 
 if(START='0' or PRESET='0') then
    state<=idle;
    args_write:=0;
    read<='1';
    STOP<='0';
    MPADDR<=x"00000000";
    MPWDATA<=x"00000000";
    args_read:=0;
    calrem<='0';
    length<=x"001";
    nmsbs<=x"0000";    
 else 
    
  if (PCLK'event and PCLK = '1') then
    
      case state is
        --***************************************************************************
        --APB Slave states
        --***************************************************************************

        when idle       => if(SPSEL='1' and SPENABLE='0') then
                           state<=ssetup;
                           end if;
        when ssetup     => if(SPSEL='1' and SPENABLE='1'and SPADDR=x"50000") then                        
                           SPREADY<='1';
                           state<=saccess;
                           elsif(SPWRITE='0') then
                           SPREADY<='0';
                           state<=saccess;
                           end if;
        when saccess    => if(SPWRITE='1') then
                           SPREADY<='1';
                           rx_data(args_read)<=SPWDATA;
                            if(args_read=6) then
                            cbits<= rx_data(4)(7 downto 0);                                                  
                            state<=START_rice;                           
                            else
                            state<=ssetup;
                            args_read:=args_read+1;
                            end if;
                           elsif (SPWRITE='0') then
                           state<=idle;
                           SPREADY<='1';
                           end if;

        ------------------ ----------------------------------------------------------
        when start_rice => state<=msetup;
                           acbits<=cbits;
                           nwords<=x"000";
                           msbcount:=31-conv_integer(cbits); 
                           rparam<=rx_data(2)(3 downto 0)-x"1";                         
                           
        --***************************************************************************
        --APB Master states
        --***************************************************************************

        when msetup     => if(P_VALID='0') then                           
                           SPREADY<='0';
                           state<=maccess;
                                if(read='1') then                            
                                MPADDR  <= rx_data(0);        
                                else                            
                                MPADDR<= rx_data(1);
                                MPWDATA<=residue;
                                end if;
                           else
                           MPADDR<=x"00000000";
                           MPWDATA<=x"00000000";
                           state<=msetup;                           
                           end if;                           
        when maccess    => if(P_VALID='0') then
                            if(MPREADY='1') then
                                
                                if(read = '1') then

                                    if(nwords=rx_data(5)(11 downto 0)) then
                                    state<=ret;
                                    length<=length-x"001";
                                    else
                                    nwords<=nwords+x"001";
                                        if(calrem='0') then
                                        state<=cmsb;
                                        else
                                        state<=remainder;
                                        calrem<='0';
                                        end if;
                                    end if;

                                word<=MPRDATA;
                                rx_data(0) <= rx_data(0) + one ;
                                else
                                nmsbs<=x"0000";

                                    if(length=rx_data(3)(11 downto 0)) then
                                    state<=ret;
                                    else
                                    length<=length+x"001";
                                        if(cbits<=x"1f") then
                                        state<=cmsb;
                                        else
                                        state<=msetup;
                                        read<='1';
                                        cbits<=x"00";
                                        end if;
                                    end if;

                                rx_data(1)<=rx_data(1)+one;                           
                                end if;

                            else
                            state<=maccess;
                            end if;
                            else   
                            MPADDR<=x"00000000";
                            MPWDATA<=x"00000000";                        
                            state<=msetup;
                            end if;
        --***************************************************************************
        --Rice Decoder states
        --***************************************************************************
           
        when cmsb       => if(cbits<=x"1f") then

                                if(word(msbcount)='1') then
                                    state<=remainder;
                                    counts<=x"1";
                                    r<=x"0000";
                                    msbcount:=msbcount-1;
                                    cbits<=cbits+1;
                                else
                                    nmsbs<=nmsbs+x"0001";
                                    msbcount:=msbcount-1;
                                    cbits<=cbits+1;
                                end if;

                           else
                           state<=msetup;
                           read<='1';
                           cbits<=x"00";--msbcount:=31;--for simulation
                           end if;
                           MPADDR<=x"00000000";
                           MPWDATA<=x"00000000";
        when remainder  => if(cbits<=x"1f") then

                                if( rx_data(2)=x"00000000") then
                                state<=zeroparm;
                                read<='0';
                                acbits<=cbits;                              
                                else
                                   if(counts<=rparam) then
                                    counts<=counts+x"1";
                                    r<=r(14 downto 0)&word(msbcount);
                                    msbcount:=msbcount-1;
                                    cbits<=cbits+1;
                                   else                              
                                    signbit<=word(msbcount);
                                    msbcount:=msbcount-1;
                                    cbits<=cbits+1;
                                    state<=addsign;
                                    read<='0';
                                    acbits<=cbits+1;
                                   end if;
                                end if;

                           else
                           state<=msetup;read<='1';
                           cbits<=x"00";
                           calrem<='1';--msbcount:=31;--for simulation
                           end if;
                           MPADDR<=x"00000000";
                           MPWDATA<=x"00000000";
        when zeroparm   => state<=msetup;
                           residue<=x"0000"&nmsbs;
        when addsign    => state<=msetup;
                           if(signbit='1') then
                           residue<= residua1 xor x"ffffffff";
                           else
                           residue<= residua1;
                           end if; 
        when ret        => tx_data(0)<=x"0"&acbits;
                           tx_data(1)<=nwords;
                           tx_data(2)<=length;
                           tx_data(3)<=x"5a5";                     
                           state<=wsetup;
                           MPADDR<=x"00000000";
                           MPWDATA<=x"00000000";

        --******************************************************************************
        --Writing the Decoder status 
        --******************************************************************************
                
        when wsetup     => if(P_VALID='0') then                           
                           state<=waccess;                           
                           MPADDR<= rx_data(6);
                           MPWDATA<=x"00000"&tx_data(args_write);
                           else 
                           MPADDR<=x"00000000";
                           MPWDATA<=x"00000000";
                           state<=wsetup;                          
                           end if;
        when waccess    => if(P_VALID='0') then
                           if(MPREADY='1') then  
                            args_write:=args_write+1;                     
                            rx_data(6)<=rx_data(6)+one;                           
                                if(args_write=3) then
                                state<=idle;                                
                                STOP<='1';
                                else                          
                                state<=wsetup;                           
                                end if;
                            end if;
                            else   
                            MPADDR<=x"00000000";
                            MPWDATA<=x"00000000";
                            state<=wsetup;
                            end if;                                
        when others     => state<=idle;
      end case;
   end if;
 end if;
end process;

--******************************************************************************
-- Registering MPSEL and MPENABLE
--******************************************************************************

sel2:process(PCLK)
begin

if (PCLK'event and PCLK = '1') then 
      if(state = waccess or state = maccess) and P_VALID='0' then        
        MPSEL<='1';
        MPENABLE<='1';
      elsif(state = msetup or state = wsetup) and P_VALID='0' then
        MPSEL<='1';
        MPENABLE<='0';
      else        
        MPSEL<='0';
        MPENABLE<='0';
      end if;
end if;

end process sel2;

--******************************************************************************
-- Registering MPWRITE
--******************************************************************************
pwrite:process(PCLK)
begin
if(PCLK'event and PCLK='1') then
    if((state = msetup and read='0') or state=wsetup) and P_VALID='0' then
    MPWRITE <= '1';
    elsif((state=maccess and read='0') or state=waccess) and P_VALID='0' then
    MPWRITE<='1';
    else
    MPWRITE <= '0';
    end if;
end if;
end process pwrite;

s0:shifter port map(nmsbs,PCLK,rparam,product);
residua1<=product(31 downto 0)+r;

end beh;