zoukankan      html  css  js  c++  java
  • FPGA4U FPGA SDRAM Controller

    -- https://fpga4u.epfl.ch/wiki/FPGA4U_Description
    -- The SDRAM is an ISSI IS42S32800B. With 32 bits data bus, validated by SDRAM_DQM<3..0> signals, 
    -- one for each Byte of data bus SDRAM_DQ<31..0>. 
    -- This memory is a synchronous SDRAM, validating address and control signals with the rising edge of SDRAM_CLK, 
    -- while SDRAM_CKE activated ('1'). The organisation is 4 banks selected by SDRAM_BA<1..0>. 
    -- Each bank as 2^12 Row and 2^9 Column selected by SDRAM_AD<11.0>, with 32 bits words 
    -- (SDRAM_DQ<31..0> (2^2 * 2^12 * 2^9 = 4 * 2M x 32 = 8Mx32 = 32MBytes).
    -- In SOPC Builder, with the SDRAM Controller, select:
    -- 4 Banks
    -- 12 Rows addresses lines
    -- 9 Columns addresses lines
    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity fpga4u_sdram_controller is
        port(
            --Avalon slave interface (pipelined, variable latency)
            signal clk, reset : in std_logic;
            signal as_address : in std_logic_vector(22 downto 0);
            signal as_read, as_write : in std_logic;
            signal as_byteenable : in std_logic_vector(3 downto 0);
            signal as_readdata : out std_logic_vector(31 downto 0);
            signal as_writedata : in std_logic_vector(31 downto 0);
            signal as_waitrequest : out std_logic;
            signal as_readdatavalid : out std_logic;
    
            --SDRAM interface to FPGA4U SDRAM
            signal ram_addr : out std_logic_vector(11 downto 0);
            signal ram_ba : out std_logic_vector(1 downto 0);
            signal ram_cas_n : out std_logic;
            signal ram_cke : out std_logic;
            signal ram_cs_n : out std_logic;
            signal ram_dq : inout std_logic_vector(31 downto 0);
            signal ram_dqm : out std_logic_vector(3 downto 0);
            signal ram_ras_n : out std_logic;
            signal ram_we_n : out std_logic
        );
    end entity;
    
    architecture arch of fpga4u_sdram_controller is
        --Initialisation signals
        type init_state_t is (init_reset, init_pre, init_wait_pre, init_ref, init_wait_ref, init_mode, init_wait_mode, init_done);
        signal init_state : init_state_t := init_reset;
        signal init_wait_counter : unsigned(15 downto 0);
        signal init_ref_counter : unsigned(3 downto 0);
    
        --Main state machine
        type state_t is (idle, ref, wait_ref, act, wait_act, read, spin_read, write, spin_write, precharge_all, wait_precharge);
        signal state : state_t := idle;
        signal ref_counter : unsigned(10 downto 0);
        signal ref_req : std_logic;
        signal wait_counter : unsigned(2 downto 0);
    
        --Active transaction signals
        signal int_address : std_logic_vector(22 downto 0);
        signal int_readdata : std_logic_vector(31 downto 0);
        signal int_writedata : std_logic_vector(31 downto 0);
        signal int_byteenable : std_logic_vector(3 downto 0);
        signal int_writeop : std_logic;
    
        --open bank and row
        signal open_bank : std_logic_vector(1 downto 0);
        signal open_row : std_logic_vector(11 downto 0);
    
        --readdata ready pipeline
        signal readdata_ready : std_logic_vector(4 downto 0);
    
        signal ram_cmd : std_logic_vector(3 downto 0);
    begin
        --State machine to handle SDRAM initialization
        INITSTATE : process(clk, reset)
        begin
            if reset = '1' then
                init_state <= init_reset;
                --power up delay
                init_wait_counter <= to_unsigned(24000,init_wait_counter'length);
                --number refresh cycles before mode register write
                init_ref_counter <= to_unsigned(2,init_ref_counter'length);
            elsif rising_edge(clk) then
                --count down when not 0
                if init_wait_counter /= 0 then
                    init_wait_counter <= init_wait_counter - 1;
                end if;
                case init_state is
                    when init_reset =>
                        if init_wait_counter = 0 then
                            init_state <= init_pre;
                        end if;
                    --do a precharge
                    when init_pre =>
                        init_wait_counter <= to_unsigned(3,init_wait_counter'length);
                        init_state <= init_wait_pre;
                    when init_wait_pre =>
                        if init_wait_counter = 0 then
                            init_state <= init_ref;
                        end if;
                    --do a refresh
                    when init_ref =>
                        init_wait_counter <= to_unsigned(8,init_wait_counter'length);
                        init_ref_counter <= init_ref_counter - 1;
                        init_state <= init_wait_ref;
                    when init_wait_ref =>
                        if init_wait_counter = 0 then
                            if init_ref_counter = 0 then
                                init_state <= init_mode;
                            else
                                init_state <= init_ref;
                            end if;
                        end if;
                    --set the mode register
                    when init_mode =>
                        init_wait_counter <= to_unsigned(2,init_wait_counter'length);
                        init_state <= init_wait_mode;
                    when init_wait_mode =>
                        if init_wait_counter = 0 then
                            init_state <= init_done;
                        end if;
                    when others =>
                        null;
                end case;
            end if;
        end process;
    
        --Asynchronous waitrequest to allow one transfer per cycle (critical path)
        as_waitrequest <= '0' when (state = idle and ref_req = '0' and (as_read = '1' or as_write = '1'))
            or ((state = read or state = spin_read) and ref_req = '0' and as_read = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank)
            or ((state = write or state = spin_write) and ref_req = '0' and as_write = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank)
            else '1';
    
        --Main state machine
        make_state : process(clk, reset)
        begin
            if reset = '1' then
                state <= idle;
                ref_counter <= (others=>'0');
                ref_req <= '1'; --begin with a refresh
                wait_counter <= (others=>'0');
                readdata_ready <= (others=>'0');
            elsif rising_edge(clk) then
                --counters for delays and refresh generation
                if wait_counter /= 0 then
                    wait_counter <= wait_counter - 1;
                end if;
                if ref_counter /= 0 then
                    ref_counter <= ref_counter - 1;
                else
                    ref_req <= '1';
                    ref_counter <= to_unsigned(1800,ref_counter'length);
                end if;
                --main state machine runs when the initialization is done
                if init_state = init_done then
                    case state is
                        when idle =>
                            if ref_req = '1' then --go do a refresh
                                ref_req <= '0';
                                state <= ref;
                            elsif as_write = '1' or as_read = '1' then --accept the request and go to open the row
                                int_address <= as_address;
                                int_writedata <= as_writedata;
                                int_byteenable <= as_byteenable;
                                int_writeop <= as_write;
                                state <= act;
                            end if;
                        when ref =>
                            wait_counter <= to_unsigned(5,wait_counter'length);
                            state <= wait_ref;
                        when wait_ref =>
                            if wait_counter = 0 then
                                state <= idle;
                            end if;
                        when act => --save the open bank and row
                            open_bank <= int_address(10 downto 9);
                            open_row <= int_address(22 downto 11);
                            wait_counter <= to_unsigned(1,wait_counter'length);
                            state <= wait_act;
                        when wait_act =>
                            if wait_counter = 0 then
                                if int_writeop = '0' then
                                    state <= read;
                                else
                                    state <= write;
                                end if;
                            end if;
                        when read => --issue a read command, feed a one in the readdata_ready pipeline, when it exits data is ready for the master
                            as_readdata <= int_readdata;
                            as_readdatavalid <= readdata_ready(4);
                            readdata_ready <= readdata_ready(3 downto 0)&'1';
                            if ref_req = '0' and as_read = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
                                int_address <= as_address;
                                state <= read;
                            else
                                state <= spin_read;
                            end if;
                        when spin_read => --wait for reads to complete and eventually issue more compatible reads
                            as_readdata <= int_readdata;
                            as_readdatavalid <= readdata_ready(4);
                            readdata_ready <= readdata_ready(3 downto 0)&'0';
                            if readdata_ready = "00000" and (ref_req = '1' or as_write = '1') then
                                state <= precharge_all;
                            elsif ref_req = '0' and as_read = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
                                int_address <= as_address;
                                state <= read;
                            elsif readdata_ready = "00000" and as_read = '1' then
                                state <= precharge_all;
                            end if;
                        when write => --the same as read, except there is no pipeline as data is presented to the SDRAM on the same cycle as the command
                            wait_counter <= to_unsigned(1,wait_counter'length);
                            if ref_req = '0' and as_write = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
                                int_address <= as_address;
                                int_writedata <= as_writedata;
                                int_byteenable <= as_byteenable;
                                state <= write;
                            else
                                state <= spin_write;
                            end if;
                        when spin_write => --same as for read
                            if wait_counter = 0 and (ref_req = '1' or as_read = '1') then
                                state <= precharge_all;
                            elsif ref_req = '0' and as_write = '1' and as_address(22 downto 11) = open_row and as_address(10 downto 9) = open_bank then
                                int_address <= as_address;
                                int_writedata <= as_writedata;
                                int_byteenable <= as_byteenable;
                                state <= write;
                            elsif wait_counter = 0 and as_write = '1' then
                                state <= precharge_all;
                            end if;
                        when precharge_all =>
                            state <= wait_precharge;
                        when wait_precharge =>
                            state <= idle;
                        when others=>
                            null;
                    end case;
                end if;
            end if;
        end process;
    
        --data from the ram needs to be sampled on the falling edge of the controller clock for proper operation
        process(clk)
        begin
            if falling_edge(clk) then
                int_readdata <= ram_dq;
            end if;
        end process;
    
        --process generating the command sequence for the SDRAM
        ram_cke <= '1';
        ram_cs_n <= ram_cmd(3);
        ram_ras_n <= ram_cmd(2);
        ram_cas_n <= ram_cmd(1);
        ram_we_n <= ram_cmd(0);
        OUTPUTS : process(clk, reset)
        begin
            if reset = '1' then
                ram_addr <= (others=>'0');
                ram_cmd <= "1111";
                ram_ba <= (others=>'0');
                ram_dq <= (others=>'Z');
                ram_dqm <= (others=>'1');
            elsif rising_edge(clk) then
                if init_state = init_pre then
                    ram_cmd <= "0010"; --precharge
                    ram_addr <= (10=>'1', others=>'0');
                elsif init_state = init_ref then
                    ram_cmd <= "0001"; --refresh
                elsif init_state = init_mode then
                    ram_cmd <= "0000"; --mode set
                    ram_addr <= "000000110000"; --no burst, three cycles latency
                elsif init_state = init_done then
                    if state = ref then
                        ram_cmd <= "0001"; --refresh
                    elsif state = act then
                        ram_cmd <= "0011"; --activate
                        ram_addr <= int_address(22 downto 11);
                        ram_ba <= int_address(10 downto 9);
                    elsif state = read then
                        ram_cmd <= "0101"; --read
                        ram_addr <= "000"&int_address(8 downto 0);
                        ram_dqm <= "0000";
                    elsif state = write then
                        ram_cmd <= "0100"; --write
                        ram_addr <= "000"&int_address(8 downto 0);
                        ram_dq <= int_writedata;
                        ram_dqm <= not int_byteenable;
                    elsif state = precharge_all then
                        ram_cmd <= "0010"; --precharge
                        ram_addr <= "010"&int_address(8 downto 0);
                        ram_dqm <= "1111";
                    else
                        ram_cmd <= "1111"; --nop
                        ram_dq <= (others=>'Z');
                    end if;
                else
                    ram_cmd <= "1111"; --nop
                end if;
            end if;
        end process;
    end arch;
  • 相关阅读:
    Document
    Echarts 图例交互事件,及使用
    Echarts 入门之基础使用(部份 API)
    对比 continue、break 在循环中的作用
    Markdown 简要语法速成
    CSS 实现必填项前/后添加红色*、√、X、▲
    9.React Context 上下文
    [leetcode sort]179. Largest Number
    [leetcode tree]102. Binary Tree Level Order Traversal
    [leetcode tree]101. Symmetric Tree
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4934967.html
Copyright © 2011-2022 走看看