-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
--
-- =============================================================================
-- Authors:					Martin Zabel
--
-- Module:					Adapter for the Xilinx MIG IP core on Spartan-6 FPGAs.
--
-- Description:
-- ------------------------------------
-- Adapter between the :ref:`PoC.Mem <INT:PoC.Mem>`
-- interface and the User Interface of the Xilinx MIG IP core for the
-- Spartan-6 FPGA Memory Controller Block (MCB). The MCB can be configured to
-- have multiple ports. One instance of this adapter is required for every
-- port. The control signals for one port of the MIG IP core are prefixed by
-- "cX_pY", meaning port Y on controller X.
--
-- Simplifies the User Interface ("user") of the Xilinx MIG IP core (UG388).
-- The PoC.Mem interface provides single-cycle fully pipelined read/write access
-- to the memory. All accesses are word-aligned. Always all bytes of a word are
-- written to the memory. More details can be found
-- :ref:`here <INT:PoC.Mem>`.
--
-- Generic parameters:
--
-- * D_BITS: Data bus width of the PoC.Mem and MIG / MCBinterface. Also size of
--   one word in bits.
--
-- * MEM_A_BITS: Address bus width of the PoC.Mem interface.
--
-- * APP_A_BTIS: Address bus width of the MIG / MCB interface.
--
-- Containts only combinational logic.
--
-- License:
-- =============================================================================
-- Copyright 2007-2016 Technische Universitaet Dresden - Germany
--										 Chair of VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--		http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- =============================================================================

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library poc;
use poc.utils.all;

entity [docs]ddr2_mem2mig_adapter_Spartan6 is

	generic (
		D_BITS     : positive;
		MEM_A_BITS : positive;
		APP_A_BITS : positive
	);

	port (
		-- PoC.Mem interface
		mem_req   : in  std_logic;
		mem_write : in  std_logic;
		mem_addr  : in  unsigned(MEM_A_BITS-1 downto 0);
		mem_wdata : in  std_logic_vector(D_BITS-1 downto 0);
		mem_wmask : in  std_logic_vector(D_BITS/8-1 downto 0) := (others => '0');
		mem_rdy   : out std_logic;
		mem_rstb  : out std_logic;
		mem_rdata : out std_logic_vector(D_BITS-1 downto 0);

		-- Xilinx MIG IP Core interface
		mig_calib_done    : in  std_logic;
		mig_cmd_full      : in  std_logic;
		mig_wr_full       : in  std_logic;
		mig_rd_empty      : in  std_logic;
		mig_rd_data       : in  std_logic_vector((D_BITS)-1 downto 0);
		mig_cmd_instr     : out std_logic_vector(2 downto 0);
		mig_cmd_en        : out std_logic;
		mig_cmd_bl        : out std_logic_vector(5 downto 0);
		mig_cmd_byte_addr : out std_logic_vector(APP_A_BITS-1 downto 0);
		mig_wr_data       : out std_logic_vector((D_BITS)-1 downto 0);
		mig_wr_mask       : out std_logic_vector((D_BITS)/8-1 downto 0);
		mig_wr_en         : out std_logic;
		mig_rd_en         : out std_logic
	);

end entity ddr2_mem2mig_adapter_Spartan6;

architecture [docs]rtl of ddr2_mem2mig_adapter_Spartan6 is
	-- The number of bits addressing the byte within the MIG address.
	constant BYTE_ADDR_BITS : positive := log2ceil(D_BITS/8);

	signal mem_rdy_i : std_logic;

begin  -- architecture rtl

	-- command & FIFO control
	mem_rdy_i <= mig_calib_done and (not mig_cmd_full) and (not mig_wr_full);
	mem_rdy   <= mem_rdy_i;

	mig_cmd_en    <= mem_rdy_i and mem_req;
	mig_wr_en     <= mem_rdy_i and mem_req and mem_write;
	mig_cmd_instr <= "00" & (not mem_write); -- with-out auto precharge
	mig_cmd_bl    <= "000000";               -- 1 word of D_BITS

	-- address
	process (mem_addr) is
	begin  -- process
		mig_cmd_byte_addr <= (others => '0');
		mig_cmd_byte_addr(MEM_A_BITS+BYTE_ADDR_BITS-1 downto BYTE_ADDR_BITS) <= std_logic_vector(mem_addr);
	end process;

	-- write data & mask
	mig_wr_data <= mem_wdata;
	mig_wr_mask <= mem_wmask;

	-- read reply
	mig_rd_en <= not mig_rd_empty;
	mem_rstb	<= not mig_rd_empty;
	mem_rdata <= mig_rd_data;

end architecture rtl;