----------------------------------------------------------------------------------
-- Company:        CERN, BE-CO-HT 
-- Engineer:       Carlos Gil Soriano
-- 
-- Create Date:    11:53:14 02/20/2012 
-- Design Name:    multiboot module
-- Module Name:    multiboot_regs - Behavioral 
-- Project Name:   CONV-TTL-BLO
-- Target Devices: Spartan 6 LX45T
-- Tool versions:  ISE 13.3
-- Description: 
--
-- Dependencies: 
--
-- Revision        Comment 
--  0.01            File created
--  0.1             Added readbacks from ICAP interface
--  0.2             Now there are two CTRL registers: CTRL0 and CTRL1
--
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity multiboot_regs is
   port(
          wb_rst_i   : in   STD_LOGIC;
          wb_clk     : in   STD_LOGIC;
          wb_we_i    : in   STD_LOGIC;
          wb_stb_i   : in   STD_LOGIC;
          wb_cyc_i   : in   STD_LOGIC;
          wb_sel_i   : in   STD_LOGIC_VECTOR (3  downto 0);
          wb_data_i  : in   STD_LOGIC_VECTOR (31 downto 0);
          wb_data_o  : out  STD_LOGIC_VECTOR (31 downto 0);
          wb_addr_i  : in   STD_LOGIC_VECTOR (3  downto 0);
          wb_ack_o   : out  STD_LOGIC;
          wb_rty_o   : out  STD_LOGIC;
          wb_err_o   : out  STD_LOGIC;

          CTRL0_o         : out  STD_LOGIC_VECTOR (15  downto 0);
          CTRL1_i         : in   STD_LOGIC_VECTOR (15  downto 0);
          STAT_ICAP_i     : in   STD_LOGIC_VECTOR (15 downto 0);
          GENERAL1_o      : out  STD_LOGIC_VECTOR (15 downto 0);
          GENERAL2_o      : out  STD_LOGIC_VECTOR (15 downto 0);
          GENERAL3_o      : out  STD_LOGIC_VECTOR (15 downto 0);
          GENERAL4_o      : out  STD_LOGIC_VECTOR (15 downto 0);
          GENERAL1_ICAP_i : in   STD_LOGIC_VECTOR (15 downto 0);
          GENERAL2_ICAP_i : in   STD_LOGIC_VECTOR (15 downto 0);
          GENERAL3_ICAP_i : in   STD_LOGIC_VECTOR (15 downto 0);
          GENERAL4_ICAP_i : in   STD_LOGIC_VECTOR (15 downto 0)
       );
end multiboot_regs;

