-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: cpu_embedded using cpu_core and rom
--
-- 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;

use work.fifo_ctrl_pkg.all;
use work.sdram_config.all;
use work.sdram_types.all;

entity tb_sdr_ctrl_fifo is
end;

architecture struct of tb_sdr_ctrl_fifo is

	-- Number of user data words for simulation
	constant CLK_PERIOD		: time := 10 ns;
	constant BURST_LEN		: natural := 2;

	signal rst				: std_logic := '1';  
	signal clk				: std_logic := '0';  
	signal rst_out			: std_logic;  
	signal clk_out			: std_logic;  
	signal clk_fb			: std_logic;  
	signal part_clk_p		: std_logic;  
	signal part_clk_n		: std_logic;  
	signal part_cke			: std_logic;  
	signal part_cs_n		: std_logic;  
	signal part_we_n		: std_logic;  
	signal part_ras_n		: std_logic;  
	signal part_cas_n		: std_logic;  
	signal part_ba			: unsigned(DDR_BANK_WIDTH-1 downto 0) := (others => '0');
	signal part_dm			: unsigned(DDR_DM_WIDTH-1 downto 0) := (others => '0');
	signal part_dqs			: unsigned(DDR_DQS_WIDTH-1 downto 0) := (others => '0');
	signal part_addr		: unsigned(DDR_ADDR_WIDTH-1 downto 0) := (others => '0');
	signal part_data		: unsigned(DDR_DATA_WIDTH-1 downto 0) := (others => '0');

	signal u_addr			: user_addr_t := (others => '0');
	signal u_tag_in			: user_tag_t := "0000";
	signal u_tag_rd			: user_tag_t;
	signal u_tag_wr			: user_tag_t;
	signal u_cmd			: user_cmd_t := UCMD_NOP;
	signal u_cmd_we			: std_logic := '0';
	signal u_busy			: std_logic;
	signal u_data_w			: unsigned(2*DDR_DATA_WIDTH-1 downto 0) := (others => '0');
	signal u_dm				: unsigned(2*DDR_DM_WIDTH-1 downto 0) := "0000";
	signal u_dm_rd_in		: unsigned(2*DDR_DM_WIDTH-1 downto 0) := "0000";
	signal u_dm_rd_out		: unsigned(2*DDR_DM_WIDTH-1 downto 0) := "0000";
	signal u_data_r			: unsigned(2*DDR_DATA_WIDTH-1 downto 0) := (others => '0');
	signal u_data_vld		: std_logic;
	signal u_req_wr			: std_logic;
	signal u_req_rd			: std_logic;
	signal u_read_en		: std_logic := '0';
	signal u_write_en		: std_logic := '0';

	signal cmd_fifo_din				: unsigned(25 downto 0) := (others => '0');
	signal cmd_fifo_dout			: unsigned(25 downto 0) := (others => '0');
	signal cmd_fifo_re				: std_logic := '0';
	signal cmd_fifo_we				: std_logic := '0';
	signal cmd_fifo_full			: std_logic := '0';
	signal cmd_fifo_empty			: std_logic := '0';
	signal cmd_fifo_almost_full		: std_logic := '0';
	signal cmd_fifo_almost_empty	: std_logic := '0';

	signal write_fifo_din			: unsigned(2*DDR_DATA_WIDTH-1 downto 0) := (others => '0');
	signal write_fifo_dout			: unsigned(2*DDR_DATA_WIDTH-1 downto 0) := (others => '0');
	signal write_fifo_re			: std_logic := '0';
	signal write_fifo_we			: std_logic := '0';
	signal write_fifo_full			: std_logic := '0';
	signal write_fifo_empty			: std_logic := '0';
	signal write_fifo_almost_full	: std_logic := '0';
	signal write_fifo_almost_empty	: std_logic := '0';

	signal read_fifo_din			: unsigned(2*DDR_DATA_WIDTH-1 downto 0) := (others => '0');
	signal read_fifo_dout			: unsigned(2*DDR_DATA_WIDTH-1 downto 0) := (others => '0');
	signal read_fifo_re				: std_logic := '0';
	signal read_fifo_we				: std_logic := '0';
	signal read_fifo_full			: std_logic := '0';
	signal read_fifo_empty			: std_logic := '0';
	signal read_fifo_almost_full	: std_logic := '0';
	signal read_fifo_almost_empty	: std_logic := '0';

	signal write_start	: std_logic := '1';
	signal read_start	: std_logic := '1';
	
	alias cmd_fifo_in is cmd_fifo_din(25 downto 24);
	alias addr_fifo_in is cmd_fifo_din(23 downto 0);
	alias cmd_fifo_out is cmd_fifo_dout(25 downto 24);
	alias addr_fifo_out is cmd_fifo_dout(23 downto 0);
	
