-------------------------------------------------------------------------
-- Project: SDRAM controller
-- This file: Top-level put all together
--
-- 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.sdram_config.all;
use work.sdram_types.all;

entity sdram_ctrl_top is
	Generic
	(
		BL 				: natural := 2;
		f_sysclk 		: natural := 100E6;
		read_phaseshift : integer := 0
	);
	Port
	(
		sys_rst_in			: in  STD_LOGIC;
		sys_clk_in			: in  STD_LOGIC;
		sys_rst_out			: out STD_LOGIC;
		sys_clk_out			: out STD_LOGIC;
		sys_clk_fb			: in  STD_LOGIC;
		
		-- User interface
		u_data_vld			: out STD_LOGIC;
		u_data_req_w		: out STD_LOGIC;
		u_data_req_r		: out STD_LOGIC;
		u_busy				: out STD_LOGIC;
		u_tag_in			: in  user_tag_t;
		u_tag_rd			: out user_tag_t;
		u_tag_wr			: out user_tag_t;
		u_addr				: in  user_addr_t;
		u_cmd				: in  user_cmd_t;
		u_cmd_we			: in  STD_LOGIC;
		u_data_wr			: in  unsigned(SDR_DATA_WIDTH-1 downto 0);
		u_dm_wr_in			: in  unsigned(SDR_DM_WIDTH-1 downto 0);
		u_dm_rd_in			: in  unsigned(SDR_DM_WIDTH-1 downto 0);
		u_dm_rd_out			: out unsigned(SDR_DM_WIDTH-1 downto 0);
		u_data_rd			: out unsigned(SDR_DATA_WIDTH-1 downto 0);
		
		-- SDRAM signals
		sd_clk_p			: out  STD_LOGIC;
		sd_clk_n			: out  STD_LOGIC;
		sd_cke				: out  STD_LOGIC;
		sd_cs_n				: out  STD_LOGIC;
		sd_cas_n			: out  STD_LOGIC;
		sd_ras_n			: out  STD_LOGIC;
		sd_we_n				: out  STD_LOGIC;
		sd_addr				: out  sdr_addr_t;
		sd_ba				: out  sdr_ba_t;
		sd_dm				: out  unsigned(DDR_DM_WIDTH-1 downto 0);
		sd_dqs				: inout unsigned(DDR_DQS_WIDTH-1 downto 0);
		sd_data				: inout unsigned(DDR_DATA_WIDTH-1 downto 0)
		
	);
end sdram_ctrl_top;

architecture rtl of sdram_ctrl_top is

	signal clk0				: std_logic;
	signal clk270			: std_logic;
	signal read_clk270		: std_logic;

	signal phy_ctrl			: phy_ctrl_t;

	signal u_tag			: user_tag_t;
	signal sd_cmd_in		: sdr_cmd_t;
	signal sd_cmd			: sdr_cmd_t;
	signal sd_cmd_we		: std_logic;
	signal cmd_ctrl			: sdr_cmd_lines_t;
	signal cke				: std_logic;
	signal ba				: unsigned(DDR_BANK_WIDTH-1 downto 0);
	signal addr				: unsigned(DDR_ADDR_WIDTH-1 downto 0);

	-- Clock generator

	signal cg_rst			: std_logic;  
	signal cg_read_clk0		: std_logic;  
	signal cg_read_clk270	: std_logic;  
	signal cg_sys_clk0		: std_logic;  
	signal cg_sys_clk270	: std_logic;  
	signal cg_locked		: std_logic;  
	signal cg_error			: std_logic;  
	signal ctrl_rst			: std_logic;  
	signal part_ctrl		: part_ctrl_t;  

	-- SD command FIFO

	constant CMD_FIFO_ADDR_WIDTH	: positive := 2;
	constant CMD_FIFO_DATA_WIDTH	: positive := user_tag_t'length + 4 + mode_word_t'length + col_addr_t'length;
	signal cmd_fifo_din				: unsigned(CMD_FIFO_DATA_WIDTH-1 downto 0);
	signal cmd_fifo_dout			: unsigned(CMD_FIFO_DATA_WIDTH-1 downto 0);
	signal cmd_fifo_re				: std_logic;
	signal cmd_fifo_we				: std_logic;
	signal cmd_fifo_full			: std_logic;
	signal cmd_fifo_empty			: std_logic;

	alias tag_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length);
	alias cmd_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-user_tag_t'length-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4);
	alias mode_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length);
	alias col_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length-1 downto 0);

	alias tag_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length);
	alias cmd_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-user_tag_t'length-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4);
	alias mode_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length);
	alias col_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length-1 downto 0);

