OpenCores
URL https://opencores.org/ocsvn/mlite/mlite/trunk

Subversion Repositories mlite

[/] [mlite/] [trunk/] [vhdl/] [ddr_ctrl.vhd] - Rev 259

Go to most recent revision | Compare with Previous | Blame | View Log

---------------------------------------------------------------------
-- TITLE: DDR SDRAM Interface
-- AUTHORS: Steve Rhoads (rhoadss@yahoo.com)
-- DATE CREATED: 7/26/07
-- FILENAME: ddr_ctrl.vhd
-- PROJECT: Plasma CPU core
-- COPYRIGHT: Software placed into the public domain by the author.
--    Software 'as is' without warranty.  Author liable for nothing.
-- DESCRIPTION:
--    Double Data Rate Sychronous Dynamic Random Access Memory Interface
--    ROW = address(25 downto 13)
--    BANK = address(12 downto 11)
--    COL = address(10 downto 2)
--    Requires CAS latency=2; burst size=2.  
--    Requires clk changes on rising_edge(clk_2x).
--    Requires active, address, byte_we, data_w stable throughout transfer.
--    DLL mode requires 77MHz.  Non-DLL mode runs at 25 MHz.
--
-- cycle_cnt 777777770000111122223333444455556666777777777777
-- clk_2x    --__--__--__--__--__--__--__--__--__--__--__--__
-- clk       ____----____----____----____----____----____----
-- SD_CLK    ----____----____----____----____----____----____
-- cmd       ____write+++WRITE+++____________________________
-- SD_DQ     ~~~~~~~~~~~~~~uuuullllUUUULLLL~~~~~~~~~~~~~~~~~~
--
-- cycle_cnt 777777770000111122223333444455556666777777777777
-- clk_2x    --__--__--__--__--__--__--__--__--__--__--__--__
-- clk       ____----____----____----____----____----____----
-- SD_CLK    ----____----____----____----____----____----____
-- cmd       ____read++++________________________read++++____
-- SD_DQ     ~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~~~
-- SD_DQnDLL ~~~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~
-- pause     ____------------------------________------------
--
-- Must run DdrInit() to initialize DDR chip.
-- Read Micron DDR SDRAM MT46V32M16 data sheet for more details.
---------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use work.mlite_pack.all;
 
entity ddr_ctrl is
   port(
      clk      : in std_logic;
      clk_2x   : in std_logic;
      reset_in : in std_logic;
 
      address  : in std_logic_vector(25 downto 2);
      byte_we  : in std_logic_vector(3 downto 0);
      data_w   : in std_logic_vector(31 downto 0);
      data_r   : out std_logic_vector(31 downto 0);
      active   : in std_logic;
      pause    : out std_logic;
 
      SD_CK_P  : out std_logic;     --clock_positive
      SD_CK_N  : out std_logic;     --clock_negative
      SD_CKE   : out std_logic;     --clock_enable
 
      SD_BA    : out std_logic_vector(1 downto 0);  --bank_address
      SD_A     : out std_logic_vector(12 downto 0); --address(row or col)
      SD_CS    : out std_logic;     --chip_select
      SD_RAS   : out std_logic;     --row_address_strobe
      SD_CAS   : out std_logic;     --column_address_strobe
      SD_WE    : out std_logic;     --write_enable
 
      SD_DQ    : inout std_logic_vector(15 downto 0); --data
      SD_UDM   : out std_logic;     --upper_byte_enable
      SD_UDQS  : inout std_logic;   --upper_data_strobe
      SD_LDM   : out std_logic;     --low_byte_enable
      SD_LDQS  : inout std_logic);  --low_data_strobe
end; --entity ddr
 
