-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: The ROM file for use in your VHDL design
--
-- Copyright (C) 2007 J. Ahrensfeld
--
-- 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 3 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, see <http://www.gnu.org/licenses/>.
--
-- For questions and ideas, please contact the author at jens@jayfield.org
--
--------------------------------------------------------------------------

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

library UNISIM;
use UNISIM.VComponents.all;

ENTITY ram IS
	Port 
	(
		clk			: in  STD_LOGIC;
		ce			: in  STD_LOGIC;
		we			: in  unsigned(3 downto 0);
		addr		: in  unsigned(31 downto 0);
		din			: in  unsigned(31 downto 0);
		dout		: out unsigned(31 downto 0)
	);
END ram;

ARCHITECTURE behavior OF ram IS 

	COMPONENT dpram_2w2r
	Generic 
	(
		addr_width : integer;
		data_width : integer
	);
	Port
	(
		clk_a		: in  STD_LOGIC;
		clk_b		: in  STD_LOGIC;
		en_a		: in  STD_LOGIC;
		en_b		: in  STD_LOGIC;
		we_a		: in  STD_LOGIC;
		we_b		: in  STD_LOGIC;
		addr_a		: in  unsigned (addr_width-1 downto 0);
		addr_b		: in  unsigned (addr_width-1 downto 0);
		din_a		: in  unsigned (data_width-1 downto 0);
		din_b		: in  unsigned (data_width-1 downto 0);
		dout_a		: out unsigned (data_width-1 downto 0);
		dout_b		: out unsigned (data_width-1 downto 0)
	);
	END COMPONENT;
	
	signal jtag_clk		: STD_LOGIC;
	signal jtag_we		: unsigned(3 downto 0);
	signal jtag_addr	: unsigned (15 downto 0);
	signal jtag_dout	: unsigned (31 downto 0);
	signal jtag_din		: unsigned (31 downto 0);
	signal bs_rst, bs_sel, bs_shift, bs_tdi, bs_tdo : std_logic;
	signal bs_capture, bs_clk0, bs_clk1, bs_update0, bs_update1 : std_logic;
	signal user_regi, user_rego : unsigned (47 downto 0);
	
BEGIN

gen_sram:
	for i in 0 to 3 generate
	begin
	inst_dpram_2w2r : dpram_2w2r
		GENERIC MAP
		(
			addr_width	=> 11,
			data_width	=> 8
		)
		PORT MAP
		(
			clk_a		=> clk,
			en_a		=> ce,
			we_a		=> we(i),
			addr_a		=> addr(12 downto 2),
			din_a		=> din((i+1)*8-1 downto i*8),
			dout_a		=> dout((i+1)*8-1 downto i*8),

			clk_b		=> jtag_clk,
			en_b		=> jtag_we(i),
			we_b		=> jtag_we(i),
			addr_b		=> jtag_addr(10 downto 0),
			din_b		=> jtag_din((i+1)*8-1 downto i*8),
			dout_b		=> jtag_dout((i+1)*8-1 downto i*8)
		);
	end generate;
	
--------------------------------------------------------------------------
-- Virtex-4: JTAG Loader
--------------------------------------------------------------------------
	i00_BUFG : BUFG
	port map
	(
		O => bs_clk1,
        I => bs_clk0
	);
	
	i01_BUFG : BUFG
	port map
	(
		O => bs_update1,
        I => bs_update0
	);

	BSCAN_VIRTEX4_inst2 : BSCAN_VIRTEX4 
	generic map
	(
		JTAG_CHAIN => 2 -- Value to set BSCAN site of device. Possible values: (1,2,3 or 4)
	)
	port map 
	(
		CAPTURE => bs_capture, -- CAPTURE output from TAP controller
		DRCK => bs_clk0,       -- Data register output for USER functions
		RESET => bs_rst,       -- Reset output from TAP controller
		SEL => bs_sel,         -- USER active output
		SHIFT => bs_shift,     -- SHIFT output from TAP controller
		TDI => bs_tdi,        -- TDI output from TAP controller
		UPDATE => bs_update0,   -- UPDATE output from TAP controller
		TDO => bs_tdo         -- Data input for USER function
	);

	jtag_addr	<= user_regi(user_regi'left downto jtag_dout'length);
	jtag_din	<= user_regi(jtag_dout'length-1 downto 0);
	jtag_clk	<= bs_update1;
	jtag_we		<= (3 downto 0 => bs_sel);
	
sipo:
	process (bs_rst, bs_clk1, bs_tdi, bs_shift)
	begin
		if bs_rst = '1' then
			user_regi <= (others => '0');
		elsif rising_edge(bs_clk1) then
			if bs_shift = '1' then
				user_regi <= bs_tdi & user_regi(user_regi'left downto 1);
			end if;
		end if;
	end process;	

piso:
	process (bs_rst, bs_clk1, bs_shift, user_rego)
	begin
		bs_tdo <= user_rego(0);
		if bs_rst = '1' then
			user_rego <= (others => '0');
		elsif rising_edge(bs_clk1) then
			if bs_shift = '1' then
				user_rego <= user_rego(0) & user_rego(user_rego'left downto 1);
			else
				user_rego <= (user_rego'left downto jtag_dout'length => '0') & jtag_dout;	
			end if;
		end if;
	end process;	
	
--------------------------------------------------------------------------
end behavior;
