738 lines
25 KiB
VHDL
738 lines
25 KiB
VHDL
|
|
------------------------------------------------------
|
||
|
|
-- FSM for a SDRAM controller
|
||
|
|
--
|
||
|
|
-- Version 0.1 - Ready to simulate
|
||
|
|
--
|
||
|
|
-- Author: Mike Field (hamster@snap.net.nz)
|
||
|
|
--
|
||
|
|
-- Feel free to use it however you would like, but
|
||
|
|
-- just drop me an email to say thanks.
|
||
|
|
-------------------------------------------------------
|
||
|
|
library ieee;
|
||
|
|
use ieee.std_logic_1164.all;
|
||
|
|
use ieee.std_logic_unsigned.all;
|
||
|
|
|
||
|
|
-- library unisim;
|
||
|
|
-- use unisim.vcomponents.all;
|
||
|
|
|
||
|
|
entity sdram_controller2 is
|
||
|
|
generic (
|
||
|
|
HIGH_BIT: integer := 24;
|
||
|
|
MHZ: integer := 96;
|
||
|
|
REFRESH_CYCLES: integer := 4096;
|
||
|
|
ADDRESS_BITS: integer := 12
|
||
|
|
);
|
||
|
|
PORT (
|
||
|
|
clock_100: in std_logic;
|
||
|
|
clock_100_delayed_3ns: in std_logic;
|
||
|
|
rst: in std_logic;
|
||
|
|
|
||
|
|
-- Signals to/from the SDRAM chip
|
||
|
|
DRAM_ADDR : OUT STD_LOGIC_VECTOR (ADDRESS_BITS-1 downto 0);
|
||
|
|
DRAM_BA : OUT STD_LOGIC_VECTOR (1 downto 0);
|
||
|
|
DRAM_CAS_N : OUT STD_LOGIC;
|
||
|
|
DRAM_CKE : OUT STD_LOGIC;
|
||
|
|
DRAM_CLK : OUT STD_LOGIC;
|
||
|
|
DRAM_CS_N : OUT STD_LOGIC;
|
||
|
|
DRAM_DQ : INOUT STD_LOGIC_VECTOR(15 downto 0);
|
||
|
|
DRAM_DQM : OUT STD_LOGIC_VECTOR(1 downto 0);
|
||
|
|
DRAM_RAS_N : OUT STD_LOGIC;
|
||
|
|
DRAM_WE_N : OUT STD_LOGIC;
|
||
|
|
|
||
|
|
pending: out std_logic;
|
||
|
|
|
||
|
|
--- Inputs from rest of the system
|
||
|
|
address : IN STD_LOGIC_VECTOR (HIGH_BIT downto 2);
|
||
|
|
req_read : IN STD_LOGIC;
|
||
|
|
req_write : IN STD_LOGIC;
|
||
|
|
data_out : OUT STD_LOGIC_VECTOR (31 downto 0);
|
||
|
|
data_out_valid : OUT STD_LOGIC;
|
||
|
|
data_in : IN STD_LOGIC_VECTOR (31 downto 0);
|
||
|
|
data_mask : IN STD_LOGIC_VECTOR (3 downto 0)
|
||
|
|
);
|
||
|
|
end entity;
|
||
|
|
|
||
|
|
|
||
|
|
architecture rtl of sdram_controller2 is
|
||
|
|
|
||
|
|
type reg is record
|
||
|
|
address : std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||
|
|
bank : std_logic_vector( 1 downto 0);
|
||
|
|
init_counter : std_logic_vector(14 downto 0);
|
||
|
|
rf_counter : integer;
|
||
|
|
rf_pending : std_logic;
|
||
|
|
rd_pending : std_logic;
|
||
|
|
wr_pending : std_logic;
|
||
|
|
act_row : std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||
|
|
act_ba : std_logic_vector(1 downto 0);
|
||
|
|
data_out_low : std_logic_vector(15 downto 0);
|
||
|
|
req_addr_q : std_logic_vector(HIGH_BIT downto 2);
|
||
|
|
req_data_write: std_logic_vector(31 downto 0);
|
||
|
|
req_mask : std_logic_vector(3 downto 0);
|
||
|
|
data_out_valid: std_logic;
|
||
|
|
dq_masks : std_logic_vector(1 downto 0);
|
||
|
|
tristate : std_logic;
|
||
|
|
end record;
|
||
|
|
|
||
|
|
signal r : reg;
|
||
|
|
signal n : reg;
|
||
|
|
|
||
|
|
signal rstate : std_logic_vector(8 downto 0);
|
||
|
|
signal nstate : std_logic_vector(8 downto 0);
|
||
|
|
signal rdata_write : std_logic_vector(15 downto 0);
|
||
|
|
signal ndata_write : std_logic_vector(15 downto 0);
|
||
|
|
|
||
|
|
|
||
|
|
-- Vectors for each SDRAM 'command'
|
||
|
|
--- CS_N, RAS_N, CAS_N, WE_N
|
||
|
|
constant cmd_nop : std_logic_vector(3 downto 0) := "0111";
|
||
|
|
constant cmd_read : std_logic_vector(3 downto 0) := "0101"; -- Must be sure A10 is low.
|
||
|
|
constant cmd_write : std_logic_vector(3 downto 0) := "0100";
|
||
|
|
constant cmd_act : std_logic_vector(3 downto 0) := "0011";
|
||
|
|
constant cmd_pre : std_logic_vector(3 downto 0) := "0010"; -- Must set A10 to '1'.
|
||
|
|
constant cmd_ref : std_logic_vector(3 downto 0) := "0001";
|
||
|
|
constant cmd_mrs : std_logic_vector(3 downto 0) := "0000"; -- Mode register set
|
||
|
|
|
||
|
|
-- State assignments
|
||
|
|
constant s_init_nop_id: std_logic_vector(4 downto 0) := "00000";
|
||
|
|
|
||
|
|
constant s_init_nop : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_nop;
|
||
|
|
constant s_init_pre : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_pre;
|
||
|
|
constant s_init_ref : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_ref;
|
||
|
|
constant s_init_mrs : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_mrs;
|
||
|
|
|
||
|
|
constant s_idle_id: std_logic_vector(4 downto 0) := "00001";
|
||
|
|
constant s_idle : std_logic_vector(8 downto 0) := s_idle_id & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rf0_id: std_logic_vector(4 downto 0) := "00010";
|
||
|
|
constant s_rf0 : std_logic_vector(8 downto 0) := s_rf0_id & cmd_ref;
|
||
|
|
|
||
|
|
constant s_rf1_id: std_logic_vector(4 downto 0) := "00011";
|
||
|
|
constant s_rf1 : std_logic_vector(8 downto 0) := "00011" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rf2_id: std_logic_vector(4 downto 0) := "00100";
|
||
|
|
constant s_rf2 : std_logic_vector(8 downto 0) := "00100" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rf3_id: std_logic_vector(4 downto 0) := "00101";
|
||
|
|
constant s_rf3 : std_logic_vector(8 downto 0) := "00101" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rf4_id: std_logic_vector(4 downto 0) := "00110";
|
||
|
|
constant s_rf4 : std_logic_vector(8 downto 0) := "00110" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rf5_id: std_logic_vector(4 downto 0) := "00111";
|
||
|
|
constant s_rf5 : std_logic_vector(8 downto 0) := "00111" & cmd_nop;
|
||
|
|
|
||
|
|
|
||
|
|
constant s_ra0_id: std_logic_vector(4 downto 0) := "01000";
|
||
|
|
constant s_ra0 : std_logic_vector(8 downto 0) := "01000" & cmd_act;
|
||
|
|
|
||
|
|
constant s_ra1_id: std_logic_vector(4 downto 0) := "01001";
|
||
|
|
constant s_ra1 : std_logic_vector(8 downto 0) := "01001" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_ra2_id: std_logic_vector(4 downto 0) := "01010";
|
||
|
|
constant s_ra2 : std_logic_vector(8 downto 0) := "01010" & cmd_nop;
|
||
|
|
|
||
|
|
|
||
|
|
constant s_dr0_id: std_logic_vector(4 downto 0) := "01011";
|
||
|
|
constant s_dr0 : std_logic_vector(8 downto 0) := "01011" & cmd_pre;
|
||
|
|
|
||
|
|
constant s_dr1_id: std_logic_vector(4 downto 0) := "01100";
|
||
|
|
constant s_dr1 : std_logic_vector(8 downto 0) := "01100" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_wr0_id: std_logic_vector(4 downto 0) := "01101";
|
||
|
|
constant s_wr0 : std_logic_vector(8 downto 0) := "01101" & cmd_write;
|
||
|
|
|
||
|
|
constant s_wr1_id: std_logic_vector(4 downto 0) := "01110";
|
||
|
|
constant s_wr1 : std_logic_vector(8 downto 0) := "01110" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_wr2_id: std_logic_vector(4 downto 0) := "01111";
|
||
|
|
constant s_wr2 : std_logic_vector(8 downto 0) := "01111" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_wr3_id: std_logic_vector(4 downto 0) := "10000";
|
||
|
|
constant s_wr3 : std_logic_vector(8 downto 0) := "10000" & cmd_write;
|
||
|
|
|
||
|
|
|
||
|
|
constant s_rd0_id: std_logic_vector(4 downto 0) := "10001";
|
||
|
|
constant s_rd0 : std_logic_vector(8 downto 0) := "10001" & cmd_read;
|
||
|
|
|
||
|
|
constant s_rd1_id: std_logic_vector(4 downto 0) := "10010";
|
||
|
|
constant s_rd1 : std_logic_vector(8 downto 0) := "10010" & cmd_read;
|
||
|
|
|
||
|
|
constant s_rd2_id: std_logic_vector(4 downto 0) := "10011";
|
||
|
|
constant s_rd2 : std_logic_vector(8 downto 0) := "10011" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rd3_id: std_logic_vector(4 downto 0) := "10100";
|
||
|
|
constant s_rd3 : std_logic_vector(8 downto 0) := "10100" & cmd_read;
|
||
|
|
|
||
|
|
constant s_rd4_id: std_logic_vector(4 downto 0) := "10101";
|
||
|
|
constant s_rd4 : std_logic_vector(8 downto 0) := "10101" & cmd_read;
|
||
|
|
|
||
|
|
constant s_rd5_id: std_logic_vector(4 downto 0) := "10110";
|
||
|
|
constant s_rd5 : std_logic_vector(8 downto 0) := "10110" & cmd_read;
|
||
|
|
|
||
|
|
constant s_rd6_id: std_logic_vector(4 downto 0) := "10111";
|
||
|
|
constant s_rd6 : std_logic_vector(8 downto 0) := "10111" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rd7_id: std_logic_vector(4 downto 0) := "11000";
|
||
|
|
constant s_rd7 : std_logic_vector(8 downto 0) := "11000" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rd8_id: std_logic_vector(4 downto 0) := "11001";
|
||
|
|
constant s_rd8 : std_logic_vector(8 downto 0) := "11001" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_rd9_id: std_logic_vector(4 downto 0) := "11011";
|
||
|
|
constant s_rd9 : std_logic_vector(8 downto 0) := "11011" & cmd_nop;
|
||
|
|
|
||
|
|
|
||
|
|
constant s_drdr0_id: std_logic_vector(4 downto 0) := "11101";
|
||
|
|
constant s_drdr0 : std_logic_vector(8 downto 0) := "11101" & cmd_pre;
|
||
|
|
|
||
|
|
constant s_drdr1_id: std_logic_vector(4 downto 0) := "11110";
|
||
|
|
constant s_drdr1 : std_logic_vector(8 downto 0) := "11110" & cmd_nop;
|
||
|
|
|
||
|
|
constant s_drdr2_id: std_logic_vector(4 downto 0) := "11111";
|
||
|
|
constant s_drdr2 : std_logic_vector(8 downto 0) := "11111" & cmd_nop;
|
||
|
|
|
||
|
|
signal addr_row : std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||
|
|
signal addr_bank: std_logic_vector(1 downto 0);
|
||
|
|
|
||
|
|
constant COLUMN_HIGH: integer := HIGH_BIT - addr_row'LENGTH - addr_bank'LENGTH - 1; -- last 1 means 16 bit width
|
||
|
|
|
||
|
|
|
||
|
|
signal addr_col : std_logic_vector(7 downto 0);
|
||
|
|
signal captured : std_logic_vector(15 downto 0);
|
||
|
|
signal busy: std_logic;
|
||
|
|
|
||
|
|
constant tOPD: time := 2.1 ns;
|
||
|
|
constant tHZ: time := 8 ns;
|
||
|
|
|
||
|
|
signal dram_dq_dly : std_logic_vector(15 downto 0);
|
||
|
|
|
||
|
|
-- Debug only
|
||
|
|
signal debug_cmd: std_logic_vector(3 downto 0);
|
||
|
|
|
||
|
|
signal not_clock_100_delayed_3ns: std_logic;
|
||
|
|
|
||
|
|
constant RELOAD: integer := (((64000000/REFRESH_CYCLES)*MHZ)/1000) - 10;
|
||
|
|
|
||
|
|
attribute IOB: string;
|
||
|
|
|
||
|
|
signal i_DRAM_CS_N: std_logic;
|
||
|
|
attribute IOB of i_DRAM_CS_N: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_RAS_N: std_logic;
|
||
|
|
attribute IOB of i_DRAM_RAS_N: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_CAS_N: std_logic;
|
||
|
|
attribute IOB of i_DRAM_CAS_N: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_WE_N: std_logic;
|
||
|
|
attribute IOB of i_DRAM_WE_N: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_ADDR: std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||
|
|
attribute IOB of i_DRAM_ADDR: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_BA: std_logic_vector(1 downto 0);
|
||
|
|
attribute IOB of i_DRAM_BA: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_DQM: std_logic_vector(1 downto 0);
|
||
|
|
attribute IOB of i_DRAM_DQM: signal is "true";
|
||
|
|
|
||
|
|
attribute IOB of rdata_write: signal is "true";
|
||
|
|
attribute IOB of captured: signal is "true";
|
||
|
|
|
||
|
|
signal i_DRAM_CLK: std_logic;
|
||
|
|
|
||
|
|
attribute fsm_encoding: string;
|
||
|
|
attribute fsm_encoding of nstate: signal is "user";
|
||
|
|
attribute fsm_encoding of rstate: signal is "user";
|
||
|
|
|
||
|
|
begin
|
||
|
|
|
||
|
|
debug_cmd <= rstate(3 downto 0);
|
||
|
|
|
||
|
|
-- Addressing is in 32 bit words - twice that of the DRAM width,
|
||
|
|
-- so each burst of four access two system words.
|
||
|
|
--addr_row <= address(23 downto 11);
|
||
|
|
--addr_bank <= address(10 downto 9);
|
||
|
|
process(r.req_addr_q)
|
||
|
|
begin
|
||
|
|
addr_bank <= r.req_addr_q(HIGH_BIT downto (HIGH_BIT-addr_bank'LENGTH)+1);
|
||
|
|
-- (24-2) downto (24-2 - 2 - 13 - 1)
|
||
|
|
-- 22 downto 6
|
||
|
|
addr_row <= --r.req_addr_q(HIGH_BIT-addr_bank'LENGTH downto COLUMN_HIGH+2);
|
||
|
|
r.req_addr_q(ADDRESS_BITS-1+9 downto 9);
|
||
|
|
addr_col <= (others => '0');
|
||
|
|
|
||
|
|
addr_col <= --r.req_addr_q(COLUMN_HIGH+1 downto 2) & "0";
|
||
|
|
r.req_addr_q(8 downto 2) & "0";
|
||
|
|
end process;
|
||
|
|
|
||
|
|
not_clock_100_delayed_3ns <= not clock_100_delayed_3ns;
|
||
|
|
|
||
|
|
clock: ODDR2
|
||
|
|
generic map (
|
||
|
|
DDR_ALIGNMENT => "NONE",
|
||
|
|
INIT => '0',
|
||
|
|
SRTYPE => "ASYNC")
|
||
|
|
port map (
|
||
|
|
D0 => '1',
|
||
|
|
D1 => '0',
|
||
|
|
Q => i_DRAM_CLK,
|
||
|
|
C0 => clock_100_delayed_3ns,
|
||
|
|
C1 => not_clock_100_delayed_3ns,
|
||
|
|
CE => '1',
|
||
|
|
R => '0',
|
||
|
|
S => '0'
|
||
|
|
);
|
||
|
|
|
||
|
|
DRAM_CKE <= '1';
|
||
|
|
|
||
|
|
DRAM_CLK <= transport i_DRAM_CLK after tOPD;
|
||
|
|
|
||
|
|
i_DRAM_CS_N <= transport rstate(3) after tOPD;
|
||
|
|
DRAM_CS_N <= i_DRAM_CS_N;
|
||
|
|
|
||
|
|
i_DRAM_RAS_N <= transport rstate(2) after tOPD;
|
||
|
|
DRAM_RAS_N <= i_DRAM_RAS_N;
|
||
|
|
|
||
|
|
i_DRAM_CAS_N <= transport rstate(1) after tOPD;
|
||
|
|
DRAM_CAS_N <= i_DRAM_CAS_N;
|
||
|
|
|
||
|
|
i_DRAM_WE_N <= transport rstate(0) after tOPD;
|
||
|
|
DRAM_WE_N <= i_DRAM_WE_N;
|
||
|
|
|
||
|
|
i_DRAM_ADDR <= transport r.address after tOPD;
|
||
|
|
DRAM_ADDR <= i_DRAM_ADDR;
|
||
|
|
|
||
|
|
i_DRAM_BA <= transport r.bank after tOPD;
|
||
|
|
DRAM_BA <= i_DRAM_BA;
|
||
|
|
|
||
|
|
i_DRAM_DQM <= transport r.dq_masks after tOPD;
|
||
|
|
DRAM_DQM <= i_DRAM_DQM;
|
||
|
|
|
||
|
|
DATA_OUT <= r.data_out_low & captured;--r.data_out_low & captured;
|
||
|
|
data_out_valid <= r.data_out_valid;
|
||
|
|
|
||
|
|
DRAM_DQ <= (others => 'Z') after tHZ when r.tristate='1' else rdata_write;
|
||
|
|
|
||
|
|
pending <= '1' when r.wr_pending='1' or r.rd_pending='1' else '0';
|
||
|
|
|
||
|
|
process (r, rstate, address, req_read, rdata_write, req_write, addr_row, addr_bank, addr_col, data_in, captured)
|
||
|
|
begin
|
||
|
|
-- copy the existing values
|
||
|
|
n <= r;
|
||
|
|
nstate <= rstate;
|
||
|
|
ndata_write <= rdata_write;
|
||
|
|
|
||
|
|
if req_read = '1' then
|
||
|
|
n.rd_pending <= '1';
|
||
|
|
if r.rd_pending='0' then
|
||
|
|
n.req_addr_q <= address;
|
||
|
|
end if;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
if req_write = '1' then
|
||
|
|
n.wr_pending <= '1';
|
||
|
|
if r.wr_pending='0' then
|
||
|
|
n.req_addr_q <= address;
|
||
|
|
-- Queue data here
|
||
|
|
n.req_data_write <= data_in;
|
||
|
|
n.req_mask <= data_mask;
|
||
|
|
end if;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
n.dq_masks <= "11";
|
||
|
|
|
||
|
|
-- first off, do we need to perform a refresh cycle ASAP?
|
||
|
|
if r.rf_counter = RELOAD then -- 781 = 64,000,000ns / 8192 / 10ns
|
||
|
|
n.rf_counter <= 0;
|
||
|
|
n.rf_pending <= '1';
|
||
|
|
else
|
||
|
|
-- only start looking for refreshes outside of the initialisation state.
|
||
|
|
if not(rstate(8 downto 4) = s_init_nop(8 downto 4)) then
|
||
|
|
n.rf_counter <= r.rf_counter + 1;
|
||
|
|
end if;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- Set the data bus into HIZ, high and low bytes masked
|
||
|
|
--DRAM_DQ <= (others => 'Z');
|
||
|
|
n.tristate <= '0';
|
||
|
|
|
||
|
|
n.init_counter <= r.init_counter-1;
|
||
|
|
|
||
|
|
--ndata_write <= (others => DontCareValue);
|
||
|
|
|
||
|
|
n.data_out_valid <= '0'; -- alvie- here, no ?
|
||
|
|
|
||
|
|
-- Process the FSM
|
||
|
|
case rstate(8 downto 4) is
|
||
|
|
when s_init_nop_id => --s_init_nop(8 downto 4) =>
|
||
|
|
nstate <= s_init_nop;
|
||
|
|
n.address <= (others => '0');
|
||
|
|
n.bank <= (others => '0');
|
||
|
|
n.act_ba <= (others => '0');
|
||
|
|
n.rf_counter <= 0;
|
||
|
|
-- n.data_out_valid <= '1'; -- alvie- not here
|
||
|
|
|
||
|
|
-- T-130, precharge all banks.
|
||
|
|
if r.init_counter = "000000010000010" then
|
||
|
|
nstate <= s_init_pre;
|
||
|
|
n.address(10) <= '1';
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- T-127, T-111, T-95, T-79, T-63, T-47, T-31, T-15, the 8 refreshes
|
||
|
|
|
||
|
|
if r.init_counter(14 downto 7) = 0 and r.init_counter(3 downto 0) = 15 then
|
||
|
|
nstate <= s_init_ref;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- T-3, the load mode register
|
||
|
|
if r.init_counter = 3 then
|
||
|
|
nstate <= s_init_mrs;
|
||
|
|
-- Mode register is as follows:
|
||
|
|
-- resvd wr_b OpMd CAS=3 Seq bust=1
|
||
|
|
n.address <= "00" & "0" & "00" & "011" & "0" & "000";
|
||
|
|
-- resvd
|
||
|
|
n.bank <= "00";
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- T-1 The switch to the FSM (first command will be a NOP
|
||
|
|
if r.init_counter = 1 then
|
||
|
|
nstate <= s_idle;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
------------------------------
|
||
|
|
-- The Idle section
|
||
|
|
------------------------------
|
||
|
|
when s_idle_id =>
|
||
|
|
nstate <= s_idle;
|
||
|
|
|
||
|
|
-- do we have to activate a row?
|
||
|
|
if r.rd_pending = '1' or r.wr_pending = '1' then
|
||
|
|
nstate <= s_ra0;
|
||
|
|
n.address <= addr_row;
|
||
|
|
n.act_row <= addr_row;
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- refreshes take priority over everything
|
||
|
|
if r.rf_pending = '1' then
|
||
|
|
nstate <= s_rf0;
|
||
|
|
n.rf_pending <= '0';
|
||
|
|
end if;
|
||
|
|
------------------------------
|
||
|
|
-- Row activation
|
||
|
|
-- s_ra2 is also the "idle with active row" state and provides
|
||
|
|
-- a resting point between operations on the same row
|
||
|
|
------------------------------
|
||
|
|
when s_ra0_id =>
|
||
|
|
nstate <= s_ra1;
|
||
|
|
when s_ra1_id =>
|
||
|
|
nstate <= s_ra2;
|
||
|
|
|
||
|
|
|
||
|
|
when s_ra2_id=>
|
||
|
|
-- we can stay in this state until we have something to do
|
||
|
|
nstate <= s_ra2;
|
||
|
|
n.tristate<='0';
|
||
|
|
|
||
|
|
if r.rf_pending = '1' then
|
||
|
|
nstate <= s_dr0;
|
||
|
|
n.address(10) <= '1';
|
||
|
|
else
|
||
|
|
|
||
|
|
-- If there is a read pending, deactivate the row
|
||
|
|
if r.rd_pending = '1' or r.wr_pending = '1' then
|
||
|
|
nstate <= s_dr0;
|
||
|
|
n.address(10) <= '1';
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- unless we have a read to perform on the same row? do that instead
|
||
|
|
if r.rd_pending = '1' and r.act_row = addr_row and addr_bank=r.bank then
|
||
|
|
nstate <= s_rd0;
|
||
|
|
n.address <= (others => '0');
|
||
|
|
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
n.act_ba <= addr_bank;
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
n.rd_pending <= '0';
|
||
|
|
--n.tristate<='1';
|
||
|
|
end if;
|
||
|
|
|
||
|
|
-- unless we have a write on the same row? writes take priroty over reads
|
||
|
|
if r.wr_pending = '1' and r.act_row = addr_row and addr_bank=r.bank then
|
||
|
|
nstate <= s_wr0;
|
||
|
|
n.address <= (others => '0');
|
||
|
|
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||
|
|
ndata_write <= r.req_data_write(31 downto 16);
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
n.act_ba <= addr_bank;
|
||
|
|
n.dq_masks<= not r.req_mask(3 downto 2);
|
||
|
|
n.wr_pending <= '0';
|
||
|
|
--n.tristate <= '0';
|
||
|
|
end if;
|
||
|
|
|
||
|
|
|
||
|
|
end if;
|
||
|
|
-- nstate <= s_dr0;
|
||
|
|
-- n.address(10) <= '1';
|
||
|
|
-- n.rd_pending <= r.rd_pending;
|
||
|
|
-- n.wr_pending <= r.wr_pending;
|
||
|
|
--n.tristate <= '0';
|
||
|
|
--end if;
|
||
|
|
|
||
|
|
------------------------------------------------------
|
||
|
|
-- Deactivate the current row and return to idle state
|
||
|
|
------------------------------------------------------
|
||
|
|
when s_dr0_id =>
|
||
|
|
nstate <= s_dr1;
|
||
|
|
when s_dr1_id =>
|
||
|
|
nstate <= s_idle;
|
||
|
|
|
||
|
|
------------------------------
|
||
|
|
-- The Refresh section
|
||
|
|
------------------------------
|
||
|
|
when s_rf0_id =>
|
||
|
|
nstate <= s_rf1;
|
||
|
|
when s_rf1_id =>
|
||
|
|
nstate <= s_rf2;
|
||
|
|
when s_rf2_id =>
|
||
|
|
nstate <= s_rf3;
|
||
|
|
when s_rf3_id =>
|
||
|
|
nstate <= s_rf4;
|
||
|
|
when s_rf4_id =>
|
||
|
|
nstate <= s_rf5;
|
||
|
|
when s_rf5_id =>
|
||
|
|
nstate <= s_idle;
|
||
|
|
------------------------------
|
||
|
|
-- The Write section
|
||
|
|
------------------------------
|
||
|
|
when s_wr0_id =>
|
||
|
|
nstate <= s_wr3;
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
n.address(0) <= '1';
|
||
|
|
ndata_write <= r.req_data_write(15 downto 0);--data_in(31 downto 16);
|
||
|
|
--DRAM_DQ <= rdata_write;
|
||
|
|
n.dq_masks<= not r.req_mask(1 downto 0);
|
||
|
|
n.tristate <= '0';
|
||
|
|
|
||
|
|
when s_wr1_id => null;
|
||
|
|
when s_wr2_id =>
|
||
|
|
nstate <= s_dr0;
|
||
|
|
n.address(10) <= '1';
|
||
|
|
|
||
|
|
|
||
|
|
when s_wr3_id =>
|
||
|
|
-- Default to the idle+row active state
|
||
|
|
nstate <= s_ra2;
|
||
|
|
--DRAM_DQ <= rdata_write;
|
||
|
|
n.data_out_valid<='1'; -- alvie- ack write
|
||
|
|
n.tristate <= '0';
|
||
|
|
n.dq_masks<= "11";
|
||
|
|
|
||
|
|
-- If there is a read or write then deactivate the row
|
||
|
|
--if r.rd_pending = '1' or r.wr_pending = '1' then
|
||
|
|
-- nstate <= s_dr0;
|
||
|
|
-- n.address(10) <= '1';
|
||
|
|
--end if;
|
||
|
|
|
||
|
|
-- But if there is a read pending in the same row, do that
|
||
|
|
--if r.rd_pending = '1' and r.act_row = addr_row and r.act_ba = addr_bank then
|
||
|
|
-- nstate <= s_rd0;
|
||
|
|
-- n.address <= (others => '0');
|
||
|
|
-- n.address(addr_col'HIGH downto 0) <= addr_col;
|
||
|
|
-- n.bank <= addr_bank;
|
||
|
|
-- --n.act_ba <= addr_bank;
|
||
|
|
-- n.dq_masks <= "00";
|
||
|
|
-- n.rd_pending <= '0';
|
||
|
|
--end if;
|
||
|
|
|
||
|
|
-- unless there is a write pending in the same row, do that
|
||
|
|
--if r.wr_pending = '1' and r.act_row = addr_row and r.act_ba = addr_bank then
|
||
|
|
-- nstate <= s_wr0;
|
||
|
|
-- n.address <= (others => '0');
|
||
|
|
-- n.address(addr_col'HIGH downto 0) <= addr_col;
|
||
|
|
-- n.bank <= addr_bank;
|
||
|
|
--n.act_ba <= addr_bank;
|
||
|
|
-- n.dq_masks<= "00";
|
||
|
|
-- n.wr_pending <= '0';
|
||
|
|
--end if;
|
||
|
|
|
||
|
|
-- But always try and refresh if one is pending!
|
||
|
|
if r.rf_pending = '1' then
|
||
|
|
nstate <= s_wr2; --dr0;
|
||
|
|
--n.address(10) <= '1';
|
||
|
|
end if;
|
||
|
|
|
||
|
|
------------------------------
|
||
|
|
-- The Read section
|
||
|
|
------------------------------
|
||
|
|
when s_rd0_id => -- 10001
|
||
|
|
nstate <= s_rd1;
|
||
|
|
n.tristate<='1';
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
n.address(0)<='1';
|
||
|
|
|
||
|
|
when s_rd1_id => -- 10010
|
||
|
|
nstate <= s_rd2;
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
n.tristate<='1';
|
||
|
|
if r.rd_pending = '1' and r.act_row = addr_row and r.act_ba=addr_bank then
|
||
|
|
|
||
|
|
nstate <= s_rd3; -- Another request came, and we can pipeline -
|
||
|
|
n.address <= (others => '0');
|
||
|
|
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
n.act_ba <= addr_bank;
|
||
|
|
n.dq_masks<= "00";
|
||
|
|
n.rd_pending <= '0';
|
||
|
|
|
||
|
|
end if;
|
||
|
|
|
||
|
|
when s_rd2_id => -- 10011
|
||
|
|
nstate <= s_rd7;
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
n.tristate<='1';
|
||
|
|
|
||
|
|
|
||
|
|
when s_rd3_id => -- 10100
|
||
|
|
|
||
|
|
nstate <= s_rd4;
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
n.address(0) <= '1';
|
||
|
|
n.tristate<='1';
|
||
|
|
|
||
|
|
|
||
|
|
-- Data is still not ready...
|
||
|
|
|
||
|
|
when s_rd4_id => -- 10101
|
||
|
|
nstate <= s_rd5;
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
--n.address(0)<='1';
|
||
|
|
n.tristate<='1';
|
||
|
|
|
||
|
|
if r.rd_pending = '1' and r.act_row = addr_row and r.act_ba=addr_bank then
|
||
|
|
nstate <= s_rd5; -- Another request came, and we can pipeline -
|
||
|
|
|
||
|
|
n.address <= (others => '0');
|
||
|
|
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
n.act_ba <= addr_bank;
|
||
|
|
n.dq_masks<= "00";
|
||
|
|
n.rd_pending <= '0';
|
||
|
|
|
||
|
|
else
|
||
|
|
nstate <= s_rd6; -- NOTE: not correct
|
||
|
|
end if;
|
||
|
|
|
||
|
|
--if r.rf_pending = '1' then
|
||
|
|
-- nstate <= s_drdr0;
|
||
|
|
-- n.address(10) <= '1';
|
||
|
|
-- n.rd_pending <= r.rd_pending; -- Keep request
|
||
|
|
--end if;
|
||
|
|
|
||
|
|
|
||
|
|
n.data_out_low <= captured;
|
||
|
|
n.data_out_valid <= '1';
|
||
|
|
|
||
|
|
|
||
|
|
when s_rd5_id =>
|
||
|
|
-- If a refresh is pending then always deactivate the row
|
||
|
|
--if r.rf_pending = '1' then
|
||
|
|
-- nstate <= s_drdr0;
|
||
|
|
-- n.address(10) <= '1';
|
||
|
|
--end if;
|
||
|
|
|
||
|
|
n.address(0) <= '1';
|
||
|
|
nstate <= s_rd4; -- Another request came, and we can pipeline -
|
||
|
|
n.dq_masks <= "00";
|
||
|
|
n.tristate<='1';
|
||
|
|
|
||
|
|
when s_rd6_id =>
|
||
|
|
nstate <= s_rd7;
|
||
|
|
n.dq_masks<= "00";
|
||
|
|
n.tristate<='1';
|
||
|
|
|
||
|
|
when s_rd7_id =>
|
||
|
|
nstate <= s_ra2;
|
||
|
|
n.data_out_low <= captured;
|
||
|
|
n.data_out_valid <= '1';
|
||
|
|
n.tristate<='1';
|
||
|
|
|
||
|
|
when s_rd8_id => null;
|
||
|
|
|
||
|
|
when s_rd9_id => null;
|
||
|
|
|
||
|
|
-- The Deactivate row during read section
|
||
|
|
------------------------------
|
||
|
|
when s_drdr0_id =>
|
||
|
|
nstate <= s_drdr1;
|
||
|
|
when s_drdr1_id =>
|
||
|
|
nstate <= s_drdr2;
|
||
|
|
n.data_out_low <= captured;
|
||
|
|
n.data_out_valid <= '1';
|
||
|
|
when s_drdr2_id =>
|
||
|
|
nstate <= s_idle;
|
||
|
|
|
||
|
|
if r.rf_pending = '1' then
|
||
|
|
nstate <= s_rf0;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
if r.rd_pending = '1' or r.wr_pending = '1' then
|
||
|
|
nstate <= s_ra0;
|
||
|
|
n.address <= addr_row;
|
||
|
|
n.act_row <= addr_row;
|
||
|
|
n.bank <= addr_bank;
|
||
|
|
end if;
|
||
|
|
|
||
|
|
when others =>
|
||
|
|
nstate <= s_init_nop;
|
||
|
|
end case;
|
||
|
|
end process;
|
||
|
|
|
||
|
|
--- The clock driven logic
|
||
|
|
process (clock_100, n)
|
||
|
|
begin
|
||
|
|
if clock_100'event and clock_100 = '1' then
|
||
|
|
if rst='1' then
|
||
|
|
rstate <= (others => '0');
|
||
|
|
r.address <= (others => '0');
|
||
|
|
r.bank <= (others => '0');
|
||
|
|
r.init_counter <= "100000000000000";
|
||
|
|
-- synopsys translate_off
|
||
|
|
r.init_counter <= "000000100000000";
|
||
|
|
-- synopsys translate_on
|
||
|
|
r.rf_counter <= 0;
|
||
|
|
r.rf_pending <= '0';
|
||
|
|
r.rd_pending <= '0';
|
||
|
|
r.wr_pending <= '0';
|
||
|
|
r.act_row <= (others => '0');
|
||
|
|
r.data_out_low <= (others => '0');
|
||
|
|
r.data_out_valid <= '0';
|
||
|
|
r.dq_masks <= "11";
|
||
|
|
r.tristate<='1';
|
||
|
|
else
|
||
|
|
r <= n;
|
||
|
|
rstate <= nstate;
|
||
|
|
rdata_write <= ndata_write;
|
||
|
|
end if;
|
||
|
|
end if;
|
||
|
|
end process;
|
||
|
|
|
||
|
|
dram_dq_dly <= transport dram_dq after 1.9 ns;
|
||
|
|
|
||
|
|
-- process (clock_100_delayed_3ns, dram_dq_dly)
|
||
|
|
-- begin
|
||
|
|
-- if clock_100_delayed_3ns'event and clock_100_delayed_3ns = '1' then
|
||
|
|
-- captured <= dram_dq_dly;
|
||
|
|
-- end if;
|
||
|
|
-- end process;
|
||
|
|
|
||
|
|
process (clock_100)
|
||
|
|
begin
|
||
|
|
if falling_edge(clock_100) then
|
||
|
|
captured <= dram_dq_dly;
|
||
|
|
end if;
|
||
|
|
end process;
|
||
|
|
|
||
|
|
end rtl;
|