LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

LIBRARY WORK;
USE WORK.spi_types.all;

ENTITY spi_master_wb IS
	Generic
	(
		CAT_FIFO_DEPTH		: natural := 4;
		DATA_FIFO_DEPTH		: natural := 16
	);
	Port
	(
		CLK_I		: in  STD_LOGIC;
		RST_I		: in  STD_LOGIC;
		INT_O		: out STD_LOGIC;
		CYC_I		: in  STD_LOGIC;
		STB_I		: in  STD_LOGIC;
		SEL_I		: in  unsigned(3 downto 0);
		WE_I		: in  STD_LOGIC;
		ACK_O		: out STD_LOGIC;
		SRDY_O		: out STD_LOGIC;
		MRDY_I		: in  STD_LOGIC;
		ADDR_I		: in  unsigned(31 downto 0);
		DAT_I		: in  unsigned(31 downto 0);
		DAT_O		: out unsigned(31 downto 0);
		spi_hold	: in std_logic;
		spi_ss		: out std_logic;
		spi_clk		: out std_logic;
		spi_miso	: in std_logic;
		spi_mosi	: out std_logic
	);
END spi_master_wb;

ARCHITECTURE rtl OF spi_master_wb IS

	-- Signals for UART connections
	signal mst_cmd					: cmd_t;
	signal mst_cmd_vld				: std_logic;
	signal mst_cmd_rdy				: std_logic;
	signal mst_shift_en				: std_logic;
	signal mst_din_vld				: std_logic;
	signal mst_din_rdy				: std_logic;

	signal mst_ctrl					: ctrl_t;
	signal mst_status				: status_t;
	signal mst_din					: unsigned(31 downto 0);
	signal mst_dout					: unsigned(31 downto 0);
	signal mst_dout_re				: std_logic;
	signal mst_dout_vld				: std_logic;
	
begin
	mst_shift_en 				<= not spi_hold;
	
	SRDY_O						<= CYC_I;
	INT_O						<= '0';

inst_spi_master : entity work.spi_master
	GENERIC MAP
	(
		WORD_WIDTH		=> 32,
		CAT_FIFO_DEPTH	=> CAT_FIFO_DEPTH,
		DATA_FIFO_DEPTH	=> DATA_FIFO_DEPTH
	)
	PORT MAP
	(
		rst			=> RST_I,
		clk			=> CLK_I,
		cmd_vld		=> mst_cmd_vld,
		cmd_rdy		=> mst_cmd_rdy,
		cmd			=> mst_cmd,
		din_vld		=> mst_din_vld,
		din_rdy		=> mst_din_rdy,
		din			=> mst_din,
		dout_re		=> mst_dout_re,
		dout_vld	=> mst_dout_vld,
		dout		=> mst_dout,
		shift_en	=> mst_shift_en,
		mosi		=> spi_mosi,
		miso		=> spi_miso,
		sclk		=> spi_clk,
		mso			=> spi_ss,
		ctrl		=> mst_ctrl,
		status		=> mst_status
		
	);
	
------------------------------------------------------------------
registers_write: 
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			mst_cmd_vld		<= '0';
			mst_din_vld		<= '0';
			if RST_I = '1' then
				mst_ctrl.clk_div		<= to_unsigned(100, 8);
				mst_ctrl.cpol			<= '0';
				mst_ctrl.cpha			<= '0';
				mst_ctrl.msb_first		<= '1';
			elsif (STB_I and CYC_I and WE_I) = '1' then
				case ADDR_I(5 downto 2) is
				
				when "0000" =>
					mst_cmd_vld			<= DAT_I(0);
					
				when "0001" =>
					mst_cmd.xfer_size	<= DAT_I;

				when "0010" =>
					mst_cmd.data_size	<= DAT_I;
					
				when "0011" =>
					mst_din				<= DAT_I;				
					mst_din_vld			<= '1';
					
				when "0100" =>
					mst_ctrl.clk_div	<= DAT_I(7 downto 0);
					mst_ctrl.cpol		<= DAT_I(8);
					mst_ctrl.cpha		<= DAT_I(9);
					mst_ctrl.msb_first	<= DAT_I(10);

				when others => null;
				end case;
			end if;	
		end if;	
	end process;

registers_read: 
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			mst_dout_re		<= '0';
			ACK_O			<= '0';
			if (STB_I and CYC_I) = '1' then
				ACK_O		<= not WE_I;
				DAT_O		<= (others => '0');
				case ADDR_I(5 downto 2) is

				when "0000" =>
					DAT_O(2 downto 0)	<= mst_dout_vld & mst_din_rdy & mst_cmd_rdy;
					DAT_O(15 downto 8)	<= spi_hold & mst_status.xfer_busy & mst_status.read_fifo_empty & mst_status.read_fifo_full & mst_status.write_fifo_empty & mst_status.write_fifo_full & mst_status.cmd_fifo_empty & mst_status.cmd_fifo_full;
					
				when "0001" =>
					DAT_O				<= mst_cmd.xfer_size;

				when "0010" =>
					DAT_O				<= mst_cmd.data_size;

				when "0011" =>
					DAT_O				<= mst_dout;
					mst_dout_re			<= not WE_I;

				when "0100" =>
					DAT_O(7 downto 0)	<= mst_ctrl.clk_div;
					DAT_O(8)			<= mst_ctrl.cpol;
					DAT_O(9)			<= mst_ctrl.cpha;
					DAT_O(10)			<= mst_ctrl.msb_first;

				when others => null;
				end case;
			end if;
		end if;	
	end process;

end rtl;