architecture Behavioral of multiboot_regs is

   -------------------------------------------------------------------
   -- CTRL0 register of the control module
   -------------------------------------------------------------------
   -- 16 bits
   -- Wishbone access: Read-write
   -------------------------------------------------------------------
   -- BIT       NAME             Description
   --  3-0       OP               OPeration to be performed
   --  4         PEND             operation PENDing
   --  15-5      x                Reserved
   -------------------------------------------------------------------
   -- List of operations
   -------------------------------------------------------------------
   --  CODE         Description                   Wishbone clocks
   --   4'h0         Full multiboot                
   --   4'h1         Write   GENERAL1 register       
   --   4'h2         Write   GENERAL2 register      
   --   4'h3         Write   GENERAL3 register      
   --   4'h4         Write   GENERAL4 register      
   --   4'h5         Refresh GENERAL1 register     
   --   4'h6         Refresh GENERAL2 register     
   --   4'h7         Refresh GENERAL3 register     
   --   4'h8         Refresh GENERAL4 register     
   --   4'hD         Refresh STAT register         
   ----------------------------------------------------------------------------
   -- READ operation
   --   ACK is performed automatically
   -- WRITE operation
   --   ACK is performed after [Wishbone clocks] of the specificic operation
   --   ACK is bounded for bad operations (BAD_OP) between [2,16] wb_clks
   ----------------------------------------------------------------------------

   constant CTRL0_addr       : STD_LOGIC_VECTOR(3 downto 0) := X"0";

   -------------------------------------------------------------------
   -- CTRL1 register of the control module
   -------------------------------------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   -------------------------------------------------------------------
   --     0        OP_ACK           valid OPeration ACKed
   --     1        FSM_RUN          a Finite-State-Machine is RUNning
   --     2        BAD_OP           a BAD OPeration was detected
   --  11-3        x                Reserved
   --    12        G1S              GENERAL1 register ICAP Synchronized
   --    13        G2S              GENERAL2 register ICAP Synchronized
   --    14        G3S              GENERAL3 register ICAP Synchronized
   --    15        G4S              GENERAL4 register ICAP Synchronized
   -------------------------------------------------------------------
   -- ACK is performed automatically
   -------------------------------------------------------------------

   constant CTRL1_addr       : STD_LOGIC_VECTOR(3 downto 0) := X"1";

   ------------------------------------------
   -- STAT Spartan 6 configuration register
   ------------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------------
   -- BIT       NAME             Description
   --  0         CRC_ERROR        CRC ERROR             
   --  1         ID_ERROR         IDCODE not validated
   --  2         DCM_LOCK         DCMs and PLL locked
   --  3         GTS_CFG_B        Global tristate
   --  4         GWE              Global Write Enable
   --  5         GHIGH_B          GHIGH
   --  6         DEC_ERROR
   --  7         PART_SECURED     Decryption set
   --  8         HSWAPEN          HSWAPEN
   --  11-9      MODE             MODE pins
   --  12        INIT_B           INIT_B
   --  13        DONE             DONE input pin
   --  14        IN_PWRDWN        suspend status
   --  15        SWWD_STRIKEOUT   config error because of invalid sync word 
   ------------------------------------------
   -- ACK is performed automatically
   -------------------------------------------------------------------

   constant STAT_addr       : STD_LOGIC_VECTOR(3 downto 0):= X"2";

   -------------------------------------------------------------
   -- GENERAL1 value to be passed to ICAP through CTRL operation
   -------------------------------------------------------------
   -- 16 bits
   -- Wishbone access: Write-read
   -------------------------------------------------------------
   -- BIT       NAME             Description
   --  15-0       MBT_ADDR_L      MultiBooT image ADDRess Lower half
   -------------------------------------------------------------
   -- ACK is performed automatically
   -------------------------------------------------------------------


   constant GENERAL1_addr   : STD_LOGIC_VECTOR(3 downto 0):= X"4";

   -------------------------------------------------------------
   -- GENERAL2 value to be passed to ICAP through CTRL operation
   -------------------------------------------------------------
   -- 16 bits
   -- Wishbone access: Write-read
   -------------------------------------------------------------
   -- BIT       NAME             Description
   --  7-0       MBT_ADDR_H       MultiBoot image ADDRess Higher half
   --  15-8      SPIO             SPI Opcode
   -------------------------------------------------------------
   -- ACK is performed automatically
   -------------------------------------------------------------------

   constant GENERAL2_addr   : STD_LOGIC_VECTOR(3 downto 0):= X"5";

   -------------------------------------------------------------
   -- GENERAL3 value to be passed to ICAP through CTRL operation
   -------------------------------------------------------------
   -- 16 bits
   -- Wishbone access: Write-read
   -------------------------------------------------------------
   -- BIT       NAME             Description
   --  15-0       GLD_ADDR_L      GoLDen image ADDRess Lower half
   -------------------------------------------------------------
   -- ACK is performed automatically
   -------------------------------------------------------------------

   constant GENERAL3_addr   : STD_LOGIC_VECTOR(3 downto 0):= X"6";

   -------------------------------------------------------------
   -- GENERAL4 value to be passed to ICAP through CTRL operation
   -------------------------------------------------------------
   -- 16 bits
   -- Wishbone access: Write-read
   -------------------------------------------------------------
   -- BIT       NAME             Description
   --  7-0       GLD_ADDR_H       GoLDen image ADDRess Higher half
   --  15-8      SPIO             SPI Opcode
   -------------------------------------------------------------
   -- ACK is performed automatically
   -------------------------------------------------------------------

   constant GENERAL4_addr   : STD_LOGIC_VECTOR(3 downto 0):= X"7";

   signal CTRL0_s     :  STD_LOGIC_VECTOR (15 downto 0);
   signal GENERAL1_s  :  STD_LOGIC_VECTOR (15 downto 0);
   signal GENERAL2_s  :  STD_LOGIC_VECTOR (15 downto 0);
   signal GENERAL3_s  :  STD_LOGIC_VECTOR (15 downto 0);
   signal GENERAL4_s  :  STD_LOGIC_VECTOR (15 downto 0);
   signal STAT_s      :  STD_LOGIC_VECTOR (15 downto 0);

   signal wb_ack_s    :  STD_LOGIC; 
   signal wb_rty_s    :  STD_LOGIC; 
   signal wb_err_s    :  STD_LOGIC; 