begin 
   
	clk_fb	<= part_clk_p after 1 ns;

	-- Instantiate synchronous FIFO
	inst_command_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width	=> 8,
		data_width	=> 2+24
	)
	PORT MAP
	(
		rst			=>	rst_out,
		clk			=>	clk_out,
		we			=>	cmd_fifo_we,
		re			=>	cmd_fifo_re,
		fifo_full	=>	cmd_fifo_full,
		fifo_empty	=>	cmd_fifo_empty,
		fifo_afull	=>	cmd_fifo_almost_full,
		fifo_aempty	=>	cmd_fifo_almost_empty,
		data_w		=>  cmd_fifo_din,
		data_r		=>  cmd_fifo_dout
	);

	-- Instantiate synchronous FIFO
	inst_write_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width	=> 8,
		data_width	=> 2*DDR_DATA_WIDTH
	)
	PORT MAP
	(
		rst			=>	rst_out,
		clk			=>	clk_out,
		we			=>	write_fifo_we,
		re			=>	write_fifo_re,
		fifo_full	=>	write_fifo_full,
		fifo_empty	=>	write_fifo_empty,
		fifo_afull	=>	write_fifo_almost_full,
		fifo_aempty	=>	write_fifo_almost_empty,
		data_w		=>  write_fifo_din,
		data_r		=>  write_fifo_dout
	);

	-- Instantiate synchronous FIFO
	inst_read_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width	=> 8,
		data_width	=> 2*DDR_DATA_WIDTH
	)
	PORT MAP
	(
		rst			=>	rst_out,
		clk			=>	clk_out,
		we			=>	read_fifo_we,
		re			=>	read_fifo_re,
		fifo_full	=>	read_fifo_full,
		fifo_empty	=>	read_fifo_empty,
		fifo_afull	=>	read_fifo_almost_full,
		fifo_aempty	=>	read_fifo_almost_empty,
		data_w		=>  read_fifo_din,
		data_r		=>  read_fifo_dout
	);

	-- DDR SDRAM Controller Core
	inst_sdram_ctrl : entity work.sdram_ctrl_top
	Generic map
	(
		BL 				=> BURST_LEN,
		read_phaseshift => 0,
		f_sysclk 		=> 100E6
	)
	Port map
	(
	
		sys_rst_in			=> rst,
		sys_clk_in			=> clk,

		sys_rst_out			=> rst_out,
		sys_clk_out			=> clk_out,
		sys_clk_fb			=> clk_fb,
		
		-- User interface
		u_data_vld			=> u_data_vld,
		u_data_req_w		=> u_req_wr,
		u_data_req_r		=> u_req_rd,
		u_tag_in			=> u_tag_in,
		u_tag_rd			=> u_tag_rd,
		u_tag_wr			=> u_tag_wr,
		u_busy				=> u_busy,
		u_addr				=> u_addr,
		u_cmd				=> u_cmd,
		u_cmd_we			=> u_cmd_we,
		u_data_wr			=> u_data_w,
		u_data_rd			=> u_data_r,
		u_dm_wr_in			=> u_dm,
		u_dm_rd_in			=> u_dm_rd_in,
		u_dm_rd_out			=> u_dm_rd_out,
		
		-- SDRAM signals
		sd_clk_p			=> part_clk_p,
		sd_clk_n			=> part_clk_n,
		sd_cke				=> part_cke,
		sd_cs_n				=> part_cs_n,
		sd_cas_n			=> part_cas_n,
		sd_ras_n			=> part_ras_n,
		sd_we_n				=> part_we_n,
		sd_addr				=> part_addr,
		sd_ba				=> part_ba,
		sd_dm				=> part_dm,
		sd_dqs				=> part_dqs,
		sd_data				=> part_data
		
	);
   
   -- MICRON DDR SDRAM Simulation Model
   i_mt46v16m16_0 : entity work.mt46v16m16 
      port map (
         dq    => std_logic_vector(part_data),
         dqs   => std_logic_vector(part_dqs),
         addr  => std_logic_vector(part_addr),
         ba    => std_logic_vector(part_ba),
         clk   => part_clk_p,
         clk_n => part_clk_n,
         cke   => part_cke,
         cs_n  => part_cs_n,
         ras_n => part_ras_n,
         cas_n => part_cas_n,
         we_n  => part_we_n,
         dm    => std_logic_vector(part_dm)
	);

