----------------------------------------------------------------------------------
-- Company:        CERN, BE-CO-HT
-- Engineer:       Carlos Gil Soriano
-- 
-- Create Date:    14:07:55 11/28/2011 
-- Design Name:    Trigger registers
-- Module Name:    trigger - Behavioral 
-- Project Name:   CTDAH
-- Target Devices: Spartan 6
-- Tool versions: 
-- Description:    Trigger module registers for interfacing easily with
--                 wishbone modules
--
-----------------------------------------------------------
--  Configuration process 
-----------------------------------------------------------
--  1.- CTR0: disable EN, EN_T
--  2.- CTR1: set MinPL, MaxPL
--  3.- CTR0: set CGM, CPL
--  4.- RAM0: set CLR_TT
--  5.- CTR0: enable EN, EN_TT, disable CLR_TT
-----------------------------------------------------------
--  Recommended masks to use for the steps                  
--  CTR0_step1     X"xxxxxxYY"     where Y is "yyy0" 
--  CTR0_step2     X"xxxxxxYY"     where Y is "yyy0"
--  CTR1_step3     X"xxxxxxxx"
--  RAM0_step4     X"xxxxxxxZ"     where Z is "zz1z"
--  CTR0_step5     X"xxxxxxYY"     where Y is "yyy1"
-----------------------------------------------------------
--
-- Dependencies:   none
--
-- Revision: 
-- Revision 0.1
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity trigger_regs is
   generic(
   g_MAX_GLITCH_STAGES      : INTEGER := 6;
   g_DEFAULT_GLITCH_MASK    : UNSIGNED (5 downto 0) := (others => '1');
  -- Minimum output pulse width is 1us
  -- Maximum output pulse width is 2us 
  -- Default values are for a reference clock of 20MHz
   g_MIN_PULSE_LENGTH       : INTEGER := 20;
   g_MAX_PULSE_LENGTH       : INTEGER := 40;
   g_DEFAULT_PULSE_LENGTH   : INTEGER := 30
);
port (
       wb_rst_i  : in   STD_LOGIC;		
       wb_clk    : in   STD_LOGIC;		
       wb_stb_i  : in   STD_LOGIC;
       wb_cyc_i  : in   STD_LOGIC;
       wb_ack_o  : out  STD_LOGIC;
       wb_err_o  : out  STD_LOGIC;
       wb_rty_o  : out  STD_LOGIC;
       wb_we_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 (2  downto 0);

       STATUS_o  : out  STD_LOGIC_VECTOR (31 downto 0);
       CTR0_o    : out  STD_LOGIC_VECTOR (31 downto 0);
       CTR1_o    : out  STD_LOGIC_VECTOR (31 downto 0);
       RAM0_o    : out  STD_LOGIC_VECTOR (31 downto 0);
       RAM1_i    : in   STD_LOGIC_VECTOR (31 downto 0);
       RAM2_o    : out  STD_LOGIC_VECTOR (31 downto 0);

       ramTT_i   : in  STD_LOGIC_VECTOR (95 downto 0); 
       ramID_i   : in  STD_LOGIC_VECTOR (31 downto 0) 
     );
end trigger_regs;