begin

   CTRL0_o      <=  CTRL0_s;

   GENERAL1_o   <=  GENERAL1_s;
   GENERAL2_o   <=  GENERAL2_s;
   GENERAL3_o   <=  GENERAL3_s;
   GENERAL4_o   <=  GENERAL4_s;

   wb_ack_o     <=  wb_ack_s;
   wb_rty_o     <=  wb_rty_s;
   wb_err_o     <=  wb_err_s;


   process (wb_clk)

   begin
      if rising_edge(wb_clk) then
         if wb_rst_i = '1' then
            wb_data_o    <= (others => '0');
            wb_ack_s     <= '0';
            wb_rty_s     <= '0';
            wb_err_s     <= '0';
            CTRL0_s      <= (others => '0');
            GENERAL1_s   <= (others => '0');
            GENERAL2_s   <= (others => '0');
            GENERAL3_s   <= (others => '0');
            GENERAL4_s   <= (others => '0');
            STAT_s       <= (others => '0');
         else

            if (wb_stb_i = '1' and wb_cyc_i = '1') then
               -- If we have no operation running or pending to acknowledge the
               -- result to wishbone, then we can accept more operations
               if CTRL1_i(1) = '1' then
                  wb_ack_s   <= '0';
                  wb_rty_s   <= '0';
                  wb_err_s   <= '0';

               elsif CTRL1_i(0) = '1' or CTRL1_i(2) = '1' then
                  if CTRL1_i(0) = '1' then
                     wb_ack_s   <= '1';
                     wb_rty_s   <= '0';
                     wb_err_s   <= '0';
                  else
                     wb_ack_s   <= '0';
                     wb_rty_s   <= '0';
                     wb_err_s   <= '1';
                  end if;
                  -- Deactivate the pending
                  CTRL0_s(4) <= '0';
               else

                  case wb_we_i is
                     when '1' =>
                        case wb_addr_i is
                           when CTRL0_addr     =>
                              CTRL0_s    <= wb_data_i(15  downto 0);
                           -- The ack will be given upon completeness of the
                           -- requested operation
                              CTRL0_s(4) <= '1';
                              wb_ack_s   <= '0';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL1_addr => 
                              GENERAL1_s <= wb_data_i(15 downto 0);
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL2_addr => 
                              GENERAL2_s <= wb_data_i(15 downto 0);
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL3_addr => 
                              GENERAL3_s <= wb_data_i(15 downto 0);
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL4_addr => 
                              GENERAL4_s <= wb_data_i(15 downto 0);
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when others        =>
                              wb_ack_s   <= '0';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '1';
                        end case;
                     when others =>
                        case wb_addr_i is
                           when CTRL0_addr     =>
                              wb_data_o(15 downto 0)   <= CTRL0_s;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when CTRL1_addr     =>
                              wb_data_o(15 downto 0)   <= CTRL1_i;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when STAT_addr     =>
                              wb_data_o(15 downto 0)   <= STAT_s;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL1_addr => 
                              wb_data_o(15 downto 0)   <= GENERAL1_s;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL2_addr => 
                              wb_data_o(15 downto 0)   <= GENERAL2_s;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL3_addr => 
                              wb_data_o(15 downto 0)   <= GENERAL3_s;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when GENERAL4_addr => 
                              wb_data_o(15 downto 0)   <= GENERAL4_s;
                              wb_data_o(31 downto 16)  <= (others => '0');
                              wb_ack_s   <= '1';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '0';
                           when others        =>
                              wb_data_o(31 downto 0)   <= (others => '0');
                              wb_ack_s   <= '0';
                              wb_rty_s   <= '0';
                              wb_err_s   <= '1';
                        end case;
                  end case;
               end if;
            else
            end if;
         end if;
      else
      end if;
   end process;

end Behavioral;
