--******************************************************************************
--* @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;