-- 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
--
-- Entity: Generic controller for SDRAM memory.
--
-- Description:
--
-- This file contains the FSM as well as parts of the datapath.
-- The board specific physical layer is defined in another file.
--
-- Configuration
-- *************
--
-- SDRAM_TYPE activates some special cases:
--
-- - 0 for SDR-SDRAM
-- - 1 for DDR-SDRAM
-- - 2 for DDR2-SDRAM (no special support yet like ODT)
--
-- 2**A_BITS specifies the number of memory cells in the SDRAM. This is the
-- size of th memory in bits divided by the native data-path width of the SDRAM
-- (also in bits).
--
-- D_BITS is the native data-path width of the SDRAM. The width might be doubled
-- by the physical interface for DDR interfaces.
--
-- Furthermore, the memory array is divided into
-- 2**R_BITS rows, 2**C_BITS columns and 2**B_BITS banks.
--
-- .. NOTE::
-- For example, the MT46V32M16 has 512 Mbit = 8M x 4 banks x 16 bit =
-- 32M cells x 16 bit, with 8K rows and 1K columns. Thus, the configuration
-- is:
--
-- - A_BITS = :math:`\log_2(32\,\mbox{M}) = 25`
-- - D_BITS = 16
-- - data-path width of phy on user side: 32-bit because of DDR
-- - R_BITS = :math:`\log_2(8\,\mbox{K}) = 13`
-- - C_BITS = :math:`\log_2(1\,\mbox{K}) = 10`
-- - B_BITS = :math:`\log_2(4) = 2`
--
-- Set CAS latency (CL, MR_CL) and burst length (BL, MR_BL) according to
-- your needs.
--
-- If you have a DDR-SDRAM then set INIT_DLL = true, otherwise false.
--
-- The definition and values of generics T_* can be calculated from the
-- datasheets of the specific SDRAM (e.g. MT46V). Just divide the
-- minimum/maximum times by clock period.
-- Auto refreshs are applied periodically, the datasheet either specifies the
-- average refresh interval (T_REFI) or the total refresh cycle time (T_REF).
-- In the latter case, divide the total time by the row count to get the
-- average refresh interval. Substract about 50 clock cycles to
-- account for pending read/writes.
--
-- INIT_WAIT specifies the time period to wait after the SDRAM is powered up.
-- It is typically 100--200 us long, see datasheet. The waiting time is
-- specified in number of average refresh periods (specified by T_REFI):
-- INIT_WAIT = ceil(wait_time / clock_period / T_REFI)
-- e.g. INIT_WAIT = ceil(200 us / 10 ns / 700) = 29
--
-- Operation
-- *********
--
-- After user_cmd_valid is asserted high, the command (user_write) and address
-- (user_addr) must be hold until user_got_cmd is asserted.
--
-- The FSM automatically waits for user_wdata_valid on writes. The data should
-- be available soon. Otherwise the auto refresh might fail. The FSM only waits
-- for the first word to write. All successive words of a burst must be valid
-- in the following cycles. (A burst can't be stalled.) ATTENTION: During
-- writes, user_cmd_got is asserted only if user_wdata_valid is set.
--
-- The write data must directly connected to the physical layer.
--
-- License:
-- =============================================================================
-- Copyright 2007-2015 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]sdram_ctrl_fsm is
generic (
SDRAM_TYPE : natural; -- SDRAM type
A_BITS : positive; -- log2ceil(memory cell count)
D_BITS : positive; -- native data width
R_BITS : positive; -- log2ceil(rows)
C_BITS : positive; -- log2ceil(columns)
B_BITS : positive; -- log2ceil(banks)
CL : positive; -- CAS Latency in clock cycles
BL : positive; -- Burst Length
T_MRD : integer; -- in clock cycles
T_RAS : integer; -- in clock cycles
T_RCD : integer; -- in clock cycles
T_RFC : integer; -- (or T_RC) in clock cycles
T_RP : integer; -- in clock cycles
T_WR : integer; -- in clock cycles
T_WTR : integer; -- in clock cycles
T_REFI : integer; -- in clock cycles
INIT_WAIT : integer); -- in T_REFI periods
port (
clk : in std_logic;
rst : in std_logic;
user_cmd_valid : in std_logic;
user_wdata_valid : in std_logic;
user_write : in std_logic;
user_addr : in std_logic_vector(A_BITS-1 downto 0);
user_got_cmd : out std_logic;
user_got_wdata : out std_logic;
sd_cke_nxt : out std_logic;
sd_cs_nxt : out std_logic;
sd_ras_nxt : out std_logic;
sd_cas_nxt : out std_logic;
sd_we_nxt : out std_logic;
sd_a_nxt : out std_logic_vector(imax(R_BITS,C_BITS+1)-1 downto 0);
sd_ba_nxt : out std_logic_vector(B_BITS-1 downto 0);
rden_nxt : out std_logic;
wren_nxt : out std_logic);
end sdram_ctrl_fsm;
architecture [docs]rtl of sdram_ctrl_fsm is
-- length of burst in clock cycles of "clk"
function [docs]burst_clock_cycles return positive is
begin
if SDRAM_TYPE > 0 then return BL/2; end if;
return BL;
end;
constant BCC : natural := burst_clock_cycles;
-- FSM
type FSM_TYPE is (INIT1, INIT2, INIT3, INIT4, INIT5, INIT6, INIT7, INIT8,
INIT9, INIT10, INIT11,
DO_ACTIVATE,
DO_READ1, DO_READ2,
DO_WRITE1, DO_WRITE2,
CHECKNXT,
DO_PRECHARGE, DO_AUTO_REFRESH);
signal fsm_cs : FSM_TYPE;
signal fsm_ns : FSM_TYPE;
-- SDRAM Commands
subtype SD_CMD_TYPE is std_logic_vector(3 downto 0);
constant SD_CMD_DESELECT : SD_CMD_TYPE := "1---";
constant SD_CMD_NOP : SD_CMD_TYPE := "0111";
constant SD_CMD_ACTIVE : SD_CMD_TYPE := "0011";
constant SD_CMD_READ : SD_CMD_TYPE := "0101";
constant SD_CMD_WRITE : SD_CMD_TYPE := "0100";
constant SD_CMD_BURST_TERMINATE : SD_CMD_TYPE := "0110";
constant SD_CMD_PRECHARGE : SD_CMD_TYPE := "0010";
constant SD_CMD_AUTO_REFRESH : SD_CMD_TYPE := "0001";
constant SD_CMD_LOAD_MODE_REG : SD_CMD_TYPE := "0000";
signal sd_cmd_nxt : SD_CMD_TYPE;
-- SDRAM address
signal bank_addr : std_logic_vector(B_BITS-1 downto 0);
signal row_addr : std_logic_vector(R_BITS-1 downto 0);
signal col_addr : std_logic_vector(C_BITS-1 downto 0);
signal precharge_all : std_logic;
signal reset_dll : std_logic;
type SD_A_SEL_TYPE is (SD_A_SEL_EXT_MODE_REG,
SD_A_SEL_MODE_REG,
SD_A_SEL_ROW_ADDR,
SD_A_SEL_COL_ADDR);
signal sd_a_sel : SD_A_SEL_TYPE;
type SD_BA_SEL_TYPE is (SD_BA_SEL_EXT_MODE_REG,
SD_BA_SEL_MODE_REG,
SD_BA_SEL_ADDR);
signal sd_ba_sel : SD_BA_SEL_TYPE;
-- Value for Extended Mode Register:
-- bit 1--0: normal drive strength, enable DLL
constant EXT_MODE_REG : std_logic_vector(1 downto 0) :=
(others => '0');
-- Value for Mode Register
-- bit 6--0: CL, sequential burst, BL
-- bit 8: reset DLL
constant MODE_REG : std_logic_vector(8 downto 0) :=
"00" & std_logic_vector(to_unsigned(CL, 3)) &
"0" & std_logic_vector(to_unsigned(BL-1, 3));
--------
-- Timer
--------
-- Timer for average periodic refresh interval.
-- Timer counts from T_REFI-2 downto -1 for easy detection of
-- "timer done". MSB is sign bit.
signal timer_tREFI : signed(log2ceil(T_REFI-2) downto 0);
constant TIMER_TREFI_INIT : signed(log2ceil(T_REFI-2) downto 0)
:= to_signed(T_REFI-2, timer_tREFI'length);
signal timer_tREFI_start : std_logic;
signal timer_tREFI_done : std_logic;
-- Timer for SDRAM commands. To wait for n clock cycles, the timer must be
-- initiated to the value n-2. The minimum allowed initial value is -1. In
-- this case the timer is done in the next clock cycles.
signal timer_cmd : signed(5 downto 0);
signal timer_cmd_init : signed(5 downto 0);
signal timer_cmd_start : std_logic;
signal timer_cmd_done : std_logic;
-- Timer for ACTIVE-to-PRECHARGE.
-- Timer counts from T_RAS-2 downto -1 for easy detection of
-- "timer done". MSB is sign bit.
-- Substract 1, because timer is checked one cycle before DO_PRECHARGE.
signal timer_tRAS : signed(log2ceil(T_RAS-2) downto 0);
constant TIMER_TRAS_INIT : signed(log2ceil(T_RAS-2) downto 0)
:= to_signed(T_RAS-1 -2, timer_tRAS'length);
signal timer_tRAS_start : std_logic;
signal timer_tRAS_done : std_logic;
--------
-- Counter
--------
-- Misc down counter. Counter is "done", when value == -1.
-- Thus, if counter is inited to n, then counter is done n+2 decrements
-- later.
signal downcnt : signed(log2ceil(INIT_WAIT-2) downto 0);
signal downcnt_init : signed(downcnt'range);
signal downcnt_set : std_logic;
signal downcnt_dec : std_logic;
signal downcnt_done : std_logic;
--------
-- Last address
--------
signal last_bank_addr_r : std_logic_vector(bank_addr'range);
signal last_bank_addr_nxt : std_logic_vector(bank_addr'range);
signal last_row_addr_r : std_logic_vector(row_addr'range);
signal last_row_addr_nxt : std_logic_vector(row_addr'range);
signal last_write_r : std_logic;
signal last_write_nxt : std_logic;
signal save_cmd_addr : std_logic;
signal same_bank_row : std_logic;
begin -- rtl
-----------------------------------------------------------------------------
-- Configuration check
-----------------------------------------------------------------------------
assert (D_BITS = 16) or (D_BITS = 8) or (D_BITS = 4)
report "Data width not yet supported."
severity failure;
-----------------------------------------------------------------------------
-- Datapath not depending on FSM
-----------------------------------------------------------------------------
-- address mapping
col_addr <= user_addr( C_BITS-1 downto 0);
row_addr <= user_addr( R_BITS+C_BITS-1 downto C_BITS);
bank_addr <= user_addr(B_BITS+R_BITS+C_BITS-1 downto R_BITS+C_BITS);
timer_tREFI_done <= timer_tREFI(timer_tREFI'left);
timer_cmd_done <= timer_cmd(timer_cmd'left);
timer_tRAS_done <= timer_tRAS(timer_tRAS'left);
downcnt_done <= downcnt(downcnt'left);
same_bank_row <= '1' when (last_bank_addr_r & last_row_addr_r) =
(bank_addr & row_addr) else '0';
last_bank_addr_nxt <= bank_addr;
last_row_addr_nxt <= row_addr;
last_write_nxt <= user_write;
-----------------------------------------------------------------------------
-- FSM
-----------------------------------------------------------------------------
process (fsm_cs,
timer_tREFI_done, timer_cmd_done, timer_tRAS_done,
downcnt_done,
same_bank_row, last_write_r,
user_cmd_valid, user_write, user_wdata_valid)
begin -- process
fsm_ns <= fsm_cs;
sd_cke_nxt <= '1';
sd_cmd_nxt <= SD_CMD_DESELECT;
sd_a_sel <= SD_A_SEL_COL_ADDR;
sd_ba_sel <= SD_BA_SEL_ADDR;
precharge_all <= '0';
reset_dll <= '-'; -- only when load_mode_reg
rden_nxt <= '0';
wren_nxt <= '0';
timer_tREFI_start <= '0';
timer_tRAS_start <= '0';
timer_cmd_init <= (others => '-');
timer_cmd_start <= '0';
downcnt_init <= (others => '-');
downcnt_set <= '0';
downcnt_dec <= '0';
user_got_cmd <= '0';
user_got_wdata <= '0';
save_cmd_addr <= '0';
case fsm_cs is
when INIT1 =>
-- Wait for SDRAM power up. See description for INIT_WAIT in header.
-- Hold sd_cke low.
sd_cke_nxt <= '0';
downcnt_init <= to_signed(INIT_WAIT-2, downcnt_init'length);
downcnt_set <= '1';
timer_tREFI_start <= '1';
fsm_ns <= INIT2;
when INIT2 =>
sd_cke_nxt <= '0';
if timer_tREFI_done = '1' then
if downcnt_done = '1' then
fsm_ns <= INIT3;
else
timer_tREFI_start <= '1';
downcnt_dec <= '1';
end if;
end if;
when INIT3 =>
-- Bring up sd_cke with a NOP command.
sd_cmd_nxt <= SD_CMD_NOP;
fsm_ns <= INIT4;
when INIT4 =>
-- Precharge all.
sd_cmd_nxt <= SD_CMD_PRECHARGE;
sd_a_sel <= SD_A_SEL_COL_ADDR;
precharge_all <= '1';
timer_cmd_init <= to_signed(T_RP-2, timer_cmd_init'length);
timer_cmd_start <= '1';
if SDRAM_TYPE >= 1 then
fsm_ns <= INIT5;
else
-- skip if SDR-SDRAM
fsm_ns <= INIT8;
end if;
when INIT5 =>
sd_a_sel <= SD_A_SEL_EXT_MODE_REG;
sd_ba_sel <= SD_BA_SEL_EXT_MODE_REG;
timer_cmd_init <= to_signed(T_MRD-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Load extended mode register
sd_cmd_nxt <= SD_CMD_LOAD_MODE_REG;
timer_cmd_start <= '1';
fsm_ns <= INIT6;
end if;
when INIT6 =>
reset_dll <= '1';
sd_a_sel <= SD_A_SEL_MODE_REG;
sd_ba_sel <= SD_BA_SEL_MODE_REG;
timer_cmd_init <= to_signed(T_MRD-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Load mode register
sd_cmd_nxt <= SD_CMD_LOAD_MODE_REG;
timer_cmd_start <= '1';
-- Wait for 200 cycles, by waiting for T_REFI.
-- This is juzst for reuse.
timer_tREFI_start <= '1';
fsm_ns <= INIT7;
end if;
when INIT7 =>
sd_a_sel <= SD_A_SEL_COL_ADDR;
precharge_all <= '1';
timer_cmd_init <= to_signed(T_RP-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Precharge all.
sd_cmd_nxt <= SD_CMD_PRECHARGE;
timer_cmd_start <= '1';
fsm_ns <= INIT8;
end if;
when INIT8 =>
timer_cmd_init <= to_signed(T_RFC-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- First auto refresh.
sd_cmd_nxt <= SD_CMD_AUTO_REFRESH;
timer_cmd_start <= '1';
fsm_ns <= INIT9;
end if;
when INIT9 =>
timer_cmd_init <= to_signed(T_RFC-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Second auto refresh.
sd_cmd_nxt <= SD_CMD_AUTO_REFRESH;
timer_cmd_start <= '1';
fsm_ns <= INIT10;
end if;
when INIT10 =>
reset_dll <= '0';
sd_a_sel <= SD_A_SEL_MODE_REG;
sd_ba_sel <= SD_BA_SEL_MODE_REG;
timer_cmd_init <= to_signed(T_MRD-2, timer_cmd_init'length);
if (timer_cmd_done = '1') and (timer_tREFI_done = '1') then
-- Now, we have waited for at least 200 cycles.
-- Load mode register, with "reset DLL" cleared.
sd_cmd_nxt <= SD_CMD_LOAD_MODE_REG;
timer_cmd_start <= '1';
fsm_ns <= INIT11;
end if;
when INIT11 =>
timer_cmd_init <= to_signed(T_RFC-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Schedule another auto refresh and restart T_REFI timer.
sd_cmd_nxt <= SD_CMD_AUTO_REFRESH;
timer_cmd_start <= '1';
timer_tREFI_start <= '1';
fsm_ns <= DO_ACTIVATE;
end if;
when DO_ACTIVATE =>
-- For activate row.
sd_a_sel <= SD_A_SEL_ROW_ADDR;
sd_ba_sel <= SD_BA_SEL_ADDR;
-- wait for finish of last command, before executing new one
if timer_cmd_done = '1' then
if user_cmd_valid = '1' then
-- Activate Row
sd_cmd_nxt <= SD_CMD_ACTIVE;
timer_cmd_init <= to_signed(T_RCD-2, timer_cmd_init'length);
timer_cmd_start <= '1';
timer_tRAS_start<= '1';
if user_write = '1' then
fsm_ns <= DO_WRITE1;
else
fsm_ns <= DO_READ1;
end if;
elsif timer_tREFI_done = '1' then
-- Auto Refresh
sd_cmd_nxt <= SD_CMD_AUTO_REFRESH;
timer_cmd_init <= to_signed(T_RFC-2, timer_cmd_init'length);
timer_cmd_start <= '1';
timer_tREFI_start <= '1';
--fsm_ns <= DO_ACTIVATE;
end if;
end if;
when DO_READ1 =>
-- wait for CL cycles.
-- Substract 1 because CHECKNXT is entered before
-- DO_PRECHARGE.
timer_cmd_init <= to_signed(CL-1 -2,
timer_cmd_init'length);
-- Additional burst cycles: BCC-1
downcnt_init <= to_signed(BCC-1-2, downcnt_init'length);
sd_a_sel <= SD_A_SEL_COL_ADDR;
sd_ba_sel <= SD_BA_SEL_ADDR;
if timer_cmd_done = '1' then
-- Read first
sd_cmd_nxt <= SD_CMD_READ;
rden_nxt <= '1';
timer_cmd_start <= '1';
downcnt_set <= '1';
user_got_cmd <= '1';
save_cmd_addr <= '1';
if (SDRAM_TYPE = 0 and BL = 1) or
(SDRAM_TYPE > 0 and BL = 2) then
fsm_ns <= CHECKNXT;
else
fsm_ns <= DO_READ2;
end if;
end if;
when DO_READ2 =>
if (SDRAM_TYPE = 0 and BL > 1) or
(SDRAM_TYPE > 0 and BL > 2)
then
-- Read more
downcnt_dec <= '1';
rden_nxt <= '1';
if downcnt_done = '1' then
fsm_ns <= CHECKNXT;
end if;
end if;
when DO_WRITE1 =>
-- wait for 1 + BCC + T_WR cycles
-- Substract 1 because CHECKNXT is entered before
-- DO_PRECHARGE.
timer_cmd_init <= to_signed(1+BCC+T_WR-1 -2,
timer_cmd_init'length);
-- Additional burst cycles: BCC-1
downcnt_init <= to_signed(BCC-1-2, downcnt_init'length);
sd_a_sel <= SD_A_SEL_COL_ADDR;
sd_ba_sel <= SD_BA_SEL_ADDR;
if (timer_cmd_done and user_wdata_valid) = '1' then
-- Write first
sd_cmd_nxt <= SD_CMD_WRITE;
wren_nxt <= '1';
timer_cmd_start <= '1';
downcnt_set <= '1';
user_got_cmd <= '1';
user_got_wdata <= '1';
save_cmd_addr <= '1';
if (SDRAM_TYPE = 0 and BL = 1) or
(SDRAM_TYPE > 0 and BL = 2) then
fsm_ns <= CHECKNXT;
else
fsm_ns <= DO_WRITE2;
end if;
end if;
when DO_WRITE2 =>
if (SDRAM_TYPE = 0 and BL > 1) or
(SDRAM_TYPE > 0 and BL > 2) then
-- Write more
downcnt_dec <= '1';
wren_nxt <= '1';
user_got_wdata <= '1';
if downcnt_done = '1' then
fsm_ns <= CHECKNXT;
end if;
end if;
when CHECKNXT =>
if last_write_r = '1' then
-- last was write
if user_write = '1' then
-- write-to-write to same bank and row
-- Set timer to zero.
timer_cmd_init <= to_signed(-2, timer_cmd_init'length);
else
-- write-to-read to same bank and row
-- We must wait for 1+BCC+T_WTR cycles since start of write.
-- We already waited for BCC due to execution of burst.
timer_cmd_init <= to_signed(1+T_WTR -2, timer_cmd_init'length);
end if;
else
-- last was read
if user_write = '1' then
-- read-to-write to same bank and row
-- We must wait for BCC+CL cycles since start of read.
-- We already waited for BCC due to execution of burst.
timer_cmd_init <= to_signed(CL -2, timer_cmd_init'length);
else
-- read-to-read to same bank and row
-- Set timer to zero.
timer_cmd_init <= to_signed(-2, timer_cmd_init'length);
end if;
end if;
if timer_tREFI_done = '1' then
-- A refresh is pending.
-- Wait here until timer_tRAS is done.
if timer_tRAS_done = '1' then
fsm_ns <= DO_PRECHARGE;
end if;
elsif (user_cmd_valid and same_bank_row) = '1' then
-- Access to same bank and row.
-- Wait timer is initiated above.
timer_cmd_start <= '1';
if user_write = '1' then
fsm_ns <= DO_WRITE1;
else
fsm_ns <= DO_READ1;
end if;
elsif timer_cmd_done = '1' then
-- Execute a precharge now for minimum latency of next access to
-- another bank/row.
-- Wait here until timer_tRAS is done.
if timer_tRAS_done = '1' then
fsm_ns <= DO_PRECHARGE;
end if;
--else: check again
end if;
when DO_PRECHARGE =>
timer_cmd_init <= to_signed(T_RP-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Precharge
-- NOTE: It is sufficient to precharge the bank in use.
-- But, because the address isn't saved, the bank is unknown.
-- Thus, precharge ALL.
sd_cmd_nxt <= SD_CMD_PRECHARGE;
precharge_all <= '1';
timer_cmd_start <= '1';
if timer_tREFI_done = '1' then
fsm_ns <= DO_AUTO_REFRESH;
else
fsm_ns <= DO_ACTIVATE;
end if;
end if;
when DO_AUTO_REFRESH =>
timer_cmd_init <= to_signed(T_RFC-2, timer_cmd_init'length);
if timer_cmd_done = '1' then
-- Auto refresh
sd_cmd_nxt <= SD_CMD_AUTO_REFRESH;
timer_cmd_start <= '1';
timer_tREFI_start <= '1';
fsm_ns <= DO_ACTIVATE;
end if;
end case;
end process;
-----------------------------------------------------------------------------
-- Datapath depending on FSM output
--
-- Command and address are registered again in the physical layer.
-----------------------------------------------------------------------------
sd_cs_nxt <= sd_cmd_nxt(3);
sd_ras_nxt <= sd_cmd_nxt(2);
sd_cas_nxt <= sd_cmd_nxt(1);
sd_we_nxt <= sd_cmd_nxt(0);
process (sd_a_sel, reset_dll, row_addr, col_addr, precharge_all)
begin -- process
sd_a_nxt <= (others => '0');
case sd_a_sel is
when SD_A_SEL_EXT_MODE_REG =>
sd_a_nxt(EXT_MODE_REG'range) <= EXT_MODE_REG;
when SD_A_SEL_MODE_REG =>
sd_a_nxt(MODE_REG'range) <= MODE_REG;
sd_a_nxt(MODE_REG'left) <= reset_dll;
when SD_A_SEL_ROW_ADDR =>
sd_a_nxt(R_BITS-1 downto 0) <= row_addr;
when SD_A_SEL_COL_ADDR =>
sd_a_nxt (imin(10, C_BITS)-1 downto 0)
<= col_addr(imin(10, C_BITS)-1 downto 0);
sd_a_nxt(10) <= precharge_all;
if C_BITS > 10 then
sd_a_nxt(C_BITS downto 11) <= col_addr(C_BITS-1 downto 10);
end if;
end case;
end process;
with sd_ba_sel select
sd_ba_nxt <=
"01" when SD_BA_SEL_EXT_MODE_REG,
"00" when SD_BA_SEL_MODE_REG,
bank_addr when others; -- SD_BA_SEL_ADDR
-----------------------------------------------------------------------------
-- Registers
-----------------------------------------------------------------------------
[docs]process (clk)
begin -- process
if rising_edge(clk) then
if rst = '1' then
fsm_cs <= INIT1;
else
fsm_cs <= fsm_ns;
end if;
if timer_tREFI_start = '1' then
timer_tREFI <= TIMER_TREFI_INIT;
elsif timer_tREFI_done = '0' then
-- auto decrement
timer_tREFI <= timer_tREFI - 1;
end if;
if timer_cmd_start = '1' then
timer_cmd <= timer_cmd_init;
elsif timer_cmd_done = '0' then
-- auto decrement
timer_cmd <= timer_cmd - 1;
end if;
if timer_tRAS_start = '1' then
timer_tRAS <= TIMER_TRAS_INIT;
elsif timer_tRAS_done = '0' then
-- auto decrement
timer_tRAS <= timer_tRAS - 1;
end if;
if downcnt_set = '1' then
downcnt <= downcnt_init;
elsif downcnt_dec = '1' then
downcnt <= downcnt - 1;
end if;
if save_cmd_addr = '1' then
last_write_r <= last_write_nxt;
last_bank_addr_r <= last_bank_addr_nxt;
last_row_addr_r <= last_row_addr_nxt;
end if;
end if;
end process;
end rtl;