--3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_
--==============================================================================
--
-- Function   : Simplex G-LINK S-LINK LDC FOR RADIATION TESTS
--              PCB#  EP 680-1110-850-A
--
-- Description: This design writes a word to the S-LINK (LWEN#=0) whenever
--              cav#, dav# or error is active. linkrdy# is ignored
--            
--              Design made for radiation tests where the transmitter
--              is supposed to send only idles.
--              G-LINK linkrdy# signal is ignored, but is sent as a bit
--              in the S-LINK datastream whenever cav#,dav# or error is active.
--
--      
-- File name  : ldc.vhd
-- Created on : 07 Oct. 1998
-- Developers : Zoltan Meggyesi & Erik van der Bij
--
-- Notes      : - Chip, Pinout and Logic options in ldc.acf file
--		- File made for EPC1441PC8 PROM
--              - File for PCB version .850-A
--
--==============================================================================
--
--    ----------------------------------------------------------------------
--   | 31  |  30  |  29 |  28 |   27..24  |    23    |  22..20  |  19..0    |
--   |CAV# | DAV# | ERR | FLG | URL[3..0] | LINKRDY# | Reserved |Data[19..0]|
--    ----------------------------------------------------------------------
--    LD (Data) bits in data mode (UTDO_N high)
--    In 16 bit mode LD[19..16] are low
--
--
-- Jumpers: TP(n) signal is '0' when the TP(n) jumper is plugged (on) 
--          TP1 off: no flag;      on: flag mode
--          TP2 off: 16 bit mode;  on: 20 bit;
--          TP3 off: Locking Methode "2" - on incoming data stream
--               on: Locking Methode "3" - with reference oscillator 
--          TP4, TP5: Reserved
--
--
-------------------------------------------------------------------------------|
-- Version | Mod.Date | Change made                                 | checksum |
-------------------------------------------------------------------------------|
--  0.1    | 03-10-98 | First Version                               |     -    |
--  0.2    | 17-02-99 | HP_LINKRDY_N neg. pulses filtered	    |          |
--  1.0 EB | 08-03-99 | write when err is active, even if           |          |
--         |          | linkrdy is not active (radiationtest)       | 001691F8 |
--  1.1 EB | 22-03-99 | Modified comments                           |          |
--  1.2 EB | 24-03-99 | Pinout for HP_SMRST0 connected (PCB vers.A) | 00169765 |
------------------------------------------------------------------------------ |
--==============================================================================
--==============================================================================


LIBRARY IEEE;
USE     IEEE.STD_LOGIC_1164.ALL;
USE     IEEE.STD_LOGIC_ARITH.ALL;
USE     IEEE.STD_LOGIC_UNSIGNED.ALL; -- Maxplus needs this, 
                                     -- comment out for leapfrog

--==============================================================================
ENTITY LDC IS
--==============================================================================

  port(
--------------------------------------------------------------------------------
--      INPUTS
--------------------------------------------------------------------------------
        QCLK            : in    std_logic;  -- 40 Mhz from Quartz
        TP              : in    std_logic_vector(5 downto 1); -- Jumpers
        
        AD_OTI          : in    std_logic; 
        AD_DIO          : in    std_logic;

        HP_STRBOUT      : in    std_logic;  -- RX clock from HP
        HP_LINKRDY_N    : in    std_logic;  -- Low when link is active    
        HP_CAV_N        : in    std_logic;  -- G control word
        HP_DAV_N        : in    std_logic;  -- G data word
        HP_ERROR        : in    std_logic;  -- Error flag
        HP_FF           : in    std_logic;  -- Fill Frame
        HP_FLAG         : in    std_logic;
        HP_STAT1        : in    std_logic;  -- HP State Machine Output
        HP_STAT0        : in    std_logic;
   
        HP_D            : in    std_logic_vector(19 downto 0);

        URL             : in    std_logic_vector(3 downto 0);
        URESET_N        : in    std_logic;
        UXOFF_N         : in    std_logic;
        UTDO_N          : in    std_logic;
        UDW             : in    std_logic_vector(1 downto 0);

        fr_rxsigdet     : in    std_logic;
        fr_rxsys        : in    std_logic_vector(1 downto 0);

--------------------------------------------------------------------------------
--      OUTPUTS
--------------------------------------------------------------------------------
        AD_CONVST_N     : out   std_logic;
        AD_SCLK         : out   std_logic;
        AD_RDWR         : out   std_logic; 
		
        HP_EQEN         : out   std_logic; -- Cable equalization
        HP_FLAGSEL      : out   std_logic; -- Flag Mode Select
        HP_LOOPEN       : out   std_logic; -- Loopback control
        HP_M20SEL       : out   std_logic; -- 20/16 bit mode
        HP_SMRST1_N     : out   std_logic; -- State m. reset
        HP_SMRST0_N     : out   std_logic; -- State m. reset
        HP_TCLK         : out   std_logic; -- External test CLK
        HP_TCLKsel      : out   std_logic; -- Enable TCLK Input
        HP_DIV          : out   std_logic_vector(1 downto 0); -- Baud rate

        LD              : out   std_logic_vector(31 downto 0);
        LCLK            : out   std_logic; -- S-Link Signals 
        LCTRL_N         : out   std_logic;
        LWEN_N          : out   std_logic;
        LDOWN_N         : out   std_logic;
        LDERR_N         : out   std_logic;

        G               : out   std_logic_vector(25 downto 0); 
          -- Unused Pins are connected to ground to improve gnd-bounce
        CK40TTL         : out   std_logic; 
        TESTLED_N       : out   std_logic; -- Leds, lights when 0
        DERRLED_N       : out   std_logic;
        LUPLED_N        : out   std_logic;
        FLOWCTLED_N     : out   std_logic);

end LDC;


--==============================================================================
ARCHITECTURE behavioural OF LDC IS
--==============================================================================

TYPE   init_state  is (DOWN, UP, RES1, RES2, RES3,  LERR);
TYPE   reset_state is (OK, RSTNOW, WAITST);
-- attribute TYPE_ENCODING_STYLE of init_state:type is ONEHOT;
-- Note: the Altera settings such as coding style are in the file ldc.acf


signal curr_reset, next_reset: reset_state;                   -- Reset SM
signal curr_init, next_init  : init_state;                    -- Link init SM
signal inreg                 : std_logic_vector(19 downto 0); -- Input reg.(.q)
signal rl                    : std_logic_vector(3 downto 0); 
signal filt                  : std_logic_vector(10 downto 0); -- Filter
signal errled_n, linkrdy_n   : std_logic;
signal cav_n, dav_n, err     : std_logic;
signal flag, sys_res, hp_up  : std_logic; 


begin

--------------------------------------------------------------------------------
-- Non-registered OUTPUTS
--------------------------------------------------------------------------------
HP_EQEN    <= '0';                             -- Cable equalization disabled
HP_FLAGSEL <= not TP(1);                       -- TP1 = vcc without jumper
HP_LOOPEN  <= (not HP_STAT1) and (not TP(3));  -- Simplex Method 2 if TP3='1' (off),
                                               -- S.M 3 if TP3='0' (on)  
HP_M20SEL  <= not TP(2);                       -- 20 bit mode with TP2 jumper
HP_TCLK    <= '0';                             -- Not used
HP_TCLKsel <= '0';                             -- Test Clock input Disabled
HP_DIV     <= "00";                            -- 700-1500 MBaud/sec

LCLK       <= not HP_STRBOUT;                  -- LCLK isInverted for better Tsu/Th 
LCTRL_N    <= '1';                             -- No control words in this version
 
TESTLED_N  <= UTDO_N;                          -- Will indicate laser/temp measurement

AD_CONVST_N<= '1';                             -- active low
AD_SCLK    <= '0';                             -- don't use A/D device now
AD_RDWR    <= '1';                             -- Read

-- "Besides placing switching pins next to a ground pin, you can create a 
--  programmable ground by creating an output pin in your design that drives
--  only ground. By connecting this output pin to ground on the board, the 
--  device ground will have another connection to the board ground, which helps
-- reduce ground bounce."(page 532 in 1998 ALTERA data book)
G          <=  (others => '0');                -- gnd outputs against gnd-bounce


--------------------------------------------------------------------------------
-- EDGE SENSITIVE RESET: Generates a pulse on negative URESET_N edge
--------------------------------------------------------------------------------
reset_reg :process(HP_STRBOUT) begin
  if (HP_STRBOUT'event and HP_STRBOUT ='1') then
      curr_reset <= next_reset;
  end if;
end process reset_reg;


reset_machine :process(curr_reset, URESET_N) begin
   case curr_reset is
      when OK =>          -- No reset, URESET_N is high
         if (URESET_N ='0') then next_reset <= RSTNOW;
         else next_reset <= OK;
         end if;

      when RSTNOW =>      -- Reset pulse 
         next_reset <= WAITST;
         
      when WAITST =>     -- Wait while URESET_N is low; 
         if (URESET_N ='1') then next_reset <= OK;
         else next_reset <= WAITST;
         end if;

      when others => next_reset <= WAITST;
   end case;
end process reset_machine;


reset_out: process (curr_reset) begin
  case curr_reset is
      when RSTNOW => sys_res <= '1'; -- Active high system reset
      when others => sys_res <= '0';
  end case;
end process reset_out;


--------------------------------------------------------------------------------
-- "Filtered" HPREADY (hpdown signal)
-- This signal has cca. 100ns wide negative pulses during 
-- synchronisation. Sync. with methode "3" @40mhz takes cca. 25ms
-- hp_up goes down if HP_LINKRDY_N goes up (G-Link Down)
-- hp_up goes up if HP_LINKRDY_N is low for >25us
--------------------------------------------------------------------------------
filter:process(HP_STRBOUT) begin   
    if (HP_STRBOUT'event and HP_STRBOUT='1') then
      if (HP_LINKRDY_N = '1') then filt <= (others => '0');
      elsif (filt(10)='1') then filt <= filt;  -- stop counting if MSB=1
      else filt <= filt + '1';
      end if;
    end if;  
end process filter;

hp_up <= filt(10);
  

--------------------------------------------------------------------------------
-- LINK INIT STATE MACHINE
--------------------------------------------------------------------------------
init_reg :process(HP_STRBOUT) begin
  if (HP_STRBOUT'event and HP_STRBOUT='1') then
  curr_init <= next_init;
end if;
end process init_reg;


init_machine: process (curr_init, sys_res) begin
 
case curr_init is 
    when DOWN =>               -- Wait for LINKRDY; Power-On state
        if (hp_up = '1') then
          next_init <= UP;     -- Link UP if LINKRDY
        elsif (sys_res = '1') then 
          next_init <= RES1;   -- HP reset possible in DOWN state
        else next_init <= DOWN;
        end if;

    when UP =>                 -- when LINK UP
        if (sys_res = '1') then next_init <= RES1;
          elsif (hp_up = '0') then next_init <= LERR; 
          else next_init <= UP;
        end if;

    when RES1 =>                -- HP Reset Pulse Here!
        next_init <= RES2;      -- As in S-LINK spec, 
   
    when RES2 =>                -- LDOWN Period for 4 LCLK 
         if (hp_up = '0') then
           next_init <= RES3;   -- Wait for HP-Down
           else NEXT_INIT <= RES2;
         end if;        
    
    when RES3 => 
         next_init <= DOWN;  
   
    when LERR =>               -- Link error, quit with URESET#
        case sys_res is        -- According to S-LINK spec.
          when '1'    => next_init <= RES1;  -- Reset HP
          when others => next_init <= LERR;
        end case;
   
    when others =>             -- Same as LERR (Link Error)
        case sys_res is
          when '1'    => next_init <= RES1;
          when others => next_init <= LERR;
	    end case;
end case;
end process init_machine;


init_out: process (HP_STRBOUT) begin
if (HP_STRBOUT'event and HP_STRBOUT='1') then
   case curr_init is
     when UP =>     LDOWN_N     <= '1'; -- Link is active in UP state
                    LUPLED_N    <= '0';
                    HP_SMRST1_N <= '1';
     when RES1 =>   LDOWN_N     <= '0';
                    LUPLED_N    <= '1';
                    HP_SMRST1_N <= '0'; -- Reset HP Here!
     when others => LDOWN_N     <= '0';
                    LUPLED_N    <= '1';
                    HP_SMRST1_N <= '1';
     end case;
end if; 
end process init_out;


HP_SMRST0_N <= '1';                     -- Not used, reset only with
                                        -- HP_SMRST1_N

refclock: process (curr_init, TP(3)) begin
case TP(3) is
  when '1' => CK40TTL <= '0';           -- TP3 off, Lock Methode "2" 
  when others =>                        -- TP3 on, Lock Methode "3"
    case curr_init is
      when UP =>     CK40TTL   <= '0';  -- Disabled when UP for less PCB noise
	                                -- For less PCB noise
      when others => CK40TTL   <= QCLK;
    end case;
end case;
end process refclock;


--------------------------------------------------------------------------------
-- DATA ERROR and FLOWCTRL LEDS 
--------------------------------------------------------------------------------
e_led: process (HP_STRBOUT) begin 
  if (HP_STRBOUT'event and HP_STRBOUT='1') then
    if (curr_init /= UP) then errled_n <= '1'; -- Goes off on URESET# or LDOWN#
      elsif (err='1') then errled_n <= '0';  
      else errled_n <= errled_n;
    end if; 
  end if;
end process e_led;
DERRLED_N <= errled_n;


f_led: process (HP_STRBOUT) begin  
  if (HP_STRBOUT'event and HP_STRBOUT='1') then
    if (UXOFF_N = '0') then FLOWCTLED_N <= '0';   -- Goes on on UXOFF_N#
    else FLOWCTLED_N <= '1';
    end if;
  end if;
end process f_led;


--------------------------------------------------------------------------------
-- INPUT REGISTER --------------------------------------------------------------------------------
inputreg: process (HP_STRBOUT) begin
    if (HP_STRBOUT'event and HP_STRBOUT='1') then

      inreg(19 downto 0) <= HP_D(19 downto 0);
      rl(3 downto 0)     <= URL(3 downto 0);
      dav_n              <= HP_DAV_N; 
      cav_n              <= HP_CAV_N;
      err                <= HP_ERROR;
      flag               <= HP_FLAG;
      linkrdy_n          <= HP_LINKRDY_N;
     
    end if;
end process inputreg;    


--------------------------------------------------------------------------------
-- OUTPUT REGISTER (pipeline) --------------------------------------------------------------------------------
outputreg: process (HP_STRBOUT) begin
  if (HP_STRBOUT'event and HP_STRBOUT='1') then
       
       LD(31) <= cav_n; LD(30) <= dav_n; LD(29) <= err; LD(28) <= flag;
       LD(27 downto 24) <= rl(3 downto 0);
       LD(23)           <= linkrdy_n;
       LD(22 downto 20) <= ('0','0','0'); 
       LD(15 downto 0)  <= inreg(15 downto 0);
       
       case TP(2) is                                            -- not HP_M20SEL
         when '0'    => LD(19 downto 16) <= inreg(19 downto 16); -- Jumper
         when others => LD(19 downto 16) <= ('0','0','0','0');   -- No jumper  
       end case;

       -- LWEN_N# signal is active on DAV# OR CAV# or ERR
      if ((err = '1') or (dav_n = '0') or (cav_n = '0')) 
        then LWEN_N <= '0';
        else LWEN_N <= '1';           -- LWEN_N is active low
      end if;            
      
      LDERR_N <= '1';  --not err;     -- Not used in this version

  end if; 
  end process outputreg;


  end behavioural;

--==============================================================================
--     END OF FILE
--==============================================================================