【Quartus FPGA】EMIF DDR3 IP 仿真记录

EMIF (External Memory Interface) 是 Quartus 平台提供的 IP,用于实现高速存储器件接口与控制器。通过 Intel Quartus Prime 软件,可以很方便地实现 EMIF IP 电路。本文记录了使用 EMIF 实现 DDR3 控制器的仿真过程,软件平台为 Quartus Prime Pro 21.3,器件型号为 10CX220YF780E6G.

目录

1 EMIF IP 介绍

2 EMIF DDR3 IP 配置

3 EMIF DDR3 IP 仿真


1 EMIF IP 介绍

 

       Intel EMIF IP 是 Quartus 平台提供的 IP,用于实现高速存储器件接口与存储控制器电路。借助 EMIF 电路,FPGA 可以与外部存储器件进行数据交换。 

        EMIF IP 实现物理层接口与存储控制器,这两部分的功能说明如下:

  • 物理层接口(Physical Layer Interface),用于建立数据通路,以及管理 FPGA 和存储器件的传输时序;
  • 存储控制器(Memory Controller),实现内存命令与协议层规范。

        EMIF IP 的总体设计流程如下图:

        EMIF IP 设计过程中涉及许多参数与配置步骤,IP 配置完成之后,可以生成参考工程,用于功能仿真,以检查参数配置是否有误。

2 EMIF DDR3 IP 配置

        新建工程,器件型号选择 10CX220YF780E6G。

 

        在 IP Catalog 中输入 memory,然后双击选择 External Memory Interfaces Intel Cyclone 10 FPGA IP。

        Memory Protocol 选 DDR3,时钟频率和 PLL 参考时钟频率根据需要配置,这里时钟频率填 933M,PLL 参考时钟频率为 116.625MHz.

 (PS:右下角 Presets 中有预设的选项,双击可以直接应用)

        容量为 1Gb 的 DDR3,行地址为 13bit,DQ width 根据实际器件类型填写。

        中间时序参数可以先跳过,最后有个仿真选项,选择 Skip Calibration,跳过校准阶段。

        IP 配置完成之后,点击 Generate Example Design,生成参考工程。

3 EMIF DDR3 IP 仿真

        在前面生成的参考工程中,仿真相关文件在 sim/ed_sim/mentor 和 sim/ed_sim/sim 路径下。修改 sim/ed_sim/sim 路径下的 ed_sim.v 文件,替换掉 ed_sim_tg 模块例化代码,就可以仿真自己编写的控制逻辑。

        仿照 ed_sim_tg 模块接口,编写 ed_sim_tg_0 模块,代码如下:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity ed_sim_tg_0 is
   generic(
      AMM_WRITE_PATTERN   : std_logic_vector := X"0102030405060708090A0B0C0D0E0F10";
      AMM_WRITE_INC       : std_logic_vector := X"01010101010101010101010101010101"
   );
   port(
      emif_usr_reset_n    : in std_logic;
      emif_usr_clk        : in std_logic; -- 233MHz
      local_cal_success   : in std_logic;
      amm_ready_0         : in std_logic;
      amm_read_0          : out std_logic;
      amm_write_0         : out std_logic;
      amm_address_0       : out std_logic_vector(28 downto 0);
      amm_readdata_0      : in std_logic_vector(127 downto 0);
      amm_writedata_0     : out std_logic_vector(127 downto 0);
      amm_burstcount_0    : out std_logic_vector(6 downto 0);
      amm_byteenable_0    : out std_logic_vector(15 downto 0);
      amm_readdatavalid_0 : in std_logic
   );
end entity;
architecture behav of ed_sim_tg_0 is
-- internal signal declarations
type state is (
   st_emif_init,
   st_amm_idle,
   st_amm_write,
   st_amm_read
);
signal pstate                  : state := st_emif_init;
signal buf_amm_read_0          : std_logic;
signal buf_amm_write_0         : std_logic;
signal cnt_amm_write_0         : std_logic_vector(7 downto 0);
signal buf_amm_address_0       : std_logic_vector(28 downto 0);
signal buf_amm_writedata_0     : std_logic_vector(127 downto 0);
signal buf_amm_burstcount_0    : std_logic_vector(6 downto 0);
signal buf_amm_byteenable_0    : std_logic_vector(15 downto 0);
signal cnt_amm_readdatavalid_0 : std_logic_vector(7 downto 0);
------------------------------------------------------
begin
------------------------------------------------------
amm_write_0      <= buf_amm_write_0;
amm_read_0       <= buf_amm_read_0;
amm_address_0    <= buf_amm_address_0;
amm_writedata_0  <= buf_amm_writedata_0;
amm_burstcount_0 <= buf_amm_burstcount_0;
amm_byteenable_0 <= buf_amm_byteenable_0;

process(emif_usr_reset_n,emif_usr_clk) 
begin
   if emif_usr_reset_n = '0' then
      pstate <= st_emif_init;
      buf_amm_write_0 <= '0';
      cnt_amm_write_0 <= (others => '0');
      buf_amm_read_0 <= '0';
      buf_amm_address_0 <= (others => '0');
      buf_amm_writedata_0 <= (others => '0');
      buf_amm_burstcount_0 <= (others => '0');
      buf_amm_byteenable_0 <= (others => '0');
      cnt_amm_readdatavalid_0 <= (others => '0');
   elsif rising_edge(emif_usr_clk) then
      case(pstate) is
         when st_emif_init => 
            if local_cal_success = '1' then
               pstate <= st_amm_idle;
            else
               pstate <= st_emif_init;
            end if;

         when st_amm_idle => 
            pstate <= st_amm_write;
            buf_amm_writedata_0 <= AMM_WRITE_PATTERN;
            buf_amm_address_0 <= buf_amm_address_0 + 1;

         when st_amm_write => 
            if cnt_amm_write_0 = 63 then
               cnt_amm_write_0 <= (others => '0');
               buf_amm_write_0 <= '0';
               buf_amm_byteenable_0 <= (others => '0');
               pstate <= st_amm_read;
               buf_amm_read_0 <= '1';
            else
               if buf_amm_write_0 = '1' and amm_ready_0 = '1' then
                  cnt_amm_write_0 <= cnt_amm_write_0 + 1;
                  buf_amm_writedata_0 <= buf_amm_writedata_0 + AMM_WRITE_INC;
               end if;
               buf_amm_write_0 <= '1';
               buf_amm_burstcount_0 <= conv_std_logic_vector(64,7);
               buf_amm_byteenable_0 <= (others => '1');
               pstate <= st_amm_write;
            end if;

         when st_amm_read => 
            if buf_amm_read_0 = '1' and amm_ready_0 = '1' then
               buf_amm_read_0 <= '0';
            end if;

            if cnt_amm_readdatavalid_0 = 64 then
               cnt_amm_readdatavalid_0 <= (others => '0');
               pstate <= st_amm_idle;
            else
               if amm_readdatavalid_0 = '1' then
                  cnt_amm_readdatavalid_0 <= cnt_amm_readdatavalid_0 + 1;
               end if;
               pstate <= st_amm_read;
            end if;

         when others => NULL;

      end case;
   end if;
end process;
end architecture;

        打开 Modelsim 读取 msim_setup.tcl 文件,编译 EMIF IP 文件与用户设计文件,并启动仿真。 

等待 emif_c10_0_status_local_cal_success 拉高,就可以进行 DDR3 数据读写操作了。

猜你喜欢

转载自blog.csdn.net/sxyang2018/article/details/131583656