PoC.mem.sdram.ctrl_fsm

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 = \(\log_2(32\,\mbox{M}) = 25\)
  • D_BITS = 16
  • data-path width of phy on user side: 32-bit because of DDR
  • R_BITS = \(\log_2(8\,\mbox{K}) = 13\)
  • C_BITS = \(\log_2(1\,\mbox{K}) = 10\)
  • B_BITS = \(\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.

Entity Declaration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
entity 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;