LIBRARY ieee;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;

LIBRARY altera_mf;
use altera_mf.altera_mf_components.sld_virtual_jtag;

LIBRARY work;
use work.utils_pkg.all;

ENTITY jtag_reg IS
	GENERIC 
	(
		INSTANCE_INDEX		: natural	:= 0;
		DATA_WIDTH			: natural	:= 8;		-- bits
		ADDR_WIDTH			: natural	:= 3		-- bits
	);
	PORT
	(
		rst					: in  std_logic;
		clk					: in  std_logic;
		addr_o				: out unsigned (ADDR_WIDTH-1 downto 0);
		reg_i				: in  unsigned (DATA_WIDTH-1 downto 0);
		reg_o				: out unsigned (DATA_WIDTH-1 downto 0);
		we_o				: out STD_LOGIC;
		re_o				: out STD_LOGIC
	);
	
END jtag_reg;

ARCHITECTURE tech_alt OF jtag_reg IS 

	signal jvi_clk			: STD_LOGIC;
	signal jvi_tdi			: STD_LOGIC;
	signal jvi_tdo			: STD_LOGIC;

	signal jvi_ir			: unsigned (ADDR_WIDTH downto 0);
	signal ir_reg			: unsigned (ADDR_WIDTH downto 0);

	signal jvi_virtual_uir		: STD_LOGIC;
	signal jvi_virtual_sdr		: STD_LOGIC;
	signal jvi_virtual_cdr		: STD_LOGIC;
	signal jvi_virtual_udr		: STD_LOGIC;
	
	constant NUM_REGS 			: natural := 2**ADDR_WIDTH;
	
	signal do_read				: STD_LOGIC;

	subtype reg_t is unsigned (DATA_WIDTH-1 downto 0);
	subtype addr_t is unsigned (ADDR_WIDTH-1 downto 0);

	signal addr					: addr_t;
	signal jvi_dr_dout_reg		: reg_t;
	signal jvi_dr_din_reg		: reg_t;

BEGIN

-- Virtual JTAG interface
inst_vjtag: component sld_virtual_jtag
	generic map
	(
		sld_auto_instance_index => "NO",
		sld_instance_index      => INSTANCE_INDEX,
		sld_ir_width            => ADDR_WIDTH+1,
		sld_sim_action          => "((00000064,1,00000000,00000004))",
		sld_sim_n_scan          => 1,
		sld_sim_total_length    => 8,
		lpm_type                => "sld_virtual_jtag",
		lpm_hint                => "sld_virtual_jtag"
	)
	port map
	(
		-- JTAG signals
		tck                => jvi_clk,
		tms                => open,
		tdo                => jvi_tdo,
		tdi                => jvi_tdi,

		-- Virtual instruction register
		unsigned(ir_in)			=> jvi_ir,
		ir_out					=> std_logic_vector(jvi_ir),
		virtual_state_uir		=> jvi_virtual_uir,
		virtual_state_cdr		=> jvi_virtual_cdr,
		virtual_state_sdr		=> jvi_virtual_sdr,
		virtual_state_udr		=> jvi_virtual_udr
	);

	jvi_tdo		<= jvi_dr_dout_reg(0);
	addr		<= jvi_ir(ADDR_WIDTH-1 downto 0);
	do_read		<= not jvi_ir(ADDR_WIDTH);
	
	addr_o		<= addr;
	reg_o		<= jvi_dr_din_reg;
	
proc_din_shift:
	process(jvi_clk)
	begin
		if rising_edge(jvi_clk) then
			if jvi_virtual_sdr = '1' then
				jvi_dr_din_reg		<= jvi_tdi & jvi_dr_din_reg(jvi_dr_din_reg'high downto 1);
			end if;
		end if;
	end process;		

proc_dout_shift:
	process(jvi_clk)
	begin
		if rising_edge(jvi_clk) then
			if jvi_virtual_sdr = '1' then
				jvi_dr_dout_reg					<= '0' & jvi_dr_dout_reg(jvi_dr_dout_reg'high downto 1);
			elsif do_read = '1' and jvi_virtual_cdr = '1' then
				jvi_dr_dout_reg					<= reg_i;
			end if;
		end if;
	end process;		
	
proc_sync_we_o:
	process(clk)
	variable p : unsigned(1 downto 0);
	begin
		if rising_edge(clk) then
			we_o <= p(0) and not p(1);
			p(1) := p(0);
			p(0) := not do_read and jvi_virtual_udr;
		end if;
	end process;		
	
proc_sync_re_o:
	process(clk)
	variable p : unsigned(1 downto 0);
	begin
		if rising_edge(clk) then
			re_o <= p(0) and not p(1);
			p(1) := p(0);
			p(0) := do_read and jvi_virtual_udr;
		end if;
	end process;		
	
end tech_alt;
