-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: testbench for system test using Xilinx ML-402

-- Copyright (C) 2007 J. Ahrensfeld

-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.

-- This library 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
-- Lesser General Public License for more details.

-- You should have received a copy of the GNU Lesser General Public
-- License along with this library; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

-- 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;

ENTITY tb_serdes IS
END tb_serdes;

ARCHITECTURE behavior OF tb_serdes IS 

	constant CLK_PERIOD		: time := 10 ns;

	signal CLK				: std_logic := '1';
	signal RST				: std_logic := '1';

	signal piso_din_vld		: std_logic := '0';
	signal piso_din_re		: std_logic;
	signal piso_din_be		: unsigned(3 downto 0) := (others => '0');
	signal piso_din			: unsigned(31 downto 0) := (others => '-');
	signal piso_dout_vld	: std_logic;
	signal piso_dout		: unsigned(7 downto 0);
	signal piso_shift_en	: std_logic;

	signal piso2_din_vld	: std_logic := '0';
	signal piso2_din_re		: std_logic;
	signal piso2_din_be		: unsigned(1 downto 0) := (others => '1');
	signal piso2_din		: unsigned(7 downto 0) := (others => '-');
	signal piso2_dout_vld	: std_logic;
	signal piso2_dout		: unsigned(3 downto 0);
	signal piso2_shift_en	: std_logic;

	signal sipo_enable		: std_logic := '0';
	signal sipo_rst			: std_logic := '0';
	signal sipo_din_vld		: std_logic := '0';
	signal sipo_din			: unsigned(7 downto 0) := (others => '-');
	signal sipo_dout_vld	: std_logic;
	signal sipo_shift_en	: std_logic;
	signal sipo_dout_be		: unsigned(3 downto 0);
	signal sipo_dout		: unsigned(31 downto 0);

	signal sipo2_enable		: std_logic := '0';
	signal sipo2_rst		: std_logic := '0';
	signal sipo2_din_vld	: std_logic := '0';
	signal sipo2_din		: unsigned(3 downto 0) := (others => '-');
	signal sipo2_dout_vld	: std_logic;
	signal sipo2_shift_en	: std_logic;
	signal sipo2_dout_be	: unsigned(1 downto 0);
	signal sipo2_dout		: unsigned(7 downto 0);

	
BEGIN

inst_piso : entity work.piso
	GENERIC MAP
	(
		data_width_in	=> 32,
		data_width_out	=> 8,
		msb_first		=> true
	)
	PORT MAP
	(
		rst			=> RST,
		clk			=> CLK,
		din_vld		=> piso_din_vld,
		din_re		=> piso_din_re,
		din_be		=> piso_din_be,
		din			=> piso_din,
		dout_vld	=> piso_dout_vld,
		shift_en		=> piso_shift_en,
		dout		=> piso_dout
		
	);

	piso_shift_en	<= piso2_din_re;
	
inst_piso2 : entity work.piso
	GENERIC MAP
	(
		data_width_in	=> 8,
		data_width_out	=> 4,
		msb_first		=> true
	)
	PORT MAP
	(
		rst			=> RST,
		clk			=> CLK,
		din_vld		=> piso2_din_vld,
		din_re		=> piso2_din_re,
		din_be		=> piso2_din_be,
		din			=> piso2_din,
		dout_vld	=> piso2_dout_vld,
		shift_en	=> piso2_shift_en,
		dout		=> piso2_dout
		
	);

	piso2_din_vld	<= piso_dout_vld;
	piso2_shift_en	<= '1';
	piso2_din		<= piso_dout;
	
inst_sipo : entity work.sipo
	GENERIC MAP
	(
		data_width_in	=> 8,
		data_width_out	=> 32,
		msb_first		=> true
	)
	PORT MAP
	(
		rst			=> RST,
		clk			=> CLK,
		din_en		=> sipo_enable,
		din_vld		=> sipo_din_vld,
		din			=> sipo_din,
		dout_be		=> sipo_dout_be,
		dout_vld	=> sipo_dout_vld,
		dout		=> sipo_dout,
		shift_en	=> sipo_shift_en
		
	);
	sipo_din		<= sipo2_dout;
	sipo_din_vld	<= sipo2_dout_vld;
	sipo_enable		<= sipo2_shift_en;
	sipo_rst		<= RST or not piso2_dout_vld;

inst_sipo2 : entity work.sipo
	GENERIC MAP
	(
		data_width_in	=> 4,
		data_width_out	=> 8,
		msb_first		=> true
	)
	PORT MAP
	(
		rst			=> RST,
		clk			=> CLK,
		din_en		=> sipo2_enable,
		din_vld		=> sipo2_din_vld,
		din			=> sipo2_din,
		dout_be		=> sipo2_dout_be,
		dout_vld	=> sipo2_dout_vld,
		dout		=> sipo2_dout,
		shift_en		=> sipo2_shift_en
		
	);
	sipo2_din		<= piso2_dout;
	sipo2_din_vld	<= piso2_dout_vld;
	sipo2_enable	<= sipo2_din_vld;
	sipo_rst		<= RST or not piso2_dout_vld;

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


-- Master
STIMULUS: process


	begin

		wait for 600*CLK_PERIOD;
		RST <= '0';
		wait for 60*CLK_PERIOD;

		for i in 1 to 10 loop

			wait until rising_edge(CLK);
			piso_din_vld	<= '1';
			piso_din		<= X"12345678";
			piso_din_be		<= "1111";
			wait until rising_edge(CLK) and piso_din_re = '1';
			piso_din		<= piso_din + X"12345678";
			piso_din_be		<= "1111";
			wait until rising_edge(CLK) and piso_din_re = '1';
			piso_din		<= piso_din + X"12345678";
			piso_din_be		<= "1111";
			wait until rising_edge(CLK) and piso_din_re = '1';
			piso_din		<= piso_din + X"12345678";
			piso_din_be		<= "1100";
			wait until rising_edge(CLK) and piso_din_re = '1';
			piso_din		<= (others => '-');
			piso_din_vld	<= '0';


			wait until rising_edge(CLK) and piso_dout_vld = '0';

--			wait until rising_edge(CLK);
--			wait until rising_edge(CLK) and sipo_dout_vld = '1';
--
			wait for 33*CLK_PERIOD;
		
		end loop;
		
		wait; 
	
	end process;
	
END;
