Files
workstation/src/memory_controller.vhd
Klemens Schölhorn e1bf43fa47 Add MIG wrapper and ddr2 constraints
We cannot add the full repository here, because it contains the mig core,
which is not allowed to be redistributed publicy.
2018-06-05 16:04:27 +02:00

242 lines
9.2 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity memory_controller is
port (
-- clocks
sys_clk0: in std_logic;
sys_clk90: in std_logic;
sys_clkdiv0: in std_logic;
sys_clk_locked: in std_logic;
sys_clk_idelay: in std_logic;
sys_reset: in std_logic;
-- read and write requests
request_addr: in std_logic_vector(27 downto 0); -- 256 MiB, no CS (SR)
request_type: in std_logic; -- read (1) or write (0)
request_data: in std_logic_vector(255 downto 0);
request_mask: in std_logic_vector(31 downto 0);
request_valid: in std_logic;
request_ready: out std_logic;
-- read responses
response_data: out std_logic_vector(255 downto 0);
response_valid: out std_logic; -- only asserted for one cycle, no ready
-- physical ddr2 interface
ddr2_dq: inout std_logic_vector(63 downto 0);
ddr2_a: out std_logic_vector(12 downto 0);
ddr2_ba: out std_logic_vector(1 downto 0);
ddr2_ras_n: out std_logic;
ddr2_cas_n: out std_logic;
ddr2_we_n: out std_logic;
ddr2_cs_n: out std_logic_vector(0 downto 0);
ddr2_odt: out std_logic_vector(0 downto 0);
ddr2_cke: out std_logic_vector(0 downto 0);
ddr2_dm: out std_logic_vector(7 downto 0);
ddr2_dqs: inout std_logic_vector(7 downto 0);
ddr2_dqs_n: inout std_logic_vector(7 downto 0);
ddr2_ck: out std_logic_vector(1 downto 0);
ddr2_ck_n: out std_logic_vector(1 downto 0)
);
end memory_controller;
architecture rtl of memory_controller is
signal clk: std_logic;
signal reset_p: std_logic;
type request_states is (
REQ_IDLE,
REQ_WRITE
);
signal request_state: request_states := REQ_IDLE;
type response_states is (
RES_IDLE,
RES_WAIT_SECOND
);
signal response_state: response_states := RES_IDLE;
signal ram_init_done: std_logic;
signal ram_address: std_logic_vector(30 downto 0);
signal ram_command: std_logic_vector(2 downto 0);
signal ram_data_in: std_logic_vector(127 downto 0);
signal ram_mask_in: std_logic_vector(15 downto 0);
signal ram_data_out: std_logic_vector(127 downto 0);
signal ram_enq_address: std_logic;
signal ram_enq_data: std_logic;
signal ram_address_afull: std_logic;
signal ram_data_afull: std_logic;
signal ram_data_valid: std_logic;
signal is_request_ready: std_logic;
signal data_in_high: std_logic_vector(127 downto 0);
signal mask_in_high: std_logic_vector(15 downto 0);
signal data_out_low: std_logic_vector(127 downto 0);
begin
reset_p <= not sys_reset;
-- the lowest three bits pick one of the 8 bytes inside the 64b ram width
ram_address <= "000000" & request_addr(27 downto 3);
-- WRITE is 000 and READ is 001
ram_command <= "00" & request_type;
-- we directly pass the lower half to the mig fifo and only store the
-- upper half for writing on a second cycle (this works because we can
-- still write 12 words to the fifo when the *almost full* signal is
-- asserted by the mig)
ram_data_in <= request_data(127 downto 0) when request_state = REQ_IDLE else
data_in_high;
ram_mask_in <= request_mask(15 downto 0) when request_state = REQ_IDLE else
mask_in_high;
-- to directly pass data to the fifos (see above) we also have to enable
-- the fifo write signals combinatorially, otherwise we miss the first part
ram_enq_address <= is_request_ready and request_valid;
-- the data write signal is only high for write requests and also has to
-- be kept high for a second cycle to write the upper half of the data
ram_enq_data <= '1' when ( (is_request_ready and request_valid) = '1' and
(request_type = '0')
) or (request_state = REQ_WRITE)
else '0';
-- we are only ready if we can write to *both* fifos and everything is
-- fully initialized (we could theoretically only look at the address fifo
-- for read requests)
is_request_ready <= '1' when (ram_init_done = '1') and
(ram_address_afull = '0') and
(ram_data_afull = '0') and
(request_state = REQ_IDLE)
else '0';
request_ready <= is_request_ready;
input: process(clk, sys_reset)
begin
if sys_reset = '1' then
request_state <= REQ_IDLE;
elsif rising_edge(clk) then
case request_state is
when REQ_IDLE =>
if is_request_ready = '1' and request_valid = '1' then
if request_type = '1' then -- READ
request_state <= REQ_IDLE;
else -- WRITE
data_in_high <= request_data(255 downto 128);
mask_in_high <= request_mask(31 downto 16);
request_state <= REQ_WRITE;
end if;
end if;
when REQ_WRITE =>
request_state <= REQ_IDLE;
end case;
end if;
end process input;
-- we pass the higher half directly from the mig
response_data <= ram_data_out & data_out_low;
-- read_valid only asserted for one cycle, must be read immediately
response_valid <= '1' when (response_state = RES_WAIT_SECOND) and
(ram_data_valid = '1')
else '0';
output: process(clk, sys_reset)
begin
if sys_reset = '1' then
response_state <= RES_IDLE;
elsif rising_edge(clk) then
case response_state is
when RES_IDLE =>
if ram_data_valid = '1' then
data_out_low <= ram_data_out;
response_state <= RES_WAIT_SECOND;
end if;
when RES_WAIT_SECOND =>
if ram_data_valid = '1' then
response_state <= RES_IDLE;
end if;
end case;
end if;
end process output;
ddr2_controller: entity work.ddr2_controller port map (
clk0 => sys_clk0,
clk90 => sys_clk90,
clkdiv0 => sys_clkdiv0,
clk200 => sys_clk_idelay,
locked => sys_clk_locked,
sys_rst_n => reset_p,
rst0_tb => open,
clk0_tb => clk,
phy_init_done => ram_init_done,
app_wdf_afull => ram_data_afull,
app_af_afull => ram_address_afull,
rd_data_valid => ram_data_valid,
app_wdf_wren => ram_enq_data,
app_af_wren => ram_enq_address,
app_af_addr => ram_address,
app_af_cmd => ram_command,
rd_data_fifo_out => ram_data_out,
app_wdf_data => ram_data_in,
app_wdf_mask_data => ram_mask_in,
ddr2_dq => ddr2_dq,
ddr2_a => ddr2_a,
ddr2_ba => ddr2_ba,
ddr2_ras_n => ddr2_ras_n,
ddr2_cas_n => ddr2_cas_n,
ddr2_we_n => ddr2_we_n,
ddr2_cs_n => ddr2_cs_n,
ddr2_odt => ddr2_odt,
ddr2_cke => ddr2_cke,
ddr2_dm => ddr2_dm,
ddr2_dqs => ddr2_dqs,
ddr2_dqs_n => ddr2_dqs_n,
ddr2_ck => ddr2_ck,
ddr2_ck_n => ddr2_ck_n
);
--~ sys_clk_p : in std_logic;
--~ sys_clk_n : in std_logic;
--~ clk200_p : in std_logic;
--~ clk200_n : in std_logic;
--~ sys_rst_n : in std_logic;
--~ rst0_tb : out std_logic;
--~ clk0_tb : out std_logic;
--~ phy_init_done : out std_logic;
--~ app_wdf_afull : out std_logic;
--~ app_af_afull : out std_logic;
--~ app_wdf_wren : in std_logic;
--~ app_af_wren : in std_logic;
--~ app_af_addr : in std_logic_vector(30 downto 0);
--~ app_af_cmd : in std_logic_vector(2 downto 0);
--~ app_wdf_data : in std_logic_vector(127 downto 0);
--~ app_wdf_mask_data : in std_logic_vector(15 downto 0);
--~ rd_data_fifo_out : out std_logic_vector(127 downto 0);
--~ rd_data_valid : out std_logic;
--~ ddr2_dq : inout std_logic_vector(63 downto 0);
--~ ddr2_a : out std_logic_vector(12 downto 0);
--~ ddr2_ba : out std_logic_vector(1 downto 0);
--~ ddr2_ras_n : out std_logic;
--~ ddr2_cas_n : out std_logic;
--~ ddr2_we_n : out std_logic;
--~ ddr2_cs_n : out std_logic_vector(0 downto 0);
--~ ddr2_odt : out std_logic_vector(0 downto 0);
--~ ddr2_cke : out std_logic_vector(0 downto 0);
--~ ddr2_dm : out std_logic_vector(7 downto 0);
--~ ddr2_dqs : inout std_logic_vector(7 downto 0);
--~ ddr2_dqs_n : inout std_logic_vector(7 downto 0);
--~ ddr2_ck : out std_logic_vector(1 downto 0);
--~ ddr2_ck_n : out std_logic_vector(1 downto 0)
end rtl;