FC2カウンター FPGAの部屋 Core Generator

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

FPGAの部屋

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

COEファイルのフォーマット

Core Generatorで生成したROMやRAMなどに初期値を入れるときは、COEファイルを生成する。
Block Memory Generaotrだったら、Page 4 of 6のMemory InitalizationのLoad Init Fileにチェックを入れて、Coe Fileを指定する。
COE_File_1_111221.png

COEファイルのフォーマットは”COE ファイルの構文”に書かれている。下に、私が使用している一部のフォーマットを引用する。

; Sample memory initialization file for Single Port Block Memory,
; v3.0 or later.
;
; This .COE file specifies initialization values for a block
; memory of depth=16, and width=8. In this case, values are
; specified in hexadecimal format.
memory_initialization_radix=16;
memory_initialization_vector=
ff,
ab,
f0,
11,
11,
00,
01,
aa,
bb,
cc,
dd,
ef,
ee,
ff,
00,
ff;


これは、memory_initialization_radix=16;で16進数に指定されている。
最後のデータは;で終了する。
間のデータのff, はff でも問題ないようだ。
  1. 2011年12月21日 14:22 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:0

FWFTモードのBlock RAM使用した非同期FIFOのrd_data_countについて

Block RAMを使用した非同期FIFOのrd_data_countについては、信用しないほうが良いようです。基本的には、emptyとalmost_emptyを使用するか、もしくは、rd_data_countとempty, almost_emptyを組み合わせたほうが良いと感じました。

非同期FIFOは、FIFO Generator 8.1で生成されていて、Write Width:32, Write Depth:71, Read Width:128, Write Depth:17の幅の違うFIFOです。RD_DATA_COUNT、empty, almost_emptyを出力させています。
FWFT_AFIFO_1_110715.png

Verilogファイルでのインスタンスを下に示します。

    assign cam_rgb_data = {{8{1'b0}}, cam_red, cam_green, cam_blue};
    // MIGとの接続用非同期FIFO
    cam2mig_fifo cam2mig_afifo_inst (
        .wr_clk(clk_cam),    // input wr_clk
        .wr_rst(reset_cam | ~frame_valid_1d),     // input wr_rst
        .rd_clk(clk_ddr2),     // input rd_clk
        .rd_rst(reset_ddr2 | ~frame_v_1d_ddr2_2),     // input rd_rst
        .din(cam_rgb_data),            // input [31 : 0] din
        .wr_en(cam_data_ena & capt_ena),         // input wr_en
        .rd_en(data_enable),         // input rd_en
        .dout(data_out),         // output [127 : 0] dout
        .full(cmfifo_full),         // output full
        .almost_full(cmfifo_almost_full), // output almost_full
        .overflow(cmfifo_overflow), // output overflow
        .empty(cmfifo_empty),         // output empty
        .almost_empty(cmfifo_almost_empty), // output almost_empty
        .underflow(cmfifo_underflow), // output underflow
        .rd_data_count(cmfifo_rd_data_count) // output [3 : 0] rd_data_count
    );


cmfifo_rd_data_countが2以上だったらcam2mig_fifo から2個ずつデータを読んでいます。
全体で1回分、つまり2このデータが少ないようなのです。なぜなんだろう?と思って調べていましたが、原因がわかりました。
下がcam2mig_fifoのシミュレーション波形です。
FWFT_AFIFO_2_110715.png

黄色の点線のカーソルのところで、cmfifo_rd_data_countが1になって、すぐに黄色の実線のカーソルで0に戻っています。黄色の実線で、cmfifo_emptyが0に落ちています。つまり、rd_data_countは、FWFTモードFIFO内部のFIFOモジュールのrd_data_countで、FIFO全体のrd_data_countと思って使用するのは危険なんじゃないかな?と思います。
次に、上のシミュレーション波形の次を下に示します。
FWFT_AFIFO_3_110715.png

cmfifo_almost_emptyでも同様の動作になって、その次の時にrd_data_countが1になりました。これでは、rd_data_countの値を見て制御していると、2個データが残ってしまうことになります。

emptyとalmost_emptyを見て制御するように変更しようと思います。
これからは、少なくともFWFTモードのBlock RAM使用した非同期FIFOのrd_data_countは、必ずしも正しくないと考えて制御回路を作る必要がありそうです。

(2011/07/19追記)
コメントでieee1394さんに教えていただいたのですが、非同期FIFOでFWFTモードの場合は、Use Extra Logic For More Accurate Data Countsのチェックボックスにチェックを入れる必要があるそうです。
FWFT_AFIFO_4_110719.png

これで、FIFOのIPを再生成して、シミュレーションしてみました。
FWFT_AFIFO_5_110719.png

確かに、emptyやalmost_emptyに関連して変化するようになったのですが、振動しているところがあります。黄色の点線のカーソルの辺りをズームしてみました。
FWFT_AFIFO_6_110719.png

emptyやalmost_emptyから1クロック遅延していることがわかりました。やはり、emptyやalmost_emptyで制御したほうが良さそうです。
  1. 2011年07月15日 17:32 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:2

Coregenで作成したFIFOのバグ

ここ2日ほど、Coregenで作成したFIFOのバグで悩んだので、その顛末を書いておく。
結論から先に書くと、Project Navigator のプロジェクトを作り直したら正常になった。

使用したFPGAは、Spartan-3E xc3s500e-4pq208、ISE12.4とISE13.1を使用して、どっちも同じ状況だった。
いつものように、プロジェクトが入ったフォルダをコピーして、改変を開始した(最初はISE12.4)。今回は、方式を大幅に変更した。以前のゴミが残るが、とりあえず無視して非同期FIFOや同期FIFOを追加して、追加した。(ちなみに、そのフォルダの下にソースファイル用、シミュレーション用、インプリメント用(各ISEのバージョンごと)にフォルダを分けています)
全体をインプリメントすると、SLICEMがオーバーしてしまった。そんなはずは無いのだが?cam_afifoは、34ビット幅で16深度なので、こんなに使うはずはない?
Coregen_1_110303.png

とりあえず、cam_afifoを分散RAMからBlockRAMにしても、BlockRAMが使われずにSLICEMがオーバーしてしまう。Camera_Controller.vhdをトップにしてやってもオーバー。
Coregen_2_110303.png

どうも、分散RAMで深度1Kワード程度で固定されて、Coregen を起動してパラメータを変更しても、変更されない気がする。
そのうちにISE13.1が出たので、インプリメント用のフォルダだけコピーして、ISE13.1にプロジェクトを変換してやってみたが、同じ状況だった。ここからISE13.1で作業を継続した。

1.インプリメントフォルダの下のipcore_dirフォルダの下のcam_afifo関連のファイルをすべて削除して、FIFO IPを新規作成してみたが、やはりダメ。
2.Project Navigator のProjectメニューからCleanup Project Files...でプロジェクトファイルを消してみてもダメだった。

最後に、プロジェクトを新規作成して、FIFO IPを新規作成したら、問題なくなった。下にそのISE13.1のProject Navigator の画面を示す。
Coregen_3_110303.png

使用しているLUTが116で正常に戻った。

Coregen で生成したIPがおかしい時は、素直にプロジェクトを作り直した方が良さそうだ。
  1. 2011年03月03日 12:30 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:4

FIFOをISimで論理シミュレーションしたときの不具合(Fifo Generator 7.2を使用)

SRAMのコントローラを作成していて、Read/WriteをバーストでアクセスするためにRead用、Write用それぞれのFIFOをFifo Generator 7.2を使って作成した。そのSRAMコントローラをISE12.4のISimでシミュレーションしているときに、おかしな動作になってしまった。FIFOの仕様は、分散RAM仕様のFWFT FIFOで、深度が16(18)、ビット幅が16(Read用)、34(Write用)、DATA_COUNT、almost_full, almost_empty付きだ。

どのようにおかしいかというと、下のISimのシミュレーション図で、まずはwr_fifoの方を見ていく。wr_fifo_emptyだが、wr_fifo_rd_enが'1'になったと同時に'1'になっている(ピンクの四角)。これは、水色の四角で示すwr_fifo_rd_enが'1'から'0'になるclk(見えていないが。。。)の立ち上がりまで'1'になる必要がある。しかも、wr_fifo_countも01のままで00にならない。
rd_fifo_emptyも黄色い四角で示す位置で'1'になるはずがならない。。。
FIFOG_1_110120.png

FIFO付近のVHDLコードを下に示す。

    -- Write Data Path
    wr_fifo_din <= wr_address & wr_data;
    wr_fifo_rd_en_node <= wr_fifo_rd_en;
    wr_fifo_inst : write_fifo port map(
        clk => clk,
        srst => reset,
        din => wr_fifo_din,
        wr_en => wr_enable,
        rd_en => wr_fifo_rd_en,
        dout => wr_fifo_dout,
        full => open,
        almost_full => wr_fifo_full,
        empty => wr_fifo_empty,
        almost_empty => wr_fifo_almost_empty,
        data_count => wr_fifo_count
    );
    
    
    -- Read Data Path
    rd_fifo_rd_en_node <= rd_fifo_rd_en;
    rd_fifo_inst : read_fifo port map(
        clk => clk,
        srst => reset,
        din => rd_address,
        wr_en => rd_enable,
        rd_en => rd_fifo_rd_en,
        dout => rd_fifo_dout,
        full => open,
        almost_full => rd_fifo_full,
        empty => rd_fifo_empty,
        almost_empty => rd_fifo_almost_empty,
        data_count => rd_fifo_count
    );
    
    -- SRAMのRead, Write 用ステートマシン(Read優先)
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_SRAM_RW <= SRAM_RW_STATE'(idle);
                wr_fifo_rd_en <= '0';
                rd_fifo_rd_en <= '0';
            else
                case cs_SRAM_RW is
                    when SRAM_RW_STATE'(idle) =>
                        if rd_fifo_empty='0' then
                            cs_SRAM_RW <= READ_STATE;
                            rd_fifo_rd_en <= '1';
                        elsif wr_fifo_empty='0' then
                            cs_SRAM_RW <= WRITE_STATE1;
                        end if;
                    when READ_STATE =>
                        if rd_fifo_almost_empty='0' then -- まだRead用FIFOに残っている
                            cs_SRAM_RW <= READ_STATE;
                        else
                            cs_SRAM_RW <= SRAM_RW_STATE'(idle);
                            rd_fifo_rd_en <= '0';
                        end if;
                    when WRITE_STATE1 =>
                        cs_SRAM_RW <= WRITE_STATE2;
                        wr_fifo_rd_en <= '1';
                    when WRITE_STATE2 =>
                        wr_fifo_rd_en <= '0';
                        if rd_fifo_empty='0' then -- Read優先, ReadとWriteの間は1クロック間を空ける。
                            cs_SRAM_RW <= SRAM_RW_STATE'(idle);
                        elsif wr_fifo_almost_empty='0' then -- まだWrite用FIFOに残っている
                            cs_SRAM_RW <= WRITE_STATE1;
                        else
                            cs_SRAM_RW <= SRAM_RW_STATE'(idle);
                        end if;
                end case;
            end if;
        end if;
    end process;



これは、どうやらデルタ遅延のいたずらのようだ。
2つのFIFOのrd_enを1つノードを通して入れると正常な動作になった。
FIFOG_2_110120.png
(注)上のVHDLコードにはバグがあったので、修正してあります。

FIFO付近のコードを以下に示す。

    -- Write Data Path
    wr_fifo_din <= wr_address & wr_data;
    wr_fifo_rd_en_node <= wr_fifo_rd_en;
    wr_fifo_inst : write_fifo port map(
        clk => clk,
        srst => reset,
        din => wr_fifo_din,
        wr_en => wr_enable,
        rd_en => wr_fifo_rd_en_node,
        dout => wr_fifo_dout,
        full => open,
        almost_full => wr_fifo_full,
        empty => wr_fifo_empty,
        almost_empty => wr_fifo_almost_empty,
        data_count => wr_fifo_count
    );    
    
    -- Read Data Path
    rd_fifo_rd_en_node <= rd_fifo_rd_en;
    rd_fifo_inst : read_fifo port map(
        clk => clk,
        srst => reset,
        din => rd_address,
        wr_en => rd_enable,
        rd_en => rd_fifo_rd_en_node,
        dout => rd_fifo_dout,
        full => open,
        almost_full => rd_fifo_full,
        empty => rd_fifo_empty,
        almost_empty => rd_fifo_almost_empty,
        data_count => rd_fifo_count
    );


2つのFIFOのrd_en に1つノードを追加した。これで正常にシミュレーションすることができた。

clkはポートから直結なんだけど?FIFO Generator のクロックのパスが長いのだろうか?いずれにせよ。これでだいぶ時間をつぶしてしまった。。IPの中なので、自分では注意できない。よって、おかしいことがあったら、まずはデルタ遅延を疑おうと思った。
  1. 2011年01月20日 12:16 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:0

Divider Generator を使ってみた

割り算器が必要になったので、ISE12.2のCore GeneratorのDivider Generator を使って割り算コアを生成してみた。
ProjectメニューのNew Source..からIP(CORE Generator & Architecture Wizard) を選択し、File Name:をdivider_perとして、割り算器を生成する。下が、Divider Generator の設定。
divider_IP_1_101001.png

Dividend and Quotient Widthが23ビット、Divisor Widthが15ビットだ。Remainder TypeはRemainderで、Clocks per Divisonは1にしてある。Operand SignはUnsigned で、Control SignalsはCE を追加してある。
このパラメータで割り算器を生成した。これだけではインプリメントとシミュレーションができないので、トップファイルとテストベンチを追加した。
まずは、トップファイルのDivider_test.vhd から下に示す。

-- Divider Test(Divider_test.vhd)

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

entity Divider_test is
    port (
        clk: IN std_logic;
        ce: IN std_logic;
        rfd: OUT std_logic;
        dividend: IN std_logic_VECTOR(22 downto 0);
        quotient: OUT std_logic_VECTOR(22 downto 0);
        fractional: OUT std_logic_VECTOR(14 downto 0)
    );
end Divider_test;

architecture RTL of Divider_test is
component divider_per
    port (
    clk: IN std_logic;
    ce: IN std_logic;
    rfd: OUT std_logic;
    dividend: IN std_logic_VECTOR(22 downto 0);
    divisor: IN std_logic_VECTOR(14 downto 0);
    quotient: OUT std_logic_VECTOR(22 downto 0);
    fractional: OUT std_logic_VECTOR(14 downto 0));
end component;

signal divisor: std_logic_VECTOR(14 downto 0);
begin
    divider_per_inst : divider_per port map (
        clk => clk,
        ce => ce,
        rfd => rfd,
        dividend => dividend,
        divisor => divisor,
        quotient => quotient,
        fractional => fractional
    );
    divisor <= "110000000000000";
end RTL;


次にテストベンチ・ファイルのDivider_test_tb.vhdを下に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
ENTITY Divider_test_tb IS
END Divider_test_tb;
 
ARCHITECTURE behavior OF Divider_test_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT Divider_test
    PORT(
         clk : IN  std_logic;
         ce : IN  std_logic;
         rfd : OUT  std_logic;
         dividend : IN  std_logic_vector(22 downto 0);
         quotient : OUT  std_logic_vector(22 downto 0);
         fractional : OUT  std_logic_vector(14 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal clk : std_logic := '0';
   signal ce : std_logic := '0';
   signal dividend : std_logic_vector(22 downto 0) := (others => '0');

     --Outputs
   signal rfd : std_logic;
   signal quotient : std_logic_vector(22 downto 0);
   signal fractional : std_logic_vector(14 downto 0);

   -- Clock period definitions
   constant clk_period : time := 40 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Divider_test PORT MAP (
          clk => clk,
          ce => ce,
          rfd => rfd,
          dividend => dividend,
          quotient => quotient,
          fractional => fractional
        );

   -- Clock process definitions
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
   end process;
 

    -- Stimulus process
    stim_proc: process
    begin
        ce <= '0';
        dividend <= "00000000000000000000000";    
        wait for clk_period*2;    
        ce <= '1';
        dividend <= "00000000110000000000000";
        wait for clk_period*2;    
        ce <= '1';
        dividend <= "00000011100000000000000";
        
        wait for clk_period*10;

        wait;
    end process;

END;


これで、とりあえずインプリメントをしてみた。無事に終了したが、Summaryには何も表示されない?
divider_IP_2_101001.png

なんででしょうか?
FPGA Editorで見てみると、FPGA内部では確かにIOとスライスが使用されている。
divider_IP_3_101001.png

次にシミュレーションを行ってみた。ISimによるシミュレーション波形を下に示す。
divider_IP_4_101001.png

rfdが1のままだった。rfdが0になることはない。rfdは入力データがコアにサンプルされるタイミングを表す。Divider Generator の設定で、Clocks per Divisonは1だったので、rfdは1クロックごとに入力データをサンプルできるはずなので、1のままなのだろう?この設定では、Dividend and Quotient Widthが23ビットなので、割り算データが出力されるレイテンシは上のシミュレーション波形のカーソルから1usec、25クロックである。データシートでもDividend and Quotient Width + 2クロックなので、25クロックとなり同一である。

次に、Clocks per Divisonを8にしてみた。
divider_IP_5_101001.png

これで、シミュレーションしてみたのが下の波形だ。
divider_IP_6_101001.png

今度は、rfdが8クロックごとに1になっていて、そこでサンプルされたデータが、1.04usec、26クロック後に割り算されて出力されている。データシートではClocks per Divisonが1以上の時は、Dividend and Quotient Width + 3クロックなので等しい。
当然、Clocks per Divisonが8の方がリソースは食わないはず。。。これで、この用途には十分だと思う。

Core Generatorの割り算器を確かめてみた。レイテンシは、Dividend and Quotient Width + 数クロックかかるということがわかった。
  1. 2010年10月01日 12:50 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:0

Write側とRead側のデータ幅の異なるFIFOのシミュレーション3

非同期FIFOの話題をもう1つ。
今度は前とは逆で、Writeのデータ幅が16ビットで、Readのデータ幅が32ビットの非同期FIFOの入出力フォーマットを検証してみた。
まずは、Write側で16ビット幅で書く場合のシミュレーション波形を下に示す。
def_width_fifo_15_100718.png

wr_enが1の時のwr_clkの立ち上がりで、FIFOにdin[15:0]のデータがWriteされる。Writeした値は、0006, 0007, 0008,0009, 000a, 000b, 000c, 000d だ。
これでRead側で32ビット幅で読んだときのシミュレーション波形を見てみる。
def_width_fifo_16_100718.png

FWFTなFIFOなので、rd_enが1の時に、rd_clkの立ち上がりでdout[15:0]に出てくるデータがそうだ。00060007, 00080009, 000a000b, 000c000d と出てくる。32ビットのうちの最初に入れた16ビットが上位、次の16ビットが下位になっている。これで、”Write側とRead側のデータ幅の異なるFIFOのシミュレーション2”と対称に成っていることがわかった。普通に使えば使えるので安心した。
  1. 2010年07月18日 10:02 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:0

Write側とRead側のデータ幅の異なるFIFOのシミュレーション2

そういえば、本来何やりたいたいかという目的を忘れていた。幅が違うFIFOの出力のフォーマットを見たかったのだった。
Writeのデータ幅が32ビットで、Readのデータ幅が16ビットの非同期FIFOの入出力フォーマットを検証してみた。
まずは、Write側で32ビット幅で書く場合のシミュレーション波形を下に示す。
def_width_fifo_13_100717.png

wr_enが1の時のwr_clkの立ち上がりで、FIFOにdin[31:0]のデータがWriteされる。Writeした値は0000000b, 0000000c, 0000000d だ。
これでRead側で16ビット幅で読んだときのシミュレーション波形を見てみる。
def_width_fifo_14_100717.png

FWFTなFIFOなので、rd_enが1の時に、rd_clkの立ち上がりでdout[15:0]に出てくるデータがそうだ。0000, 000b, 0000, 000c, 0000, 000d と出てくるので、32ビットで書いたときの上位16ビット、下位16ビットの順で出てくる。

これで、Writeのデータ幅が32ビットで、Readのデータ幅が16ビットの非同期FIFOの入出力フォーマットを検証することができた。
  1. 2010年07月17日 19:08 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:0
»