Skip to content

Instantly share code, notes, and snippets.

@xesscorp
Created September 16, 2011 03:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xesscorp/1221094 to your computer and use it in GitHub Desktop.
Save xesscorp/1221094 to your computer and use it in GitHub Desktop.
SDRAM interface test code
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use WORK.CommonPckg.all;
use work.ClkgenPckg.all;
use WORK.SdramCntlPckg.all;
library UNISIM;
use UNISIM.VComponents.all;
entity xula_sdram is
generic(
BASE_FREQ_G : real := 12.0; -- base frequency in MHz
CLK_MUL_G : natural := 25; -- multiplier for base frequency
CLK_DIV_G : natural := 3; -- divider for base frequency
PIPE_EN_G : boolean := false;
DATA_WIDTH_G : natural := 16; -- width of data
HADDR_WIDTH_G : natural := 23; -- host-side address width
SADDR_WIDTH_G : natural := 12; -- SDRAM address bus width
NROWS_G : natural := 4096; -- number of rows in each SDRAM bank
NCOLS_G : natural := 512; -- number of words in each row
-- beginning and ending addresses for the entire SDRAM
BEG_ADDR_G : natural := 16#00_0000#;
END_ADDR_G : natural := 16#7F_FFFF#;
-- beginning and ending address for the memory tester
BEG_TEST_G : natural := 16#00_0000#;
END_TEST_G : natural := 16#3F_FFFF#
);
port(
fpgaClk_i : in std_logic; -- main clock input from external clock source
sdClk_o : out std_logic; -- clock to SDRAM
sdClkFb_i : in std_logic; -- SDRAM clock comes back in
sdRas_bo : out std_logic; -- SDRAM RAS
sdCas_bo : out std_logic; -- SDRAM CAS
sdWe_bo : out std_logic; -- SDRAM write-enable
sdBs_o : out std_logic; -- SDRAM bank-address
sdAddr_o : out std_logic_vector(SADDR_WIDTH_G-1 downto 0); -- SDRAM address bus
sdData_io : inout std_logic_vector(DATA_WIDTH_G-1 downto 0); -- data bus to/from SDRAM
chan_io : inout std_logic_vector(5 downto 1)
);
end xula_sdram;
architecture Behavioral of xula_sdram is
constant FREQ_G : real := (BASE_FREQ_G * real(CLK_MUL_G)) / real(CLK_DIV_G);
signal clk : std_logic;
-- constant HADDR_WIDTH_G : natural := Log2(END_ADDR_G-BEG_ADDR_G+1);
signal rst_i : std_logic; -- internal reset signal
signal divCnt : unsigned(20 downto 0); -- clock divider
-- signals that go through the SDRAM host-side interface
signal begun : std_logic; -- SDRAM operation started indicator
signal earlyBegun : std_logic; -- SDRAM operation started indicator
signal done : std_logic; -- SDRAM operation complete indicator
signal rdDone : std_logic; -- SDRAM operation complete indicator
signal hAddr : std_logic_vector(HADDR_WIDTH_G-1 downto 0); -- host address bus
signal hDIn : std_logic_vector(DATA_WIDTH_G-1 downto 0); -- host-side data to SDRAM
signal hDOut : std_logic_vector(DATA_WIDTH_G-1 downto 0); -- host-side data from SDRAM
signal rd : std_logic; -- host-side read control signal
signal wr : std_logic; -- host-side write control signal
signal rdPending : std_logic; -- read operation pending in SDRAM pipeline
-- my new variables
type STATE_TYPE is (S_BEGIN, S_WAIT, S_READ, S_READWAIT, S_COMPARE, S_GOOD, S_BAD);
signal CS, ns : STATE_TYPE;
begin
-- Generate a faster clock for the RAM
u0 : Clkgen
generic map (BASE_FREQ_G => BASE_FREQ_G, CLK_MUL_G => CLK_MUL_G, CLK_DIV_G => CLK_DIV_G)
port map(I => fpgaClk_i, O => sdClk_o);
clk <= sdClkFb_i; -- main clock is SDRAM clock fed back into FPGA
------------------------------------------------------------------------
-- internal reset flag is set active right after configuration is done
-- because the reset counter starts at zero, and then gets reset after
-- the counter reaches its upper threshold.
------------------------------------------------------------------------
process(clk)
constant reset_dly_c : natural := 100;
variable rst_cntr : natural range 0 to reset_dly_c := 0;
begin
if rising_edge(clk) then
rst_i <= NO;
if rst_cntr < reset_dly_c then
rst_i <= YES;
rst_cntr := rst_cntr + 1;
end if;
end if;
end process;
------------------------------------------------------------------------
-- Instantiate the SDRAM controller that connects the
-- module and interfaces to the external SDRAM chip.
------------------------------------------------------------------------
u1 : SdramCntl
generic map(
FREQ_G => FREQ_G,
IN_PHASE_G => true,
PIPE_EN_G => PIPE_EN_G,
MAX_NOP_G => 10000,
DATA_WIDTH_G => DATA_WIDTH_G,
NROWS_G => NROWS_G,
NCOLS_G => NCOLS_G,
HADDR_WIDTH_G => HADDR_WIDTH_G,
SADDR_WIDTH_G => SADDR_WIDTH_G
)
port map(
clk_i => clk, -- master clock from external clock source (unbuffered)
lock_i => YES, -- no DLLs, so frequency is always locked
rst_i => rst_i, -- reset
rd_i => rd, -- host-side SDRAM read control from memory tester
wr_i => wr, -- host-side SDRAM write control from memory tester
earlyOpBegun_o => earlyBegun, -- early indicator that memory operation has begun
opBegun_o => begun, -- indicates memory read/write has begun
rdPending_o => rdPending, -- read operation to SDRAM is in progress_o
done_o => done, -- SDRAM memory read/write done indicator
rdDone_o => rdDone, -- indicates SDRAM memory read operation is done
hostAddr_i => hAddr, -- host-side address from memory tester to SDRAM
hostData_i => hDIn, -- test data pattern from memory tester to SDRAM
sdramData_o => hDOut, -- SDRAM data output to memory tester
status_o => open, -- SDRAM controller state (for diagnostics)
sdRas_bo => sdRas_bo, -- SDRAM RAS
sdCas_bo => sdCas_bo, -- SDRAM CAS
sdWe_bo => sdWe_bo, -- SDRAM write-enable
sdBs_o(0) => sdBs_o, -- SDRAM bank address
sdAddr_o => sdAddr_o, -- SDRAM address
sdData_io => sdData_io -- data to/from SDRAM
);
process(clk)
begin
if rising_edge(clk) then
if rst_i = '1' then
CS <= S_BEGIN;
else
case CS is
when S_BEGIN =>
chan_io(1) <= '0';
chan_io(3) <= '0';
chan_io(4) <= '0';
chan_io(5) <= '0';
hAddr <= "0";
hDIn <= X"5555";
wr <= '1';
CS <= S_WAIT;
when S_WAIT =>
if (done = '1') then
wr <= '0';
CS <= S_READ;
end if;
when S_READ =>
-- Light the yellow light if we get this far
chan_io(3) <= '1';
hAddr <= "0";
rd <= '1';
CS <= S_READWAIT;
when S_READWAIT =>
if (done = '1') then
rd <= '0';
CS <= S_COMPARE;
end if;
when S_COMPARE =>
-- Light the blue light if we get this far
chan_io(5) <= '1';
if (hDOut = X"5555") then
CS <= S_GOOD;
else
CS <= S_BAD;
end if;
when S_GOOD =>
-- Light the green light
chan_io(1) <= '1';
when S_BAD =>
-- Light the red light
chan_io(4) <= '1';
end case;
end if;
end if;
end process;
end Behavioral;
@xesscorp
Copy link
Author

I used the clk signal for all the processes, including the SDRAM controller, because everything should be clocked off the SDRAM feedback clock so the external SDRAM and the internal FPGA logic stay in sync.

I disabled the SDRAM controller pipelining. You don't need that complexity to start.

I rolled the reset process and the main state machine process together and use just the CS to store the current state.

You also had the roles of hDIn and hDOut reversed: hDIn is the value that is sent into the SDRAM controller which it writes out to the SDRAM; hDOut is the value read from the SDRAM by the controller which is then sent to the host logic in the FPGA.

Try it out and see if it fixes any of your problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment