|
楼主 |
发表于 2012-5-7 11:21:58
|
显示全部楼层
- -- FSM for a SDRAM controller
- --
- -- Version 0.1 - Ready to simulate
- --
- -- Author: Mike Field (hamster@snap.net.nz)
- --
- -- Feel free to use it however you would like, but
- -- just drop me an email to say thanks.
- -------------------------------------------------------
- library ieee;
- use ieee.std_logic_1164.all;
- use ieee.std_logic_unsigned.all;
- entity sdram_controller is
- port (
- CLOCK_50 : in STD_LOGIC;
- -- Signals to/from the SDRAM chip
- DRAM_ADDR : out STD_LOGIC_VECTOR (12 downto 0);
- DRAM_BA : out STD_LOGIC_VECTOR (1 downto 0);
- DRAM_CAS_N : out STD_LOGIC;
- DRAM_CKE : out STD_LOGIC;
- DRAM_CLK : out STD_LOGIC;
- DRAM_CS_N : out STD_LOGIC;
- DRAM_DQ : inout STD_LOGIC_VECTOR(15 downto 0);
- DRAM_DQM : out STD_LOGIC_VECTOR(1 downto 0);
- DRAM_RAS_N : out STD_LOGIC;
- DRAM_WE_N : out STD_LOGIC;
- --- Inputs from rest of the system
- address : in STD_LOGIC_VECTOR (23 downto 0);
- req_read : in STD_LOGIC;
- req_write : in STD_LOGIC;
- data_out : out STD_LOGIC_VECTOR (31 downto 0);
- data_out_valid : out STD_LOGIC;
- data_in : in STD_LOGIC_VECTOR (31 downto 0)
- );
- end entity;
- architecture rtl of sdram_controller is
- type reg is record
- state : std_logic_vector(8 downto 0);
- address : std_logic_vector(12 downto 0);
- bank : std_logic_vector( 1 downto 0);
- init_counter : std_logic_vector(14 downto 0);
- rf_counter : std_logic_vector( 9 downto 0);
- rf_pending : std_logic;
- rd_pending : std_logic;
- wr_pending : std_logic;
- act_row : std_logic_vector(12 downto 0);
- data_out_low : std_logic_vector(15 downto 0);
- data_out_valid : std_logic;
- dq_masks : std_logic_vector(1 downto 0);
- end record;
- component sdram_clk_gen
- port
- (
- inclk0 : in STD_LOGIC;
- c0 : out STD_LOGIC;
- c1 : out STD_LOGIC
- );
- end component;
- -- note to self - this constant should be "(others => '0')" when not simulating!!!
- signal r : reg := ((others => '0'), (others => '0'),
- (others => '0'), "000000000001000", (others => '0'),
- '0', '0', '0', (others => '0'), (others => '0'), '0', (others => '0'));
- signal n : reg;
- -- Vectors for each SDRAM 'command'
- --- CS_N, RAS_N, CAS_N, WE_N
- constant cmd_nop : std_logic_vector(3 downto 0) := "0111";
- constant cmd_read : std_logic_vector(3 downto 0) := "0101"; -- Must be sure A10 is low.
- constant cmd_write : std_logic_vector(3 downto 0) := "0100";
- constant cmd_act : std_logic_vector(3 downto 0) := "0011";
- constant cmd_pre : std_logic_vector(3 downto 0) := "0010"; -- Must set A10 to '1'.
- constant cmd_ref : std_logic_vector(3 downto 0) := "0001";
- constant cmd_mrs : std_logic_vector(3 downto 0) := "0000"; -- Mode register set
- -- State assignments
- constant s_init_nop : std_logic_vector(8 downto 0) := "00000" & cmd_nop;
- constant s_init_pre : std_logic_vector(8 downto 0) := "00000" & cmd_pre;
- constant s_init_ref : std_logic_vector(8 downto 0) := "00000" & cmd_ref;
- constant s_init_mrs : std_logic_vector(8 downto 0) := "00000" & cmd_mrs;
- constant s_idle : std_logic_vector(8 downto 0) := "00001" & cmd_nop;
- constant s_rf0 : std_logic_vector(8 downto 0) := "00010" & cmd_ref;
- constant s_rf1 : std_logic_vector(8 downto 0) := "00011" & cmd_nop;
- constant s_rf2 : std_logic_vector(8 downto 0) := "00100" & cmd_nop;
- constant s_rf3 : std_logic_vector(8 downto 0) := "00101" & cmd_nop;
- constant s_rf4 : std_logic_vector(8 downto 0) := "00110" & cmd_nop;
- constant s_rf5 : std_logic_vector(8 downto 0) := "00111" & cmd_nop;
- constant s_ra0 : std_logic_vector(8 downto 0) := "01000" & cmd_act;
- constant s_ra1 : std_logic_vector(8 downto 0) := "01001" & cmd_nop;
- constant s_ra2 : std_logic_vector(8 downto 0) := "01010" & cmd_nop;
- constant s_dr0 : std_logic_vector(8 downto 0) := "01011" & cmd_pre;
- constant s_dr1 : std_logic_vector(8 downto 0) := "01100" & cmd_nop;
- constant s_wr0 : std_logic_vector(8 downto 0) := "01101" & cmd_write;
- constant s_wr1 : std_logic_vector(8 downto 0) := "01110" & cmd_nop;
- constant s_wr2 : std_logic_vector(8 downto 0) := "01111" & cmd_nop;
- constant s_wr3 : std_logic_vector(8 downto 0) := "10000" & cmd_nop;
- constant s_rd0 : std_logic_vector(8 downto 0) := "10001" & cmd_read;
- constant s_rd1 : std_logic_vector(8 downto 0) := "10010" & cmd_nop;
- constant s_rd2 : std_logic_vector(8 downto 0) := "10011" & cmd_nop;
- constant s_rd3 : std_logic_vector(8 downto 0) := "10100" & cmd_nop;
- constant s_rd4 : std_logic_vector(8 downto 0) := "10101" & cmd_read;
- constant s_rd5 : std_logic_vector(8 downto 0) := "10110" & cmd_nop;
- constant s_rd6 : std_logic_vector(8 downto 0) := "10111" & cmd_nop;
- constant s_rd7 : std_logic_vector(8 downto 0) := "11000" & cmd_nop;
- constant s_rd8 : std_logic_vector(8 downto 0) := "11001" & cmd_nop;
- constant s_rd9 : std_logic_vector(8 downto 0) := "11011" & cmd_nop;
- constant s_drdr0 : std_logic_vector(8 downto 0) := "11101" & cmd_pre;
- constant s_drdr1 : std_logic_vector(8 downto 0) := "11110" & cmd_nop;
- constant s_drdr2 : std_logic_vector(8 downto 0) := "11111" & cmd_nop;
- signal addr_row : std_logic_vector(12 downto 0);
- signal addr_bank : std_logic_vector(1 downto 0);
- signal addr_col : std_logic_vector(9 downto 0);
- signal captured : std_logic_vector(15 downto 0);
- signal clock_100 : std_logic;
- signal clock_100_delayed_3ns : std_logic;
- begin
- -- Addressing is in 32 bit words - twice that of the DRAM width,
- -- so each burst of four access two system words.
- addr_row <= address(23 downto 11);
- addr_bank <= address(10 downto 9);
- addr_col <= address(8 downto 1) & "00";
- sdram_clk_pll : sdram_clk_gen
- -- Generate the 100MHz clock and the same phase shifted by 3ns
- port map
- (
- inclk0 => CLOCK_50,
- c0 => clock_100,
- c1 => clock_100_delayed_3ns
- );
- DRAM_CLK <= clock_100_delayed_3ns;
- DRAM_CKE <= '1';
- DRAM_CS_N <= r.state(3);
- DRAM_RAS_N <= r.state(2);
- DRAM_CAS_N <= r.state(1);
- DRAM_WE_N <= r.state(0);
- DRAM_ADDR <= r.address;
- DRAM_BA <= r.bank;
- DATA_OUT <= captured & r.data_out_low;
- DRAM_DQM <= r.dq_masks;
- data_out_valid <= r.data_out_valid;
- process (r, address, req_read, req_write, addr_row, addr_bank, addr_col, data_in, captured)
- begin
- -- copy the existing values
- n <= r;
- if req_read = '1' then
- n.rd_pending <= '1';
- end if;
- if req_write = '1' then
- n.wr_pending <= '1';
- end if;
- n.dq_masks <= "11";
- -- first off, do we need to perform a refresh cycle ASAP?
- if r.rf_counter = 770 then -- 781 = 64,000,000ns / 8192 / 10ns
- n.rf_counter <= (others => '0');
- n.rf_pending <= '1';
- else
- -- only start looking for refreshes outside of the initialisation state.
- if not(r.state(8 downto 4) = s_init_nop(8 downto 4)) then
- n.rf_counter <= r.rf_counter + 1;
- end if;
- end if;
- -- Set the data bus into HIZ, high and low bytes masked
- DRAM_DQ <= (others => 'Z');
- n.init_counter <= r.init_counter-1;
- -- Process the FSM
- case r.state(8 downto 4) is
- when s_init_nop(8 downto 4) =>
- n.state <= s_init_nop;
- n.address <= (others => '0');
- n.bank <= (others => '0');
- n.rf_counter <= (others => '0');
- n.data_out_valid <= '1';
- -- T-130, precharge all banks.
- if r.init_counter = "000000010000010" then
- n.state <= s_init_pre;
- n.address(10) <= '1';
- end if;
- -- T-127, T-111, T-95, T-79, T-63, T-47, T-31, T-15, the 8 refreshes
- if r.init_counter(14 downto 7) = 0 and r.init_counter(3 downto 0) = 15 then
- n.state <= s_init_ref;
- end if;
- -- T-3, the load mode register
- if r.init_counter = 3 then
- n.state <= s_init_mrs;
- -- Mode register is as follows:
- -- resvd wr_b OpMd CAS=3 Seq bust=4
- n.address <= "000" & "0" & "00" & "011" & "0" & "010";
- -- resvd
- n.bank <= "00";
- end if;
- -- T-1 The switch to the FSM (first command will be a NOP
- if r.init_counter = 1 then
- n.state <= s_idle;
- end if;
- ------------------------------
- -- The Idle section
- ------------------------------
- when s_idle(8 downto 4) =>
- n.state <= s_idle;
- -- do we have to activate a row?
- if r.rd_pending = '1' or r.wr_pending = '1' then
- n.state <= s_ra0;
- n.address <= addr_row;
- n.act_row <= addr_row;
- end if;
- -- refreshes take priority over everything
- if r.rf_pending = '1' then
- n.state <= s_rf0;
- n.rf_pending <= '0';
- end if;
- ------------------------------
- -- Row activation
- -- s_ra2 is also the "idle with active row" state and provides
- -- a resting point between operations on the same row
- ------------------------------
- when s_ra0(8 downto 4) =>
- n.state <= s_ra1;
- when s_ra1(8 downto 4) =>
- n.state <= s_ra2;
- when s_ra2(8 downto 4) =>
- -- we can stay in this state until we have something to do
- n.state <= s_ra2;
- -- If there is a read pending, deactivate the row
- if r.rd_pending = '1' or r.wr_pending = '1' then
- n.state <= s_dr0;
- n.address(10) <= '1';
- end if;
- -- unless we have a read to perform on the same row? do that instead
- if r.rd_pending = '1' and r.act_row = addr_row then
- n.state <= s_rd0;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- n.rd_pending <= '0';
- end if;
- -- unless we have a write on the same row? writes take priroty over reads
- if r.wr_pending = '1' and r.act_row = addr_row then
- n.state <= s_wr0;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- n.wr_pending <= '0';
- end if;
- -- But refreshes take piority over everything!
- if r.rf_pending = '1' then
- n.state <= s_dr0;
- n.address(10) <= '1';
- end if;
- ------------------------------------------------------
- -- Deactivate the current row and return to idle state
- ------------------------------------------------------
- when s_dr0(8 downto 4) =>
- n.state <= s_dr1;
- when s_dr1(8 downto 4) =>
- n.state <= s_idle;
- ------------------------------
- -- The Refresh section
- ------------------------------
- when s_rf0(8 downto 4) =>
- n.state <= s_rf1;
- when s_rf1(8 downto 4) =>
- n.state <= s_rf2;
- when s_rf2(8 downto 4) =>
- n.state <= s_rf3;
- when s_rf3(8 downto 4) =>
- n.state <= s_rf4;
- when s_rf4(8 downto 4) =>
- n.state <= s_rf5;
- when s_rf5(8 downto 4) =>
- n.state <= s_idle;
- ------------------------------
- -- The Write section
- ------------------------------
- when s_wr0(8 downto 4) =>
- n.state <= s_wr1;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- DRAM_DQ <= data_in(15 downto 0);
- n.dq_masks <= "00";
- when s_wr1(8 downto 4) =>
- n.state <= s_wr2;
- DRAM_DQ <= data_in(31 downto 16);
- n.dq_masks <= "00";
- when s_wr2(8 downto 4) =>
- DRAM_DQ <= data_in(15 downto 0);
- n.state <= s_wr3;
- n.dq_masks <= "00";
- when s_wr3(8 downto 4) =>
- -- Default to the idle+row active state
- n.state <= s_ra2;
- DRAM_DQ <= data_in(31 downto 16);
- n.dq_masks <= "11";
- -- If there is a read or write then deactivate the row
- if r.rd_pending = '1' or r.wr_pending = '1' then
- n.state <= s_dr0;
- n.address(10) <= '1';
- end if;
- -- But if there is a read pending in the same row, do that
- if r.rd_pending = '1' and r.act_row = addr_row then
- n.state <= s_rd0;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- n.rd_pending <= '0';
- end if;
- -- unless there is a write pending in the same row, do that
- if r.wr_pending = '1' and r.act_row = addr_row then
- n.state <= s_wr0;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- n.wr_pending <= '0';
- end if;
- -- But always try and refresh if one is pending!
- if r.rf_pending = '1' then
- n.state <= s_dr0;
- n.address(10) <= '1';
- end if;
- ------------------------------
- -- The Read section
- ------------------------------
- when s_rd0(8 downto 4) =>
- n.state <= s_rd1;
- n.dq_masks <= "00";
- when s_rd1(8 downto 4) =>
- n.state <= s_rd2;
- n.dq_masks <= "00";
- when s_rd2(8 downto 4) =>
- n.state <= s_rd3;
- n.dq_masks <= "00";
- when s_rd3(8 downto 4) =>
- -- default is to end the read with the row open
- n.state <= s_rd7;
- -- otherwise if there is a read or write prepare to deactivate the row.
- -- (This is overridden if the read/write is to the same page)
- if r.rd_pending = '1' or r.wr_pending = '1' then
- n.state <= s_drdr0;
- n.address(10) <= '1';
- end if;
- -- override if the write is from the same row
- if r.wr_pending = '1' and r.act_row = addr_row then
- n.state <= s_rd7;
- end if;
- -- override if the read is from the same row
- if r.rd_pending = '1' and r.act_row = addr_row then
- n.state <= s_rd4;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- end if;
- -- If a refresh is pending then always deactivate the row
- if r.rf_pending = '1' then
- n.state <= s_drdr0;
- n.address(10) <= '1';
- end if;
- n.data_out_low <= captured;
- n.data_out_valid <= '1';
- when s_rd4(8 downto 4) =>
- n.state <= s_rd5;
- n.dq_masks <= "00";
- when s_rd5(8 downto 4) =>
- n.state <= s_rd6;
- n.data_out_low <= captured;
- n.data_out_valid <= '1';
- n.dq_masks <= "00";
- when s_rd6(8 downto 4) =>
- n.state <= s_rd3;
- n.dq_masks <= "00";
- when s_rd7(8 downto 4) =>
- n.state <= s_rd8;
- n.data_out_low <= captured;
- n.data_out_valid <= '1';
- when s_rd8(8 downto 4) =>
- n.state <= s_rd9;
- when s_rd9(8 downto 4) =>
- -- by default go to the idle-with-row-active state
- n.state <= s_ra2;
- n.data_out_low <= captured;
- n.data_out_valid <= '1';
- -- otherwise if there is a read or write prepare to deactivate the row.
- -- (This is overridden if the read/write is to the same row)
- if r.rd_pending = '1' or r.wr_pending = '1' then
- n.state <= s_dr0;
- n.address(10) <= '1';
- end if;
- -- this is to catch if a read has turned up since the choices at state s_dr3
- if r.rd_pending = '1' and r.act_row = addr_row then
- n.state <= s_rd0;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- n.rd_pending <= '0';
- end if;
- -- this is to catch if a read has turned up since the choices at state s_dr3
- if r.wr_pending = '1' and r.act_row = addr_row then
- n.state <= s_wr0;
- n.address <= "000" & addr_col;
- n.bank <= addr_bank;
- n.dq_masks <= "00";
- n.wr_pending <= '0';
- end if;
- if r.rf_pending = '1' then
- n.state <= s_dr0;
- n.address(10) <= '1';
- end if;
- ------------------------------
- -- The Deactivate row during read section
- ------------------------------
- when s_drdr0(8 downto 4) =>
- n.state <= s_drdr1;
- when s_drdr1(8 downto 4) =>
- n.state <= s_drdr2;
- n.data_out_low <= captured;
- n.data_out_valid <= '1';
- when s_drdr2(8 downto 4) =>
- n.state <= s_idle;
- if r.rf_pending = '1' then
- n.state <= s_rf0;
- end if;
- if r.rd_pending = '1' or r.wr_pending = '1' then
- n.state <= s_ra0;
- n.address <= addr_row;
- n.act_row <= addr_row;
- n.bank <= addr_bank;
- end if;
- when others =>
- n.state <= s_init_nop;
- end case;
- end process;
- --- The clock driven logic
- process (clock_100, n)
- begin
- if clock_100'event and clock_100 = '1' then
- r <= n;
- end if;
- end process;
- process (clock_100_delayed_3ns, dram_dq)
- begin
- if clock_100_delayed_3ns'event and clock_100_delayed_3ns = '1' then
- captured <= dram_dq;
- end if;
- end process;
- end rtl;
复制代码 |
|