summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames <james.mckenzie@citrix.com>2013-10-14 12:18:34 +0100
committerJames <james.mckenzie@citrix.com>2013-10-14 12:18:34 +0100
commitd42c62b84db2da7dbaf1e17d17b12116e2e712fe (patch)
tree212bd13e23649b86854e5a37f07226a67a9cea98
parentbbcf3c7f967fd1f63225991cf945644547115f10 (diff)
downloadsdram-d42c62b84db2da7dbaf1e17d17b12116e2e712fe.tar.gz
sdram-d42c62b84db2da7dbaf1e17d17b12116e2e712fe.tar.bz2
sdram-d42c62b84db2da7dbaf1e17d17b12116e2e712fe.zip
fish
-rw-r--r--sdram_ctrl.vhd260
1 files 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;