-- https://fpga4u.epfl.ch/wiki/FPGA4U_Description
-- The SDRAM is an ISSI IS42S32800B. With 32 bits data bus, validated by SDRAM_DQM<3..0> signals,
-- one for each Byte of data bus SDRAM_DQ<31..0>.
-- This memory is a synchronous SDRAM, validating address and control signals with the rising edge of SDRAM_CLK,
-- while SDRAM_CKE activated ('1'). The organisation is 4 banks selected by SDRAM_BA<1..0>.
-- Each bank as 2^12 Row and 2^9 Column selected by SDRAM_AD<11.0>, with 32 bits words
-- (SDRAM_DQ<31..0> (2^2 * 2^12 * 2^9 = 4 * 2M x 32 = 8Mx32 = 32MBytes).
-- In SOPC Builder, with the SDRAM Controller, select:
-- 4 Banks
-- 12 Rows addresses lines
-- 9 Columns addresses lines
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fpga4u_sdram_controller is
port(
--Avalon slave interface (pipelined, variable latency)
signal clk, reset : in std_logic;
signal as_address : in std_logic_vector(22 downto 0);
signal as_read, as_write : in std_logic;
signal as_byteenable : in std_logic_vector(3 downto 0);
signal as_readdata : out std_logic_vector(31 downto 0);
signal as_writedata : in std_logic_vector(31 downto 0);
signal as_waitrequest : out std_logic;
signal as_readdatavalid : out std_logic;
--SDRAM interface to FPGA4U SDRAM
signal ram_addr : out std_logic_vector(11 downto 0);
signal ram_ba : out std_logic_vector(1 downto 0);
signal ram_cas_n : out std_logic;
signal ram_cke : out std_logic;
signal ram_cs_n : out std_logic;
signal ram_dq : inout std_logic_vector(31 downto 0);
signal ram_dqm : out std_logic_vector(3 downto 0);
signal ram_ras_n : out std_logic;
signal ram_we_n : out std_logic
);
end entity;
architecture arch of fpga4u_sdram_controller is
--Initialisation signals
type init_state_t is (init_reset, init_pre, init_wait_pre, init_ref, init_wait_ref, init_mode, init_wait_mode, init_done);
signal init_state : init_state_t := init_reset;
signal init_wait_counter : unsigned(15 downto 0);
signal init_ref_counter : unsigned(3 downto 0);
--Main state machine
type state_t is (idle, ref, wait_ref, act, wait_act, read, spin_read, write, spin_write, precharge_all, wait_precharge);
signal state : state_t := idle;
signal ref_counter : unsigned(10 downto 0);
signal ref_req : std_logic;
signal wait_counter : unsigned(2 downto 0);
--Active transaction signals
signal int_address : std_logic_vector(22 downto 0);
signal int_readdata : std_logic_vector(31 downto 0);
signal int_writedata : std_logic_vector(31 downto 0);
signal int_byteenable : std_logic_vector(3 downto 0);
signal int_writeop : std_logic;
--open bank and row
signal open_bank : std_logic_vector(1 downto 0);
signal open_row : std_logic_vector(11 downto 0);
--readdata ready pipeline
signal readdata_ready : std_logic_vector(4 downto 0);
signal ram_cmd : std_logic_vector(3 downto 0);
begin
--State machine to handle SDRAM initialization
INITSTATE : process(clk, reset)
begin
if reset = '1' then
init_state <= init_reset;
--power up delay
init_wait_counter <= to_unsigned(24000,init_wait_counter'length);
--number refresh cycles before mode register write
init_ref_counter <= to_unsigned(2,init_ref_counter'length);
elsif rising_edge(clk) then
--count down when not 0
if init_wait_counter /= 0 then
init_wait_counter <= init_wait_counter - 1;
end if;
case init_state is
when init_reset =>
if init_wait_counter = 0 then
init_state <= init_pre;
end if;
--do a precharge
when init_pre =>
init_wait_counter <= to_unsigned(3,init_wait_counter'length);
init_state <= init_wait_pre;
when init_wait_pre =>
if init_wait_counter = 0 then
init_state <= init_ref;
end if;
--do a refresh
when init_ref =>
init_wait_counter <= to_unsigned(8,init_wait_counter'length);
init_ref_counter <= init_ref_counter - 1;
init_state <= init_wait_ref;
when init_wait_ref =>
if init_wait_counter = 0 then
if init_ref_counter = 0 then
init_state <= init_mode;
else
init_state <= init_ref;
end if;
end if;
--set the mode register
when init_mode =>
init_wait_counter <= to_unsigned(2,init_wait_counter'length);
init_state <= init_wait_mode;
when init_wait_mode =>
if init_wait_counter = 0 then
init_state <= init_done;
end if;
when others =>
null;
end case;
end if;
end process;
--Asynchronous waitrequest to allow one transfer per cycle (critical path)
as_waitrequest <= '0' when (state = idle and ref_req = '0' and (as_read = '1' or as_write = '1'))
or ((state = read or state = spin_read) and ref_req = '0' and as_read = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank)
or ((state = write or state = spin_write) and ref_req = '0' and as_write = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank)
else '1';
--Main state machine
make_state : process(clk, reset)
begin
if reset = '1' then
state <= idle;
ref_counter <= (others=>'0');
ref_req <= '1'; --begin with a refresh
wait_counter <= (others=>'0');
readdata_ready <= (others=>'0');
elsif rising_edge(clk) then
--counters for delays and refresh generation
if wait_counter /= 0 then
wait_counter <= wait_counter - 1;
end if;
if ref_counter /= 0 then
ref_counter <= ref_counter - 1;
else
ref_req <= '1';
ref_counter <= to_unsigned(1800,ref_counter'length);
end if;
--main state machine runs when the initialization is done
if init_state = init_done then
case state is
when idle =>
if ref_req = '1' then --go do a refresh
ref_req <= '0';
state <= ref;
elsif as_write = '1' or as_read = '1' then --accept the request and go to open the row
int_address <= as_address;
int_writedata <= as_writedata;
int_byteenable <= as_byteenable;
int_writeop <= as_write;
state <= act;
end if;
when ref =>
wait_counter <= to_unsigned(5,wait_counter'length);
state <= wait_ref;
when wait_ref =>
if wait_counter = 0 then
state <= idle;
end if;
when act => --save the open bank and row
open_bank <= int_address(10 downto 9);
open_row <= int_address(22 downto 11);
wait_counter <= to_unsigned(1,wait_counter'length);
state <= wait_act;
when wait_act =>
if wait_counter = 0 then
if int_writeop = '0' then
state <= read;
else
state <= write;
end if;
end if;
when read => --issue a read command, feed a one in the readdata_ready pipeline, when it exits data is ready for the master
as_readdata <= int_readdata;
as_readdatavalid <= readdata_ready(4);
readdata_ready <= readdata_ready(3 downto 0)&'1';
if ref_req = '0' and as_read = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
int_address <= as_address;
state <= read;
else
state <= spin_read;
end if;
when spin_read => --wait for reads to complete and eventually issue more compatible reads
as_readdata <= int_readdata;
as_readdatavalid <= readdata_ready(4);
readdata_ready <= readdata_ready(3 downto 0)&'0';
if readdata_ready = "00000" and (ref_req = '1' or as_write = '1') then
state <= precharge_all;
elsif ref_req = '0' and as_read = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
int_address <= as_address;
state <= read;
elsif readdata_ready = "00000" and as_read = '1' then
state <= precharge_all;
end if;
when write => --the same as read, except there is no pipeline as data is presented to the SDRAM on the same cycle as the command
wait_counter <= to_unsigned(1,wait_counter'length);
if ref_req = '0' and as_write = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
int_address <= as_address;
int_writedata <= as_writedata;
int_byteenable <= as_byteenable;
state <= write;
else
state <= spin_write;
end if;
when spin_write => --same as for read
if wait_counter = 0 and (ref_req = '1' or as_read = '1') then
state <= precharge_all;
elsif ref_req = '0' and as_write = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
int_address <= as_address;
int_writedata <= as_writedata;
int_byteenable <= as_byteenable;
state <= write;
elsif wait_counter = 0 and as_write = '1' then
state <= precharge_all;
end if;
when precharge_all =>
state <= wait_precharge;
when wait_precharge =>
state <= idle;
when others=>
null;
end case;
end if;
end if;
end process;
--data from the ram needs to be sampled on the falling edge of the controller clock for proper operation
process(clk)
begin
if falling_edge(clk) then
int_readdata <= ram_dq;
end if;
end process;
--process generating the command sequence for the SDRAM
ram_cke <= '1';
ram_cs_n <= ram_cmd(3);
ram_ras_n <= ram_cmd(2);
ram_cas_n <= ram_cmd(1);
ram_we_n <= ram_cmd(0);
OUTPUTS : process(clk, reset)
begin
if reset = '1' then
ram_addr <= (others=>'0');
ram_cmd <= "1111";
ram_ba <= (others=>'0');
ram_dq <= (others=>'Z');
ram_dqm <= (others=>'1');
elsif rising_edge(clk) then
if init_state = init_pre then
ram_cmd <= "0010"; --precharge
ram_addr <= (10=>'1', others=>'0');
elsif init_state = init_ref then
ram_cmd <= "0001"; --refresh
elsif init_state = init_mode then
ram_cmd <= "0000"; --mode set
ram_addr <= "000000110000"; --no burst, three cycles latency
elsif init_state = init_done then
if state = ref then
ram_cmd <= "0001"; --refresh
elsif state = act then
ram_cmd <= "0011"; --activate
ram_addr <= int_address(22 downto 11);
ram_ba <= int_address(10 downto 9);
elsif state = read then
ram_cmd <= "0101"; --read
ram_addr <= "000"&int_address(8 downto 0);
ram_dqm <= "0000";
elsif state = write then
ram_cmd <= "0100"; --write
ram_addr <= "000"&int_address(8 downto 0);
ram_dq <= int_writedata;
ram_dqm <= not int_byteenable;
elsif state = precharge_all then
ram_cmd <= "0010"; --precharge
ram_addr <= "010"&int_address(8 downto 0);
ram_dqm <= "1111";
else
ram_cmd <= "1111"; --nop
ram_dq <= (others=>'Z');
end if;
else
ram_cmd <= "1111"; --nop
end if;
end if;
end process;
end arch;