-- -*- Mode: VHDL -*- ------------------------------------------------------------------------------- -- Title : Interface the IPbus to the JTAG Master -- Project : ------------------------------------------------------------------------------- -- File : LocalJTAGBridge.vhd -- Author : Stephen Goadhouse -- Company : Univ. of Virginia, Physics Dept. -- Created : 2012-04-17 -- Last update: 2012-06-22 -- Platform : -- Standard : VHDL'93 ------------------------------------------------------------------------------- -- Description: Bridge between the IPbus local interface and JTAG pins -- on the ngCCM via the GBT. Instatiate multiple times for -- multiple busses. ------------------------------------------------------------------------------- -- Copyright (c) 2012 ------------------------------------------------------------------------------- -- Revisions : -- Date Ver Author Description -- 2012-04-17 0.1 GOADHOUSE Created -- 2012-06-22 1.0 GOADHOUSE Released -- 2016-04-25 1.5 COSTANZA Adding sleep mode ------------------------------------------------------------------------------- --============================================================================ -- IPbus Memory Map: (NOTE: must examine the code to determine the memory map) -- data[0] = -- data[1] = -- data[2] = -- data[3] = -- data[4] = -- data[5] = -- data[6] = -- data[7] = -- data[8] = -- data[9] = -- data[10] = -- data[13] = -- data[14] = -- data[15] = --============================================================================ LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; LIBRARY work; --USE work.Constant_Declaration.ALL; ENTITY LocalJTAGBridge IS PORT ( -- IPbus Local interface (sync'ed to clk_local) reset_local : IN STD_LOGIC; clk_local : IN STD_LOGIC; strobe_local : IN STD_LOGIC; write_local : IN STD_LOGIC; addr_local : IN STD_LOGIC_VECTOR(9 DOWNTO 0); DataIn_local : IN STD_LOGIC_VECTOR(31 DOWNTO 0); DataOut_local : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); TimeoutError : OUT STD_LOGIC; -- These two registers should be within the register file, so output them -- seperately. The Local IPbus interface is primarily for sending and -- receiving the data blocks. jtag_reg_wr : IN STD_LOGIC; jtag_reg_i : IN STD_LOGIC_VECTOR(31 DOWNTO 0); jtag_reg_o : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); jtag_en_o : OUT STD_LOGIC; -- output of the divided down clock ctrl_clk_o : OUT STD_LOGIC; TCK_in_rise : OUT STD_LOGIC; -- Input pins read from GBT interface. Not necessarily sync'ed to -- clk_local so must be sync'ed before using. tdo_i : IN STD_LOGIC; tck_i : IN STD_LOGIC; -- tdi_i : IN STD_LOGIC; tms_i : IN STD_LOGIC; trst_i : IN STD_LOGIC; -- output pins to be written to GBT interface tck_o : OUT STD_LOGIC; tdi_o : OUT STD_LOGIC; tms_o : OUT STD_LOGIC; trst_o : OUT STD_LOGIC ); END ENTITY LocalJTAGBridge; ARCHITECTURE rtl OF LocalJTAGBridge IS CONSTANT kJTAG_ADDR_BITS : INTEGER := 10; -- Number of Address bits used for JTAG I/F CONSTANT kJTAG_DATA_BITS : INTEGER := DataIn_local'length; -- Number of Data bits used for JTAG I/F COMPONENT JTAGMaster IS GENERIC ( gADDR_BITS : NATURAL := kJTAG_ADDR_BITS; gDATA_BITS : NATURAL := kJTAG_DATA_BITS); PORT ( RST : IN STD_LOGIC; CLK : IN STD_LOGIC; Enable : IN STD_LOGIC; ClkDiv : IN STD_LOGIC_VECTOR(3 DOWNTO 0); ctrl_clk_o : OUT STD_LOGIC; TCK_in_rise : OUT STD_LOGIC; IgnoreTDO : IN STD_LOGIC; BitCount : IN STD_LOGIC_VECTOR (15 DOWNTO 0); Go : IN STD_LOGIC; TDO : IN STD_LOGIC; TCK_in : IN STD_LOGIC; TCK : OUT STD_LOGIC; TMS : OUT STD_LOGIC; TDI : OUT STD_LOGIC; TRst : OUT STD_LOGIC; Busy : OUT STD_LOGIC; TimeoutError : OUT STD_LOGIC; StateReset : IN STD_LOGIC; StateEnd : IN STD_LOGIC_VECTOR(3 DOWNTO 0); StateCurrent : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); A : IN STD_LOGIC_VECTOR (gADDR_BITS-1 DOWNTO 0); WR : IN STD_LOGIC; Din : IN STD_LOGIC_VECTOR (gDATA_BITS-1 DOWNTO 0); Dout : OUT STD_LOGIC_VECTOR (gDATA_BITS-1 DOWNTO 0)); END COMPONENT JTAGMaster; SIGNAL BitCount : STD_LOGIC_VECTOR (15 DOWNTO 0); SIGNAL TRst : STD_LOGIC; SIGNAL JTAGEnable : STD_LOGIC; SIGNAL JTAGStart : STD_LOGIC; SIGNAL JTAGBusy : STD_LOGIC; SIGNAL JTAGIgnoreTDO: STD_LOGIC; SIGNAL Busy : STD_LOGIC; SIGNAL StateReset : STD_LOGIC; SIGNAL StateEnd : STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL StateCurrent : STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL WR : STD_LOGIC; SIGNAL DoSleep : STD_LOGIC; SIGNAL DoCapture : STD_LOGIC; SIGNAL Sleeping : STD_LOGIC; SIGNAL SleepCount : INTEGER; SIGNAL Count_o : STD_LOGIC_VECTOR(15 DOWNTO 0); SIGNAL DoCapture_o : STD_LOGIC; SIGNAL ClkDiv_o : STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL StateReset_o : STD_LOGIC; SIGNAL JTAGIgnoreTDO_o : STD_LOGIC; -- Clock divider for creating the JTAG clock which is 4x the desired TCK frequency SIGNAL ClkDiv : STD_LOGIC_VECTOR(3 DOWNTO 0); BEGIN -- ARCHITECTURE rtl WR <= write_local AND strobe_local; JTAGMaster_inst : JTAGMaster GENERIC MAP ( gADDR_BITS => kJTAG_ADDR_BITS, gDATA_BITS => kJTAG_DATA_BITS) PORT MAP ( RST => reset_local, CLK => clk_local, Enable => JTAGEnable, ClkDiv => ClkDiv, ctrl_clk_o => ctrl_clk_o, TCK_in_rise => TCK_in_rise, IgnoreTDO => JTAGIgnoreTDO, BitCount => BitCount, Go => JTAGStart, TDO => tdo_i, TCK_in => tck_i, TCK => tck_o, TMS => tms_o, TDI => tdi_o, TRst => TRst, Busy => JTAGBusy, TimeoutError => TimeoutError, StateReset => StateReset, StateEnd => StateEnd, StateCurrent => StateCurrent, A => addr_local(kJTAG_ADDR_BITS-1 DOWNTO 0), WR => WR, Din => DataIn_local, Dout => DataOut_local); -- Output the JTAG TRst signal trst_o <= TRst; -- purpose: Handle the JTAG register bits. Latch them only when JTAGStart is asserted and get a write to the register. -- type : sequential jtag_reg_proc: PROCESS (clk_local, reset_local) IS BEGIN -- PROCESS jtag_reg_proc IF reset_local = '1' THEN -- asynchronous reset (active high) BitCount <= (OTHERS => '0'); StateEnd <= (OTHERS => '0'); -- TEST_LOGIC_RESET ClkDiv <= (OTHERS => '1'); StateReset <= '1'; JTAGIgnoreTDO <= '1'; JTAGStart <= '0'; DoSleep <= '0'; DoCapture <= '0'; SleepCount <= -1; Count_o <= (OTHERS => '0'); DoCapture_o <= '0'; ClkDiv_o <= (OTHERS => '0'); StateReset_o <= '0'; JTAGIgnoreTDO_o <= '1'; ELSIF rising_edge(clk_local) THEN -- rising clock edge IF jtag_reg_i(9) = '1' THEN JTAGStart <= JTAGStart; SleepCount <= SleepCount - 1; IF SleepCount < 0 and std_match(DoSleep, '0') and jtag_reg_wr = '1' THEN SleepCount <= to_integer(unsigned(jtag_reg_i(31 DOWNTO 16))); DoSleep <= '1'; ELSIF SleepCount = 0 THEN SleepCount <= -1; DoSleep <= '0'; END IF; -- output Count_o <= jtag_reg_i(31 DOWNTO 16); DoCapture_o <= jtag_reg_i(8); ClkDiv_o <= jtag_reg_i(7 DOWNTO 4); StateReset_o <= jtag_reg_i(3); JTAGIgnoreTDO_o <= jtag_reg_i(2); ELSIF jtag_reg_i(1) = '1' AND jtag_reg_wr = '1' THEN JTAGStart <= '1'; -- make JTAGStart a single pulse DoSleep <= '0'; -- Latch bits from jtag_reg_i, the input REGISTER, when the JTAGStart -- bit is set on a register write. These bits are being latched so -- that the user can make changes to the register in preparation and -- not cause any action until JTAGStart is '1' on a register -- write. Those register changes will not cause side-effects in the -- running jtagMaster logic since the bits are latched. -- Alternatively, the user can make all register changes and set -- JTAGStart in a single write, which is probably how it will be -- typically used. BitCount <= jtag_reg_i(31 DOWNTO 16); StateEnd <= jtag_reg_i(15 DOWNTO 12); DoCapture <= jtag_reg_i(8); ClkDiv <= jtag_reg_i(7 DOWNTO 4); StateReset <= jtag_reg_i(3); -- Speeds up transfers if don't have to wait for TCK_in and TDO before moving to the next transistion JTAGIgnoreTDO <= jtag_reg_i(2); -- output Count_o <= jtag_reg_i(31 DOWNTO 16); DoCapture_o <= jtag_reg_i(8); ClkDiv_o <= jtag_reg_i(7 DOWNTO 4); StateReset_o <= jtag_reg_i(3); JTAGIgnoreTDO_o <= jtag_reg_i(2); ELSE JTAGStart <= '0'; DoSleep <= DoSleep; END IF; END IF; END PROCESS jtag_reg_proc; -- Connect JTAGEnable directly to the register bit. If that bit is ever -- cleared, the JTAG controller is disabled and TRst is pulled low to put -- the target JTAG device into RESET. Also the jtagMaster goes into a sort -- of reset state, but not a full reset. -- -- TODO: If TRst is not being used by the JTAG target, then it would be good -- to add code to go to the TEST_LOGIC_RESET state when this bit is -- cleared. As it is now, must manually set StateReset with JTAGStart and -- once that is done then clear the JTAGEnable bit. JTAGEnable <= jtag_reg_i(0); -- Make sure that Busy is asserted immediately when set the start -- signal. Busy is asserted on the next clock and will stay high until the -- cycle is complete. So a simple OR works here. Busy <= JTAGStart OR JTAGBusy OR DoSleep; -- NOTE: returning the latched values. Perhaps it is better to return the -- jtag_reg_i bits instead? jtag_reg_o <= Count_o & StateCurrent & "00" & DoSleep & DoCapture_o & ClkDiv_o & StateReset_o & JTAGIgnoreTDO_o & Busy & JTAGEnable; -- let the world know if we are enabled jtag_en_o <= JTAGEnable; END ARCHITECTURE rtl;