--******************************************************************************
--* @short   Simplified version of a ScanPSC100 JTAG controller (by J. Ero)
--*
--*   JTAG Controller that supports two JTAG chains.
--*
--*   The controller is accessed through 8 registers mapped into
--*   VME address space. Except for a few minor exception these
--*   registers are the same as for the National Semiconductor
--*   ScanPSC100F Chip.
--*
--*   The controller's JTAG ports should be connected directly to
--*   the I/O pins of the FPGA without any flip-flops in between.
--*
--*   Furthermore the controller needs the 40 MHz clock and a reset signal
--*   which has to be asserted at startup to initalize the controller.
--*
--*   Important Note on the VME Interface:
--*   The JTAG controller uses a simplified VME interface. vme_en is used as a
--*   strobe. It has to be active until vme_dtack ends the cycle. While vme_en is
--*   active, bot the addresses and data (for a write) have to be valid. vme_en must
--*   change synchronously to the 40 MHz clock (no asynchronous clear) as the
--*   falling edge of vme_en is used to trigger actions. )
--*   vme_wr has to be valid and stable duing the whole cycle and for two clocks
--*   after the vme_en goes to low.
--*
--*   Main differences to ScanPSC100:
--*    @li no double buffering
--*    @li no loopback or other test commands
--*    @li no running of the JTAG clock without shifting data on TDO or TMS
--*    @li when shifting, both tdi and tdo have to be enabled. All data shifted
--*        in has to be read out subsequently.
--* 
--*    @generic base_address      VME base address in bytes
--*    @generic address_increment address increment bewteen successive
--*       registers in bytes (2 for word access, 4 for long word access)
--*    @generic addr_high         upper index of vme_addr vector
--*    @generic addr_low          lower index of vme_addr vector
--*       (1 for word access, 2 for long word access)
--* 
--*    @port oTck  JTAG clock output
--*    @port oTms0 TMS output for chain 0
--*    @port oTms1 TMS output for chain 1
--*    @port oTdo  TDO output (bot chains)
--*    @port iTdi0 TDI input for chain 0
--*    @port iTdi1 TDI inout for chain 1
--*
--*    @port vme_addr      VME adresses (range defined by generics)
--*    @port vme_data      VME data from VME bus 
--*    @port vme_en        VME enable strobe (see text above)
--*    @port vme_wr        VME write (see text above)
--*    @port vme_dtack     VME dtack (see text above)
--*    @port vme_data_out  VME data to VME bus (16 bit but only lower 8 bits
--*                        are used) 
--*    @port vme_en_out    VME enabled and one of the  registers was addressed.
--*                        used to multiplex vme_data_out from multiple registers.
--*
--*    @port    clk        40 MHz clock
--*    @port    reset      asynchronous reset, active high (to be asserted at startup)
--*
--*    @see ScanPSC100F documentation(http://www.national.com/ds/SC/SCANPSC100F.pdf)
--*    
--******************************************************************************
--* @date    $Date: 2004/12/16 18:58:56 $
--* @version $Revision: 1.11 $
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv3.cern.ch>
--******************************************************************************
--/

-- generic parameter for address width of vme_addr implemented (HB)
-------------------------------------------------------------------------------
-- based on:

-- Title:        VHDL Controller Chip for the PHTF Soc2
-- Author:       JEJr. %
-- This VHDL Modul of the Boardīs VME Controller
-- Version | Author | Mod. Date | Change |
-----------|--------|------------|      --------------------------------------------------|
-- 1 | JEJr | 31.03.2004 | First design (derived from ETTF_contr_jxx) |
-----------|--------|------------|      --------------------------------------------------|

library IEEE;
library work;

use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
USE IEEE.STD_LOGIC_UNSIGNED.ALL; 
------------------------------------------------------------------------
-- Entity Declaration
------------------------------------------------------------------------


entity JTAGController is
  generic (
    base_address      : integer := 0;   -- base address (in bytes)
    address_increment : integer := 2;   -- increment (2 for word access,
                                        -- 4 for long word access)
    addr_high : integer := 3;           -- upper index of vme_addr vector
    addr_low  : integer := 1            -- lower index of vme_addr vector
    );      
                                      
  port (

    -- JTAG port
    -- to be connected directly to I/O pins of chip
    oTck  : out std_logic;              
    oTms0 : out std_logic;
    oTms1 : out std_logic;
    oTdo  : out std_logic;
    iTdi0 : in  std_logic;
    iTdi1 : in  std_logic;

    -- VME port
    vme_addr       : in    std_logic_vector(addr_high downto addr_low);  
                                              
    vme_data       : in    std_logic_vector(15 downto 0);  -- has to be at least 8 bit
    vme_en         : in    std_logic;   -- should not be a pulse when writing
    vme_wr         : in    std_logic;   -- state. must remain for at least two
                                        -- clocks after enable goes to 0
    vme_dtack      : out   std_logic;         -- not inverted

    vme_data_out   : out   std_logic_vector(15 downto 0);
    vme_en_out     : out   std_logic;
        
    -- Clock and control
    clk            : in    std_logic;
    reset          : in    std_logic);  -- asynchronous reset, active high
  
end;

-------------------------------------------------------------------------------
-- VME signals:
-- 
-- the unit assumes that data and address are valid for the whole time
-- that vme_en is active
--
-- the unit further assumes that vme_en is a synchronous signal (no
-- asynchronous clear) as the falling edge of vme_en is used to trigger actions.
-------------------------------------------------------------------------------


------------------------------------------------------------------------
-- Architecture declaration
------------------------------------------------------------------------

architecture behavioral of JTAGController is

  -- need the following attributes to force Synplify to use
  -- input and output flip-flops
  -- (currently does not work for TDI, TMS)
  attribute syn_useioff               : boolean;
  attribute syn_useioff of behavioral : architecture is true;

-- JTAG Registers

  signal mode0_reg : std_logic_vector( 7 downto 0);
  signal mode1_reg : std_logic_vector( 7 downto 0);
  signal mode2_reg : std_logic_vector( 7 downto 0);
  signal cnt32_reg : unsigned (31 downto 0);
  signal tms0_reg  : std_logic_vector( 7 downto 0);
  signal tms1_reg  : std_logic_vector( 7 downto 0);
  signal tdo_reg   : std_logic_vector( 7 downto 0);
  signal tdi_reg   : std_logic_vector( 7 downto 0);


-- JTAG Register Enable Signals

  signal ena       : std_logic;
  signal mode0_ena : std_logic;
  signal mode1_ena : std_logic;
  signal mode2_ena : std_logic;
  signal cnt32_ena : std_logic;
  signal tms0_ena  : std_logic;
  signal tms1_ena  : std_logic;
  signal tdo_ena   : std_logic;
  signal tdi_ena   : std_logic;

  signal tdi_ena_d  : std_logic;
  signal tdi_ena_d2 : std_logic;

  signal tdi_stat : std_logic;

-- JTAG status signals
  signal cnt_loaded     : std_logic;
  signal tdo_empty      : std_logic;
  signal tms0_empty     : std_logic;
  signal tms1_empty     : std_logic;
  signal tdi_full       : std_logic;
  signal cnt_loaded_del : std_logic;
  signal tdo_empty_del  : std_logic;
  signal tms0_empty_del : std_logic;
  signal tms1_empty_del : std_logic;
  signal tdi_full_del   : std_logic;

  signal cnt_pointer : unsigned ( 1 downto 0);
  signal dtack_ff    : std_logic;

  signal tms0_a_exit : std_logic;
  signal tms1_a_exit : std_logic;

--DTACK flip-flops

  signal tdo_rdy_ff : std_logic;
  signal tdi_rdy_ff : std_logic;
  signal reg_rdy_ff        : std_logic;
  signal reg_rdy_ff_del    : std_logic;
  signal ds_del_sig        : std_logic;


-- JTAG Registers

  signal jtag_ck_cnt     : unsigned (2 downto 0);
  signal jtag_ck         : std_logic;
  signal jtag_ck_pulse   : std_logic;

  signal shift_enable : std_logic;


  signal tms01_sig : std_logic;  -- Memorize last TMS action


  signal cnt001 : std_logic;


  signal tdo_enable   : std_logic;
  signal tdi_enable   : std_logic;
  signal cnt32_enable : std_logic;
  signal tms0_enable  : std_logic;
  signal tms1_enable  : std_logic;
  signal auto_tms_h   : std_logic;
  signal int_reset    : std_logic;
  signal int_dtack    : std_logic;

  signal cnt_stat      : std_logic;
  signal cnt_stat_del  : std_logic;
  signal tms0_stat     : std_logic;
  signal tms0_stat_del : std_logic;
  signal tms1_stat     : std_logic;
  signal tms1_stat_del : std_logic;
  signal tdo_stat      : std_logic;
  signal tdo_stat_del  : std_logic;

-- JTAG Outputs internal name

  signal stms0 : std_logic;
  signal stms1 : std_logic;
  signal stdo  : std_logic;
  signal stdi0 : std_logic;
  signal stdi1 : std_logic;


  function addr_match (
    constant vme_addr : std_logic_vector;
    constant address  : integer)        -- in bytes
    return boolean is

    variable my_addr_vec : std_logic_vector(vme_addr'high downto 0);
  begin  -- process vme_addr_decode
    my_addr_vec := std_logic_vector( TO_UNSIGNED ( address, vme_addr'high+1 ) );
    return my_addr_vec(addr_high downto addr_low) = vme_addr(addr_high downto addr_low);
  end;

  signal vme_en_d  : std_logic;

  signal nreset  : std_logic;
  signal vme_cycend_p : std_logic;
  
begin  -- Main

  nreset <= not reset;

  -----------------------------------------------------------------------------
  -- Address Decode
  -----------------------------------------------------------------------------
  

  tdo_ena   <= vme_en when addr_match(vme_addr, base_address)    else '0';
  tdi_ena   <= vme_en when addr_match(vme_addr, base_address+ address_increment)  else '0';
  tms0_ena  <= vme_en when addr_match(vme_addr, base_address+ address_increment*2) else '0';
  tms1_ena  <= vme_en when addr_match(vme_addr, base_address+ address_increment*3) else '0';
  cnt32_ena <= vme_en when addr_match(vme_addr, base_address+ address_increment*4) else '0';
  mode0_ena <= vme_en when addr_match(vme_addr, base_address+ address_increment*5) else '0';
  mode1_ena <= vme_en when addr_match(vme_addr, base_address+ address_increment*6) else '0';
  mode2_ena <= vme_en when addr_match(vme_addr, base_address+ address_increment*7) else '0';

  ena <= mode0_ena
                or mode1_ena
                or mode2_ena
                or ( tdi_ena and tdi_full )
                or cnt32_ena
                or tdo_ena
                or tms0_ena
                or tms1_ena;

  -----------------------------------------------------------------------------
  -- Synchronization
  -----------------------------------------------------------------------------
  
  Synchro : process (clk, nreset)

  begin
    if nreset = '0' then
      vme_cycend_p <= '0';
      vme_en_d <= '0';
    elsif clk'event and clk='1' then
      vme_en_d <= vme_en;
      
      if (( vme_en = '0' ) and ( vme_en_d = '1' )) then
        vme_cycend_p <= '1';
      else
        vme_cycend_p <= '0';
      end if;
    end if;
  end process Synchro;


  -----------------------------------------------------------------------------
  -- Write registers
  -----------------------------------------------------------------------------

  write_reg: process (clk, reset) 
  begin  -- process write_reg
    if reset = '1' then
      mode0_reg              <= "00100000";  --HS
      mode1_reg              <= (others => '0');
      mode2_reg (1 downto 0) <= (others => '0');
    elsif clk'event and clk = '1' then  -- rising clock edge
      if int_reset = '1' then
        mode0_reg              <= "00100000";  --HS
        mode1_reg              <= (others => '0');
        -- do not reset mode2 as it is being written to
      end if;   
      if (vme_wr = '1') then
        if (mode0_ena = '1' and vme_en_d = '0') then mode0_reg <= vme_data(7 downto 0); end if;
        if (mode1_ena = '1' and vme_en_d = '0') then mode1_reg <= vme_data(7 downto 0); end if;
        if (mode2_ena = '1' and vme_en_d = '0') then mode2_reg(1 downto 0) <= vme_data(1 downto 0); end if;
      end if;
    end if;
  end process write_reg;

-- mode registers are complete
  -----------------------------------------------------------------------------
  -- Connect status signals to registers
  -----------------------------------------------------------------------------

  tdo_enable   <= mode0_reg (7);
  tdi_enable   <= mode0_reg (6);
  cnt32_enable <= mode0_reg (5);
  tms0_enable  <= mode0_reg (4);
  tms1_enable  <= mode0_reg (3);
  auto_tms_h   <= mode0_reg (1);
  -- mode0, bit 0: loopback not implemented.

   
  int_reset <= mode2_reg (1);
  
  

  -- mode2, bit 0: single step not implemented
  -- mode2, bit 2: update status not implemented (status is always updated)
  -- mode2, bit 3: continuous update not implemented (status is always updated)
  
  mode2_reg (7) <= tdo_empty;
  mode2_reg (6) <= tdi_full;
  mode2_reg (5) <= not cnt_loaded;
  mode2_reg (4) <= tms0_empty;
  mode2_reg (3) <= tms1_empty;
  mode2_reg (2) <= shift_enable;  --????


  -- TBD: jtag mode 2 reg reset bit has to return to 0 after reset

  -- mode2, bit0: Single step CNT32 not implemented.

  -----------------------------------------------------------------------------
  -- Read registers
  -----------------------------------------------------------------------------

  vme_data_out <=      ( "00000000" & mode0_reg ) when mode0_ena = '1'
                  else ( "00000000" & mode1_reg ) when mode1_ena = '1'
                  else ( "00000000" & mode2_reg ) when mode2_ena = '1'
                  else ( "00000000" & tdi_reg )   when (( tdi_ena = '1' ) and ( tdi_full = '1' ))
                  else ( "00000000" & std_logic_vector ( cnt32_reg ( 7 downto 0 )))   when cnt32_ena = '1'
                  else ( "00000000" & std_logic_vector ( cnt32_reg ( 15 downto 8 )))  when tdo_ena = '1'
                  else ( "00000000" & std_logic_vector ( cnt32_reg ( 23 downto 16 ))) when tms0_ena = '1'
                  else ( "00000000" & std_logic_vector ( cnt32_reg ( 31 downto 24 ))) when tms1_ena = '1'
                  else (others => '0');
  
  vme_en_out <= ena;
 
  -------------------------------------------------------------------------------
  -- DTACK generation
  -------------------------------------------------------------------------------

  -- we do need a special dtack generation:
  --   dtack is delayed if registers are not ready when
  --   reading from tdi or writing to tms0/1, tdo and cnt32.

  -- HS : do not yet understand ds_synch story .

  
  Dtack_Synchro : process (clk, nreset)

  begin

    if nreset = '0' then
      reg_rdy_ff   <= '0';
--      ds_del_sig   <= '0';
    elsif clk'event and clk='1' then
--       if ds_synch = "00" then
--         ds_del_sig <= '0';
--       elsif ( not (ds_synch = "00" ) and valid_address = '1' ) then
--         ds_del_sig <= '1';
--       end if;

--       if ds_synch = "00" then
--         reg_rdy_ff   <= '0';
--       elsif ds_del_sig = '1' then
      if ena = '0' then
        reg_rdy_ff   <= '0';
      else
        if ( tdi_ena or tdo_ena or tms0_ena or tms1_ena or cnt32_ena) = '1' then
          reg_rdy_ff <= dtack_ff;
        else
          reg_rdy_ff <= '1';
        end if;
      end if;
    end if;
  end process Dtack_Synchro;


  Dtack_del_proc : process ( clk, nreset)

  begin
    if ( nreset = '0' ) then
      reg_rdy_ff_del <= '0';
--      dtack_del      <= '0';

    elsif clk'event and clk='1' then
      reg_rdy_ff_del <= reg_rdy_ff;
--      dtack_del      <= int_dtack;
    end if;
  end process Dtack_del_proc;

  int_dtack <= reg_rdy_ff_del and ena;

  vme_dtack <= int_dtack;



  -- generate dtack only when register is ready to be read/written

  -- HS: deadlocks: two successive writes to cnt without  
  
  
  Jtag_dtack : process ( clk, nreset)

  begin
    if ( nreset = '0' ) then
      dtack_ff <= '0';
    elsif clk'event and clk='1'  then
      if ena = '1' then

        if (( cnt32_ena = '1' ) and ( vme_wr = '1' ) and ( cnt_loaded = '0' )) then
          dtack_ff <= '1';
        elsif (( cnt32_ena = '1' ) and ( vme_wr = '0' )) then
          dtack_ff <= '1';
        end if;

        if (( tdo_ena = '1' ) and ( vme_wr = '1' ) and ( tdo_empty = '1' )) then
          dtack_ff <= '1';
        elsif (( tdo_ena = '1' ) and ( vme_wr = '0' )) then
          dtack_ff <= '1';
        end if;

        if (( tms0_ena = '1' ) and ( vme_wr = '1' ) and ( tms0_empty = '1' )) then
          dtack_ff <= '1';
        elsif (( tms0_ena = '1' ) and ( vme_wr = '0' )) then
          dtack_ff <= '1';
        end if;

        if (( tms1_ena = '1' ) and ( vme_wr = '1' ) and ( tms1_empty = '1' )) then
          dtack_ff <= '1';
        elsif (( tms1_ena = '1' ) and ( vme_wr = '0' )) then
          dtack_ff <= '1';
        end if;

        if (( tdi_ena = '1' ) and ( vme_wr = '0' ) and ( tdi_full = '1' )) then
          dtack_ff <= '1';
        elsif (( tdi_ena = '1' ) and ( vme_wr = '1' )) then
          dtack_ff <= '1';
        end if;

      else
        dtack_ff   <= '0';
      end if;


    end if;
  end process Jtag_dtack;
  




  
  ----------------------------------
  -- Generate JTAG Clock 40 MHz / 4 = 10 MHz
  ----------------------------------
  JTAG_Clock : process (clk, nreset)

  begin

    if ( nreset = '0' ) then

      jtag_ck_cnt     <= (others => '0');
      jtag_ck         <= '0';
      jtag_ck_pulse   <= '0';


    elsif clk'event and clk='1' then

      if ( shift_enable = '1' ) then
        jtag_ck_cnt <= jtag_ck_cnt + 1;
      end if;

      if ( shift_enable = '0' ) then
        jtag_ck_cnt <= (others => '0');
      end if;

      jtag_ck <= jtag_ck_cnt (2);

      -- pulse on rising JTAG clock
      if (( jtag_ck_cnt (2) = '1' ) and ( jtag_ck = '0' )) then
        jtag_ck_pulse <= '1';
      else
        jtag_ck_pulse <= '0';
      end if;

    end if;
  end process JTAG_Clock;

  -----------------------------------------------------------------------------
  -- memorize last TMS operation
  -----------------------------------------------------------------------------
  
  TMSmem : process (clk, nreset)

  begin
    if ( nreset = '0' ) then
      tms01_sig   <= '0';
    elsif clk'event and clk='1' then
      if tms0_enable = '1' then
        tms01_sig <= '0';
      elsif tms1_enable = '1' then
        tms01_sig <= '1';
      end if;
    end if;
  end process TMSmem;


  cnt001 <= '1' when ( cnt32_reg = "00000000000000000000000000000001" ) else '0';

  -----------------------------------------------------------------------------
  -- 32 bit counter
  -----------------------------------------------------------------------------
  
  Counter : process (clk, nreset)

  begin

    if ( nreset = '0' ) then

      cnt32_reg      <= (others => '0');
      cnt_pointer    <= (others => '0');
      cnt_stat       <= '0';
      cnt_stat_del   <= '0';
      cnt_loaded     <= '0';
      cnt_loaded_del <= '0';
      tms0_a_exit           <= '0';
      tms1_a_exit           <= '0';

    elsif clk'event and clk='1' then
      if int_reset = '1' then
        cnt32_reg      <= (others => '0');
        cnt_pointer    <= (others => '0');
        cnt_stat       <= '0';
        cnt_stat_del   <= '0';
        cnt_loaded     <= '0';
        cnt_loaded_del <= '0';
        tms0_a_exit           <= '0';
        tms1_a_exit           <= '0';
      end if;

      --
      -- Load counter
      --
      if (( vme_wr = '1' ) and ( cnt32_ena = '1' ) and ( cnt_loaded = '0' )) then
        cnt_stat <= '1';
        case cnt_pointer is
          when "00"   => cnt32_reg ( 7 downto 0 )   <= unsigned ( vme_data ( 7 downto 0 ));
          when "01"   => cnt32_reg ( 15 downto 8 )  <= unsigned ( vme_data ( 7 downto 0 ));
          when "10"   => cnt32_reg ( 23 downto 16 ) <= unsigned ( vme_data ( 7 downto 0 ));
          when "11"   => cnt32_reg ( 31 downto 24 ) <= unsigned ( vme_data ( 7 downto 0 ));
          when others => cnt32_reg ( 7 downto 0 )   <= unsigned ( vme_data ( 7 downto 0 ));
        end case;
      end if;

      --
      -- Increment pointer at end of VME cycle
      --
      if (( vme_cycend_p = '1' ) and ( cnt_stat = '1' )) then
        cnt_pointer      <= cnt_pointer + 1;
        cnt_stat     <= '0';
        if cnt_pointer = "11" then
          cnt_loaded_del <= '1';
        end if;
      end if;

      cnt_loaded <= cnt_loaded_del;

      if cnt_loaded = '1' then
        cnt_pointer <= (others => '0');
      end if;

      --
      -- count down
      --
      if (( jtag_ck_pulse = '1' ) and ( shift_enable = '1' )) then
        cnt32_reg        <= cnt32_reg - 1;
        if cnt001 = '1' then
          cnt_loaded_del <= '0';
        end if;
      end if;

      --
      -- auto TMS high
      -- 
      if (( auto_tms_h = '1') and (cnt001 = '1') and (cnt_loaded = '1' )) then
        if tms01_sig = '0' then
          tms0_a_exit <= '1';
        else
          tms1_a_exit <= '1';
        end if;
      end if;

      if ( cnt32_reg =  "00000000000000000000000000000000" ) then
        tms0_a_exit <= '0';
        tms1_a_exit <= '0';
      end if;

    end if;
  end process Counter;


  -----------------------------------------------------------------------------
  -- TMS 0
  -----------------------------------------------------------------------------
  tms0 : process (clk, nreset)

    variable tms0_bytcnt : unsigned ( 3 downto 0 );

  begin

    if ( nreset = '0' ) then

      tms0_reg       <= (others => '0');
      tms0_empty     <= '1';
      tms0_empty_del <= '1';
      tms0_bytcnt := (others    => '0');
      tms0_stat      <= '0';
      tms0_stat_del  <= '0';

    elsif clk'event and clk='1' then
      if int_reset = '1' then
        tms0_reg       <= (others => '0');
        tms0_empty     <= '1';
        tms0_empty_del <= '1';
        tms0_bytcnt := (others    => '0');
        tms0_stat      <= '0';
        tms0_stat_del  <= '0';
      end if;

      tms0_empty <= tms0_empty_del;

      -- load TMS0 register
      if ( vme_wr and tms0_ena ) = '1' and tms0_empty = '1' then
        tms0_reg      <= vme_data ( 7 downto 0);
        tms0_stat_del <= '1';
      end if;

      tms0_stat <= tms0_stat_del;

      if (( tms0_stat = '1' ) and ( vme_cycend_p = '1' )) then
        tms0_bytcnt := "1000";
        tms0_empty_del <= '0';
        tms0_stat_del  <= '0';
      end if;

      if (( jtag_ck_pulse = '1' ) and ( shift_enable = '1' ) and ( tms0_enable = '1' )) then
        tms0_reg <= '0' & tms0_reg ( 7 downto 1);

        tms0_bytcnt := tms0_bytcnt - 1;

        if tms0_bytcnt = "0000" then
          tms0_empty_del <= '1';
        end if;
      end if;
      if cnt_loaded_del = '0' then
        tms0_empty_del   <= '1';
      end if;
    end if;
  end process tms0;

  stms0 <= tms0_reg (0) or tms0_a_exit;


  -----------------------------------------------------------------------------
  -- TMS 1
  -----------------------------------------------------------------------------
  tms1 : process (clk, nreset)

    variable tms1_bytcnt : unsigned ( 3 downto 0 );

  begin

    if ( nreset = '0' ) then

      tms1_reg       <= (others => '0');
      tms1_empty     <= '1';
      tms1_empty_del <= '1';
      tms1_bytcnt := (others    => '0');
      tms1_stat      <= '0';
      tms1_stat_del  <= '0';

    elsif clk'event and clk='1' then
      if int_reset = '1' then
        tms1_reg       <= (others => '0');
        tms1_empty     <= '1';
        tms1_empty_del <= '1';
        tms1_bytcnt := (others    => '0');
        tms1_stat      <= '0';
        tms1_stat_del  <= '0';
      end if;

      tms1_empty <= tms1_empty_del;

      if ( vme_wr and tms1_ena ) = '1' and  tms1_empty = '1' then
        tms1_reg      <= vme_data ( 7 downto 0);
        tms1_stat_del <= '1';
      end if;

      tms1_stat <= tms1_stat_del;

      if (( tms1_stat = '1' ) and ( vme_cycend_p = '1' )) then
        tms1_bytcnt := "1000";
        tms1_empty_del <= '0';
        tms1_stat_del  <= '0';
      end if;
      if (( jtag_ck_pulse = '1' ) and ( shift_enable = '1' ) and ( tms1_enable = '1' )) then
        tms1_reg <= '0' & tms1_reg ( 7 downto 1);

        tms1_bytcnt := tms1_bytcnt - 1;

        if tms1_bytcnt = "0000" then
          tms1_empty_del <= '1';
        end if;
      end if;
      if cnt_loaded = '0' then
        tms1_empty_del   <= '1';
      end if;
    end if;
  end process tms1;

  stms1 <= tms1_reg (0) or tms1_a_exit;

  -----------------------------------------------------------------------------
  -- TDO
  -----------------------------------------------------------------------------
  tdo : process (clk, nreset)

    variable tdo_bytcnt : unsigned ( 3 downto 0 );

  begin

    if ( nreset = '0' ) then

      tdo_reg       <= (others => '0');
      tdo_empty     <= '1';
      tdo_empty_del <= '1';
      tdo_bytcnt := (others    => '0');
      tdo_stat      <= '0';
      tdo_stat_del  <= '0';

    elsif clk'event and clk='1' then
      if int_reset = '1' then
        tdo_reg       <= (others => '0');
        tdo_empty_del <= '1';
        tdo_bytcnt := (others    => '0');
        tdo_stat      <= '0';
        tdo_stat_del  <= '0';
      end if;

      tdo_empty <= tdo_empty_del;

      if ( vme_wr and tdo_ena ) = '1' and tdo_empty = '1' then
        tdo_reg      <= vme_data ( 7 downto 0);
        tdo_stat_del <= '1';
      end if;

      tdo_stat <= tdo_stat_del;

      if tdo_stat = '1' and vme_cycend_p = '1' then
        tdo_bytcnt := "1000";
        tdo_empty_del <= '0';
        tdo_stat_del  <= '0';
      end if;

      if (( jtag_ck_pulse = '1' ) and ( shift_enable = '1' ) and ( tdo_enable = '1')) then
        tdo_reg <= '0' & tdo_reg ( 7 downto 1);

        tdo_bytcnt := tdo_bytcnt - 1;

        if tdo_bytcnt = "0000" then
          tdo_empty_del <= '1';
        end if;
      end if;

      if cnt_loaded = '0' then
        tdo_empty_del <= '1';
      end if;
    end if;
  end process tdo;

  stdo <= tdo_reg (0);


  -----------------------------------------------------------------------------
  -- TDI
  -----------------------------------------------------------------------------
  tdi : process (clk, nreset)

    variable tdi_bytcnt : unsigned ( 3 downto 0 );

  begin

    if ( nreset = '0' ) then

      tdi_reg      <= (others => '0');
      tdi_full_del <= '0';
      tdi_full     <= '0';
      tdi_bytcnt := "1000";
  --    tdi_ena_d  <= '0';
  --    tdi_ena_d2 <= '0';
      tdi_stat <= '0';
    elsif clk'event and clk='1' then
      if int_reset = '1' then
        tdi_reg  <= (others => '0');
        tdi_full_del <= '0';
        tdi_full <= '0';
        tdi_bytcnt := "1000";
        tdi_stat <= '0';
      end if;

      -- delay tdi_ena so that it is still valid during vme_cycend_p
--      tdi_ena_d  <= tdi_ena;        
--      tdi_ena_d2 <= tdi_ena_d;        
      -- vme_wr stays on bus longer, do not need to delay
      
      -- set stat if there is a read on the TDI register
      if (( vme_wr = '0' ) and ( tdi_ena = '1' ) and ( tdi_full = '1' )) then
        tdi_stat <= '1';
      end if;
    
      -- if stat is set, clear full on end of cycle
      if ( (tdi_stat = '1') and (vme_cycend_p = '1')) then
        tdi_stat <= '0';
        tdi_full_del <= '0';
        tdi_bytcnt := "1000";
      end if;

      tdi_full <= tdi_full_del;  -- Delay full signal by one clock

      if (( jtag_ck_pulse = '1' ) and ( shift_enable = '1' ) and ( tdi_enable = '1' )) then

        tdi_reg ( 6 downto 0 ) <= tdi_reg ( 7 downto 1 );

        if tms01_sig = '0' then
          tdi_reg ( 7 ) <= stdi0;
        else
          tdi_reg ( 7 ) <= stdi1;
        end if;

        tdi_bytcnt := tdi_bytcnt - 1;

        -- HS: condition unnecessary? would not get here if shift_enable was 0
        
        if (( tdi_bytcnt = "0000" ) or (shift_enable = '0')) then
          tdi_full_del <= '1';
        end if;
      end if;

      -- stop shifting if at last JTAG clock pulse
      if (( jtag_ck_pulse = '1' ) and ( cnt001 = '1' ) and ( tdi_enable = '1' ))then
        tdi_full_del   <= '1';
      end if;
    end if;


-- HS: why different stop conditions? cnt_loaded, cnt_loaded_del, cnt001
    


  end process tdi;




  -----------------------------------------------------------------------------
  -- Shift Enable
  -----------------------------------------------------------------------------

  -- HS: shift enable, when counter loaded _AND_ one of the following:
  --     TMS0 enabled and not empty
  --     TMS1 enabled and not empty
  --     TD0 enabled and not empty _AND_ TDI enabled and not full

  -- only works if TDO and TDI are enabled and if TDI is actually read out
  
  shift_en_proc : process (clk, nreset)

  begin

    if ( nreset = '0' ) then

      shift_enable <= '0';

    elsif clk'event and clk='1' then

      if cnt_loaded = '1' then
        if (( tms0_enable = '1') and ( tms0_empty = '0' )) then
          shift_enable <= '1';
        elsif (( tms1_enable = '1') and ( tms1_empty = '0' )) then
          shift_enable <= '1';
        elsif (( tdo_enable = '1') and ( tdo_empty = '0' )
               and ( tdi_enable = '1') and ( tdi_full = '0' )) then
          shift_enable <= '1';
        else
          shift_enable <= '0';
        end if;
      else
        shift_enable   <= '0';

      end if;
    end if;
  end process shift_en_proc;

  -----------------------------------------------------------------------------
  -- Test clock generation
  -----------------------------------------------------------------------------

  -- HS: why invert the clock ??
  -- internal operations shpuld happen on falling edge, external ones on rising
  -- edge. 

  tclk_generation : process (clk, nreset)

  begin

    if ( nreset = '0' ) then

      oTck <= '0';

    elsif clk'event and clk='1' then
      if shift_enable = '1' then
        oTck <= not jtag_ck;
      else
        oTck <= '0';
      end if;
    end if;

  end process tclk_generation;



-------------------------

  oTdo   <= stdo;
  oTms0  <= stms0;
  oTms1  <= stms1; 
  stdi0 <= iTdi0; 
  stdi1 <= iTdi1;                   -- Separate TDI inputs (as long no tri-state at ETTF_P chip)


end behavioral;