-- ============================================================================
--
-- Design unit      :   tech_sbox_stage
--
-- File Name        :   tech_sbox_stage_virtex2.vhd
--
-- Purpose          :   The module provides S-box stage for implementation of
--                      encryption, decryption and key schedule using 32-bit
--                      datapath on Virtex-II family
--
--
-- Depends on       :
--
--  - Package(s)    :   aes_definitions, tech_iface
--
--  - Module(s)     :   dual_sbox_virtex2 (dual-port RAM block)
--
--
-- Dev. Platform    :   Xilinx ISE 8.1i SP3 / Win32 (W2k SP4)
--
--  - Simulator(s)  :   Modelsim XE III 6.0d
--
--  - Synthesis     :   Xilinx XST
--
--  - Place & Route :   Xilinx PAR
--
--
-- Errors           :   None known
--
--
-- Limitations      :   None known
--
--
-- Notes            :   S-box type mapping as required by 128-bit key schedule
--
--
-- Author(s)        :   A. Freund (af) <a.freund@dsi-it.de>
--                      Digitale Signalverabeitung & Informationstechnik GmbH,
--                      Bremen, Germany
--
--
-- ============================================================================
--
-- Revision List:
-- Version      Author(s)       Date        Changes
--
-- v0.00        af              2006-11-02  initial version
--
-- see SVN logs
--
-- ============================================================================
--
-- Naming conventions:
--
--  - active-low signals are indicated by appending "_n"
--  - constants are in UPPERCASE
--  - name parts are separated by "_"
--
-- ============================================================================


library ieee;
use ieee.std_logic_1164.all;


use work.aes_definitions.all;
use work.tech_iface.all;


entity tech_sbox_stage is
	port (
		rst		: 	in	std_logic;					-- reset
		clk		:	in	std_logic;					-- clock
		data_i	:	in	sbox_stage_in_type;			-- see package tech_iface
		data_o	:	out	sbox_stage_out_type;		-- see package tech_iface
		load_i	:	in	sbox_stage_load_in_type		-- see package tech_iface
	);
end tech_sbox_stage;


architecture behavioural of tech_sbox_stage is


	component dual_sbox_virtex2 is
		port (
				clk		:	in std_logic;						-- clock (rising)
				enca	:	in std_logic;						-- encryption (0) / decryption (1) mode
				encb	:	in std_logic;						-- encryption (0) / decryption (1) mode
				posa	:	in std_logic_vector(7 downto 0);	-- position
				posb	:	in std_logic_vector(7 downto 0);	-- position
				dina	:	in std_logic_vector(7 downto 0);	-- write data
				dinb	:	in std_logic_vector(7 downto 0);	-- write data
				wea		:	in std_logic;						-- write enable
				web		:	in std_logic;    					-- write enable
				douta	:	out std_logic_vector(7 downto 0);	-- read data
				doutb	:	out std_logic_vector(7 downto 0);	-- read data
				is_init	:	out std_logic						-- pre-initialised memory
		);
	end component;


	signal s_din : std_logic_vector(31 downto 0);			-- S-box input data
	signal s_ed_mode : std_logic;							-- en-/decryption mode selection

	signal s_wen : std_logic;								-- write enable
	signal s_ready : std_logic;								-- S-box is ready

	signal s_is_init : std_logic_vector(1 downto 0);		-- S-box is pre-initialized


begin


	-- handle activation of load I/F
	process (load_i, data_i)
	begin
		if (load_i.act = '1')
			then
				s_din <= load_i.pos & load_i.pos & load_i.pos & load_i.pos;
				s_ed_mode <= load_i.ed_mode;
				s_wen <= load_i.wen;
			else
				s_din <= data_i.din;
				s_ed_mode <= data_i.ed_mode;
				s_wen <= '0';
		end if;
	end process;


	sbox_2x8_1: dual_sbox_virtex2
		port map (
			clk		=>	clk,
			enca	=>	s_ed_mode,
			encb	=>	s_ed_mode,
			posa	=>	s_din(31 downto 24),
			posb	=>	s_din(23 downto 16),
			dina	=>	load_i.din,
			dinb	=>	(others => '0'),
			wea		=>	s_wen,
			web		=>	'0',
			douta	=>	data_o.dout(31 downto 24),
			doutb	=> 	data_o.dout(23 downto 16),
			is_init	=>	s_is_init(1)
		);


	sbox_2x8_0: dual_sbox_virtex2
		port map (
			clk		=>	clk,
			enca	=>	s_ed_mode,
			encb	=>	s_ed_mode,
			posa	=>	s_din(15 downto 8),
			posb	=>	s_din(7 downto 0),
			dina	=>	load_i.din,
			dinb	=>	(others => '0'),
			wea		=>	s_wen,
			web		=>	'0',
			douta	=>	data_o.dout(15 downto 8),
			doutb	=> 	data_o.dout(7 downto 0),
			is_init	=>	s_is_init(0)
		);


	-- generate S-box ready flag
	process
	begin
		wait until rising_edge(clk);
		if (rst = '1')
			then
				s_ready <= s_is_init(0) and s_is_init(1);
		elsif (load_i.act = '1') and (load_i.wen = '1')
			then
				s_ready <= '0';
		elsif (load_i.act = '1') and (load_i.done = '1')
			then
				s_ready <= '1';
		end if;
	end process;


	data_o.ready <= (not load_i.act) and s_ready;


end behavioural;
