You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			299 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			VHDL
		
	
			
		
		
	
	
			299 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			VHDL
		
	
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;
 | 
						|
 |