From 9ddb6a83a8e0f29876c427be70b5ef3eff665ba9 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Oct 2013 19:56:36 +0100 Subject: fish --- sdram_ctrl.vhd | 615 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 615 insertions(+) create mode 100644 sdram_ctrl.vhd (limited to 'sdram_ctrl.vhd') diff --git a/sdram_ctrl.vhd b/sdram_ctrl.vhd new file mode 100644 index 0000000..b0b4a1f --- /dev/null +++ b/sdram_ctrl.vhd @@ -0,0 +1,615 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +library work; +use work.sdram_util.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; + + bus_cs_n : in std_logic; + bus_rnw : in std_logic; + + bus_wait_n : out std_logic; + + bus_addr : in addr_t; + bus_data_in : in data_t; + bus_data_out : out data_t; + + sdram_clk : out std_logic; + sdram_cke : out std_logic; + + sdram_cs_n : out std_logic; + + 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); + + sdram_dq : inout data_t; + sdram_dqm : out dqm_t; + + debug : out std_logic_vector(7 downto 0) + ); +end entity; + + +architecture rtl of sdram_ctrl is + + + signal clock : std_logic; + + + constant DEBUG_0 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#3F#,7)); + constant DEBUG_1 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#06#,7)); + constant DEBUG_2 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#5B#,7)); + constant DEBUG_3 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#4F#,7)); + constant DEBUG_4 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#66#,7)); + constant DEBUG_5 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#6D#,7)); + constant DEBUG_6 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#7D#,7)); + constant DEBUG_7 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#07#,7)); + constant DEBUG_8 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#7F#,7)); + constant DEBUG_9 : std_logic_vector(6 downto 0) := std_logic_vector(to_unsigned(16#6F#,7)); + + -- 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; + + -- debuging + signal i_debug : std_logic_vector(6 downto 0); + signal m_debug : std_logic_vector(7 downto 0); + signal b_debug : std_logic_vector(7 downto 0); + + -- 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(3 downto 0); + + -- bus logic + signal post_request: std_logic; + + -- bus fsm + signal b_state : std_logic_vector(4 downto 0); + + constant B_ST_WAIT_CS_N_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_N_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,refresh_counter) begin + if l2b_al(reset_n) then + request_pending <= '0'; + elsif rising_edge(clock) then + --request_pending <= post_request or (request_pending and not b2l_ah(refresh_counter = 0 )); + 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; + i_debug <= DEBUG_0; + elsif rising_edge(clock) then + + if i_state = I_ST_RESET_WAIT then + i_debug <= DEBUG_1; + -- 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; + elsif i_state = I_ST_PRECHARGE then + i_debug <= DEBUG_2; + -- 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 + i_debug <= DEBUG_3; + -- 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 + i_debug <= DEBUG_4; + -- 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 + i_debug <= DEBUG_5; + -- 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; + i_state <= I_ST_WAIT_COUNT; + + elsif i_state=I_ST_DONE then + i_debug <= DEBUG_6; + 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,i_debug) 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'; + m_debug(6 downto 0) <=(others =>'0'); + m_debug(7) <='1'; + elsif rising_edge(clock) then + if m_state =M_ST_WAITING_INIT then + m_debug(6 downto 0) <= i_debug; + m_debug(7) <='1'; + mem_addr <= i_addr; + mem_cmd <= i_cmd; + mem_cs_n <= i_cs_n; + + if l2b_ah(init_done) then + m_state <= M_ST_IDLE; + end if; + elsif m_state = M_ST_IDLE then + m_debug(6 downto 0) <= DEBUG_1; + m_debug(7) <='0'; + mem_cmd <= MEM_CMD_NOP; + + ack_refresh <='0'; + + 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<=MEM_CS_N_ALL; + + -- 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; + else + -- 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 + m_debug(6 downto 0) <= DEBUG_2; + -- 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 <= MEM_CMD_ACTV; + mem_bank(1) <= active_addr(23); + mem_bank(0) <= active_addr(9); + mem_addr <= active_addr(22 downto 10); + mem_data_out <= active_data; + mem_dqm <= active_dqm; + + m_state <= M_ST_NOP_COUNT; + m_count <= 2; --t 3 clocks : FIXME + if l2b_ah(active_rnw) then + m_next <= M_ST_READ; + else + m_next <= M_ST_WRITE; + end if; + elsif m_state = M_ST_NOP_COUNT then + m_debug(6 downto 0) <= DEBUG_3; + -- 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; + else + m_state <= m_next; + end if; + elsif m_state = M_ST_READ then + m_debug(6 downto 0) <= DEBUG_4; + ack_request <='0'; + + mem_cmd <=MEM_CMD_READ; + + mem_addr(12 downto 9) <= (others => '0'); + mem_addr(8 downto 0) <= active_addr(8 downto 0); + + m_state <= M_ST_ACTIVE; + elsif m_state = M_ST_WRITE then + m_debug(6 downto 0) <= DEBUG_5; + ack_request <='0'; + + 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_out <= active_data; + + m_state <=M_ST_ACTIVE; + elsif m_state = M_ST_ACTIVE then + m_debug(6 downto 0) <= DEBUG_6; + -- 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 <= 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 + m_debug(6 downto 0) <= DEBUG_7; + -- wait count then do a precharge + mem_cmd <= MEM_CMD_NOP; + if m_count > 1 then + m_count <= m_count -1; + else + m_state<=M_ST_PRECHARGE; + end if; + elsif m_state = M_ST_PRECHARGE then + m_debug(6 downto 0) <= DEBUG_8; + -- do a precharge, wait two clocks, then goto m_next + mem_addr <= (others => '1'); + mem_cmd <= MEM_CMD_PRE; + m_count <= 1; + m_state <= M_ST_NOP_COUNT; + elsif m_state=M_ST_REFRESH then + m_debug(6 downto 0) <= DEBUG_9; + -- do a refresh, wait six clocks, return to idle + + 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 + -- shouldn't be here - crash + m_debug(7) <='1'; + m_debug(6 downto 0) <= DEBUG_9; + mem_cmd <=MEM_CMD_NOP; + mem_cs_n <= MEM_CS_N_NONE; + mem_oe <= '0'; + 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; + + sdram_dq_tristate: process(mem_oe,mem_data_out) begin + if l2b_ah(mem_oe) then + sdram_dq <= mem_data_out; + else + sdram_dq <= (others => 'Z' ); + end if; + end process; + + 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(2 downto 0)<=r_data_valid(3 downto 1); + r_data_valid(3) <= b2l_ah(mem_cmd = MEM_CMD_READ); + end if; + end process; + + + bus_fsm: process (reset_n,clock,b_state,bus_cs_n,bus_rnw,bus_addr,bus_data_in,ack_request,r_data_valid) begin + if l2b_al(reset_n) then + bus_data_out <= (others => '0'); + request_data <= (others => '0'); + request_addr <= (others => '0'); + request_rnw <= '0'; + request_cs_n <= MEM_CS_N_NONE; + request_dqm <= "00"; + b_state <= B_ST_WAIT_CS_N_LOW; + b_debug(6 downto 0) <= DEBUG_0; + b_debug(7) <='0'; + bus_wait_n <= '0'; + elsif rising_edge(clock) then + if b_state = B_ST_WAIT_CS_N_LOW then + b_debug(6 downto 0) <= DEBUG_1; + bus_wait_n <= '0'; + 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; + + -- send to first chip and all bytes + request_cs_n <= "0"; -- (others => '1'); + request_dqm <= "00"; + + b_state <= B_ST_LODGE_REQUEST; + end if; + elsif b_state =B_ST_LODGE_REQUEST then + b_debug(6 downto 0) <= DEBUG_2; + post_request <='0'; + b_state <= B_ST_WAIT_ACK; + elsif b_state =B_ST_WAIT_ACK then + b_debug(6 downto 0) <= DEBUG_3; + 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 + 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 + b_debug(6 downto 0) <= DEBUG_4; + if l2b_ah(r_data_valid(0)) then + bus_data_out <= mem_data_in; +-- bus_data_out <= request_addr(15 downto 0); + b_state <= B_ST_WAIT_CS_N_HIGH; + end if; + elsif b_state = B_ST_WAIT_CS_N_HIGH then + b_debug(6 downto 0) <= DEBUG_5; + b_debug(7) <='1'; + bus_wait_n <= '1'; + 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; +-- debug <=b_debug; + debug <= m_debug; + + +end; + + + + + -- cgit v1.2.3