architecture logic of ddr_ctrl is
 
   --Commands for bits RAS & CAS & WE
   subtype command_type is std_logic_vector(2 downto 0);
   constant COMMAND_LMR          : command_type := "000";
   constant COMMAND_AUTO_REFRESH : command_type := "001";
   constant COMMAND_PRECHARGE    : command_type := "010";
   constant COMMAND_ACTIVE       : command_type := "011";
   constant COMMAND_WRITE        : command_type := "100";
   constant COMMAND_READ         : command_type := "101";
   constant COMMAND_TERMINATE    : command_type := "110";
   constant COMMAND_NOP          : command_type := "111";
 
   subtype ddr_state_type is std_logic_vector(3 downto 0);
   constant STATE_POWER_ON     : ddr_state_type := "0000";
   constant STATE_IDLE         : ddr_state_type := "0001";
   constant STATE_ROW_ACTIVATE : ddr_state_type := "0010";
   constant STATE_ROW_ACTIVE   : ddr_state_type := "0011";
   constant STATE_READ         : ddr_state_type := "0100";
   constant STATE_READ2        : ddr_state_type := "0101";
   constant STATE_READ3        : ddr_state_type := "0110";
   constant STATE_PRECHARGE    : ddr_state_type := "0111";
   constant STATE_PRECHARGE2   : ddr_state_type := "1000";
 
   signal state_prev   : ddr_state_type;
   signal refresh_cnt  : std_logic_vector(7 downto 0);
   signal data_write2  : std_logic_vector(47 downto 0); --write pipeline
   signal byte_we_reg2 : std_logic_vector(5 downto 0);  --write pipeline
   signal write_active : std_logic;
   signal write_prev   : std_logic;
   signal cycle_count  : std_logic_vector(2 downto 0);  --half clocks since op
   signal cycle_count2 : std_logic_vector(2 downto 0);  --delayed by quarter clock
   signal cke_reg      : std_logic;
   signal clk_p        : std_logic;
   signal bank_open    : std_logic_vector(3 downto 0);
   signal data_read    : std_logic_vector(31 downto 0);
 