architecture Behavioral of trigger_regs is


  type RAM_fsm is (S0_IDLE, S1_READ_B0, S2_READ_B1, S3_READ_B2, S4_READ_B3);
  signal RAMstate         : RAM_fsm;

  -------------------------------------
  -- STATUS register
  -------------------------------------
  -- 32 bits
  -- Wishbone access: Read-only
  ------------------------------------
  -- BIT       NAME      Description
  --  0         EN        General ENable
  --  1         CLR       General CLeaR
  --  3-2       x         Reserved
  --  4         EN_TT     ENable Time-Tagging
  --  5         CLR_TT    CLeaR Time-Tagging
  --  7-6       x         Reserved
  --  8         EMPTY     RAM empty flag
  --  9         FULL      RAM full flag
  --  10        WA        RAM wrapped around
  --  15-11     x         Reserved
  --  31-16     CPL       Current Pulse Length
  -------------------------------------
  constant STATUS_addr  : STD_LOGIC_VECTOR (2 downto 0)  := "000";

  -------------------------------------
  -- CTR0 register
  -------------------------------------
  -- 32 bits
  -- Wishbone access: Read-write
  -------------------------------------
  -- BIT       NAME      Description
  --  0         EN        General ENable
  --  1         CLR       General CLeaR
  --  3-2       x         Reserved
  --  4         EN_TT     ENable Time-Tagging
  --  5         CLR_TT    CLeaR time-tagging
  --  7-6       RDM       time-tagging ReaD Mode
  --  15-8      CGM       Current Glitch Mask
  --  31-16     CPL       Current Pulse Length
  -------------------------------------
  -- TIP: CGM is used from lowest to highest
  -------------------------------------
  constant CTR0_addr    : STD_LOGIC_VECTOR (2 downto 0)  := "001"; 

  -------------------------------------
  -- CTR1 register
  -------------------------------------
  -- 32 bits
  -- Wishbone access: Read-write
  -------------------------------------
  -- BIT       NAME      Description
  --  15-0      MinPL     Minimum Pulse Length
  --  31-16     MaxPL     Maximum Pulse Length
  -------------------------------------
  constant CTR1_addr    : STD_LOGIC_VECTOR (2 downto 0)  := "010";

  -------------------------------------
  -- RAM0 register
  -------------------------------------
  -- 32 bits
  -- Wishbone access: Read-write
  -------------------------------------
  -- BIT       NAME      Description
  --  0         EN_TT     Enable Time-tagging
  --  1         CLR_TT    Clear whole contents
  --  3-2       RDM       time-tagging ReaD Mode
  --  4         EMPTY     RAM empty
  --  5         FULL      RAM full
  --  6         WA        RAM Wrapped around
  --  7         RQT       ReQuesT read
  --  31-8      x         Reserved
  -------------------------------------
  constant RAM0_addr    : STD_LOGIC_VECTOR (2 downto 0) := "101";

  -------------------------------------
  -- RAM1 register
  -------------------------------------
  -- 32 bits
  -- Wishbone access: Read-only
  -------------------------------------
  -- BIT       NAME      Description
  --  15-0      CRA        Current Read Address   
  --  31-16     CWA        Current Write Address
  -------------------------------------
  constant RAM1_addr    : STD_LOGIC_VECTOR (2 downto 0) := "110";

  -------------------------------------
  -- RAM2 register
  -------------------------------------
  -- 32 bits
  -- Wishbone access: Read-write
  -------------------------------------
  -- BIT       NAME      Description
  --  15-0      SA        Starting read Address        
  --  31-16     EA        Ending read Address
  -------------------------------------
  constant RAM2_addr    : STD_LOGIC_VECTOR (2 downto 0) := "111";

  signal STATUS_reg     : STD_LOGIC_VECTOR (31 downto 0);
  signal CTR0_reg       : STD_LOGIC_VECTOR (31 downto 0);
  signal CTR1_reg       : STD_LOGIC_VECTOR (31 downto 0);
  signal RAM0_reg       : STD_LOGIC_VECTOR (31 downto 0);
  signal RAM1_reg       : STD_LOGIC_VECTOR (31 downto 0);
  signal RAM2_reg       : STD_LOGIC_VECTOR (31 downto 0);

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

  signal EN      : STD_LOGIC; 
  signal CLR     : STD_LOGIC;
  signal EN_TT   : STD_LOGIC;
  signal CLR_TT  : STD_LOGIC;
  signal EMPTY   : STD_LOGIC;
  signal FULL    : STD_LOGIC;
  signal WA      : STD_LOGIC;
  signal RDM     : STD_LOGIC_VECTOR(1  downto 0);
  signal CGM     : STD_LOGIC_VECTOR(7  downto 0);
  signal CPL     : STD_LOGIC_VECTOR(15 downto 0);
  signal MinPL   : STD_LOGIC_VECTOR(15 downto 0);
  signal MaxPL   : STD_LOGIC_VECTOR(15 downto 0);
  signal RQT     : STD_LOGIC;
  signal CRA     : STD_LOGIC_VECTOR(15 downto 0);
  signal CWA     : STD_LOGIC_VECTOR(15 downto 0);
  signal SA      : STD_LOGIC_VECTOR(15 downto 0);
  signal EA      : STD_LOGIC_VECTOR(15 downto 0);

