From b34674c513c61f426111e6d698440ec6978b7f22 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 14 Oct 2013 14:09:47 +0100 Subject: finished --- sdram_ctrl.vhd | 808 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 461 insertions(+), 347 deletions(-) diff --git a/sdram_ctrl.vhd b/sdram_ctrl.vhd index 55c1cae..b89ece5 100644 --- a/sdram_ctrl.vhd +++ b/sdram_ctrl.vhd @@ -5,42 +5,6 @@ use IEEE.NUMERIC_STD.ALL; -- a simple dram controller (no pipelineing) -- that looks like a slow static ram -entity sdram_ctrl is -port -( - clock_100 : in std_logic; - reset_n : in std_logic; - - b_cs_n : in std_logic; - b_rd_n : in std_logic; - b_wr_n : in std_logic; - - b_wait_n : out std_logic; - - b_addr : in std_logic_vector(15 downto 0); - b_data : inout std_logic_vector(15 downto 0); - - - sdram_clk : out std_logic; - - sdramem_cs_n : out std_logic; - sdram_cas_n : out std_logic; - sdram_ras_n : out std_logic; - sdram_we_n : out std_logic; - sdram_cke : out std_logic; - - sdramem_addr : out std_logic_vector(12 downto 0); - sdram_ba : out std_logic_vector(1 downto 0); - - sdram_dq : inout std_logic_vector(15 downto 0); - sdramem_dqm : out std_logic_vector(1 downto 0) -); -end entity; - -architecture rtl of sdram_ctrl is - -signal clock : std_logic; - subtype uint3_t is integer range 0 to 7; subtype uint4_t is integer range 0 to 15; subtype uint13_t is integer range 0 to 8191; @@ -50,395 +14,545 @@ subtype data_t is std_logic_vector(15 downto 0); subtype dqm_t is std_logic_vector(1 downto 0); --- bits in the CMD register RAS_N CAS_N WE_N - -constant CMD_NOP : std_logic_vector(2 downto 0 ):="111"; -constant CMD_READ : std_logic_vector(2 downto 0 ):="101"; -constant CMD_WRIT : std_logic_vector(2 downto 0 ):="100"; -constant CMD_ACTV : std_logic_vector(2 downto 0 ):="011"; -constant CMD_PRE : std_logic_vector(2 downto 0 ):="010"; -constant CMD_REF : std_logic_vector(2 downto 0 ):="001"; -constant CMD_MRS : std_logic_vector(2 downto 0 ):="000"; - -constant CS_N_ALL : cs_n_t := "0"; -constant CS_N_NONE : cs_n_t := "1"; - --- refresh logic - -signal need_refresh : std_logic; -signal refresh_counter : uint13_t; - --- init logic - -signal init_done : std_logic; -signal i_addr : std_logic_vector(12 downto 0); -signal i_cs_n: cs_n_t; -signal i_cmd : std_logic_vector(2 downto 0); -signal i_count : uint4_t; -signal i_next : uint3_t; -signal i_refs : uint3_t; - --- init fsm -signal i_state :uint3_t; - -constant I_ST_RESET_WAIT : uint3_t:=0; -constant I_ST_PRECHARGE : uint3_t :=1; -constant I_ST_REFRESH : uint3_t :=2; -constant I_ST_WAIT_COUNT : uint3_t :=3; -constant I_ST_SET_MODE : uint3_t :=4; -constant I_ST_DONE : uint3_t :=5; - - --- memory interface wires -signal mem_cs_n : cs_n_t; -signal mem_bank : std_logic_vector(1 downto 0); -signal mem_cmd : std_logic_vector(2 downto 0); -signal mem_addr : std_logic_vector(12 downto 0); -signal mem_data : data_t; -signal mem_dqm : dqm_t; - --- main logic -signal ack_refresh : std_logic; -signal ack_request : std_logic; -signal mem_oe: std_logic; -signal m_count: uint3_t; - -signal active_cs_n : cs_n_t; -signal active_addr : addr_t; -signal active_data : data_t; -signal active_rnw : std_logic; -signal active_dqm : dqm_t; - --- main fsm -signal m_state : std_logic_vector(9 downto 0); -signal m_next : std_logic_vector(9 downto 0); - -constant M_ST_WAITING_INIT : std_logic_vector(9 downto 0 ):="0000000001"; -constant M_ST_IDLE : std_logic_vector(9 downto 0 ):="0000000010"; -constant M_ST_RAS : std_logic_vector(9 downto 0 ):="0000000100"; -constant M_ST_NOP_COUNT : std_logic_vector(9 downto 0 ):="0000001000"; -constant M_ST_READ : std_logic_vector(9 downto 0 ):="0000010000"; -constant M_ST_WRITE : std_logic_vector(9 downto 0 ):="0000100000"; -constant M_ST_ACTIVE : std_logic_vector(9 downto 0 ):="0001000000"; -constant M_ST_WAIT_FOR_PRECHARGE : std_logic_vector(9 downto 0 ):="0010000000"; -constant M_ST_PRECHARGE : std_logic_vector(9 downto 0 ):="0100000000"; -constant M_ST_REFRESH : std_logic_vector(9 downto 0 ):="1000000000"; - --- bus logic -signal request_ready: std_logic; -signal request_cs_n : cs_n_t; -signal request_addr : addr_t; -signal request_data : data_t; -signal request_rnw : std_logic; -signal request_dqm : dqm_t; - - --- convert boolean to active high logic -function b2l_h(constant val : in boolean) return std_logic is begin - if val then - return '1'; - else - return '0'; - end if; -end function; +entity sdram_ctrl is + port + ( + clock_100 : in std_logic; + reset_n : in std_logic; + bus_cs_n : in std_logic; + bus_rd_n : in std_logic; + bus_wr_n : in std_logic; --- convert active high logic to boolean value -function l2b_h(constant val : in std_logic) return boolean is begin - return val='1'; -end function; + bus_wait_n : out std_logic; -function same_bank_and_row( - constant a1: in addr_t; - constant a2: in addr_t -) return boolean is begin - return a1(23 downto 9) = a2(23 downto 9); -end function; + bus_addr : in addr_t; + bus_data : inout data_t; -begin + sdram_clk : out std_logic; + sdram_cke : out std_logic; -clock<=clock_100; + sdram_cs_n : out std_logic; -refresh_counter_process: process(reset_n,clock) begin - if reset_n = '0' then - refresh_counter <= 8000; - elsif rising_edge(clock) then - if refresh_counter = 0 then - refresh_counter <= 624; - else - refresh_counter <= refresh_counter - 1; - end if; - end if; -end process; + sdram_cas_n : out std_logic; + sdram_ras_n : out std_logic; + sdram_we_n : out std_logic; + sdram_addr : out std_logic_vector(12 downto 0); + sdram_ba : out std_logic_vector(1 downto 0); -need_refresh_process: process(reset_n,clock,refresh_counter,need_refresh,init_done,ack_refresh) begin - if reset_n = '0' then - need_refresh <= '0'; - elsif rising_edge(clock) then - need_refresh <= (b2l_h(refresh_counter = 0) or need_refresh) and init_done and not ack_refresh; - end if; -end process; + sdram_dq : inout data_t; + sdram_dqm : out dqm_t; + ); +end entity; -init_done_process: process (reset_n,clock,i_state) begin - if reset_n = '0' then - init_done <= '0'; - elsif rising_edge(clock) then - init_done <= init_done or b2l_h(i_state = I_ST_DONE ); - end if; -end process; - -init_fsm: process (reset_n,clock,i_state,i_count,i_next,refresh_counter) begin - if reset_n = '0' then - i_state <= I_ST_RESET_WAIT; - i_next <= I_ST_RESET_WAIT; - i_cs_n <=CS_N_NONE; - i_cmd <= CMD_NOP; - i_addr <= (others => '1'); - i_count <= 0; - elsif rising_edge(clock) then - - if i_state = I_ST_RESET_WAIT then - -- after reset wait until the refresh_counter ticks over for RAM to stabalize - i_cs_n <=CS_N_NONE; - i_cmd <= CMD_NOP; - i_refs <= 0; - if refresh_counter=0 then - i_state <= I_ST_PRECHARGE; - end if; - elsif i_state = I_ST_PRECHARGE then - -- precharge all banks, wait one clock, then go to refresh - i_cs_n <=CS_N_ALL; - i_cmd <=CMD_PRE; - i_state <= I_ST_WAIT_COUNT; - i_count <= 1; - i_next <= I_ST_REFRESH; - elsif i_state =I_ST_REFRESH then - -- repeat 7 times { refresh, wait 5 counts } - i_cs_n <=CS_N_ALL; - i_cmd <=CMD_REF; - i_refs <= i_refs + 1; - - i_state <= I_ST_WAIT_COUNT; - i_count <= 5; - - if i_refs = 7 then - i_next <= I_ST_SET_MODE; - else - i_next <= I_ST_REFRESH; - end if; - elsif i_state = I_ST_WAIT_COUNT then - -- wait i_count ticks then goto state i_next - i_cs_n <=CS_N_ALL; - i_cmd <= CMD_NOP; - if (i_count > 1) then - i_count <= i_count -1; - else - i_state <= i_next; - end if; +architecture rtl of sdram_ctrl is - elsif i_state=I_ST_SET_MODE then - -- set mode, wait 3 ticks then goto done - i_cs_n <=CS_N_ALL; - i_cmd <= CMD_MRS; - - -- reserverd 000 - -- opcode burst read/write 0 - -- reserved 00 - -- cas latency 3 011 - -- sequential burst 0 - -- burst length 1 000 - - i_addr <= "0000000110000"; - i_count <= 3; - i_next <= I_ST_DONE; - - elsif i_state=I_ST_DONE then - i_state <= I_ST_DONE; - else - i_state <= I_ST_RESET_WAIT; - end if; + signal clock : std_logic; + + -- bits in the MEM_CMD register RAS_N CAS_N WE_N + + constant MEM_CMD_NOP : std_logic_vector(2 downto 0 ):="111"; + constant MEM_CMD_READ : std_logic_vector(2 downto 0 ):="101"; + constant MEM_CMD_WRIT : std_logic_vector(2 downto 0 ):="100"; + constant MEM_CMD_ACTV : std_logic_vector(2 downto 0 ):="011"; + constant MEM_CMD_PRE : std_logic_vector(2 downto 0 ):="010"; + constant MEM_CMD_REF : std_logic_vector(2 downto 0 ):="001"; + constant MEM_CMD_MRS : std_logic_vector(2 downto 0 ):="000"; + + constant MEM_CS_N_ALL : cs_n_t := "0"; + constant MEM_CS_N_NONE : cs_n_t := "1"; + + -- refresh logic + + signal need_refresh : std_logic; + signal refresh_counter : uint13_t; + + -- init logic + + signal init_done : std_logic; + signal i_addr : std_logic_vector(12 downto 0); + signal i_cs_n: cs_n_t; + signal i_cmd : std_logic_vector(2 downto 0); + signal i_count : uint4_t; + signal i_next : uint3_t; + signal i_refs : uint3_t; + + -- init fsm + signal i_state :uint3_t; + + constant I_ST_RESET_WAIT : uint3_t:=0; + constant I_ST_PRECHARGE : uint3_t :=1; + constant I_ST_REFRESH : uint3_t :=2; + constant I_ST_WAIT_COUNT : uint3_t :=3; + constant I_ST_SET_MODE : uint3_t :=4; + constant I_ST_DONE : uint3_t :=5; + + -- memory interface wires + signal mem_cs_n : cs_n_t; + signal mem_bank : std_logic_vector(1 downto 0); + signal mem_cmd : std_logic_vector(2 downto 0); + signal mem_addr : std_logic_vector(12 downto 0); + signal mem_data_out : data_t; + signal mem_data_in : data_t; + signal mem_dqm : dqm_t; + signal mem_oe: std_logic; + + -- main logic + signal ack_refresh : std_logic; + signal ack_request : std_logic; + signal m_count: uint3_t; + + signal active_cs_n : cs_n_t; + signal active_addr : addr_t; + signal active_data : data_t; + signal active_rnw : std_logic; + signal active_dqm : dqm_t; + + -- main fsm + signal m_state : std_logic_vector(9 downto 0); + signal m_next : std_logic_vector(9 downto 0); + + constant M_ST_WAITING_INIT : std_logic_vector(9 downto 0 ):="0000000001"; + constant M_ST_IDLE : std_logic_vector(9 downto 0 ):="0000000010"; + constant M_ST_RAS : std_logic_vector(9 downto 0 ):="0000000100"; + constant M_ST_NOP_COUNT : std_logic_vector(9 downto 0 ):="0000001000"; + constant M_ST_READ : std_logic_vector(9 downto 0 ):="0000010000"; + constant M_ST_WRITE : std_logic_vector(9 downto 0 ):="0000100000"; + constant M_ST_ACTIVE : std_logic_vector(9 downto 0 ):="0001000000"; + constant M_ST_WAIT_FOR_PRECHARGE : std_logic_vector(9 downto 0 ):="0010000000"; + constant M_ST_PRECHARGE : std_logic_vector(9 downto 0 ):="0100000000"; + constant M_ST_REFRESH : std_logic_vector(9 downto 0 ):="1000000000"; + + + -- request logic + signal request_pending: std_logic; + signal request_cs_n : cs_n_t; + signal request_addr : addr_t; + signal request_data : data_t; + signal request_rnw : std_logic; + signal request_dqm : dqm_t; + + -- read state logic + signal r_data_valid: std_logic_vector(2 downto 0); + + -- bus logic + signal request_post: std_logic; + + -- bus fsm + signal b_state : std_logic_vector(4 downto 0); + + constant B_ST_WAIT_CS_LOW : std_logic_vector(4 downto 0):="00001"; + constant B_ST_LODGE_REQUEST : std_logic_vector(4 downto 0):="00010"; + constant B_ST_WAIT_ACK : std_logic_vector(4 downto 0):="00100"; + constant B_ST_WAIT_DATA : std_logic_vector(4 downto 0):="01000"; + constant B_ST_WAIT_CS_HIGH : std_logic_vector(4 downto 0):="10000"; + + -- convert boolean to active high logic + function b2l_ah(constant val : in boolean) return std_logic is begin + if val then + return '1'; + else + return '0'; + end if; + end function; + + + -- convert active high logic to boolean value + function l2b_ah(constant val : in std_logic) return boolean is begin + return val='1'; + end function; + + function l2b_al(constant val : in std_logic) return boolean is begin + return val='0'; + end function; + + + function same_bank_and_row ( constant a1: in addr_t; constant a2: in addr_t ) return boolean is begin + return a1(23 downto 9) = a2(23 downto 9); + end function; + +begin + + clock<=clock_100; + + refresh_counter_process: process(reset_n,clock) begin + if l2b_al(reset_n) then + refresh_counter <= 8000; + elsif rising_edge(clock) then + if refresh_counter = 0 then + refresh_counter <= 624; + else + refresh_counter <= refresh_counter - 1; + end if; + end if; + end process; + + + need_refresh_process: process(reset_n,clock,refresh_counter,need_refresh,init_done,ack_refresh) begin + if l2b_al(reset_n) then + need_refresh <= '0'; + elsif rising_edge(clock) then + need_refresh <= (b2l_ah(refresh_counter = 0) or need_refresh) and init_done and not ack_refresh; + end if; + end process; + + request_pending_process: process(reset_n, clock, post_request, request_pending,ack_request) begin + if l2b_al(reset_n) then + request_pending <= '0'; + elsif rising_edge(clock) then + request_pending <= post_request or (request_pending and not ack_request); + end if; + end process; + + + init_done_process: process (reset_n,clock,i_state) begin + if l2b_al(reset_n) then + init_done <= '0'; + elsif rising_edge(clock) then + init_done <= init_done or b2l_ah(i_state = I_ST_DONE ); + end if; + end process; + + init_fsm: process (reset_n,clock,i_state,i_count,i_next,refresh_counter) begin + if l2b_al(reset_n) then + i_state <= I_ST_RESET_WAIT; + i_next <= I_ST_RESET_WAIT; + i_cs_n <=MEM_CS_N_NONE; + i_cmd <= MEM_CMD_NOP; + i_addr <= (others => '1'); + i_count <= 0; + elsif rising_edge(clock) then + + if i_state = I_ST_RESET_WAIT then + -- after reset wait until the refresh_counter ticks over for RAM to stabalize + i_cs_n <=MEM_CS_N_NONE; + i_cmd <= MEM_CMD_NOP; + i_refs <= 0; + if refresh_counter=0 then + i_state <= I_ST_PRECHARGE; end if; -end process; - -main_fsm: process (reset_n,clock,m_state,need_refresh,request_ready,request_addr,request_data,request_cs_n,request_rnw,request_dqm) begin - -if reset_n ='0' then -m_state <= M_ST_WAITING_INIT; -m_next <= M_ST_WAITING_INIT; -mem_cmd <= CMD_NOP; -mem_cs_n <= CS_N_NONE; -mem_bank <= (others => '0'); -mem_addr <= (others => '0'); -mem_data <= (others => '0'); -mem_dqm <= (others => '0'); -m_count <= 0; -ack_refresh <= '0'; -ack_request <= '0'; -mem_oe <= '0'; -elsif rising_edge(clock) then -if m_state =M_ST_WAITING_INIT then + elsif i_state = I_ST_PRECHARGE then + -- precharge all banks, wait one clock, then go to refresh + i_cs_n <=MEM_CS_N_ALL; + i_cmd <=MEM_CMD_PRE; + i_state <= I_ST_WAIT_COUNT; + i_count <= 1; + i_next <= I_ST_REFRESH; + elsif i_state =I_ST_REFRESH then + -- repeat 7 times { refresh, wait 5 counts } + i_cs_n <=MEM_CS_N_ALL; + i_cmd <=MEM_CMD_REF; + i_refs <= i_refs + 1; + + i_state <= I_ST_WAIT_COUNT; + i_count <= 5; + + if i_refs = 7 then + i_next <= I_ST_SET_MODE; + else + i_next <= I_ST_REFRESH; + end if; + elsif i_state = I_ST_WAIT_COUNT then + -- wait i_count ticks then goto state i_next + i_cs_n <=MEM_CS_N_ALL; + i_cmd <= MEM_CMD_NOP; + if (i_count > 1) then + i_count <= i_count -1; + else + i_state <= i_next; + end if; + + elsif i_state=I_ST_SET_MODE then + -- set mode, wait 3 ticks then goto done + i_cs_n <=MEM_CS_N_ALL; + i_cmd <= MEM_CMD_MRS; + + -- reserverd 000 + -- opcode burst read/write 0 + -- reserved 00 + -- cas latency 3 011 + -- sequential burst 0 + -- burst length 1 000 + + i_addr <= "0000000110000"; + i_count <= 3; + i_next <= I_ST_DONE; + + elsif i_state=I_ST_DONE then + i_state <= I_ST_DONE; + else + i_state <= I_ST_RESET_WAIT; + end if; + end if; + end process; + + main_fsm: process (reset_n,clock,m_state,need_refresh,request_pending,request_addr,request_data,request_cs_n,request_rnw,request_dqm) begin + + if reset_n ='0' then + m_state <= M_ST_WAITING_INIT; + m_next <= M_ST_WAITING_INIT; + mem_cmd <= MEM_CMD_NOP; + mem_cs_n <= MEM_CS_N_NONE; + mem_bank <= (others => '0'); + mem_addr <= (others => '0'); + mem_data_out <= (others => '0'); + mem_dqm <= (others => '0'); + m_count <= 0; + ack_refresh <= '0'; + ack_request <= '0'; + mem_oe <= '0'; + elsif rising_edge(clock) then + if m_state =M_ST_WAITING_INIT then mem_addr <= i_addr; mem_cmd <= i_cmd; mem_cs_n <= i_cs_n; - - if l2b_h(init_done) then - m_state <= M_ST_IDLE; + + if l2b_ah(init_done) then + m_state <= M_ST_IDLE; end if; -elsif m_state = M_ST_IDLE then - mem_cmd <= CMD_NOP; + elsif m_state = M_ST_IDLE then + mem_cmd <= MEM_CMD_NOP; ack_refresh <='0'; - if l2b_h(need_refresh) then - -- If we got here needing a refresh - -- we may have come straight from a - -- read so leave CS on so we get - -- that data + if l2b_ah(need_refresh) then + -- If we got here needing a refresh + -- we may have come straight from a + -- read so leave CS on so we get + -- that data - mem_cs_n<=CS_N_ALL; + mem_cs_n<=MEM_CS_N_ALL; - -- precharge everyone (putting back - -- the open row if we did come from a read - -- or write) then refresh everyone. + -- precharge everyone (putting back + -- the open row if we did come from a read + -- or write) then refresh everyone. - m_state <= M_ST_PRECHARGE; - m_next <= M_ST_REFRESH; + m_state <= M_ST_PRECHARGE; + m_next <= M_ST_REFRESH; else - -- idle to all chips (CMD_IGN) - mem_cs_n<=CS_N_NONE; - - -- find out if anyone wants us - if l2b_h(request_ready) then - active_cs_n <= request_cs_n; - active_rnw <= request_rnw; - active_addr <= request_addr; - active_data <= request_data; - active_dqm <= request_dqm; - m_state <= M_ST_RAS; - ack_request <='1'; - end if; + -- idle to all chips (MEM_CMD_IGN) + mem_cs_n<=MEM_CS_N_NONE; + + -- find out if anyone wants us + if l2b_ah(request_pending) then + active_cs_n <= request_cs_n; + active_rnw <= request_rnw; + active_addr <= request_addr; + active_data <= request_data; + active_dqm <= request_dqm; + m_state <= M_ST_RAS; + ack_request <='1'; + end if; end if; -elsif m_state = M_ST_RAS then - -- activate the relevant ROW, wait 3 clocks, then go and do the read or write + elsif m_state = M_ST_RAS then + -- activate the relevant ROW, wait 3 clocks, then go and do the read or write ack_request <='0'; mem_cs_n <= active_cs_n; - mem_cmd <= CMD_ACTV; + mem_cmd <= MEM_CMD_ACTV; mem_bank(1) <= active_addr(23); mem_bank(0) <= active_addr(9); mem_addr <= active_addr(22 downto 10); - mem_data <= active_data; + mem_data_out <= active_data; mem_dqm <= active_dqm; m_state <= M_ST_NOP_COUNT; m_count <= 2; --t 3 clocks : FIXME - if l2b_h(active_rnw) then - m_next <= M_ST_READ; + if l2b_ah(active_rnw) then + m_next <= M_ST_READ; else - m_next <= M_ST_WRITE; + m_next <= M_ST_WRITE; end if; -elsif m_state = M_ST_NOP_COUNT then - -- send nops for m_count, then go to state m_next - mem_cmd <=CMD_NOP; + elsif m_state = M_ST_NOP_COUNT then + -- send nops for m_count, then go to state m_next + mem_cmd <=MEM_CMD_NOP; if m_count > 1 then - m_count <= m_count - 1; + m_count <= m_count - 1; else - m_state <= m_next; + m_state <= m_next; end if; -elsif m_state = M_ST_READ then + elsif m_state = M_ST_READ then ack_request <='0'; - mem_cmd <=CMD_READ; + mem_cmd <=MEM_CMD_READ; mem_addr(12 downto 9) <= (others => '0'); mem_addr(8 downto 0) <= active_addr(8 downto 0); m_next <= M_ST_ACTIVE; -elsif m_state = M_ST_WRITE then + elsif m_state = M_ST_WRITE then ack_request <='0'; - mem_cmd<=CMD_WRIT; + mem_cmd<=MEM_CMD_WRIT; mem_addr(12 downto 9) <= (others => '0'); mem_addr(8 downto 0) <= active_addr(8 downto 0); mem_oe <= '1'; - mem_data <= active_data; + mem_data_out <= active_data; m_state <=M_ST_ACTIVE; -elsif m_state = M_ST_ACTIVE then - -- turn off drivers (we might have come from a write) + elsif m_state = M_ST_ACTIVE then + -- turn off drivers (we might have come from a write) mem_oe <= '0'; - -- sit doing NOPS on this row until either we get a new request - -- or we need a refresh - mem_cmd <= M_CMD_NOP; - - if l2b_h(need_refresh) then - -- the refresh will first precharge everything, so no need to precharge - -- just this row. - m_state <= M_ST_NOP_COUNT; - m_next <= M_ST_IDLE; - m_count <= 1; - elsif l2b_h(request_ready) then - if (active_cs_n = request_cs_n) and (active_rnw = request_rnw) and same_bank_and_row(active_addr,request_addr) then - -- this request matches our currently active row - -- we can process it - - active_addr <= request_addr; - active_data <= request_data; - active_dqm <= request_dqm; - - ack_request <='1'; - - if l2b_h(request_rnw) then - m_state <= M_ST_READ; - else - m_state <= M_ST_WRITE; - end if; - else - -- new request doesn't match, precharge and go to idle - m_state <= M_ST_WAIT_FOR_PRECHARGE; - m_next <= M_ST_IDLE; - end if; + -- sit doing NOPS on this row until either we get a new request + -- or we need a refresh + mem_cmd <= MEM_CMD_NOP; + + if l2b_ah(need_refresh) then + -- the refresh will first precharge everything, so no need to precharge + -- just this row. + m_state <= M_ST_NOP_COUNT; + m_next <= M_ST_IDLE; + m_count <= 1; + elsif l2b_ah(request_pending) then + if (active_cs_n = request_cs_n) and (active_rnw = request_rnw) and same_bank_and_row(active_addr,request_addr) then + -- this request matches our currently active row + -- we can process it + + active_addr <= request_addr; + active_data <= request_data; + active_dqm <= request_dqm; + + ack_request <='1'; + + if l2b_ah(request_rnw) then + m_state <= M_ST_READ; + else + m_state <= M_ST_WRITE; + end if; + else + -- new request doesn't match, precharge and go to idle + m_state <= M_ST_WAIT_FOR_PRECHARGE; + m_next <= M_ST_IDLE; + end if; end if; -elsif m_state = M_ST_WAIT_FOR_PRECHARGE then - -- wait count then do a precharge - mem_cmd <= CMD_NOP; + elsif m_state = M_ST_WAIT_FOR_PRECHARGE then + -- wait count then do a precharge + mem_cmd <= MEM_CMD_NOP; if m_count > 1 then - m_count <= m_count -1; + m_count <= m_count -1; else - m_state<=M_ST_PRECHARGE; + m_state<=M_ST_PRECHARGE; end if; -elsif m_state = M_ST_PRECHARGE then + elsif m_state = M_ST_PRECHARGE then -- do a precharge, wait two clocks, then goto m_next mem_addr <= (others => '1'); - mem_cmd <= CMD_PRE; + mem_cmd <= MEM_CMD_PRE; m_count <= 1; m_state <= M_ST_NOP_COUNT; -elsif m_state=M_ST_REFRESH then + elsif m_state=M_ST_REFRESH then -- do a refresh, wait six clocks, return to idle - mem_cmd <= CMD_REF; + mem_cmd <= MEM_CMD_REF; m_count <=5; m_next <=M_ST_IDLE; m_state <= M_ST_NOP_COUNT; -- tell the gubbins we did the refresh ack_refresh <= '1'; -else + else -- shouldn't be here - crash - mem_cmd <=CMD_NOP; - mem_cs_n <= M_CS_NONE; + mem_cmd <=MEM_CMD_NOP; + mem_cs_n <= MEM_CS_N_NONE; mem_oe <= '0'; -end if; -end if; + end if; + end if; + + end process; + + -- drive the memory lines + sdram_clk <= clock; + sdram_cke <= '1'; + sdram_cs_n <= mem_cs_n(0); + sdram_ras_n <= mem_cmd(2); + sdram_cas_n <= mem_cmd(1); + sdram_we_n <= mem_cmd(0); + sdram_addr <= mem_addr; + sdram_ba <= mem_bank; + + if l2b_ah(mem_oe) then + sdram_dq <= mem_data_out; + else + sdram_dq <= (others => 'Z' ); + end if; + mem_data_in <= sdram_dq; + + sdram_dqm <= mem_dqm; + + -- a shift register to track the reads + read_process: process(reset_n,clock, mem_cmd) begin + if l2b_al(reset_n) then + r_data_valid <= (others => '0'); + elsif rising_edge(clock) then + r_data_valid(1 downto 0)=r_data_valid(2 downto 1); + r_data_valid(2) <= b2l_ah(mem_cmd = MEM_CMD_READ); + end if; + end process; + -end process; + bus: process (reset_n,clock,b_state,bus_cs_n,bus_rnw,bus_addr,bus_data,ack_request,r_data_valid) begin + if l2b_al(reset_n) then + request_pending <= '0'; + bus_data_out <= (others => '0'); + request_data <= (others => '0'); + request_addr <= (others => '0'); + request_rnw <= '0'; + request_cs_n <= CS_N_NONE; + request_dqm <= "00"; + b_state <= B_ST_WAIT_CS_N_LOW; + elsif rising_edge(clock) then + if b_state = B_ST_WAIT_CS_N_LOW then + if l2b_al(bus_cs_n) then + -- new request ship it to the main state machine + post_request <='1'; + request_addr <= bus_addr; + request_rnw <= bus_rnw; + request_data <= bus_data_in; + request_rnw <= '0'; + + -- send to first chip and all bytes + request_cs_n <= "0" (others => '1'); + request_dqm <= "00"; + + bus_wait_n <= '0'; + b_state <= B_ST_LODGE_REQUEST; + end if; + elsif b_state =B_ST_LODGE_REQUEST then + post_request <='0'; + b_state <= B_ST_WAIT_ACK; + elsif b_state =B_ST_WAIT_ACK then + if not l2b_ah(request_pending) then + -- the logic has pushed the request to the ram + if l2b_al(request_rnw) then + -- if it's a write we're all done + bus_wait_n <= '1'; + b_state <= B_ST_WAIT_CS_N_HIGH; + else + -- if it's a read we have to wait for the data + b_state <= B_ST_WAIT_DATA; + end if; + end if; + elsif b_state = B_ST_WAIT_DATA then + if l2b_ah(r_data_valid(0)) then + bus_data_out <= mem_data_in; + bus_wait_n <= '1'; + b_state <= B_ST_WAIT_CS_N_HIGH; + end if; + elsif b_state = B_ST_WAIT_CS_N_HIGH: + if not l2b_al(bus_cs_n) then + b_state <=B_ST_WAIT_CS_N_LOW; + end if; + else + b_state <=B_ST_WAIT_CS_N_LOW; + end if; + end if; + end process; end; -- cgit v1.2.3