begin
   ddr_proc: process(clk, clk_p, clk_2x, reset_in, 
                     address, byte_we, data_w, active,
                     SD_DQ, SD_UDQS, SD_LDQS,
                     state_prev, refresh_cnt,  
                     byte_we_reg2, data_write2, 
                     cycle_count, cycle_count2, write_prev,
                     write_active, cke_reg, bank_open,
                     data_read)
   type address_array_type is array(3 downto 0) of std_logic_vector(12 downto 0);
   variable address_row    : address_array_type;
   variable command        : std_logic_vector(2 downto 0); --RAS & CAS & WE
   variable bank_index     : integer;
   variable state_current  : ddr_state_type;
 
   begin
 
      command := COMMAND_NOP;
      bank_index := conv_integer(address(12 downto 11));
      state_current := state_prev;
 
      --DDR state machine to determine state_current and command
      case state_prev is
         when STATE_POWER_ON =>
            if active = '1' then
               if byte_we /= "0000" then
                  command := address(6 downto 4); --LMR="000"
               else
                  state_current := STATE_IDLE;  --read transistions to STATE_IDLE
               end if;
            end if;
 
         when STATE_IDLE =>
            if refresh_cnt(7) = '1' then
               if write_prev = '0' then
                  state_current := STATE_PRECHARGE;
                  command := COMMAND_AUTO_REFRESH;
               end if;
            elsif active = '1' then
               state_current := STATE_ROW_ACTIVATE;
               command := COMMAND_ACTIVE;
            end if;
 
         when STATE_ROW_ACTIVATE =>
            state_current := STATE_ROW_ACTIVE;
 
         when STATE_ROW_ACTIVE =>
            if refresh_cnt(7) = '1' then
               if write_prev = '0' then
                  state_current := STATE_PRECHARGE;
                  command := COMMAND_PRECHARGE;
               end if;
            elsif active = '1' then
               if bank_open(bank_index) = '0' then
                  state_current := STATE_ROW_ACTIVATE;
                  command := COMMAND_ACTIVE;
               elsif address(25 downto 13) /= address_row(bank_index) then
                  if write_prev = '0' then
                     state_current := STATE_PRECHARGE;
                     command := COMMAND_PRECHARGE;
                  end if;
               else
                  if byte_we /= "0000" then
                     command := COMMAND_WRITE;
                  elsif write_prev = '0' then
                     state_current := STATE_READ;
                     command := COMMAND_READ;
                  end if;
               end if;
            end if;
 
         when STATE_READ =>
            state_current := STATE_READ2;
 
         when STATE_READ2 =>
            state_current := STATE_READ3;
 
         when STATE_READ3 =>
            state_current := STATE_ROW_ACTIVE;
 
         when STATE_PRECHARGE =>
            state_current := STATE_PRECHARGE2;
 
         when STATE_PRECHARGE2 =>
            state_current := STATE_IDLE;
 
         when others =>
            state_current := STATE_IDLE;
      end case; --state_prev
 
      --rising_edge(clk) domain registers
      if reset_in = '1' then
         state_prev   <= STATE_POWER_ON;
         cke_reg      <= '0';
         refresh_cnt  <= ZERO(7 downto 0);
         write_prev   <= '0';
         write_active <= '0';
         bank_open    <= "0000";
      elsif rising_edge(clk) then
 
         if active = '1' then
            cke_reg <= '1';
         end if;
 
         if command = COMMAND_WRITE then
            write_prev <= '1';
         elsif cycle_count2(2 downto 1) = "11" then
            write_prev <= '0';
         end if;
 
         if command = COMMAND_WRITE then
            write_active <= '1';
         elsif cycle_count2 = "100" then
            write_active <= '0';
         end if;
 
         if state_current = STATE_ROW_ACTIVATE then
            bank_open(bank_index) <= '1';
            address_row(bank_index) := address(25 downto 13);
         end if;
 
         if state_current = COMMAND_AUTO_REFRESH then
            bank_open <= "0000";
            refresh_cnt <= ZERO(7 downto 0);
         else
            refresh_cnt <= refresh_cnt + 1;
         end if;
 
         state_prev <= state_current;
 
      end if; --rising_edge(clk)
 
      --rising_edge(clk_2x) domain registers
      if reset_in = '1' then
         cycle_count <= "000";
      elsif rising_edge(clk_2x) then
         --Cycle_count
         if (command = COMMAND_READ or command = COMMAND_WRITE) and clk = '1' then
            cycle_count <= "000";
         elsif cycle_count /= "111" then
            cycle_count <= cycle_count + 1;
         end if;
 
         clk_p <= clk;  --earlier version of not clk         
 
         --Read data (DLL disabled)
         if cycle_count = "100" then
            data_read(31 downto 16) <= SD_DQ; --data
         elsif cycle_count = "101" then
            data_read(15 downto 0) <= SD_DQ;
         end if;
      end if;
 
      --falling_edge(clk_2x) domain registers
      if reset_in = '1' then
         cycle_count2 <= "000";
         data_write2 <= ZERO(15 downto 0) & ZERO;
         byte_we_reg2 <= "000000";
      elsif falling_edge(clk_2x) then
         cycle_count2 <= cycle_count;
 
         --Write pipeline
         if clk = '0' then
            data_write2 <= data_write2(31 downto 16) & data_w;
            byte_we_reg2 <= byte_we_reg2(3 downto 2) & byte_we;
         else
            data_write2(47 downto 16) <= data_write2(31 downto 0);
            byte_we_reg2(5 downto 2) <= byte_we_reg2(3 downto 0);
         end if;
 
         --Read data (DLL enabled)
         --if cycle_count = "100" then
         --   data_read(31 downto 16) <= SD_DQ; --data
         --elsif cycle_count = "101" then
         --   data_read(15 downto 0) <= SD_DQ;
         --end if;
      end if;
 
      data_r <= data_read;
 
      --Write data
      if write_active = '1' then
         SD_UDQS <= clk_p;                   --upper_data_strobe 
         SD_LDQS <= clk_p;                   --low_data_strobe
         SD_DQ <= data_write2(47 downto 32); --data
         SD_UDM <= not byte_we_reg2(5);      --upper_byte_enable
         SD_LDM <= not byte_we_reg2(4);      --low_byte_enable
      else
         SD_UDQS <= 'Z';               --upper_data_strobe 
         SD_LDQS <= 'Z';               --low_data_strobe
         SD_DQ <= "ZZZZZZZZZZZZZZZZ";  --data
         SD_UDM <= 'Z';
         SD_LDM <= 'Z';
      end if;
 
      --DDR control signals
      SD_CK_P <= clk_p;                --clock_positive
      SD_CK_N <= not clk_p;            --clock_negative
      SD_CKE  <= cke_reg;              --clock_enable
 
      SD_BA   <= address(12 downto 11);  --bank_address
      if command = COMMAND_ACTIVE or state_current = STATE_POWER_ON then
         SD_A <= address(25 downto 13);  --address row
      elsif command = COMMAND_READ or command = COMMAND_WRITE then
         SD_A <= "000" & address(10 downto 2) & "0"; --address col
      else
         SD_A <= "0010000000000";      --PERCHARGE all banks
      end if;
 
      SD_CS   <= not cke_reg;          --chip_select
      SD_RAS  <= command(2);           --row_address_strobe
      SD_CAS  <= command(1);           --column_address_strobe
      SD_WE   <= command(0);           --write_enable
 
      if active = '1' and state_current /= STATE_POWER_ON and
         command /= COMMAND_WRITE and state_prev /= STATE_READ3 then
         pause <= '1';
      else
         pause <= '0';
      end if;
 
   end process; --ddr_proc
 
end; --architecture logic
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.