Intital revision

git-svn-id: http://moon:8086/svn/vhdl/trunk@24 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
2008-10-02 13:37:55 +00:00
parent de0e513eb0
commit 6eb25882ba
17 changed files with 4004 additions and 0 deletions
+487
View File
@@ -0,0 +1,487 @@
-------------------------------------------------------------------------
-- Project: SDRAM controller
-- This file: SDRAM main controller and user I/F
--
-- Copyright (C) 2007 J. Ahrensfeld
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- For questions and ideas, please contact the author at jens@jayfield.org
--
--------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use work.sdram_config.all;
use work.sdram_types.all;
use work.utils_pkg.all;
entity sdram_ctrl is
Generic
(
f_sysclk : natural := 100E6;
BL : natural := 2
);
Port (
rst : in STD_LOGIC;
clk : in STD_LOGIC;
u_busy : out STD_LOGIC;
u_tag_in : in user_tag_t;
u_tag_out : out user_tag_t;
u_addr : in user_addr_t;
u_cmd : in user_cmd_t;
u_cmd_we : in STD_LOGIC;
col_addr : out col_addr_t;
sdr_cmd_busy : in STD_LOGIC;
sdr_cmd : out sdr_cmd_t;
sdr_cmd_we : out STD_LOGIC;
sdr_mode : out mode_word_t;
sdr_cke : out STD_LOGIC
);
end sdram_ctrl;
architecture behaviour of sdram_ctrl is
constant LMR_BURST_LEN : natural := NextExpBaseTwo(BL);
type ctrl_state_t is (RESET, POWER_WAIT, INIT, INIT_WAIT, USER_READY, USER_WRITE_PRE, USER_WRITE_ACT, USER_WRITE, USER_READ_PRE, USER_READ_ACT, USER_READ, REFRESH);
signal st_ctrl, st_ctrl_next : ctrl_state_t;
constant PWR_UP_CLOCK_INTERVAL : natural := PWR_UP_WAIT*(f_sysclk/1E6);
signal pwr_up_cnt : natural range 0 to PWR_UP_CLOCK_INTERVAL-1;
signal pwr_up_cnt_rst : std_logic;
signal pwr_up_finished : std_logic;
signal cycle_cnt : natural range 0 to 255;
signal cc_preset : natural range 0 to 255;
signal cc_load_en : std_logic;
signal cycle_finished : std_logic;
signal seq_cnt : natural range 0 to 31;
signal seq_rst_en : std_logic;
signal seq_cnt_en : std_logic;
constant REFRESH_CLOCK_INTERVAL : natural := natural(REFRESH_INTERVAL*real(f_sysclk)/1.0E6);
signal refresh_cnt : natural range 0 to REFRESH_CLOCK_INTERVAL-1;
signal refresh_request : std_logic;
signal refresh_cnt_rst : std_logic;
signal addr_reg_load_en : std_logic;
signal u_tag_reg : user_tag_t;
signal bank_addr_reg : bank_addr_t;
signal row_addr_reg : row_addr_t;
signal col_addr_reg : col_addr_t;
signal u_bank_addr : bank_addr_t;
signal u_row_addr : row_addr_t;
signal u_col_addr : col_addr_t;
signal act_request : std_logic;
signal act_request_set : std_logic;
signal act_request_clr : std_logic;
type init_seq_rom_t is array (0 to 14) of init_seq_t;
constant init_seq_rom : init_seq_rom_t :=
(
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_PRE,
mode_word => "000010000000000",
wait_cycle => 0
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_LMR,
mode_word => to_unsigned(LMR_REG_EXTENDED, 2) & "0000000000010",
wait_cycle => 0
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_LMR,
mode_word => to_unsigned(LMR_REG_BASE, 2) & to_unsigned(LMR_OP_RES_DLL, 6) & to_unsigned(LMR_CL2, 3) & '0' & to_unsigned(LMR_BURST_LEN, 3),
wait_cycle => 200
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_PRE,
mode_word => "000010000000000",
wait_cycle => 0
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_AR,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_AR,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
),
(
cmd => SD_LMR,
mode_word => to_unsigned(LMR_REG_BASE, 2) & to_unsigned(LMR_OP_NORMAL, 6) & to_unsigned(LMR_CL2, 3) & '0' & to_unsigned(LMR_BURST_LEN, 3),
wait_cycle => 200
),
(
cmd => SD_NOP,
mode_word => (others => '0'),
wait_cycle => 0
)
);
begin
u_row_addr <= u_addr(user_addr_t'left downto user_addr_t'left-row_addr_t'length+1);
u_bank_addr <= u_addr(user_addr_t'left-row_addr_t'length downto user_addr_t'left-row_addr_t'length-bank_addr_t'length+1);
u_col_addr <= u_addr(user_addr_t'left-row_addr_t'length-bank_addr_t'length downto 0);
------------------------------------------------------------------------------------------
fsm_ctrl_state:
process (st_ctrl, u_tag_in, u_tag_reg, u_cmd, u_cmd_we, sdr_cmd_busy, pwr_up_finished, seq_cnt, cycle_finished, u_bank_addr, u_row_addr, bank_addr_reg, row_addr_reg, u_col_addr, col_addr_reg, refresh_request, act_request)
begin
u_busy <= '1';
pwr_up_cnt_rst <= '0';
cc_preset <= init_seq_rom(seq_cnt).wait_cycle;
cc_load_en <= '0';
sdr_cmd <= init_seq_rom(seq_cnt).cmd;
sdr_cmd_we <= '0';
sdr_mode <= bank_addr_reg & row_addr_reg;
col_addr <= col_addr_reg;
sdr_cke <= '1';
seq_cnt_en <= '0';
seq_rst_en <= '0';
addr_reg_load_en <= '0';
refresh_cnt_rst <= '0';
act_request_set <= '0';
act_request_clr <= '0';
u_tag_out <= u_tag_reg;
st_ctrl_next <= st_ctrl;
case st_ctrl is
when RESET =>
sdr_cke <= '0';
pwr_up_cnt_rst <= '1';
st_ctrl_next <= POWER_WAIT;
when POWER_WAIT =>
sdr_cke <= '0';
if pwr_up_finished = '1' then
seq_rst_en <= '1';
st_ctrl_next <= INIT;
end if;
when INIT =>
sdr_mode <= init_seq_rom(seq_cnt).mode_word;
sdr_cmd <= init_seq_rom(seq_cnt).cmd;
cc_preset <= init_seq_rom(seq_cnt).wait_cycle;
if seq_cnt = init_seq_rom_t'high then
act_request_set <= '1';
refresh_cnt_rst <= '1';
st_ctrl_next <= USER_READY;
elsif sdr_cmd_busy = '0' then
cc_load_en <= '1';
sdr_cmd_we <= '1';
st_ctrl_next <= INIT_WAIT;
end if;
when INIT_WAIT =>
if sdr_cmd_busy = '0' and cycle_finished = '1' then
seq_cnt_en <= '1';
st_ctrl_next <= INIT;
end if;
when USER_READY =>
if sdr_cmd_busy = '0' then
if refresh_request = '1' then
sdr_mode(BIT_PRE_ALL) <= '1';
sdr_cmd_we <= '1';
sdr_cmd <= SD_PRE;
st_ctrl_next <= REFRESH;
else
u_busy <= '0';
if u_cmd_we = '1' then
case u_cmd is
when UCMD_NOP =>
sdr_cmd <= SD_NOP;
when UCMD_LMR =>
sdr_cmd <= SD_NOP;
when UCMD_WRITE =>
col_addr <= u_col_addr;
u_tag_out <= u_tag_in;
sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE;
addr_reg_load_en <= '1';
act_request_clr <= '1';
sdr_cmd <= SD_WRITE;
if (u_row_addr /= row_addr_reg) or act_request = '1' then
st_ctrl_next <= USER_WRITE_PRE;
elsif (u_bank_addr /= bank_addr_reg) then
if ENABLE_PRE_ALL = '1' then
st_ctrl_next <= USER_WRITE_ACT;
else
st_ctrl_next <= USER_WRITE_PRE;
end if;
elsif sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
else
st_ctrl_next <= USER_WRITE;
end if;
when UCMD_READ =>
col_addr <= u_col_addr;
u_tag_out <= u_tag_in;
sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE;
addr_reg_load_en <= '1';
act_request_clr <= '1';
sdr_cmd <= SD_READ;
if (u_row_addr /= row_addr_reg) or act_request = '1' then
st_ctrl_next <= USER_READ_PRE;
elsif (u_bank_addr /= bank_addr_reg) then
if ENABLE_PRE_ALL = '1' then
st_ctrl_next <= USER_READ_ACT;
else
st_ctrl_next <= USER_READ_PRE;
end if;
elsif sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
else
st_ctrl_next <= USER_READ;
end if;
when others => null;
end case;
end if;
end if;
end if;
when USER_WRITE_PRE =>
sdr_cmd <= SD_PRE;
sdr_mode(BIT_PRE_ALL) <= ENABLE_PRE_ALL;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_WRITE_ACT;
end if;
when USER_WRITE_ACT =>
sdr_cmd <= SD_ACT;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_WRITE;
end if;
when USER_WRITE =>
sdr_cmd <= SD_WRITE;
sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_READY;
end if;
when USER_READ_PRE =>
sdr_cmd <= SD_PRE;
sdr_mode(BIT_PRE_ALL) <= ENABLE_PRE_ALL;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_READ_ACT;
end if;
when USER_READ_ACT =>
sdr_cmd <= SD_ACT;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_READ;
end if;
when USER_READ =>
sdr_cmd <= SD_READ;
sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_READY;
end if;
when REFRESH =>
sdr_cmd <= SD_AR;
if sdr_cmd_busy = '0' then
sdr_cmd_we <= '1';
st_ctrl_next <= USER_READY;
refresh_cnt_rst <= '1';
act_request_set <= '1';
end if;
when others =>
st_ctrl_next <= RESET;
end case;
end process;
fsm_ctrl_state_next:
process (rst, clk)
begin
if rst = '1' then
st_ctrl <= RESET;
elsif rising_edge(clk) then
st_ctrl <= st_ctrl_next;
end if;
end process;
------------------------------------------------------------------------------------------
act_request_register:
process (rst, clk)
begin
if rst = '1' then
act_request <= '1';
elsif rising_edge(clk) then
if act_request_set = '1' then
act_request <= '1';
elsif act_request_clr = '1' then
act_request <= '0';
end if;
end if;
end process;
------------------------------------------------------------------------------------------
user_addr_register:
process (rst, clk)
begin
if rst = '1' then
bank_addr_reg <= (others => '0');
row_addr_reg <= (others => '0');
col_addr_reg <= (others => '0');
u_tag_reg <= (others => '0');
elsif rising_edge(clk) then
if addr_reg_load_en = '1' then
bank_addr_reg <= u_bank_addr;
row_addr_reg <= u_row_addr;
col_addr_reg <= u_col_addr;
u_tag_reg <= u_tag_in;
end if;
end if;
end process;
------------------------------------------------------------------------------------------
power_up_counter:
process (rst, clk)
begin
if rst = '1' then
pwr_up_cnt <= 0;
pwr_up_finished <= '0';
elsif rising_edge(clk) then
pwr_up_finished <= '0';
if pwr_up_cnt_rst = '1' then
pwr_up_cnt <= PWR_UP_CLOCK_INTERVAL-1;
else
if pwr_up_cnt /= 0 then
pwr_up_cnt <= pwr_up_cnt - 1;
else
pwr_up_finished <= '1';
end if;
end if;
end if;
end process;
------------------------------------------------------------------------------------------
refresh_counter:
process (rst, clk)
begin
if rst = '1' then
refresh_cnt <= 0;
refresh_request <= '0';
elsif rising_edge(clk) then
refresh_request <= '0';
if refresh_cnt_rst = '1' then
refresh_cnt <= REFRESH_CLOCK_INTERVAL-1;
else
if refresh_cnt /= 0 then
refresh_cnt <= refresh_cnt - 1;
else
refresh_request <= '1';
end if;
end if;
end if;
end process;
------------------------------------------------------------------------------------------
cycle_counter:
process (rst, clk)
begin
if rst = '1' then
cycle_cnt <= 0;
cycle_finished <= '0';
elsif rising_edge(clk) then
cycle_finished <= '0';
if cc_load_en = '1' then
cycle_cnt <= cc_preset;
elsif cycle_cnt /= 0 then
cycle_cnt <= cycle_cnt - 1;
else
cycle_finished <= '1';
end if;
end if;
end process;
------------------------------------------------------------------------------------------
seq_counter:
process (rst, clk)
begin
if rst = '1' then
seq_cnt <= 0;
elsif rising_edge(clk) then
if seq_rst_en = '1' then
seq_cnt <= 0;
elsif seq_cnt_en = '1' then
if seq_cnt /= init_seq_rom_t'high then
seq_cnt <= seq_cnt + 1;
end if;
end if;
end if;
end process;
------------------------------------------------------------------------------------------
end behaviour;