Estoy utilizando la placa de evaluación Spartan SP601, que incluye 1 GB Elpida EDE1116ACBG-8E-E SDRAM. Me gustaría construir un controlador de RAM, pero no tengo experiencia en trabajar con RAM antes. En gran parte basé mi diseño en un controlador de RAM en un libro de texto para dispositivos Spartan-3. Proporcioné mi diseño a continuación en caso de que sea de ayuda. Las señales de control para la SDRAM son cas_b
, ras_b
y we_b
.
Tengo las siguientes preguntas:
-
¿Hay alguna forma de depurar mi controlador SDRAM? Me parece que funciona bien o no funciona, y realmente no puedo decir qué interacciones están ocurriendo entre el controlador y la SDRAM.
-
¿Cuáles son los parámetros de tiempo más relevantes que debo tener en cuenta para mi SDRAM? La cantidad de parámetros de tiempo que figuran en la hoja de datos de Elpida es abrumadora de ver.
-
¿Tiene algún otro consejo para desarrollar un controlador SDRAM que funcione? ¿Es mi diseño debajo de un buen comienzo?
Circuito de prueba SDRAM básico
library IEEE;
library UNISIM;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use UNISIM.vcomponents.all;
entity ram_ctrl_test is
Port ( reset : in STD_LOGIC;
-- clk : in STD_LOGIC;
I, IB : in STD_LOGIC;
btn : in STD_LOGIC_VECTOR (2 downto 0);
rx : in STD_LOGIC;
tx : out STD_LOGIC;
led : out STD_LOGIC_VECTOR (7 downto 0);
ad : out STD_LOGIC_VECTOR (12 downto 0);
dio_a : inout STD_LOGIC_VECTOR (15 downto 0);
bank : out STD_LOGIC_VECTOR (2 downto 0);
cke : out STD_LOGIC;
cas_b, ras_b, we_b : out STD_LOGIC);
end ram_ctrl_test;
architecture arch of ram_ctrl_test is
constant ADDR_W: integer := 13;
constant DATA_W: integer := 16;
signal clk, O: std_logic;
signal addr: std_logic_vector(ADDR_W-1 downto 0);
signal sw : std_logic_vector(7 downto 0);
signal data_f2s, data_s2f: std_logic_vector(DATA_W-1 downto 0);
signal mem, rw: std_logic;
signal data_reg: std_logic_vector(7 downto 0);
signal db_btn: std_logic_vector(2 downto 0);
signal rx_empty, update: std_logic;
signal in_data, out_data: std_logic_vector(7 downto 0);
begin
IBUFGDS_inst : IBUFGDS
generic map (
DIFF_TERM => FALSE, -- Differential Termination
IBUF_LOW_PWR => FALSE, -- Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
IOSTANDARD => "DEFAULT")
port map (
O => O, -- Clock buffer output
I => I, -- Diff_p clock buffer input (connect directly to top-level port)
IB => IB -- Diff_n clock buffer input (connect directly to top-level port)
);
BUFG_inst : BUFG
port map (
O => clk, -- 1-bit output: Clock buffer output
I => O -- 1-bit input: Clock buffer input
);
ctrl_unit: entity work.sram_ctrl
port map(clk=>clk,reset=>reset,mem=>mem,rw=>rw,addr=>addr,data_f2s=>data_f2s,ready=>open,data_s2f_r=>data_s2f,
data_s2f_ur=>open,ad=>ad,dio_a=>dio_a,bank=>bank,cke=>cke,cas_b=>cas_b,ras_b=>ras_b,we_b=>we_b);
debounce_unit0: entity work.debounce
port map(clk=>clk,reset=>reset,sw=>btn(0),db_level=>open,db_tick=>db_btn(0));
debounce_unit1: entity work.debounce
port map(clk=>clk,reset=>reset,sw=>btn(1),db_level=>open,db_tick=>db_btn(1));
debounce_unit2: entity work.debounce
port map(clk=>clk,reset=>reset,sw=>btn(2),db_level=>open,db_tick=>db_btn(2));
uart: entity work.uart(str_arch)
port map(clk=>clk,reset=>reset,rx=>rx,rd_uart=>update,wr_uart=>update,w_data=>out_data,tx_full=>open,
rx_empty=>rx_empty,r_data=>in_data,tx=>tx);
enabler: entity work.enable(fsm_arch)
port map(clk=>clk,reset=>reset,rx_empty=>rx_empty,en=>update);
address: entity work.addr_controller(fsm_arch)
port map(clk=>clk,reset=>reset,update=>update,in_data=>in_data,out_data=>out_data,sw=>sw);
-- data registers
process(clk)
begin
if rising_edge(clk) then
if (db_btn(0) = '1') then
data_reg <= sw;
end if;
end if;
end process;
-- address
addr <= "00000" & sw;
-- command
process(db_btn,data_reg)
begin
data_f2s <= (others => '0');
if db_btn(1) = '1' then -- write
mem <= '1';
rw <= '0';
data_f2s <= "00000000" & data_reg;
elsif db_btn(2) = '1' then -- read
mem <= '1';
rw <= '1';
else
mem <= '0';
rw <= '1';
end if;
end process;
-- output
led <= data_s2f(7 downto 0);
end arch;
Controlador de RAM
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity sram_ctrl is
Port ( clk, reset : in STD_LOGIC;
-- to/from main system
mem : in STD_LOGIC;
rw : in STD_LOGIC;
addr : in STD_LOGIC_VECTOR (12 downto 0);
data_f2s : in STD_LOGIC_VECTOR (15 downto 0);
ready : out STD_LOGIC;
data_s2f_r, data_s2f_ur : out STD_LOGIC_VECTOR (15 downto 0);
-- to/from chip
ad : out STD_LOGIC_VECTOR (12 downto 0);
bank : out STD_LOGIC_VECTOR (2 downto 0);
cke : out STD_LOGIC;
dio_a : inout STD_LOGIC_VECTOR (15 downto 0);
cas_b, ras_b, we_b : out STD_LOGIC);
end sram_ctrl;
architecture arch of sram_ctrl is
type state_type is (idle, rd1, rd2, wr1, wr2);
signal state_reg, state_next: state_type;
signal data_f2s_reg, data_f2s_next: std_logic_vector(15 downto 0);
signal data_s2f_reg, data_s2f_next: std_logic_vector(15 downto 0);
signal addr_reg, addr_next: std_logic_vector(12 downto 0);
signal cas_buf, ras_buf, we_buf, tri_buf: std_logic;
signal cas_reg, ras_reg, we_reg, tri_reg: std_logic;
begin
-- state & data registers
process(clk,reset)
begin
if (reset = '1') then
state_reg <= idle;
addr_reg <= (others => '0');
data_f2s_reg <= (others => '0');
data_s2f_reg <= (others => '0');
cas_reg <= '1';
ras_reg <= '1';
we_reg <= '1';
tri_reg <= '1';
elsif rising_edge(clk) then
state_reg <= state_next;
addr_reg <= addr_next;
data_f2s_reg <= data_f2s_next;
data_s2f_reg <= data_s2f_next;
cas_reg <= cas_buf;
ras_reg <= ras_buf;
we_reg <= we_buf;
tri_reg <= tri_buf;
end if;
end process;
-- next-state logic
process(state_reg, mem, rw, dio_a, addr, data_f2s, data_f2s_reg, data_s2f_reg, addr_reg)
begin
addr_next <= addr_reg;
data_f2s_next <= data_f2s_reg;
data_s2f_next <= data_s2f_reg;
ready <= '0';
case state_reg is
when idle =>
if mem = '0' then
state_next <= idle;
else
addr_next <= addr;
if rw='0' then --write
state_next <= wr1;
data_f2s_next <= data_f2s;
else --read
state_next <= rd1;
end if;
end if;
ready <= '1';
when wr1 =>
state_next <= wr2;
when wr2 =>
state_next <= idle;
when rd1 =>
state_next <= rd2;
when rd2 =>
data_s2f_next <= dio_a;
state_next <= idle;
end case;
end process;
-- "look-ahead" output logic
process(state_next)
begin
cas_buf <= '1'; --default
ras_buf <= '1';
we_buf <= '1';
tri_buf <= '1';
case state_next is
when idle =>
when wr1 =>
tri_buf <= '0';
cas_buf <= '0';
we_buf <= '0';
when wr2 =>
tri_buf <= '0';
when rd1 =>
cas_buf <= '0';
when rd2 =>
cas_buf <= '0';
end case;
end process;
-- to main system
data_s2f_r <= data_s2f_reg;
data_s2f_ur <= dio_a;
-- to SRAM
cas_b <= cas_reg;
ras_b <= ras_reg;
we_b <= we_reg;
ad <= addr_reg;
bank <= "001";
-- i/o for SRAM chip a
cke <= '0';
dio_a <= data_f2s_reg when tri_reg = '0' else (others => 'Z');
end arch;