FC2カウンター FPGAの部屋 Spartan-6のMemory Contoller Block(MCB)の勉強1
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Spartan-6のMemory Contoller Block(MCB)の勉強1

Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”で、Memory Contoller Block(MCB)の勉強をすることにした。

まずは仕様を下に示す。”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”より引用。

1. DDR, DDR2, DDR3, and LPDDR (Mobile DDR)サポート
2. 800Mbps(400MHz DDR)までサポート
3. パッケージに最大4つのMCBが入っている。それぞれのMCBコアは以下の特徴がある。
 ・4、8、16ビット長の1つのメモリを制御する。
 ・メモリのサイズとしては4Gbitまで。
 ・最大12.8Gbit/secの性能。(800MHz X 16bit = 12,800Mbit/sec = 12.8Gbit/sec)
4. MCBはユーザーロジックからマルチポートのメモリ・コントローラとして使うことができる。
 ・1ポートから6ポートまで設定できる。
 ・データポートを32、64、128ビットのバス幅に設定できる。
 ・2つの両方向ポートと4つの片方向ポートがある。
5. 8個までのバンクを同時に開くことが出来る。(これは凄い、私の作ったコントローラは1つのバンクしか開かない、でもプリチャージは自分で管理するのかな?)
6. ハードマクロでコントローラ、PHYが内蔵されている。
7. それぞれのMCBで使用するピン配置は決定されている。(これも性能を取ったらそうなるだろう?)
8. メモリデバイスのパラメータは設定可能。
 ・ドライバのドライブ強度
 ・On-Die Termination(ODT)
 ・CAS Latency
 ・Self refresh
 ・リフレッシュ間隔
 ・Write recovery time
9. Readの時のDQSとDQの自動遅延キャリブレーション
10. FPGAon-chip input terminationのオプションの自動キャリブレーション
11. COER Generator とEDKでサポート
 ・MIGでサポート
 ・EDKからはマルチポートのメモリ・コントローラ(MPMC)IPとしてサポート


下に、”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”の11ページの Figure 1-1: Spartan-6 FPGA Memory Controller Block (IP Wrapper View) を引用する。
MCB_1_100420.png

上の図を見るとわかるように、6つのコマンドFIFOと6つの両方向または片方向のデータポートがある。アービタやコントローラ、データパス、PHY、キャリブレーションロジックなどがある。

DDRの最大データレートは400Mbits/sec、DDR2とDDR3は800Mbits/sec、LPDDRは400Mbis/sec。

メモリ・コントローラのアトリビュートとポートはVHDLのコンポーネントを見るとよくわかる。unisim_VCOMP.vhdのMCBのコンポーネント宣言を下に引用する。