begin 
      	
	---------------------------------
	clk0			<= cg_sys_clk0;
	clk270			<= cg_sys_clk270;
	read_clk270		<= cg_read_clk270;
	cg_rst			<= not cg_locked;
	
	---------------------------------
	sys_clk_out		<= cg_sys_clk0;
	sys_rst_out		<= ctrl_rst;
	
	---------------------------------
	part_ctrl.cmd	<= cmd_ctrl;
	part_ctrl.ba	<= ba;
	part_ctrl.addr	<= addr;
	part_ctrl.cke	<= cke;

	---------------------------------
	sd_cmd_we		<= not cmd_fifo_empty;
	cmd_fifo_in		<= to_unsigned(sd_cmd_in, 4);
	sd_cmd			<= sdr_cmd_t(to_integer(cmd_fifo_out));

	---------------------------------
	inst_reset: entity work.reset
	port map
	(
		clk					=> clk0,
		rst_in				=> cg_rst,
		rst_out				=> ctrl_rst
	);
	
	inst_clockgen : entity work.clockgen
	generic map
	(
		read_phaseshift => read_phaseshift,
		frequency_hz  => f_sysclk
	)
	port map
	(
		rst					=> sys_rst_in,
		clk_in				=> sys_clk_in,
		clk_fb_in			=> sys_clk_fb,
		read_clk0_out		=> cg_read_clk0,
		read_clk270_out		=> cg_read_clk270,
		sys_clk0_out		=> cg_sys_clk0,
		sys_clk270_out		=> cg_sys_clk270,
		locked_out			=> cg_locked,
		error_out			=> cg_error
	);
   
	-- Main controller
	inst_sdram_ctrl : entity work.sdram_ctrl
	Generic map 
	(
		f_sysclk	=> 100E6,
		BL			=> BL
	)
	Port map 
	(
		rst				=> ctrl_rst,
		clk				=> clk0,
		u_busy			=> u_busy,
		u_tag_in		=> u_tag_in,
		u_tag_out		=> tag_fifo_in,
		u_cmd			=> u_cmd,
		u_cmd_we		=> u_cmd_we,
		u_addr			=> u_addr,
		sdr_cmd_busy	=> cmd_fifo_full,
		sdr_cmd			=> sd_cmd_in,
		sdr_cmd_we		=> cmd_fifo_we,
		col_addr		=> col_fifo_in,
		sdr_mode		=> mode_fifo_in,
		sdr_cke			=> cke
	);
   
	-- Instantiate synchronous FIFO
	inst_sd_cmd_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> CMD_FIFO_ADDR_WIDTH,
		data_width			=> CMD_FIFO_DATA_WIDTH,
		almost_full_thresh	=> 2**(CMD_FIFO_ADDR_WIDTH-1),
		almost_empty_thresh	=> 2**(CMD_FIFO_ADDR_WIDTH-1)
	)
	PORT MAP
	(
		rst			=>	ctrl_rst,
		clk			=>	clk0,
		we			=>	cmd_fifo_we,
		re			=>	cmd_fifo_re,
		fifo_full	=>	cmd_fifo_full,
		fifo_empty	=>	cmd_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  cmd_fifo_din,
		data_r		=>  cmd_fifo_dout
	);

	-- DDR SDRAM command fsm
	inst_sdram_cmd : entity work.sdram_cmd
	Generic map
	(
		BL				=> BL
	)
	Port map
	(
		rst				=> ctrl_rst,
		clk				=> clk0,
		u_tag_in		=> tag_fifo_out,
		u_tag_out		=> u_tag,
		phy_ctrl		=> phy_ctrl,
		enable			=> cke,
		cmd				=> sd_cmd,
		cmd_we			=> sd_cmd_we,
		cmd_ack			=> cmd_fifo_re,
		sdr_cmd_ctrl	=> cmd_ctrl,
		col_addr		=> col_fifo_out,
		mode_word		=> mode_fifo_out,
		sdr_ba			=> ba,
		sdr_addr		=> addr
	);
   
	-- DDR phy
	inst_ddr_phy : entity work.ddr_phy
	Port map
	(
		sys_rst			=> ctrl_rst,
		sys_clk0		=> clk0,
		sys_clk270		=> clk270,
		u_tag_in		=> u_tag,
		u_tag_rd		=> u_tag_rd,
		u_tag_wr		=> u_tag_wr,
		read_clk		=> read_clk270,
		phy_ctrl		=> phy_ctrl,
		part_ctrl		=> part_ctrl,
		sdr_data_req_w	=> u_data_req_w,
		sdr_data_req_r	=> u_data_req_r,
		sdr_data_w		=> u_data_wr,
		sdr_dm_wr_in	=> u_dm_wr_in,
		sdr_dm_rd_in	=> u_dm_rd_in,
		sdr_dm_rd_out	=> u_dm_rd_out,
		sdr_data_r		=> u_data_rd,
		sdr_data_vld	=> u_data_vld,
		part_clk_p		=> sd_clk_p,
		part_clk_n		=> sd_clk_n,
		part_addr		=> sd_addr,
		part_ba			=> sd_ba,
		part_dm			=> sd_dm,
		part_dqs		=> sd_dqs,
		part_data		=> sd_data,
		part_cs_n		=> sd_cs_n,
		part_we_n		=> sd_we_n,
		part_cas_n		=> sd_cas_n,
		part_ras_n		=> sd_ras_n,
		part_cke		=> sd_cke
	);
   
end architecture rtl;

