--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.math_real.all;
+
+library work;
+use work.wishbone_types.all;
+
+entity dmi_dtm is
+ generic(ABITS : INTEGER:=8;
+ DBITS : INTEGER:=64);
+
+ port(sys_clk : in std_ulogic;
+ sys_reset : in std_ulogic;
+ dmi_addr : out std_ulogic_vector(ABITS - 1 downto 0);
+ dmi_din : in std_ulogic_vector(DBITS - 1 downto 0);
+ dmi_dout : out std_ulogic_vector(DBITS - 1 downto 0);
+ dmi_req : out std_ulogic;
+ dmi_wr : out std_ulogic;
+ dmi_ack : in std_ulogic
+-- dmi_err : in std_ulogic TODO: Add error response
+ );
+end entity dmi_dtm;
+
+architecture behaviour of dmi_dtm is
+ -- Signals coming out of the JTAGG block
+ signal jtag_reset_n : std_ulogic;
+ signal tdi : std_ulogic;
+ signal tdo : std_ulogic;
+ signal tck : std_ulogic;
+ signal jce1 : std_ulogic;
+ signal jshift : std_ulogic;
+ signal update : std_ulogic;
+
+ -- signals to match dmi_dtb_xilinx
+ signal jtag_reset : std_ulogic;
+ signal capture : std_ulogic;
+ signal jtag_clk : std_ulogic;
+ signal sel : std_ulogic;
+ signal shift : std_ulogic;
+
+ -- delays
+ signal jce1_d : std_ulogic;
+ constant TCK_DELAY : INTEGER := 8;
+ signal tck_d : std_ulogic_vector(TCK_DELAY+1 downto 1);
+
+ -- ** JTAG clock domain **
+
+ -- Shift register
+ signal shiftr : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
+
+ -- Latched request
+ signal request : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
+
+ -- A request is present
+ signal jtag_req : std_ulogic;
+
+ -- Synchronizer for jtag_rsp (sys clk -> jtag_clk)
+ signal dmi_ack_0 : std_ulogic;
+ signal dmi_ack_1 : std_ulogic;
+
+ -- ** sys clock domain **
+
+ -- Synchronizer for jtag_req (jtag clk -> sys clk)
+ signal jtag_req_0 : std_ulogic;
+ signal jtag_req_1 : std_ulogic;
+
+ -- ** combination signals
+ signal jtag_bsy : std_ulogic;
+ signal op_valid : std_ulogic;
+ signal rsp_op : std_ulogic_vector(1 downto 0);
+
+ -- ** Constants **
+ constant DMI_REQ_NOP : std_ulogic_vector(1 downto 0) := "00";
+ constant DMI_REQ_RD : std_ulogic_vector(1 downto 0) := "01";
+ constant DMI_REQ_WR : std_ulogic_vector(1 downto 0) := "10";
+ constant DMI_RSP_OK : std_ulogic_vector(1 downto 0) := "00";
+ constant DMI_RSP_BSY : std_ulogic_vector(1 downto 0) := "11";
+
+ attribute ASYNC_REG : string;
+ attribute ASYNC_REG of jtag_req_0: signal is "TRUE";
+ attribute ASYNC_REG of jtag_req_1: signal is "TRUE";
+ attribute ASYNC_REG of dmi_ack_0: signal is "TRUE";
+ attribute ASYNC_REG of dmi_ack_1: signal is "TRUE";
+
+ -- ECP5 JTAGG
+ component JTAGG is
+ generic (
+ ER1 : string := "ENABLED";
+ ER2 : string := "ENABLED"
+ );
+ port(
+ JTDO1 : in std_ulogic;
+ JTDO2 : in std_ulogic;
+ JTDI : out std_ulogic;
+ JTCK : out std_ulogic;
+ JRTI1 : out std_ulogic;
+ JRTI2 : out std_ulogic;
+ JSHIFT : out std_ulogic;
+ JUPDATE : out std_ulogic;
+ JRSTN : out std_ulogic;
+ JCE1 : out std_ulogic;
+ JCE2 : out std_ulogic
+ );
+ end component;
+
+ component LUT4 is
+ generic (
+ INIT : std_logic_vector
+ );
+ port(
+ A : in STD_ULOGIC;
+ B : in STD_ULOGIC;
+ C : in STD_ULOGIC;
+ D : in STD_ULOGIC;
+ Z : out STD_ULOGIC
+ );
+ end component;
+
+begin
+
+ jtag: JTAGG
+ generic map(
+ ER2 => "DISABLED"
+ )
+ port map (
+ JTDO1 => tdo,
+ JTDO2 => '0',
+ JTDI => tdi,
+ JTCK => tck,
+ JRTI1 => open,
+ JRTI2 => open,
+ JSHIFT => jshift,
+ JUPDATE => update,
+ JRSTN => jtag_reset_n,
+ JCE1 => jce1,
+ JCE2 => open
+ );
+
+ -- JRTI1 looks like it could be connected to SEL, but
+ -- in practise JRTI1 is only high briefly, not for the duration
+ -- of the transmission. possibly mw_debug could be modified.
+ -- The ecp5 is probably the only jtag device anyway.
+ sel <= '1';
+
+ -- TDI needs to align with TCK, we use LUT delays here.
+ -- From https://github.com/enjoy-digital/litex/pull/1087
+ tck_d(1) <= tck;
+ del: for i in 1 to TCK_DELAY generate
+ attribute keep : boolean;
+ attribute keep of l: label is true;
+ begin
+ l: LUT4
+ generic map(
+ INIT => b"0000_0000_0000_0010"
+ )
+ port map (
+ A => tck_d(i),
+ B => '0', C => '0', D => '0',
+ Z => tck_d(i+1)
+ );
+ end generate;
+ jtag_clk <= tck_d(TCK_DELAY+1);
+
+ -- capture signal
+ jce1_sync : process(jtag_clk)
+ begin
+ if rising_edge(jtag_clk) then
+ jce1_d <= jce1;
+ capture <= jce1 and not jce1_d;
+ end if;
+ end process;
+
+ -- latch the shift signal, otherwise
+ -- we miss the last shift in
+ -- (maybe because we are delaying tck?)
+ shift_sync : process(jtag_clk)
+ begin
+ if (sys_reset = '1') then
+ shift <= '0';
+ elsif rising_edge(jtag_clk) then
+ shift <= jshift;
+ end if;
+ end process;
+
+ jtag_reset <= not jtag_reset_n;
+
+ -- dmi_req synchronization
+ dmi_req_sync : process(sys_clk)
+ begin
+ -- sys_reset is synchronous
+ if rising_edge(sys_clk) then
+ if (sys_reset = '1') then
+ jtag_req_0 <= '0';
+ jtag_req_1 <= '0';
+ else
+ jtag_req_0 <= jtag_req;
+ jtag_req_1 <= jtag_req_0;
+ end if;
+ end if;
+ end process;
+ dmi_req <= jtag_req_1;
+
+ -- dmi_ack synchronization
+ dmi_ack_sync: process(jtag_clk, jtag_reset)
+ begin
+ -- jtag_reset is async (see comments)
+ if jtag_reset = '1' then
+ dmi_ack_0 <= '0';
+ dmi_ack_1 <= '0';
+ elsif rising_edge(jtag_clk) then
+ dmi_ack_0 <= dmi_ack;
+ dmi_ack_1 <= dmi_ack_0;
+ end if;
+ end process;
+
+ -- jtag_bsy indicates whether we can start a new request, we can when
+ -- we aren't already processing one (jtag_req) and the synchronized ack
+ -- of the previous one is 0.
+ --
+ jtag_bsy <= jtag_req or dmi_ack_1;
+
+ -- decode request type in shift register
+ with shiftr(1 downto 0) select op_valid <=
+ '1' when DMI_REQ_RD,
+ '1' when DMI_REQ_WR,
+ '0' when others;
+
+ -- encode response op
+ rsp_op <= DMI_RSP_BSY when jtag_bsy = '1' else DMI_RSP_OK;
+
+ -- Some DMI out signals are directly driven from the request register
+ dmi_addr <= request(ABITS + DBITS + 1 downto DBITS + 2);
+ dmi_dout <= request(DBITS + 1 downto 2);
+ dmi_wr <= '1' when request(1 downto 0) = DMI_REQ_WR else '0';
+
+ -- TDO is wired to shift register bit 0
+ tdo <= shiftr(0);
+
+ -- Main state machine. Handles shift registers, request latch and
+ -- jtag_req latch. Could be split into 3 processes but it's probably
+ -- not worthwhile.
+ --
+ shifter: process(jtag_clk, jtag_reset, sys_reset)
+ begin
+ if jtag_reset = '1' or sys_reset = '1' then
+ shiftr <= (others => '0');
+ jtag_req <= '0';
+ request <= (others => '0');
+ elsif rising_edge(jtag_clk) then
+
+ -- Handle jtag "commands" when sel is 1
+ if sel = '1' then
+ -- Shift state, rotate the register
+ if shift = '1' then
+ shiftr <= tdi & shiftr(ABITS + DBITS + 1 downto 1);
+ end if;
+
+ -- Update state (trigger)
+ --
+ -- Latch the request if we aren't already processing one and
+ -- it has a valid command opcode.
+ --
+ if update = '1' and op_valid = '1' then
+ if jtag_bsy = '0' then
+ request <= shiftr;
+ jtag_req <= '1';
+ end if;
+ -- Set the shift register "op" to "busy". This will prevent
+ -- us from re-starting the command on the next update if
+ -- the command completes before that.
+ shiftr(1 downto 0) <= DMI_RSP_BSY;
+ end if;
+
+ -- Request completion.
+ --
+ -- Capture the response data for reads and clear request flag.
+ --
+ -- Note: We clear req (and thus dmi_req) here which relies on tck
+ -- ticking and sel set. This means we are stuck with dmi_req up if
+ -- the jtag interface stops. Slaves must be resilient to this.
+ --
+ if jtag_req = '1' and dmi_ack_1 = '1' then
+ jtag_req <= '0';
+ if request(1 downto 0) = DMI_REQ_RD then
+ request(DBITS + 1 downto 2) <= dmi_din;
+ end if;
+ end if;
+
+ -- Capture state, grab latch content with updated status
+ if capture = '1' then
+ shiftr <= request(ABITS + DBITS + 1 downto 2) & rsp_op;
+ end if;
+
+ end if;
+ end if;
+ end process;
+end architecture behaviour;
+