DDR3の使い方
Artix-7でDDR3メモリを使うには、ISEに内蔵されたCoreGeneratorを使ってIPコアを生成します(MIGという)。ISEのバージョンは14.5または14.7を使用してください。
Spartan-6のときのDDR3 IPコア
Spartan-6のDDR3メモリコアは、下の図のように、MCBというハードウェアブロックで行っていました。MCBは複数のユーザポートを持っていて、それぞれのユーザポートは独立して動きました。MCBのユーザ側ポートはFIFOベースの単純なものだったので、センサから取り込んだデータをUSBに転送したりCPU(MicroBlaze等)で扱う設計が比較的楽にできました。
Artix-7のDDR3 IPコア
しかし、Artix-7のDDR3メモリコア(MIG)はユーザ側ポート1ポートしかありません。DDR3メモリをUSBから操作するようなアプリを作ったら、それだけで終わってしまいます。センサをつなぐところがもうないのです。
だから、複数のポートに拡張しなければなりませんが、ソフトコアにはクロックドメインが1つか用意されていないので簡単ではありません。
そこで、Artix-7のソフトコアをAXIバス形式で生成し、AXIインターコネクトを使って拡張するのが一番簡単です。
つまり、USBのコアも、センサ(お客様回路)も、すべてAXIバスに準拠して作り、XILINXのCoreGeneratorを使ってAXI ICとソフトコアを生成してつなげる、という形になります。
プロジェクトの設定はVerilog
CoreGeneratorを使ったAXI版のDDR3コアはVerilogで生成されます。したがって、ISEプロジェクトをVerilogにしておく必要があります。
VHDLで使うにはラッパを通す
当社はVHDL派なので、CoreGenの作ったVerilog版AXI-DDR3コアをVHDLでラップして使っています。直接インスタンシエートするのではなく、いったん、ラッパを通してから使います。
component axi_ddr3_wrap is port ( ddr3_dq : inout STD_LOGIC_VECTOR(7 downto 0); ddr3_dqs_n : inout STD_LOGIC_VECTOR(0 downto 0); ddr3_dqs_p : inout STD_LOGIC_VECTOR(0 downto 0); -- Outputs ddr3_addr : out STD_LOGIC_VECTOR(14 downto 0); ddr3_ba : out STD_LOGIC_VECTOR(2 downto 0); ddr3_ras_n : out STD_LOGIC; ddr3_cas_n : out STD_LOGIC; ddr3_we_n : out STD_LOGIC; ddr3_cs_n : out STD_LOGIC_VECTOR(0 downto 0); ddr3_reset_n : out STD_LOGIC; ddr3_ck_p : out STD_LOGIC_VECTOR(0 downto 0); ddr3_ck_n : out STD_LOGIC_VECTOR(0 downto 0); ddr3_cke : out STD_LOGIC_VECTOR(0 downto 0); ddr3_dm : out STD_LOGIC_VECTOR(0 downto 0); ddr3_odt : out STD_LOGIC_VECTOR(0 downto 0); -- Inputs -- Single-ended system clock sys_clk_i : in STD_LOGIC; clk_ref_i : in STD_LOGIC; ui_clk : out STD_LOGIC; ui_clk_sync_rst : out STD_LOGIC; mmcm_locked : out STD_LOGIC; aresetn : in STD_LOGIC; app_sr_req : in STD_LOGIC; app_sr_active : out STD_LOGIC; app_ref_req : in STD_LOGIC; app_ref_ack : out STD_LOGIC; app_zq_req : in STD_LOGIC; app_zq_ack : out STD_LOGIC; -- Slave Interface Write Address Ports s_axi_awid : in STD_LOGIC_VECTOR(3 downto 0); s_axi_awaddr : in STD_LOGIC_VECTOR(31 downto 0); s_axi_awlen : in STD_LOGIC_VECTOR(7 downto 0); s_axi_awsize : in STD_LOGIC_VECTOR(2 downto 0); s_axi_awburst : in STD_LOGIC_VECTOR(1 downto 0); s_axi_awlock : in STD_LOGIC_VECTOR(0 downto 0); s_axi_awcache : in STD_LOGIC_VECTOR(3 downto 0); s_axi_awprot : in STD_LOGIC_VECTOR(2 downto 0); s_axi_awqos : in STD_LOGIC_VECTOR(3 downto 0); s_axi_awvalid : in STD_LOGIC; s_axi_awready : out STD_LOGIC; -- Slave Interface Write Data Ports s_axi_wdata : in STD_LOGIC_VECTOR(63 downto 0); s_axi_wstrb : in STD_LOGIC_VECTOR(7 downto 0); s_axi_wlast : in STD_LOGIC; s_axi_wvalid : in STD_LOGIC; s_axi_wready : out STD_LOGIC; -- Slave Interface Write Response Ports s_axi_bready : in STD_LOGIC; s_axi_bid : out STD_LOGIC_VECTOR(3 downto 0); s_axi_bresp : out STD_LOGIC_VECTOR(1 downto 0); s_axi_bvalid : out STD_LOGIC; -- Slave Interface Read Address Ports s_axi_arid : in STD_LOGIC_VECTOR(3 downto 0); s_axi_araddr : in STD_LOGIC_VECTOR(31 downto 0); s_axi_arlen : in STD_LOGIC_VECTOR(7 downto 0); s_axi_arsize : in STD_LOGIC_VECTOR(2 downto 0); s_axi_arburst : in STD_LOGIC_VECTOR(1 downto 0); s_axi_arlock : in STD_LOGIC_VECTOR(0 downto 0); s_axi_arcache : in STD_LOGIC_VECTOR(3 downto 0); s_axi_arprot : in STD_LOGIC_VECTOR(2 downto 0); s_axi_arqos : in STD_LOGIC_VECTOR(3 downto 0); s_axi_arvalid : in STD_LOGIC; s_axi_arready : out STD_LOGIC; -- Slave Interface Read Data Ports s_axi_rready : in STD_LOGIC; s_axi_rid : out STD_LOGIC_VECTOR(3 downto 0); s_axi_rdata : out STD_LOGIC_VECTOR(63 downto 0); s_axi_rresp : out STD_LOGIC_VECTOR(1 downto 0); s_axi_rlast : out STD_LOGIC; s_axi_rvalid : out STD_LOGIC; init_calib_complete : out STD_LOGIC; -- System reset - Default polarity of sys_rst pin is Active Low. -- System reset polarity will change based on the option -- selected in GUI. sys_rst : in std_logic ); end component;
まとめると、DDR3メモリを使うための基本は、
- CoreGenを使ってDDR3メモリコアを生成する
- AXIバスとして作る
- ラッパを通す
使うには、CoreGenの知識と、AXIバスの知識が必要になります。