From d42c62b84db2da7dbaf1e17d17b12116e2e712fe Mon Sep 17 00:00:00 2001 From: James Date: Mon, 14 Oct 2013 12:18:34 +0100 Subject: fish --- sdram_ctrl.vhd | 260 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 152 insertions(+), 108 deletions(-) diff --git a/sdram_ctrl.vhd b/sdram_ctrl.vhd index 457364a..55c1cae 100644 --- a/sdram_ctrl.vhd +++ b/sdram_ctrl.vhd @@ -2,6 +2,9 @@ library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; +-- a simple dram controller (no pipelineing) +-- that looks like a slow static ram + entity sdram_ctrl is port ( @@ -15,22 +18,22 @@ port b_wait_n : out std_logic; b_addr : in std_logic_vector(15 downto 0); - b_data : inout std_logic_vector(7 downto 0); + b_data : inout std_logic_vector(15 downto 0); sdram_clk : out std_logic; - sdram_cs_n : 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; - sdram_addr : out std_logic_vector(12 downto 0); + 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); - sdram_dqm : out std_logic_vector(1 downto 0) + sdramem_dqm : out std_logic_vector(1 downto 0) ); end entity; @@ -38,21 +41,44 @@ 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; +subtype cs_n_t is std_logic_vector(0 downto 0); +subtype addr_t is std_logic_vector(23 downto 0); +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 ack_need_refresh : std_logic; signal need_refresh : std_logic; -subtype uint13_t is integer range 0 to 8191; signal refresh_counter : uint13_t; -signal init_done : std_logic; +-- init logic +signal init_done : std_logic; signal i_addr : std_logic_vector(12 downto 0); -signal i_cmd : std_logic_vector(3 downto 0); -subtype uint4_t is integer range 0 to 15; +signal i_cs_n: cs_n_t; +signal i_cmd : std_logic_vector(2 downto 0); signal i_count : uint4_t; -subtype uint3_t is integer range 0 to 7; 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; @@ -63,32 +89,52 @@ constant I_ST_SET_MODE : uint3_t :=4; constant I_ST_DONE : uint3_t :=5; --- 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"; - -signal m_state : std_logic_vector(8 downto 0); - - -constant M_ST_IDLE : std_logic_vector(8 downto 0 ):="000000001"; -constant M_ST_RAS : std_logic_vector(8 downto 0 ):="000000010"; -constant M_ST_NOP_COUNT : std_logic_vector(8 downto 0 ):="000000100"; -constant M_ST_READ : std_logic_vector(8 downto 0 ):="000001000"; -constant M_ST_WRITE : std_logic_vector(8 downto 0 ):="000010000"; -constant M_ST_WAIT_FOR_PRECHARGE : std_logic_vector(8 downto 0 ):="000100000"; -constant M_ST_PRECHARGE : std_logic_vector(8 downto 0 ):="001000000"; -constant M_ST_REFRESH : std_logic_vector(8 downto 0 ):="010000000"; -constant M_ST_FETCH_NEXT : std_logic_vector(8 downto 0 ):="100000000"; - - - -function active_high(constant val : in boolean) return std_logic is begin +-- 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 @@ -97,19 +143,18 @@ function active_high(constant val : in boolean) return std_logic is begin end function; - -function ternary( - constant val : in boolean, - constant if_true : in std_logic, - constant if_false : in std_logic -) return std_logic is begin - if val then - return if_true; - else - return if_false; - end if; +-- convert active high logic to boolean value +function l2b_h(constant val : in std_logic) return boolean is begin + return val='1'; 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; @@ -127,11 +172,11 @@ refresh_counter_process: process(reset_n,clock) begin end process; -need_refresh_process: process(reset_n,clock,refresh_counter,need_refresh,init_done,ack_need_refresh) begin +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 <= (active_high(refresh_counter = 0) or need_refresh) and init_done and not ack_need_refresh; + need_refresh <= (b2l_h(refresh_counter = 0) or need_refresh) and init_done and not ack_refresh; end if; end process; @@ -140,7 +185,7 @@ 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 active_high(i_state = I_ST_DONE ); + init_done <= init_done or b2l_h(i_state = I_ST_DONE ); end if; end process; @@ -217,45 +262,42 @@ init_fsm: process (reset_n,clock,i_state,i_count,i_next,refresh_counter) begin end if; end process; -main_fsm: process (reset_n,clock,m_state,refresh_counter) begin - -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; -m_cmd <= CMD_NOP; -m_cs_n <= '1'; -m_bank <= "00"; -m_addr <= "0000000000000"; -m_data <= "0000000000000000"; -m_dqm <= "00"; +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_need_refresh <= 0; -f_pop <= 0; -oe <= 0; -bus_busy<=1; +ack_refresh <= '0'; +ack_request <= '0'; +mem_oe <= '0'; elsif rising_edge(clock) then if m_state =M_ST_WAITING_INIT then - m_addr <= i_addr; - m_cmd <= i_cmd; - m_cs_n <= i_cs_n; + mem_addr <= i_addr; + mem_cmd <= i_cmd; + mem_cs_n <= i_cs_n; - if active_high(init_done) then + if l2b_h(init_done) then m_state <= M_ST_IDLE; end if; elsif m_state = M_ST_IDLE then - m_cmd <= CMD_NOP; + mem_cmd <= CMD_NOP; - ack_need_refresh <='0'; + ack_refresh <='0'; - if active_high(need_refresh) then + 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 - m_cs_n<=CS_N_ALL; + mem_cs_n<=CS_N_ALL; -- precharge everyone (putting back -- the open row if we did come from a read @@ -265,10 +307,10 @@ elsif m_state = M_ST_IDLE then m_next <= M_ST_REFRESH; else -- idle to all chips (CMD_IGN) - m_cs_n<=CS_N_NONE; + mem_cs_n<=CS_N_NONE; -- find out if anyone wants us - if active_high(request_ready) then + if l2b_h(request_ready) then active_cs_n <= request_cs_n; active_rnw <= request_rnw; active_addr <= request_addr; @@ -283,23 +325,24 @@ elsif m_state = M_ST_RAS then ack_request <='0'; - m_cs_n <= active_cs_n; - m_cmd <= CMD_ACTV; - m_bank <= active_bank; - m_addr <= active_addr(22 downto 10); - m_data <= active_data; - m_dqm <= active_dqm; + mem_cs_n <= active_cs_n; + mem_cmd <= 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_dqm <= active_dqm; m_state <= M_ST_NOP_COUNT; m_count <= 2; --t 3 clocks : FIXME - if (active_high(active_rnw)) then + if l2b_h(active_rnw) then m_next <= M_ST_READ; else 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 - m_cmd <=CMD_NOP; + mem_cmd <=CMD_NOP; if m_count > 1 then m_count <= m_count - 1; else @@ -308,40 +351,40 @@ elsif m_state = M_ST_NOP_COUNT then elsif m_state = M_ST_READ then ack_request <='0'; - m_cmd <=CMD_READ; + mem_cmd <=CMD_READ; - m_addr(13 downto 10) <= (others => '0'); - m_addr(9 downto 0) <= active_addr[8:0]; + mem_addr(12 downto 9) <= (others => '0'); + mem_addr(8 downto 0) <= active_addr(8 downto 0); - m_next <= M_ST_ACTIVE + m_next <= M_ST_ACTIVE; elsif m_state = M_ST_WRITE then ack_request <='0'; - m_cmd<=CMD_WRIT; + mem_cmd<=CMD_WRIT; - m_addr(13 downto 10) <= (others => '0'); - m_addr(9 downto 0) <= active_addr[8:0]; + mem_addr(12 downto 9) <= (others => '0'); + mem_addr(8 downto 0) <= active_addr(8 downto 0); - oe <= '1'; - m_data <= active_data; + mem_oe <= '1'; + mem_data <= active_data; - m_state <=M_ST_ACTIVE + m_state <=M_ST_ACTIVE; elsif m_state = M_ST_ACTIVE then -- turn off drivers (we might have come from a write) - oe <= '0'; + mem_oe <= '0'; -- sit doing NOPS on this row until either we get a new request -- or we need a refresh - m_cmd <= M_CMD_NOP; + mem_cmd <= M_CMD_NOP; - if active_high(need_refresh) then + 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 active_high(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 + 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 @@ -351,7 +394,7 @@ elsif m_state = M_ST_ACTIVE then ack_request <='1'; - if active_high(request_rnw) then + if l2b_h(request_rnw) then m_state <= M_ST_READ; else m_state <= M_ST_WRITE; @@ -365,33 +408,34 @@ elsif m_state = M_ST_ACTIVE then elsif m_state = M_ST_WAIT_FOR_PRECHARGE then -- wait count then do a precharge - m_cmd <= CMD_NOP; + mem_cmd <= CMD_NOP; if m_count > 1 then m_count <= m_count -1; else - m_state=M_ST_PRECHARGE; - end; + m_state<=M_ST_PRECHARGE; + end if; elsif m_state = M_ST_PRECHARGE then -- do a precharge, wait two clocks, then goto m_next - m_addr <= (others => '1'); - m_cmd <= CMD_PRE; - m_count = 1; + mem_addr <= (others => '1'); + mem_cmd <= CMD_PRE; + m_count <= 1; m_state <= M_ST_NOP_COUNT; elsif m_state=M_ST_REFRESH then -- do a refresh, wait six clocks, return to idle - m_cmd <= CMD_REF; + mem_cmd <= CMD_REF; m_count <=5; m_next <=M_ST_IDLE; m_state <= M_ST_NOP_COUNT; -- tell the gubbins we did the refresh - ack_need_refresh <= '1'; + ack_refresh <= '1'; else -- shouldn't be here - crash - m_cmd <=CMD_NOP; - m_cs_n <= M_CS_NONE - oe <= '0'; + mem_cmd <=CMD_NOP; + mem_cs_n <= M_CS_NONE; + mem_oe <= '0'; +end if; end if; end process; -- cgit v1.2.3