?? tag2.vhd
字號:
--
-- Copyright (C) 2003 by J. Kearney, Bolton, Massachusetts
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-- for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
library unisim;
use unisim.vcomponents.all;
entity JTAG_Controller is
generic
(NUM_TAPS : integer := 2;
NUM_BUFS : integer := 4);
port
(clk : in std_logic;
usb_d : inout std_logic_vector(7 downto 0);
usb_rd_n : buffer std_logic;
usb_wr : buffer std_logic;
usb_txe_n : in std_logic;
usb_rxf_n : in std_logic;
usb_si : out std_logic;
jtag_tck_A : out std_logic_vector(0 to NUM_TAPS-1);
jtag_tck_B : out std_logic_vector(0 to NUM_TAPS-1);
jtag_tck_fb : in std_logic_vector(0 to NUM_TAPS-1);
jtag_tdo : in std_logic_vector(0 to NUM_TAPS-1);
jtag_tdi_term : out std_logic_vector(0 to NUM_TAPS-1);
jtag_tdi : out std_logic_vector(0 to NUM_TAPS-1);
jtag_tms : out std_logic_vector(0 to NUM_TAPS-1);
jtag_trst_n : out std_logic_vector(0 to NUM_TAPS-1);
jtag_rst_n : out std_logic_vector(0 to NUM_TAPS-1);
jtag_dint : out std_logic_vector(0 to NUM_TAPS-1);
jtag_vgnd : out std_logic_vector(0 to 3);
LEDs : out std_logic_vector(3 downto 0);
jtag_extra : inout std_logic_vector(0 to 7);
reconfigure : out std_logic);
attribute clock_buffer : string;
attribute clock_buffer of jtag_tck_fb : signal is "ibufg";
attribute clock_buffer of usb_rxf_n : signal is "ibuf";
attribute clock_buffer of usb_txe_n : signal is "ibuf";
end JTAG_Controller;
architecture RTL of JTAG_Controller is
constant DEBUG : boolean := false;
-- Action Commands (msb of received byte is '0', this code is in b6..b4).
subtype JCCMD is std_logic_vector(2 downto 0);
constant CMD_SETCURTAP : JCCMD := "000"; -- new current TAP is in b3..0
constant CMD_GETSTATUS : JCCMD := "001"; -- return status byte (see below)
constant CMD_WRBUF : JCCMD := "010"; -- write to current output buffer using COUNT and ADDR (*)
constant CMD_RDBUF : JCCMD := "011"; -- read from input buffer using COUNT and ADDR (*)
constant CMD_RUN : JCCMD := "100"; -- start TAP cycle (see below)
constant CMD_COPY : JCCMD := "101"; -- copy input buffer to current
-- output buffer ADDR..ADDR+COUNT-1
constant CMD_DELAY : JCCMD := "110"; -- delay COUNT+(8192-ADDR)*8191 USB cycles (62.5ns)
-- If msb is '1', b6..b4 are register number, b3..b0 are high 4 bits to
-- put in that register and next received byte is low 8 bits.
-- registers are 12 bits each
constant GLOBAL: integer := 0; -- global configuration settings
constant COUNT : integer := 1; -- number of bytes to transfer to/from buffer
constant TMS : integer := 2; -- tms data (*1)
constant BITS : integer := 3; -- length of vector in bits
constant ADDR : integer := 4; -- offset into buffer
-- reg 5 unused, next two are mapped to 6 and 7
constant CONFIG1: integer := 0; -- settings, on a per-TAP basis
constant CONFIG2: integer := 1; -- settings, on a per-TAP basis
subtype JCRegister is unsigned(11 downto 0);
type JCRegFile is array(GLOBAL to ADDR) of JCRegister;
type JCSetupRegFile is array(CONFIG1 to CONFIG2) of JCRegister;
-- GLOBAL reg:
-- b0..3 LEDs (1=on)
-- b11..8 reconfigure when = 1001
-- CONFIG1 reg:
-- b0 output enable jtag_extra(0)
-- b1 output value jtag_extra(1)
-- b2..b7 same for jtag_extra(1..3)
-- b9 TDO termination on
-- b10 TCK termination A on
-- b11 TCK termination B on
-- CONFIG2 reg:
-- b3..0 clock setting
-- 0000 => 48, 32, 24, 16, 12, 8, 6, 4, 3, 2, 1.5, 1, 0.75, 0.5, 0.375, 0.25 MHz
-- b6..4 current output buffer assignment
-- b7 tristated
-- b8 rst (active low)
-- b9 trst (active low)
-- b10 dint (active high)
-- b11 free-running TCK mode
-- CMD_GETSTATUS returns: (specific to current TAP)
-- b0 running
-- b1 DLLs locked
-- b4..7 values at jtag_extra() pins
-- CMD_RUN takes:
-- b0 1=>store tdi into input buffer, else unchanged
-- b1 1=>output tdo from output buffer, else '0'
-- b2 1=>raise TMS on last bit
-- register BITS determines how many tck pulses there will be
-- register TMS contains the bit pattern to be put on TMS. The last bit will be repeated
-- if BITS is greater than 12.
-- These registers can be changed any time after CMD_RUN is issued
-- Timing:
-- With a 48 MHz clock, the USB state machine cycle is 62.5 ns.
-- This means that each byte of a command will take 125 ns,
-- and any additional bytes sent or received 125 ns each.
-- E.g. a register set command
-- will take 250 ns, exclusive of any USB latency.
-- A couple of special cases:
-- CMD_RUN will finish when the TAP state machine starts, which depends on the
-- TAP clock speed.
-- CMD_DELAY will take 125+62.5*(COUNT+8191*(8192-ADDR)) ns
-- Note (*) - bit ordering follows Xilinx convention of lsb being first bit shifted out or in
-- attributes used
attribute clock_signal : string;
attribute clkdv_divide : string;
-- components used
component Sync is
Port ( RESET : in std_logic;
REQ : in std_logic;
ACK : in std_logic;
STATUS : buffer std_logic);
end component;
-- signals
signal reset : std_logic;
signal clk_2 : std_logic; -- 96 MHz
signal clk_1_5 : std_logic; -- 64 MHz
signal clk_lock_1, clk_lock_2 : std_logic; -- DLLs locked
signal usb_clk : std_logic; -- 16 MHz
signal jtag_clk: std_logic_vector(0 to NUM_TAPS-1);-- selected tck freq
attribute clock_signal of usb_clk : signal is "true";
type CmdStates is
(Idle,
GetAck,
GetAck_wait,
PutCmd,
PutLow_wait,
PutLow,
PutLowT_wait,
PutLowT,
PutBuf_wait,
PutBuf,
GetStatus_wait,
GetStatus,
GetBuf_wait,
GetBuf,
RunStart,
RunAck,
Copy1,
Copy2,
Delay);
signal cmd_state : CmdStates;
attribute fsm_encoding : string;
attribute fsm_encoding of cmd_state : signal is "sequential";
signal cur_tap : integer range 0 to NUM_TAPS-1;
signal want_tdi, want_tdo, want_pingTMS: boolean;
signal cur_reg : integer range JCRegFile'range;
signal cur_setup_reg : integer range JCSetupRegFile'range;
signal reading_buf, reading_status, reading_ack: boolean;
signal ack_code: std_logic_vector(7 downto 0);
signal reg : JCRegFile;
type JCSetupRegs is array(0 to NUM_TAPS-1) of JCSetupRegFile;
signal setup_reg: JCSetupRegs;
-- TCK feedback
signal tck_fb: std_logic_vector(NUM_TAPS-1 downto 0);
-- buffer signals from the TAP side
subtype BVAddr is unsigned(11 downto 0); -- 4096x1
type TAPAddrs is array(0 to NUM_TAPS-1) of BVAddr;
signal TAP_rd_addr, TAP_wr_addr : TAPAddrs;
signal done_flagged,
done_ack,
TAP_rd_data,
TAP_rd_clk,
TAP_wr_data,
TAP_wr_store,
TAP_wr_clk,
TAP_start,
TAP_ack,
TAP_busy : std_logic_vector(0 to NUM_TAPS-1);
-- buffer signals from the USB side
subtype BFAddr is unsigned(8 downto 0); -- 512x8
type BFDatas is array(0 to NUM_TAPS-1) of std_logic_vector(7 downto 0);
signal Buf_rd_data : BFDatas;
-- synchronized USB signals
signal sync_rd : std_logic;
begin
jtag_vgnd <= (others => '0');
debug_output: if DEBUG generate
signal xstate : std_logic_vector(0 to 4);
begin
xstate <= std_logic_vector(to_unsigned(CmdStates'pos(cmd_state), 5));
jtag_extra(0 to 4) <= xstate;
jtag_extra(5) <= sync_rd;
jtag_extra(6) <= '0';
jtag_extra(7) <= usb_clk;
end generate;
--===========================================================================
-- Reset
--===========================================================================
-- We use built-in 'reset on configure' component so that the VHDL can be
-- coded with explicit resets. This is really the built-in startup logic,
-- so no extra circuitry is generated.
-----------------------------------------------------------------------------
global_reset: ROC port map (O => reset);
--===========================================================================
-- Clock Generation
--===========================================================================
-- 96 Mhz, 64 Mhz and 16 MHz clocks are generated from the input 48 MHz clock
-- here.
-----------------------------------------------------------------------------
global_clk_gen: if true generate
attribute clkdv_divide of clk_div_1_5 : label is "1.5";
signal clk_int, clk_2_int, clk_2_fb : std_logic;
signal dll2, dll2fb, rst2 : std_logic;
signal usb_clk_int : std_logic;
signal usb_clk_div : unsigned(1 downto 0);
begin
-- if we need the BUFG's, 2x and /1.5 could be done in logic -
-- see XCell and TechXclusives on Xilinx website.
clkpad : IBUFG port map (I => clk, O => clk_int);
-- generate 96 MHz clock
clk_dll: CLKDLL
port map (RST => reset,
CLKIN => clk_int, CLK2X => clk_2_int, CLKFB => clk_2,
LOCKED => clk_lock_1);
clk2fb: BUFG port map (I => clk_2_int, O => clk_2);
-- hold 2nd DLL in reset until the 1st is locked
rst2 <= not clk_lock_1;
-- generate 64 MHz clock
clk_div_1_5: CLKDLLHF
port map (RST => rst2,
CLKIN => clk_2, CLK0 => dll2, CLKFB => dll2fb,
CLKDV => clk_1_5, LOCKED => clk_lock_2);
dll_fb: BUFG port map (I => dll2, O => dll2fb);
-- divide 72 MHz downto 16MHz - get 62.5 ns period clock used for communicating with the
-- FT245BM, which wants >= 50 ns pulses for RD and WR.
process (reset, clk_1_5)
begin
if reset = '1' then
usb_clk_div <= (others => '0');
elsif rising_edge(clk_1_5) then
usb_clk_div <= usb_clk_div + 1;
end if;
end process;
-- put the usb clock onto a clock net
usb_clk_buf: BUFG
port map (I => usb_clk_div(usb_clk_div'high), O => usb_clk);
end generate;
--===========================================================================
-- Global Configuration register
--===========================================================================
-- global feature selects
-----------------------------------------------------------------------------
--LEDs <= std_logic_vector(not reg(GLOBAL)(3 downto 0));
LEDs(3) <= '0' when (reg(GLOBAL)(3) = '1') or (cmd_state = IDle) else '1';
LEDs(2) <= '0' when (reg(GLOBAL)(2) = '1') or (cmd_state = Delay) else '1';
LEDs(1) <= '0' when (reg(GLOBAL)(1) = '1') or (TAP_busy(0) = '1') else '1';
LEDs(0) <= '0' when (reg(GLOBAL)(0) = '1') or (TAP_busy(1) = '1') else '1';
reconfigure <= '0' when reg(GLOBAL)(11 downto 8) = "1001" else 'Z';
--===========================================================================
-- USB command state machine
--===========================================================================
-- this state machine controls all communications with the USB interface,
-- and command decoding and execution.
-----------------------------------------------------------------------------
-- async process to write data to USB data bus
process (reading_buf, reading_status, reading_ack,
cur_tap, Buf_rd_data, jtag_extra, ack_code)
begin
if reading_status then
usb_d(0) <= TAP_busy(cur_tap); -- doing TAP run?
usb_d(1) <= '1'; -- clocks locked?
usb_d(2) <= '0';
usb_d(3) <= '0';
if DEBUG then
usb_d(7 downto 4) <= (others => '0');
else
extra_rd: for idx in 0 to 3 loop
usb_d(idx+4) <= jtag_extra(cur_tap*4+idx);
end loop;
end if;
elsif reading_buf then
usb_d <= Buf_rd_data(cur_tap);
elsif reading_ack then
usb_d <= ack_code;
else
usb_d <= (others => 'Z');
end if;
end process;
-- handshake USB RXF with RD - data available when sync_rd is set
hs_rd: Sync port map
(RESET => reset, REQ => not usb_rxf_n, ACK => usb_rd_n, STATUS => sync_rd);
-- track done statusi
dones: for cur in 0 to NUM_TAPS-1 generate
begin
doneflag: Sync port map
(RESET => reset, REQ => not TAP_busy(cur),
ACK => done_ack(cur), STATUS => done_flagged(cur));
end generate;
-- generate usb_rd_n and usb_wr
process (reset, cmd_state)
begin
if reset = '1' then
usb_rd_n <= '1';
usb_wr <= '0';
else
case cmd_state is
when PutCmd | PutLow | PutLowT | PutBuf =>
usb_rd_n <= '0';
usb_wr <= '0';
when GetStatus | GetBuf | GetAck =>
usb_rd_n <= '1';
usb_wr <= '1';
when others =>
usb_rd_n <= '1';
usb_wr <= '0';
end case;
end if;
end process;
-- generate usb_si
usb_si <= '0' when cmd_state = Idle else '1';
-- sync process manages all USB communication and executes commands
process (clk_lock_2, usb_clk, usb_d, sync_rd, usb_txe_n)
variable reg_num : integer;
variable acking : boolean;
begin
if clk_lock_2 = '0' then -- indirect result of reset
cmd_state <= Idle;
cur_tap <= 0;
TAP_start <= (others => '0');
reading_status <= false;
reading_buf <= false;
reading_ack <= false;
done_ack <= (others => '0');
-- init registers all to 0
for idx in reg'left to reg'right loop
reg(idx) <= (others => '0');
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -