【Vivado】IP Catalogを使用したデュアルポートメモリの実装方法

Xilinxから用意されたIPは、IP Catalogを使用することで実装可能です。今回はデュアルポートメモリを実装して、シミュレーションで動作確認するところまでを試してみます。

IPの説明はXilinxのBlock Memory Generator v8.3 LogiCORE IP Product Guideを参考にしています。

Vivadoプロジェクト作成

今回のプロジェクト設定です。

項目 設定
Project Name
  Project name dpm_test
  Project location C:/fpga/dpm_test/2016.3
Project Type RTL Project
Add Sources デフォルト
Add Existing IP(optional) デフォルト
Add Constraints(optional) デフォルト
Default Part
  Select Boards
  Display Name Zybo

今回はシミュレーションまでしか行わないので、Partは上記の通りでなくても問題ないです。

IP CatalogでのデュアルポートメモリIP生成

Vivado起動後、”Flow Navigator”→”Project Manager”→”IP Catalog”を選択し、IP Catalogを起動。
Vivado IP Catalog

今回はBlock RAMを使用したデュアルポートメモリを使用したいので、”Memories & Storage Elements”→”RAMs & ROMs & BRAM”→”Block Memory Generator”を選択。
Vivado IP Catalog BRAM

“Custmize IP”ダイアログが表示されます。このダイアログからパラメータを設定して、自分の使用したいデュアルポートメモリを生成します。パラメータは色々なものがあるので、デフォルトから設定変更する箇所のみ説明します。

Basicタブ
項目 設定 説明
Component Name dpm_16x24 IP Entity名
Memory Type Simple Dual Port RAM Port AをWrite専用、Port BをRead専用
Common Clock チェック有 Port A,Bで共通クロック

IP Catalog BRAM Basic

Port A Optionsタブ
項目 設定 説明
Port A Width 24 Port Aデータビット幅
Port A Depth 65536 Port Aからアクセスする際のBRAMの深さ
Operating Mode Read First 同クロックで同アドレスへWrite/Readが行われた場合はライト前のデータを出力
Enable Port Type Always Enabled Port Aクロックイネーブル未使用

IP Catalog BRAM Port A Options

Port B Optionsタブ
項目 設定 説明
Port B Width 24 Port Bデータビット幅
Enable Port Type Always Enabled Port Bクロックイネーブル未使用

IP Catalog BRAM Port B Options

Other Optionsタブはデフォルトから未変更です。
IP Catalog BRAM Other Options

最後に設定概要が表示されるので、確認してOKをクリック。
IP Catalog BRAM Summary

そのあとに表示される”Generate Output Products”はそのまま”Generate”を押下。
IP Catalog Generate Output Products

最終的にVivadoプロジェクトでは下画像のような状態になります。
Vivado IP Catalog Hierarchy

シミュレーション動作確認

IP Catalogからデュアルポートメモリを生成できたので、シミュレーションで動作確認してみます。

テストベンチ

簡単な動作をするテストベンチを作成してみました。

  • リセット解除後、ライトアドレス/データをインクリメント
  • ライトイネーブルはリセット解除後常にアサート
  • ライトイネーブルをアサートして一定期間経過後、リードアドレスをインクリメント開始
  • 尚、コンポーネント宣言しているデュアルポートメモリ(dpm_16x24)は以下パスにvhdファイルが生成されています。
    C:\fpga\dpm_test\2016.3\dpm_test.srcs\sources_1\ip\dpm_16x24\synth\dpm_16x24.vhd

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all;
    
    entity testbench is
    end testbench;
    
    architecture rtl of testbench is
    
    component dpm_16x24 IS
      PORT (
        clka    : IN STD_LOGIC;
        wea     : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        addra   : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        dina    : IN STD_LOGIC_VECTOR(23 DOWNTO 0);
        clkb    : IN STD_LOGIC;
        addrb   : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        doutb   : OUT STD_LOGIC_VECTOR(23 DOWNTO 0)
      );
    END component;
    
    signal srstn_i      :   std_logic;
    signal clk_i        :   std_logic;
    signal inc          :   std_logic_vector (15 downto 0);
    signal wea          :   std_logic_vector (15 downto 0);
    signal addra        :   std_logic_vector (15 downto 0);
    signal dina         :   std_logic_vector (23 downto 0);
    signal addrb        :   std_logic_vector (15 downto 0);
    signal doutb        :   std_logic_vector (23 downto 0);
    
    begin
    
    process begin
        srstn_i <= '0';
        wait for 100 ns;
        wait until (rising_edge(clk_i));
        srstn_i <= '1';
        wait;
    end process;
    
    process begin
        clk_i   <= '0';
        wait for 5 ns;
        clk_i   <= '1';
        wait for 5 ns;
    end process;
    
    process (clk_i) begin
        if (rising_edge(clk_i)) then
            if (srstn_i = '0') then
                wea   <= (others => '0');
            else
                wea   <= wea(14 downto 0) & '1';
            end if;
        end if;
    end process;
    
    process (clk_i) begin
        if (rising_edge(clk_i)) then
            if (srstn_i = '0') then
                inc   <= (others => '0');
            else
                inc   <= inc + 1;
            end if;
        end if;
    end process;
    
    addra   <= inc;
    dina    <= (23 downto 16 => '0') & inc;
    
    process (clk_i) begin
        if (rising_edge(clk_i)) then
            if (srstn_i = '0') then
                addrb   <= (others => '0');
            else
                if (wea(15) = '1') then
                    addrb   <= addrb + 1;
                end if;
            end if;
        end if;
    end process;
    
    u_dpm   :   dpm_16x24
      PORT map  (
        clka    => clk_i,       --: IN STD_LOGIC;
        wea(0)  => wea(0),      --: IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        addra   => addra,       --: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        dina    => dina,        --: IN STD_LOGIC_VECTOR(23 DOWNTO 0);
        clkb    => clk_i,       --: IN STD_LOGIC;
        addrb   => addrb,       --: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        doutb   => doutb        --: OUT STD_LOGIC_VECTOR(23 DOWNTO 0)
      );
    
    end rtl;

    作成したテストベンチファイルをプロジェクトへ追加します。”Sources”ビューの”Hierarchy”タブを開き、”Simulation Sources”を右クリック後、”Add Sources”を選択。
    Vivado Simulation Sources Add

    “Add sources”ダイアログにて”Add or create simulation sources”を選択してNext。
    Add Sources simulation sources

    “Add Files”を選択するとファイル選択ダイアログが表示されるので、作成したテストベンチファイルを追加します。
    Add or Create Simulation Sources

    無事プロジェクトへファイルが追加されると、”Hierarchy”タブの”Simulation Sources”にテストベンチファイルが表示されます。
    Vivado Simulation Sources

    Vivadoシミュレータでの動作確認

    VivadoシミュレータはVivadoに標準搭載されたシミュレータです。今回は詳細な使い方は説明しません。

    “Flow Navigator”→”Simulation”→”Run Simulation”を選択するとシミュレータが起動します。特に問題なければ、設定時間(デフォルト1us)だけシミュレーションが自動実行されます。
    Vivado Simulation

    ちなみに何らかの問題が出ると次のようなダイアログ画面が表示されます。指示通り、Vivadoメイン画面下側に表示されている”Tcl Console”にて何が問題かを確認します。今回は、テストベンチに記述ミスがあったために表示されました。

    Vivado Critical Messages

    最後にシミュレーション結果です。期待通り、Port Aからライトしたデータが、一定期間後にPort Bからリード出来ていることが分かります。
    Vivado Simulation BRAM

    シェアする

    • このエントリーをはてなブックマークに追加

    フォローする