Line 38... |
Line 38... |
-- the mt46v32m16 chip. Dunno if it will work anywhere else.
|
-- the mt46v32m16 chip. Dunno if it will work anywhere else.
|
-- Uses the ODDR2 and DCM Xilinx primitives, for other FPGAs, you'll need to
|
-- Uses the ODDR2 and DCM Xilinx primitives, for other FPGAs, you'll need to
|
-- patch in equivalents. See sdram_support for the details.
|
-- patch in equivalents. See sdram_support for the details.
|
-- I'd strongly recommend running it through a post-PAR simulation if you're
|
-- I'd strongly recommend running it through a post-PAR simulation if you're
|
-- porting to any other FPGA, as the timings will probably change on you.
|
-- porting to any other FPGA, as the timings will probably change on you.
|
-- Consumes two DCMs, runs off of the main 50mhz board clock. Could possibly
|
-- Consumes one DCM, needs a 100mhz clock or an external DCM to supply it.
|
-- consume one DCM if you want to feed it the 100mhz clock directly.
|
|
-- Has an 8bit wide datapath, moderate changes could support 16bits, 32 bits
|
-- Has an 8bit wide datapath, moderate changes could support 16bits, 32 bits
|
-- you'll have to work some. You want more than that, you'll be doing brain
|
-- you'll have to work some. You want more than that, you'll be doing brain
|
-- surgery on the FSMs - good luck.
|
-- surgery on the FSMs - good luck.
|
|
|
-- This design has been tested with the testbench only. There may be glitches
|
-- This design has now been tested with a t80 soft cpu, however, it hasn't been
|
-- hidden in here somewhere still. Consider this to be an alpha release.
|
-- exhaustively tested with the rest of the system. Glitches may still exist.
|
-- Did I mention that you shouldn't put this in anything mission critical?
|
-- Did I mention that you shouldn't put this in anything mission critical?
|
|
|
-- Be careful with the synthesizer settings too. Do not let the FSM extractor
|
-- Be careful with the synthesizer settings too. Do not let the FSM extractor
|
-- choose something other than one-hot. Be careful with equivalent register
|
-- choose something other than one-hot. Be careful with equivalent register
|
-- removal. I've rolled all synthesizer settings back to default and things
|
-- removal. I've rolled all synthesizer settings back to default and things
|
Line 219... |
Line 218... |
addr_out : out std_logic_vector(12 downto 0)
|
addr_out : out std_logic_vector(12 downto 0)
|
);
|
);
|
end component;
|
end component;
|
-- component decls end here
|
-- component decls end here
|
|
|
-- DRAM commands - <we,cas,ras>
|
-- DRAM commands - <we_n,cas_n,ras_n>
|
constant CMD_NOP : std_logic_vector(2 downto 0) := "111";
|
constant CMD_NOP : std_logic_vector(2 downto 0) := "111";
|
constant CMD_ACTIVE : std_logic_vector(2 downto 0) := "110"; -- opens a row within a bank
|
constant CMD_ACTIVE : std_logic_vector(2 downto 0) := "110"; -- opens a row within a bank
|
constant CMD_READ : std_logic_vector(2 downto 0) := "101";
|
constant CMD_READ : std_logic_vector(2 downto 0) := "101";
|
constant CMD_WRITE : std_logic_vector(2 downto 0) := "001";
|
constant CMD_WRITE : std_logic_vector(2 downto 0) := "001";
|
constant CMD_BURST_TERM : std_logic_vector(2 downto 0) := "011";
|
constant CMD_BURST_TERM : std_logic_vector(2 downto 0) := "011";
|
Line 231... |
Line 230... |
constant CMD_AUTO_REFR : std_logic_vector(2 downto 0) := "100";
|
constant CMD_AUTO_REFR : std_logic_vector(2 downto 0) := "100";
|
constant CMD_LOAD_MR : std_logic_vector(2 downto 0) := "000";
|
constant CMD_LOAD_MR : std_logic_vector(2 downto 0) := "000";
|
|
|
-- various wait counter values
|
-- various wait counter values
|
constant AUTO_REFRESH_CLKS : integer := 700; -- spec says 7.8us, which is 780 clocks @ 100Mhz, I'm setting it to 700
|
constant AUTO_REFRESH_CLKS : integer := 700; -- spec says 7.8us, which is 780 clocks @ 100Mhz, I'm setting it to 700
|
constant WRITE_RECOVER_CLKS : integer := 5; -- these are fudged a bit, you *might* be able to shave a clock or two off
|
constant WRITE_RECOVER_CLKS : integer := 6; -- these are fudged a bit, you *might* be able to shave a clock or two off
|
constant READ_DONE_CLKS : integer := 5;
|
constant READ_DONE_CLKS : integer := 5;
|
|
|
type CMD_STATES is ( STATE_START, STATE_INIT, STATE_WAIT_INIT, STATE_IDLE, STATE_IDLE_AUTO_REFRESH, STATE_IDLE_WAIT_AR_CTR,
|
type CMD_STATES is ( STATE_START, STATE_INIT, STATE_WAIT_INIT, STATE_IDLE, STATE_IDLE_AUTO_REFRESH,
|
STATE_IDLE_WAIT_AUTO_REFRESH, STATE_WRITE_ROW_OPEN, STATE_WRITE_WAIT_ROW_OPEN, STATE_WRITE_ISSUE_CMD,
|
STATE_IDLE_CHECK_OP_PENDING, STATE_IDLE_WAIT_AR_CTR, STATE_IDLE_WAIT_AUTO_REFRESH,
|
STATE_WRITE_WAIT_RECOVER, STATE_READ_ROW_OPEN, STATE_READ_WAIT_ROW_OPEN, STATE_READ_ISSUE_CMD,
|
STATE_WRITE_ROW_OPEN, STATE_WRITE_WAIT_ROW_OPEN, STATE_WRITE_ISSUE_CMD, STATE_WRITE_WAIT_RECOVER,
|
STATE_READ_WAIT_CAPTURE );
|
STATE_READ_ROW_OPEN, STATE_READ_WAIT_ROW_OPEN, STATE_READ_ISSUE_CMD, STATE_READ_WAIT_CAPTURE );
|
|
|
signal cmd_state : CMD_STATES := STATE_START;
|
signal cmd_state : CMD_STATES := STATE_START;
|
|
|
signal cmd_oddr2_rising : std_logic_vector(2 downto 0) := CMD_NOP;
|
signal cmd_oddr2_rising : std_logic_vector(2 downto 0) := CMD_NOP;
|
signal bank_oddr2_rising : std_logic_vector(1 downto 0) := "00";
|
signal bank_oddr2_rising : std_logic_vector(1 downto 0) := "00";
|
Line 290... |
Line 289... |
signal read_wait_done : std_logic;
|
signal read_wait_done : std_logic;
|
|
|
signal data0_o : std_logic_vector(7 downto 0);
|
signal data0_o : std_logic_vector(7 downto 0);
|
signal data1_o : std_logic_vector(7 downto 0);
|
signal data1_o : std_logic_vector(7 downto 0);
|
|
|
--
|
-- capture signals
|
signal cap_en : std_logic;
|
signal cap_en : std_logic;
|
|
signal op_save : std_logic_vector(1 downto 0);
|
signal addr_save : std_logic_vector(25 downto 0);
|
signal addr_save : std_logic_vector(25 downto 0);
|
signal datai_save : std_logic_vector(7 downto 0);
|
signal datai_save : std_logic_vector(7 downto 0);
|
|
|
begin
|
begin
|
|
|
Line 456... |
Line 456... |
|
|
debug_reg <= x"00";
|
debug_reg <= x"00";
|
dram_cs <= '0';
|
dram_cs <= '0';
|
data_o <= data1_o when addr_save(0) = '1' else data0_o;
|
data_o <= data1_o when addr_save(0) = '1' else data0_o;
|
|
|
|
-- capture the addr when op is captured by cmd fsm
|
process (clk_000)
|
process (clk_000)
|
begin
|
begin
|
if (rising_edge(clk_000)) then
|
if (rising_edge(clk_000)) then
|
if (cap_en = '1') then
|
if (cap_en = '1') then
|
addr_save <= addr;
|
addr_save <= addr;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- capture data_i when op is captured by cmd fsm
|
|
process (clk_000)
|
|
begin
|
|
if (rising_edge(clk_000)) then
|
|
if (cap_en = '1') then
|
datai_save <= data_i;
|
datai_save <= data_i;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
|
process (clk_000)
|
|
begin
|
|
if (rising_edge(clk_000)) then
|
|
if (cap_en = '1') then
|
|
op_save <= op;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
-- command state machine
|
-- command state machine
|
process (clk_000)
|
process (clk_000)
|
begin
|
begin
|
if (rising_edge(clk_000)) then
|
if (rising_edge(clk_000)) then
|
if (dcm_locked = '1') then
|
if (dcm_locked = '1') then
|
Line 500... |
Line 519... |
when STATE_IDLE =>
|
when STATE_IDLE =>
|
-- this is the main hub state
|
-- this is the main hub state
|
-- this is where reads and writes return to after being completed
|
-- this is where reads and writes return to after being completed
|
busy_n <= '1';
|
busy_n <= '1';
|
op_ack <= '0';
|
op_ack <= '0';
|
|
cap_en <= '0';
|
need_ar_rst <= '0';
|
need_ar_rst <= '0';
|
cap_en <= '1';
|
|
main_sel <= '1';
|
main_sel <= '1';
|
writer_rst <= '1';
|
writer_rst <= '1';
|
reader_rst <= '1';
|
reader_rst <= '1';
|
|
cap_en <= '1';
|
if (need_ar = '1') then
|
if (need_ar = '1') then
|
busy_n <= '0';
|
busy_n <= '0';
|
cmd_state <= STATE_IDLE_AUTO_REFRESH;
|
cmd_state <= STATE_IDLE_AUTO_REFRESH;
|
elsif (op = "01" and en = '1') then
|
elsif (op = "01") then
|
busy_n <= '0';
|
busy_n <= '0';
|
|
op_ack <= '1';
|
cmd_state <= STATE_READ_ROW_OPEN;
|
cmd_state <= STATE_READ_ROW_OPEN;
|
elsif (op = "10" and en = '1') then
|
elsif (op = "10") then
|
busy_n <= '0';
|
busy_n <= '0';
|
|
op_ack <= '1';
|
cmd_state <= STATE_WRITE_ROW_OPEN;
|
cmd_state <= STATE_WRITE_ROW_OPEN;
|
else
|
else
|
cmd_state <= cmd_state;
|
cmd_state <= cmd_state;
|
end if;
|
end if;
|
|
|
when STATE_IDLE_AUTO_REFRESH =>
|
when STATE_IDLE_AUTO_REFRESH =>
|
|
if (op = "01" or op = "10") then
|
|
cap_en <= '0';
|
|
end if;
|
need_ar_rst <= '1';
|
need_ar_rst <= '1';
|
wait_ar_rst <= '1';
|
wait_ar_rst <= '1';
|
main_cmd <= CMD_AUTO_REFR;
|
main_cmd <= CMD_AUTO_REFR;
|
main_bank <= "00";
|
main_bank <= "00";
|
main_addr <= "0000000000000";
|
main_addr <= "0000000000000";
|
cmd_state <= STATE_IDLE_WAIT_AR_CTR;
|
cmd_state <= STATE_IDLE_WAIT_AR_CTR;
|
|
|
when STATE_IDLE_WAIT_AR_CTR =>
|
when STATE_IDLE_WAIT_AR_CTR =>
|
|
if (op = "01" or op = "10") then
|
|
cap_en <= '0';
|
|
end if;
|
wait_ar_rst <= '0';
|
wait_ar_rst <= '0';
|
main_cmd <= CMD_NOP;
|
main_cmd <= CMD_NOP;
|
main_bank <= "00";
|
main_bank <= "00";
|
main_addr <= "0000000000000";
|
main_addr <= "0000000000000";
|
cmd_state <= STATE_IDLE_WAIT_AUTO_REFRESH;
|
cmd_state <= STATE_IDLE_WAIT_AUTO_REFRESH;
|
|
|
when STATE_IDLE_WAIT_AUTO_REFRESH =>
|
when STATE_IDLE_WAIT_AUTO_REFRESH =>
|
|
if (op = "01" or op = "10") then
|
|
cap_en <= '0';
|
|
end if;
|
main_cmd <= CMD_NOP;
|
main_cmd <= CMD_NOP;
|
main_bank <= "00";
|
main_bank <= "00";
|
main_addr <= "0000000000000";
|
main_addr <= "0000000000000";
|
if (wait_ar_done = '1') then
|
if (wait_ar_done = '1') then
|
cmd_state <= STATE_IDLE;
|
cmd_state <= STATE_IDLE_CHECK_OP_PENDING;
|
else
|
else
|
cmd_state <= cmd_state;
|
cmd_state <= cmd_state;
|
end if;
|
end if;
|
|
|
when STATE_WRITE_ROW_OPEN =>
|
when STATE_IDLE_CHECK_OP_PENDING =>
|
|
if (op_save = "01") then
|
op_ack <= '1';
|
op_ack <= '1';
|
|
cmd_state <= STATE_READ_ROW_OPEN;
|
|
elsif (op_save = "10") then
|
|
op_ack <= '1';
|
|
cmd_state <= STATE_WRITE_ROW_OPEN;
|
|
else
|
|
cmd_state <= STATE_IDLE;
|
|
end if;
|
|
|
|
when STATE_WRITE_ROW_OPEN =>
|
|
cap_en <= '0';
|
dqs_dir <= '1';
|
dqs_dir <= '1';
|
dq_dir <= '1';
|
dq_dir <= '1';
|
cap_en <= '0';
|
|
main_cmd <= CMD_ACTIVE;
|
main_cmd <= CMD_ACTIVE;
|
main_bank <= addr_save(25 downto 24);
|
main_bank <= addr_save(25 downto 24);
|
main_addr <= addr_save(23 downto 11);
|
main_addr <= addr_save(23 downto 11);
|
cmd_state <= STATE_WRITE_WAIT_ROW_OPEN;
|
cmd_state <= STATE_WRITE_WAIT_ROW_OPEN;
|
|
|
Line 579... |
Line 620... |
else
|
else
|
cmd_state <= cmd_state;
|
cmd_state <= cmd_state;
|
end if;
|
end if;
|
|
|
when STATE_READ_ROW_OPEN =>
|
when STATE_READ_ROW_OPEN =>
|
op_ack <= '1';
|
cap_en <= '0';
|
dqs_dir <= '0';
|
dqs_dir <= '0';
|
dq_dir <= '0';
|
dq_dir <= '0';
|
cap_en <= '0';
|
|
main_cmd <= CMD_ACTIVE;
|
main_cmd <= CMD_ACTIVE;
|
main_bank <= addr_save(25 downto 24);
|
main_bank <= addr_save(25 downto 24);
|
main_addr <= addr_save(23 downto 11);
|
main_addr <= addr_save(23 downto 11);
|
cmd_state <= STATE_READ_WAIT_ROW_OPEN;
|
cmd_state <= STATE_READ_WAIT_ROW_OPEN;
|
|
|