CLK_GEN: process
	begin
		wait for CLK_PERIOD/2;
		clk <= not clk;
	end process;

------------------------------------------------------------------------------------------
	u_cmd_we		<= (not cmd_fifo_empty) and write_start and (not u_busy);
	u_cmd			<= cmd_fifo_out;
	u_addr			<= addr_fifo_out;

	write_fifo_re	<= u_req_wr and (not write_fifo_empty);
	cmd_fifo_re		<= u_cmd_we;
	u_data_w		<= write_fifo_dout;
	read_fifo_re 	<= (not read_fifo_empty) and read_start;
	read_fifo_we	<= u_data_vld;
	read_fifo_din	<= u_data_r;	

	process
	begin
         
	-- Write MAX_WORDS to DDR SDRAM Controller
	wait for 4*CLK_PERIOD;
	rst <= '0';

	wait for 4*CLK_PERIOD;
	wait until rising_edge(clk_out) and rst_out='0';


	write_fifo_we <= '1';
	cmd_fifo_we	<= '1';
	write_fifo_din <= X"01020304";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000000";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"05060708";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000002";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"00001111";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000004";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"22223333";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000006";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"44445555";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000008";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"66667777";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"00000a";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"88889999";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"00000c";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"AAAABBBB";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"00000e";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"CCCCDDDD";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000010";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"EEEEFFFF";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000012";

	wait until rising_edge(clk_out);
	write_fifo_we <= '0';
	cmd_fifo_we <= '0';
	
--	wait until rising_edge(clk_out) and u_busy='0';
--	write_start <= '1';
--	wait until rising_edge(clk_out) and write_fifo_empty='1';

	write_fifo_we <= '1';
	cmd_fifo_we	<= '1';
	write_fifo_din <= X"01234567";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000014";

	wait until rising_edge(clk_out);
	write_fifo_we <= '0';
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"000014";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"89ABCDEF";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000016";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"11223344";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000018";

	wait until rising_edge(clk_out);
	write_fifo_we <= '0';
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"000010";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"55667788";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"00001a";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"99990000";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"00001c";

	wait until rising_edge(clk_out);
	write_fifo_we <= '1';
	write_fifo_din <= X"AAAA5555";
	cmd_fifo_in <= UCMD_WRITE;
	addr_fifo_in <= X"000020";

	wait until rising_edge(clk_out);
	write_fifo_we <= '0';
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"000000";

	wait until rising_edge(clk_out);
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"000018";

	wait until rising_edge(clk_out);
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"00001A";

	wait until rising_edge(clk_out);
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"00001C";

	wait until rising_edge(clk_out);
	cmd_fifo_in <= UCMD_READ;
	addr_fifo_in <= X"000020";

	wait until rising_edge(clk_out);
	write_fifo_we <= '0';
	cmd_fifo_we <= '0';

	wait for 40*CLK_PERIOD;
	read_start <= '1';
	wait;
	
	end process;
	
end architecture struct;