component MCB
  generic (
     ARB_NUM_TIME_SLOTS : integer := 12;
     ARB_TIME_SLOT_0 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_1 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_10 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_11 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_2 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_3 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_4 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_5 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_6 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_7 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_8 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_9 : bit_vector := "111111111111111111";
     CAL_BA : bit_vector := X"0";
     CAL_BYPASS : string := "YES";
     CAL_CA : bit_vector := X"000";
     CAL_CALIBRATION_MODE : string := "NOCALIBRATION";
     CAL_CLK_DIV : integer := 1;
     CAL_DELAY : string := "QUARTER";
     CAL_RA : bit_vector := X"0000";
     MEM_ADDR_ORDER : string := "BANK_ROW_COLUMN";
     MEM_BA_SIZE : integer := 3;
     MEM_BURST_LEN : integer := 8;
     MEM_CAS_LATENCY : integer := 4;
     MEM_CA_SIZE : integer := 11;
     MEM_DDR1_2_ODS : string := "FULL";
     MEM_DDR2_3_HIGH_TEMP_SR : string := "NORMAL";
     MEM_DDR2_3_PA_SR : string := "FULL";
     MEM_DDR2_ADD_LATENCY : integer := 0;
     MEM_DDR2_DIFF_DQS_EN : string := "YES";
     MEM_DDR2_RTT : string := "50OHMS";
     MEM_DDR2_WRT_RECOVERY : integer := 4;
     MEM_DDR3_ADD_LATENCY : string := "OFF";
     MEM_DDR3_AUTO_SR : string := "ENABLED";
     MEM_DDR3_CAS_LATENCY : integer := 7;
     MEM_DDR3_CAS_WR_LATENCY : integer := 5;
     MEM_DDR3_DYN_WRT_ODT : string := "OFF";
     MEM_DDR3_ODS : string := "DIV7";
     MEM_DDR3_RTT : string := "DIV2";
     MEM_DDR3_WRT_RECOVERY : integer := 7;
     MEM_MDDR_ODS : string := "FULL";
     MEM_MOBILE_PA_SR : string := "FULL";
     MEM_MOBILE_TC_SR : integer := 0;
     MEM_RAS_VAL : integer := 0;
     MEM_RA_SIZE : integer := 13;
     MEM_RCD_VAL : integer := 1;
     MEM_REFI_VAL : integer := 0;
     MEM_RFC_VAL : integer := 0;
     MEM_RP_VAL : integer := 0;
     MEM_RTP_VAL : integer := 0;
     MEM_TYPE : string := "DDR3";
     MEM_WIDTH : integer := 4;
     MEM_WR_VAL : integer := 0;
     MEM_WTR_VAL : integer := 3;
     PORT_CONFIG : string := "B32_B32_B32_B32"
  );
  port (
     ADDR : out std_logic_vector(14 downto 0);
     BA : out std_logic_vector(2 downto 0);
     CAS : out std_ulogic;
     CKE : out std_ulogic;
     DQIOWEN0 : out std_ulogic;
     DQON : out std_logic_vector(15 downto 0);
     DQOP : out std_logic_vector(15 downto 0);
     DQSIOWEN90N : out std_ulogic;
     DQSIOWEN90P : out std_ulogic;
     IOIDRPADD : out std_ulogic;
     IOIDRPADDR : out std_logic_vector(4 downto 0);
     IOIDRPBROADCAST : out std_ulogic;
     IOIDRPCLK : out std_ulogic;
     IOIDRPCS : out std_ulogic;
     IOIDRPSDO : out std_ulogic;
     IOIDRPTRAIN : out std_ulogic;
     IOIDRPUPDATE : out std_ulogic;
     LDMN : out std_ulogic;
     LDMP : out std_ulogic;
     ODT : out std_ulogic;
     P0CMDEMPTY : out std_ulogic;
     P0CMDFULL : out std_ulogic;
     P0RDCOUNT : out std_logic_vector(6 downto 0);
     P0RDDATA : out std_logic_vector(31 downto 0);
     P0RDEMPTY : out std_ulogic;
     P0RDERROR : out std_ulogic;
     P0RDFULL : out std_ulogic;
     P0RDOVERFLOW : out std_ulogic;
     P0WRCOUNT : out std_logic_vector(6 downto 0);
     P0WREMPTY : out std_ulogic;
     P0WRERROR : out std_ulogic;
     P0WRFULL : out std_ulogic;
     P0WRUNDERRUN : out std_ulogic;
     P1CMDEMPTY : out std_ulogic;
     P1CMDFULL : out std_ulogic;
     P1RDCOUNT : out std_logic_vector(6 downto 0);
     P1RDDATA : out std_logic_vector(31 downto 0);
     P1RDEMPTY : out std_ulogic;
     P1RDERROR : out std_ulogic;
     P1RDFULL : out std_ulogic;
     P1RDOVERFLOW : out std_ulogic;
     P1WRCOUNT : out std_logic_vector(6 downto 0);
     P1WREMPTY : out std_ulogic;
     P1WRERROR : out std_ulogic;
     P1WRFULL : out std_ulogic;
     P1WRUNDERRUN : out std_ulogic;
     P2CMDEMPTY : out std_ulogic;
     P2CMDFULL : out std_ulogic;
     P2COUNT : out std_logic_vector(6 downto 0);
     P2EMPTY : out std_ulogic;
     P2ERROR : out std_ulogic;
     P2FULL : out std_ulogic;
     P2RDDATA : out std_logic_vector(31 downto 0);
     P2RDOVERFLOW : out std_ulogic;
     P2WRUNDERRUN : out std_ulogic;
     P3CMDEMPTY : out std_ulogic;
     P3CMDFULL : out std_ulogic;
     P3COUNT : out std_logic_vector(6 downto 0);
     P3EMPTY : out std_ulogic;
     P3ERROR : out std_ulogic;
     P3FULL : out std_ulogic;
     P3RDDATA : out std_logic_vector(31 downto 0);
     P3RDOVERFLOW : out std_ulogic;
     P3WRUNDERRUN : out std_ulogic;
     P4CMDEMPTY : out std_ulogic;
     P4CMDFULL : out std_ulogic;
     P4COUNT : out std_logic_vector(6 downto 0);
     P4EMPTY : out std_ulogic;
     P4ERROR : out std_ulogic;
     P4FULL : out std_ulogic;
     P4RDDATA : out std_logic_vector(31 downto 0);
     P4RDOVERFLOW : out std_ulogic;
     P4WRUNDERRUN : out std_ulogic;
     P5CMDEMPTY : out std_ulogic;
     P5CMDFULL : out std_ulogic;
     P5COUNT : out std_logic_vector(6 downto 0);
     P5EMPTY : out std_ulogic;
     P5ERROR : out std_ulogic;
     P5FULL : out std_ulogic;
     P5RDDATA : out std_logic_vector(31 downto 0);
     P5RDOVERFLOW : out std_ulogic;
     P5WRUNDERRUN : out std_ulogic;
     RAS : out std_ulogic;
     RST : out std_ulogic;
     SELFREFRESHMODE : out std_ulogic;
     STATUS : out std_logic_vector(31 downto 0);
     UDMN : out std_ulogic;
     UDMP : out std_ulogic;
     UOCALSTART : out std_ulogic;
     UOCMDREADYIN : out std_ulogic;
     UODATA : out std_logic_vector(7 downto 0);
     UODATAVALID : out std_ulogic;
     UODONECAL : out std_ulogic;
     UOREFRSHFLAG : out std_ulogic;
     UOSDO : out std_ulogic;
     WE : out std_ulogic;
     DQI : in std_logic_vector(15 downto 0);
     DQSIOIN : in std_ulogic;
     DQSIOIP : in std_ulogic;
     IOIDRPSDI : in std_ulogic;
     P0ARBEN : in std_ulogic;
     P0CMDBA : in std_logic_vector(2 downto 0);
     P0CMDBL : in std_logic_vector(5 downto 0);
     P0CMDCA : in std_logic_vector(11 downto 0);
     P0CMDCLK : in std_ulogic;
     P0CMDEN : in std_ulogic;
     P0CMDINSTR : in std_logic_vector(2 downto 0);
     P0CMDRA : in std_logic_vector(14 downto 0);
     P0RDCLK : in std_ulogic;
     P0RDEN : in std_ulogic;
     P0RWRMASK : in std_logic_vector(3 downto 0);
     P0WRCLK : in std_ulogic;
     P0WRDATA : in std_logic_vector(31 downto 0);
     P0WREN : in std_ulogic;
     P1ARBEN : in std_ulogic;
     P1CMDBA : in std_logic_vector(2 downto 0);
     P1CMDBL : in std_logic_vector(5 downto 0);
     P1CMDCA : in std_logic_vector(11 downto 0);
     P1CMDCLK : in std_ulogic;
     P1CMDEN : in std_ulogic;
     P1CMDINSTR : in std_logic_vector(2 downto 0);
     P1CMDRA : in std_logic_vector(14 downto 0);
     P1RDCLK : in std_ulogic;
     P1RDEN : in std_ulogic;
     P1RWRMASK : in std_logic_vector(3 downto 0);
     P1WRCLK : in std_ulogic;
     P1WRDATA : in std_logic_vector(31 downto 0);
     P1WREN : in std_ulogic;
     P2ARBEN : in std_ulogic;
     P2CLK : in std_ulogic;
     P2CMDBA : in std_logic_vector(2 downto 0);
     P2CMDBL : in std_logic_vector(5 downto 0);
     P2CMDCA : in std_logic_vector(11 downto 0);
     P2CMDCLK : in std_ulogic;
     P2CMDEN : in std_ulogic;
     P2CMDINSTR : in std_logic_vector(2 downto 0);
     P2CMDRA : in std_logic_vector(14 downto 0);
     P2EN : in std_ulogic;
     P2WRDATA : in std_logic_vector(31 downto 0);
     P2WRMASK : in std_logic_vector(3 downto 0);
     P3ARBEN : in std_ulogic;
     P3CLK : in std_ulogic;
     P3CMDBA : in std_logic_vector(2 downto 0);
     P3CMDBL : in std_logic_vector(5 downto 0);
     P3CMDCA : in std_logic_vector(11 downto 0);
     P3CMDCLK : in std_ulogic;
     P3CMDEN : in std_ulogic;
     P3CMDINSTR : in std_logic_vector(2 downto 0);
     P3CMDRA : in std_logic_vector(14 downto 0);
     P3EN : in std_ulogic;
     P3WRDATA : in std_logic_vector(31 downto 0);
     P3WRMASK : in std_logic_vector(3 downto 0);
     P4ARBEN : in std_ulogic;
     P4CLK : in std_ulogic;
     P4CMDBA : in std_logic_vector(2 downto 0);
     P4CMDBL : in std_logic_vector(5 downto 0);
     P4CMDCA : in std_logic_vector(11 downto 0);
     P4CMDCLK : in std_ulogic;
     P4CMDEN : in std_ulogic;
     P4CMDINSTR : in std_logic_vector(2 downto 0);
     P4CMDRA : in std_logic_vector(14 downto 0);
     P4EN : in std_ulogic;
     P4WRDATA : in std_logic_vector(31 downto 0);
     P4WRMASK : in std_logic_vector(3 downto 0);
     P5ARBEN : in std_ulogic;
     P5CLK : in std_ulogic;
     P5CMDBA : in std_logic_vector(2 downto 0);
     P5CMDBL : in std_logic_vector(5 downto 0);
     P5CMDCA : in std_logic_vector(11 downto 0);
     P5CMDCLK : in std_ulogic;
     P5CMDEN : in std_ulogic;
     P5CMDINSTR : in std_logic_vector(2 downto 0);
     P5CMDRA : in std_logic_vector(14 downto 0);
     P5EN : in std_ulogic;
     P5WRDATA : in std_logic_vector(31 downto 0);
     P5WRMASK : in std_logic_vector(3 downto 0);
     PLLCE : in std_logic_vector(1 downto 0);
     PLLCLK : in std_logic_vector(1 downto 0);
     PLLLOCK : in std_ulogic;
     RECAL : in std_ulogic;
     SELFREFRESHENTER : in std_ulogic;
     SYSRST : in std_ulogic;
     UDQSIOIN : in std_ulogic;
     UDQSIOIP : in std_ulogic;
     UIADD : in std_ulogic;
     UIADDR : in std_logic_vector(4 downto 0);
     UIBROADCAST : in std_ulogic;
     UICLK : in std_ulogic;
     UICMD : in std_ulogic;
     UICMDEN : in std_ulogic;
     UICMDIN : in std_ulogic;
     UICS : in std_ulogic;
     UIDONECAL : in std_ulogic;
     UIDQCOUNT : in std_logic_vector(3 downto 0);
     UIDQLOWERDEC : in std_ulogic;
     UIDQLOWERINC : in std_ulogic;
     UIDQUPPERDEC : in std_ulogic;
     UIDQUPPERINC : in std_ulogic;
     UIDRPUPDATE : in std_ulogic;
     UILDQSDEC : in std_ulogic;
     UILDQSINC : in std_ulogic;
     UIREAD : in std_ulogic;
     UISDI : in std_ulogic;
     UIUDQSDEC : in std_ulogic;
     UIUDQSINC : in std_ulogic
  );
end component;


とてもじゃないが、プリミティブで使う気になれない。。。(詳しい機能は”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”を参照のこと)やはりCORE GeneratorからMIGを起動して使うのが良いと思う。
上のコンポーネント宣言を見ると、独立したデータポート、コマンドポートが6つあるのがわかる。

MCBはコマンドを入れてRead, Write, Prechargeなどを行う。その辺の様子が、”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”47ページのInstructionsから下辺りに書いてある。

大体、MCBの概要はわかったので、SP605に対応するDDR3 SDRAMコントローラをMIGで生成してシミュレーションしてみたい。
  1. 2010年04月20日 05:26 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1440-51b628b8
この記事にトラックバックする(FC2ブログユーザー)