begin


  STATUS_reg   <= CPL & "00000" & WA & FULL & EMPTY & "00" & CLR_TT & EN_TT & "00" & CLR & EN; 
  CTR0_reg     <= CPL & CGM & RDM & CLR_TT & EN_TT & "00" & CLR & EN;
  CTR1_reg     <= MaxPL & MinPL ; 
  RAM0_reg     <= X"000000" & RQT & WA & FULL & EMPTY & RDM & CLR_TT & EN_TT;
  RAM2_reg     <= EA  & SA;

  STATUS_o    <=  STATUS_reg; 
  CTR0_o      <=  CTR0_reg;  
  CTR1_o      <=  CTR1_reg;   
  RAM0_o      <=  RAM0_reg;   
  RAM2_o      <=  RAM2_reg;   


  process(wb_clk)
  begin
    if rising_edge(wb_clk) then
      if wb_rst_i = '1' then
        RAMstate <= S0_IDLE;
        EN      <= '1';         
        CLR     <= '1';
        EN_TT   <= '1';
        CLR_TT  <= '1';
        EMPTY   <= '1';
        FULL    <= '0';
        WA      <= '0';
        -- TIP: the lenght of the repeated pulse must be 1us by default.
        --      Considering that wb period is 50 ns (20 MHz) a value of
        --      30 jiffies should be set by default.
        CPL     <= STD_LOGIC_VECTOR(TO_UNSIGNED(g_DEFAULT_PULSE_LENGTH, 16));
        -- Read mode is set to a default 0
        RDM     <= (others => '0');
        -- Simple mask length 
        CGM     <= (others => '1');
        MinPL   <= STD_LOGIC_VECTOR(TO_UNSIGNED(g_MIN_PULSE_LENGTH, 16));
        MaxPL   <= STD_LOGIC_VECTOR(TO_UNSIGNED(g_MAX_PULSE_LENGTH, 16));
        RQT     <= '0';
        CRA     <= (others => '0');
        CWA     <= (others => '0');
        SA      <= (others => '0');
        EA      <= (others => '0');
        wb_ack_o   <= '0';
        wb_err_o   <= '0';
        wb_rty_o   <= '0';
        wb_ack_s   <= '0';
        wb_err_s   <= '0';
        wb_rty_s   <= '0';
        wb_data_o  <= (others => '0');
      elsif wb_stb_i = '1' and wb_cyc_i = '1' then
        -- Block mode behaviour
        if wb_ack_s = '1' or wb_err_s = '1' or wb_rty_s = '1' then
          wb_ack_o   <= '0';
          wb_err_o   <= '0';
          wb_rty_o   <= '0';
          wb_ack_s   <= '0';
          wb_err_s   <= '0';
          wb_rty_s   <= '0';
        else
          if wb_we_i = '0' then
            case wb_addr_i (2 downto 0) is
              when STATUS_addr =>
                wb_data_o <= STATUS_reg;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when CTR0_addr   =>
                wb_data_o <= CTR0_reg;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when CTR1_addr   =>
                wb_data_o <= CTR1_reg;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when RAM0_addr    =>
                wb_data_o <= RAM0_reg;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when RAM1_addr    =>
                wb_data_o <= RAM1_i;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when RAM2_addr    =>
                wb_data_o <= RAM2_reg;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when others =>
                wb_ack_o <= '0';
                wb_err_o <= '1';
                wb_rty_o <= '0';
                wb_ack_s <= '0';
                wb_err_s <= '1';
                wb_rty_s <= '0';
            end case;
          else
            case wb_addr_i is
              when CTR0_addr   =>
                EN     <= wb_data_i(0);   
                CLR    <= wb_data_i(1);
                EN_TT  <= wb_data_i(4);
                CLR_TT <= wb_data_i(5);
                RDM    <= wb_data_i(7  downto 6);
                -- HW protection: anticipating bad CTR0 configuration
                if wb_data_i(15 downto 8) = X"00" then
                  CGM <= X"01";
                else
                  CGM    <= wb_data_i(15 downto 8);
                end if;
                CPL    <= wb_data_i(31 downto 16);
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when CTR1_addr   =>
                MinPL   <= wb_data_i(15 downto 0);  
                MaxPL   <= wb_data_i(31 downto 16); 
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when RAM0_addr    =>
                EN_TT   <= wb_data_i(0); 
                CLR_TT  <= wb_data_i(1);
                RDM     <= wb_data_i(3 downto 2);
--                EMPTY   <= wb_data_i(4);
--                FULL    <= wb_data_i(5);
--                WA      <= wb_data_i(6);
                RQT     <= wb_data_i(7);
                if STATUS_reg(0) = '1' and wb_data_i(0) = '1' and wb_data_i (7) = '1' then
                  case RAMstate is 
                    when S0_IDLE  =>
                      RAMstate    <= S1_READ_B0; 
                      wb_ack_o    <= '0';
                      wb_err_o    <= '0';
                      wb_rty_o    <= '0';
                    when S1_READ_B0  =>
                      wb_data_o   <= RAMTT_i(31 downto 0); 
                      RAMstate    <= S2_READ_B1; 
                      wb_ack_o    <= '0';
                      wb_err_o    <= '0';
                      wb_rty_o    <= '0';
                    when S2_READ_B1  =>
                      wb_data_o   <= RAMTT_i(63 downto 32); 
                      RAMstate    <= S3_READ_B2; 
                      wb_ack_o    <= '0';
                      wb_err_o    <= '0';
                      wb_rty_o    <= '0';
                    when S3_READ_B2  =>
                      wb_data_o   <= RAMTT_i(95 downto 64);
                      RAMstate    <= S4_READ_B3; 
                      wb_ack_o    <= '0';
                      wb_err_o    <= '0';
                      wb_rty_o    <= '0';
                    when S4_READ_B3  =>
                      wb_data_o   <= RAMID_i(31 downto 0);
                      RAMstate    <= S0_IDLE;
                      wb_ack_o    <= '1';
                      wb_err_o    <= '0';
                      wb_rty_o    <= '0';
                    when others      =>
                      RAMstate    <= S0_IDLE;
                      wb_ack_o    <= '0';
                      wb_err_o    <= '1';
                      wb_rty_o    <= '0';
                  end case;
                else
                end if;
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when RAM2_addr    =>
                SA    <= wb_data_i(15 downto 0);
                EA    <= wb_data_i(31 downto 16);
                wb_ack_o <= '1';
                wb_err_o <= '0';
                wb_rty_o <= '0';
                wb_ack_s <= '1';
                wb_err_s <= '0';
                wb_rty_s <= '0';
              when others =>
                wb_ack_o <= '0';
                wb_err_o <= '1';
                wb_rty_o <= '0';
                wb_ack_s <= '0';
                wb_err_s <= '1';
                wb_rty_s <= '0';
            end case;
          end if;
        end if;
      end if;

    end if;
  end process;

end Behavioral;
