workstation/src/memory_controller.vhd

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;