FC2カウンター FPGAの部屋 2012年04月

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

FPGAの部屋

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

”テルマエ・ロマエ”を見てきました

昨日、テルマエ・ロマエを見てきました。漫画は全巻買って読んでいて、好きな漫画なので、楽しみにしていました。映画はコメディタッチでした。漫画もそうなんですけどね。。。ハリーポッターの真ん中くらいの作品と同じでストーリーが圧縮されて、更に付け加えられ感じ(温泉旅館のおじさんたち)です。少し、期待はずれ感が有りましたが、奥さんは楽しめたようです。私も楽しかったんですが、やはり、イタリア人が主演のほうが良かったような気がします?
そうそう、テルマエ・ロマエ特別編の漫画小冊子をもらいました。映画の情報も書いてありましたよ。

  1. 2012年04月30日 07:57 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Altium でC to Hardware(ラプラシアンフィルタ)

Altium でもう一度、C to Hardwareをやってみた。今度はラプラシアンフィルタを自分で作ってやってみた。

最初に、Cのコードを書いた。
Altium_Designer_C2H_25_120430.png

Cコードを下に示す。

#include <stdint.h>
#include <stdbool.h>

void Laplacian_filer(uint8_t x0y0, uint8_t x1y0, uint8_t x2y0, uint8_t x0y1, uint8_t x1y1, uint8_t x2y1, uint8_t x0y2, uint8_t x1y2, uint8_t x2y2, uint8_t * out_sig)
{
     int32_t temp;

     temp = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
     if (temp <0)
        *out_sig = 0;
     else if (temp>255)
        *out_sig = 255;
     else
        *out_sig = temp;
}


入力8ビット、出力8ビットにしてあるので、飽和演算を入れてある。

・ファイルメニュー -> 新規 -> 回路図 で新規回路図を作成した。

・デザインメニュー -> C言語からコードシンボル作成 でC言語のコードシンボルを作成した。

・ポートを置いて回路図を作成した。
Altium_Designer_C2H_26_120430.png

・最初は、Parallel Combinatorial でやってみたが、エラーだった。(”Altium Designer でC to Hardware のサンプルを試してみる2”を参照のこと)

やはり、自動変数のtemp を定義してしまっているので組み合わせ回路にならないのだろうか?

・前回同様、Parallel Multi-cycle で設定するとコンパイルができた。
Altium_Designer_C2H_24_120429.png

・ログを見ると、clock cycles は at leastとのことだった。一体何クロックかかるのだろうか?

・生成されたVHDLファイル(laplacian_filter_u_laplacian_filer.VHD)をISEのプロジェクトに入れて、インプリメントしてみた。使用FPGAは XC3S1400AN-FGG676-4。

・CLOCKのPERIOD制約を150MHzにしてみたが、結果はタイミングエラーだった。最小周期は9.439ns だったので100MHzでは動作する。

・テストベンチ(Laplacian_filter_tb.vhd) を作成して、シミュレーションを行った。
Laplacian_filter_tb.vhdを下に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY Laplacian_filter_tb IS
END Laplacian_filter_tb;
 
ARCHITECTURE behavior OF Laplacian_filter_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT Laplacian_filter_U_Laplacian_filer
    PORT(
         CLOCK : IN  std_logic;
         DONE : OUT  std_logic;
         RESET : IN  std_logic;
         RESET_DONE : OUT  std_logic;
         START : IN  std_logic;
         out_sig : OUT  std_logic_vector(7 downto 0);
         x0y0 : IN  std_logic_vector(7 downto 0);
         x0y1 : IN  std_logic_vector(7 downto 0);
         x0y2 : IN  std_logic_vector(7 downto 0);
         x1y0 : IN  std_logic_vector(7 downto 0);
         x1y1 : IN  std_logic_vector(7 downto 0);
         x1y2 : IN  std_logic_vector(7 downto 0);
         x2y0 : IN  std_logic_vector(7 downto 0);
         x2y1 : IN  std_logic_vector(7 downto 0);
         x2y2 : IN  std_logic_vector(7 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal CLOCK : std_logic := '0';
   signal RESET : std_logic := '0';
   signal START : std_logic := '0';
   signal x0y0 : std_logic_vector(7 downto 0) := (others => '0');
   signal x0y1 : std_logic_vector(7 downto 0) := (others => '0');
   signal x0y2 : std_logic_vector(7 downto 0) := (others => '0');
   signal x1y0 : std_logic_vector(7 downto 0) := (others => '0');
   signal x1y1 : std_logic_vector(7 downto 0) := (others => '0');
   signal x1y2 : std_logic_vector(7 downto 0) := (others => '0');
   signal x2y0 : std_logic_vector(7 downto 0) := (others => '0');
   signal x2y1 : std_logic_vector(7 downto 0) := (others => '0');
   signal x2y2 : std_logic_vector(7 downto 0) := (others => '0');

     --Outputs
   signal DONE : std_logic;
   signal RESET_DONE : std_logic;
   signal out_sig : std_logic_vector(7 downto 0);

   -- Clock period definitions
   constant CLOCK_period : time := 10 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Laplacian_filter_U_Laplacian_filer PORT MAP (
          CLOCK => CLOCK,
          DONE => DONE,
          RESET => RESET,
          RESET_DONE => RESET_DONE,
          START => START,
          out_sig => out_sig,
          x0y0 => x0y0,
          x0y1 => x0y1,
          x0y2 => x0y2,
          x1y0 => x1y0,
          x1y1 => x1y1,
          x1y2 => x1y2,
          x2y0 => x2y0,
          x2y1 => x2y1,
          x2y2 => x2y2
        );

   -- Clock process definitions
   CLOCK_process :process
   begin
        CLOCK <= '0';
        wait for CLOCK_period/2;
        CLOCK <= '1';
        wait for CLOCK_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin
      RESET <= '1';
      START <= '0';
      x0y0 <= CONV_STD_LOGIC_VECTOR(0, 8);
      x1y0 <= CONV_STD_LOGIC_VECTOR(10, 8);
      x2y0 <= CONV_STD_LOGIC_VECTOR(20, 8);
      x0y1 <= CONV_STD_LOGIC_VECTOR(30, 8);
      x1y1 <= CONV_STD_LOGIC_VECTOR(40, 8);
      x2y1 <= CONV_STD_LOGIC_VECTOR(50, 8);
      x0y2 <= CONV_STD_LOGIC_VECTOR(60, 8);
      x1y2 <= CONV_STD_LOGIC_VECTOR(70, 8);
      x2y2 <= CONV_STD_LOGIC_VECTOR(80, 8);
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      wait for CLOCK_period*10;

      -- insert stimulus here 
      RESET <= '0';
      wait for CLOCK_period;
      
      for i in 1 to 10 loop
          START <= '1';
          wait for CLOCK_period;
          START <= '0';
          wait for CLOCK_period*5;
          x0y0 <= x0y0;
          x1y0 <= x1y0;
          x2y0 <= x2y0;
          x0y1 <= x0y1;
          x1y1 <= x1y1 + i;
          x2y1 <= x2y1;
          x0y2 <= x0y2;
          x1y2 <= x1y2;
          x2y2 <= x2y2;
      end loop;

      wait;
   end process;

END;


.ISim でシミュレーションした結果を下に示す。
Altium_Designer_C2H_27_120430.png

ラプラシアンフィルタの演算に5クロックかかっているようだ。
  1. 2012年04月30日 05:55 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

Alitum でHardware Software Co-designのサンプルをやってみた

今回は、NB3000 CHC Graphics というサンプルをやってみた。これは、プロセッサ・システムでどうやらCの同じようなプログラムをソフトウェアとハードウェアで実行して、その速度差を比べるサンプルだった。
実際にはNB3000の液晶ディスプレイに線や円を書いて、ソフトウェアとハードウェアでの速度差をソフト端末に表示する。

下に示すようにCプログラムのmain関数はsw_plot() 関数とhw_plot() 関数が両方書かれている。
Altium_Designer_C2H_22_120428.png

sw_line(), hw_line(), sw_circle(), hw_circle() もあった。これをインプリメントして、FPGAにダウンロードした。
・SOFT_TERMINAL をダブルクリックしてソフト端末を起動した。
・MCU TSK3000Aの下のCompile ボタンをクリックしてコンパイルする。
・その下のUp to Data Download ボタンでFPGAにダウンロードした。
Altium_Designer_C2H_21_120428.png

そうすると、SW lineとHW line、SW circleとHW circle の速度差がソフト端末に表示された。lineは16.4倍、circleは 7.75倍ハードウェアの方が早い。でもplotは殆ど変わらない。ソフト端末に表示されたメッセージを下に貼る。

CHC Performance Test, file main.c, compiled on Apr 28 2012

Running Tests:
--------------
- SW plot (pixels)
- HW plot (pixels)
- SW lines
- HW lines
- SW circles
- HW circles

Results
-------

SW plot = 5529600 cycles
HW plot = 5344977 cycles
Performance gain = 3%

SW line = 43425358 cycles
HW line = 2493835 cycles
Performance gain = 1641%

SW circle = 513557 cycles
HW circle = 63216 cycles
Performance gain = 712%


液晶ディスプレイにはこんな感じで表示される。
Altium_Designer_C2H_23_120428.png

Altium Designer ではHardware Software Co-designもできることがわかった。
  1. 2012年04月28日 21:17 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

ポートを配列で宣言して下位階層に配線を接続する

VHDLでポートを配列で宣言して下位階層に配線を接続する方法を備忘録として書いておく。この場合は、packege を宣言してパッケージに配列の宣言を書いておく。なお、使用ツールはISE13.4だ。

最初の array_test_pack.vhd を示す。

library IEEE;
use IEEE.STD_LOGIC_1164.all;

package array_test_pack is
type define_nn_array is array (16 downto 1) of std_logic_vector(7 downto 0);
type define_sig_out_array is array (3 downto 0) of std_logic_vector(7 downto 0);

end package array_test_pack;


トップファイル、array_test_top.vhd を下に示す。
このパッケージをuse するとdefine_nn_array、define_sig_out_array 宣言を使うことができる。

-- array_test_top.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

library work;
use work.array_test_pack.all;

entity array_test_top is
    port(
        clk : in std_logic;
        reset : in std_logic;
        sig_out0 : out std_logic_vector(7 downto 0);
        sig_out1 : out std_logic_vector(7 downto 0);
        sig_out2 : out std_logic_vector(7 downto 0);
        sig_out3 : out std_logic_vector(7 downto 0)
    );
end array_test_top;

architecture Behavioral of array_test_top is
signal nn_array : define_nn_array;
signal sig_node : define_sig_out_array;
component array_test
    port (
        nn_array : in define_nn_array;
        sig_out : out define_sig_out_array
    );
end component;
begin
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                for i in 1 to 16 loop
                    nn_array(i) <= CONV_STD_LOGIC_VECTOR(i,8);
                end loop;
            else
                for i in 1 to 16 loop
                    nn_array(i) <= nn_array(i) + 1;
                end loop;
            end if;
        end if;
    end process;
    
    array_test_inst : array_test port map(
        nn_array => nn_array,
        sig_out => sig_node
    );
    
    sig_out0 <= sig_node(0);
    sig_out1 <= sig_node(1);
    sig_out2 <= sig_node(2);
    sig_out3 <= sig_node(3);
end Behavioral;


下位階層のarray_test.vhd を下に示す。
port に書く信号はパッケージで宣言しておかないとエラーになってしまう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

library work;
use work.array_test_pack.all;

entity array_test is
    port (
        nn_array : in define_nn_array;
        sig_out : out define_sig_out_array
    );
end array_test;

architecture Behavioral of array_test is

begin
    sig_out(0) <= nn_array(1) + nn_array(2) + nn_array(3) + nn_array(4);
    sig_out(1) <= nn_array(5) + nn_array(6) + nn_array(7) + nn_array(8);
    sig_out(2) <= nn_array(9) + nn_array(10) + nn_array(11) + nn_array(12);
    sig_out(3) <= nn_array(13) + nn_array(14) + nn_array(15) + nn_array(16);

end Behavioral;


最後にトップファイル、array_test_top.vhd のテストベンチ、array_test_top_tb.vhd を下に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY array_test_top_tb IS
END array_test_top_tb;
 
ARCHITECTURE behavior OF array_test_top_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT array_test_top
    PORT(
         clk : IN  std_logic;
         reset : IN  std_logic;
         sig_out0 : OUT  std_logic_vector(7 downto 0);
         sig_out1 : OUT  std_logic_vector(7 downto 0);
         sig_out2 : OUT  std_logic_vector(7 downto 0);
         sig_out3 : OUT  std_logic_vector(7 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';

     --Outputs
   signal sig_out0 : std_logic_vector(7 downto 0);
   signal sig_out1 : std_logic_vector(7 downto 0);
   signal sig_out2 : std_logic_vector(7 downto 0);
   signal sig_out3 : std_logic_vector(7 downto 0);

   -- Clock period definitions
   constant clk_period : time := 10 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: array_test_top PORT MAP (
          clk => clk,
          reset => reset,
          sig_out0 => sig_out0,
          sig_out1 => sig_out1,
          sig_out2 => sig_out2,
          sig_out3 => sig_out3
        );

   -- 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        
      -- hold reset state for 100 ns.
        reset <= '1';
      wait for 100 ns;    

      wait for clk_period*10;

      -- insert stimulus here 
        reset <= '0';
      wait;
   end process;

END;


これらのシミュレーション結果を下に示す。
VHDL_array_1_120427.png

なお、バス信号は十進数で表示してある。
  1. 2012年04月27日 17:00 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:2

Altium Designer でC to Hardware のサンプルを試してみる2

Altium Designer でC to Hardware のサンプルを試してみる1”の続き。

まずは、C-to-Hardware Compiler User Manual があった。よく書いてあるようだ。

次に、Altium Designer でC to Hardware のサンプルを試してみる1のシミュレーション波形だが、1つの累算が終わってから、次の累算のstart を入れていたが、done しないうちにstart を入れたらどうだろう?と思ってテストベンチを変更してやってみた。
Altium_Designer_C2H_11_120427.png

パイプラインにはなっていないようだ。必ずdone が上がってからstart 信号を入れる必要があるようだ。ちなみに下の波形が前回のシミュレーション波形だ。
Altium_Designer_C2H_10_120426.png

表示メニューからデバイスビューを表示して、FPGAのCompile を開き、Generate HDL for ... のりポートファイルを開く。
Altium_Designer_C2H_12_120427.png

下にリポートファイルを開いた様子を示す。
Altium_Designer_C2H_13_120427.png

リポートファイルに下のような記述があった。引用する。

* Accumulate
============
+------------------------------------------------------------------------------------------------+
| calling convention | parallel multi cycle, entry point, register outputs, start on rising edge |
| states | 4 |
| registers | 64 bits |
| clock cycles | 3 |
| ALU | 32 |
+------------------------------------------------------------------------------------------------+


やはりクロックサイクルは3だそうだ。

・次に、トップの回路図でCモジュール、U_Accumulate をダブルクリックする。
Altium_Designer_C2H_17_120427.png

・C コード シンボル・ダイアログが開く。
Altium_Designer_C2H_14_120427.png

・エントリ・タブをクリックする。インターフェースタイプは現在は、Parallel Multi-cycle になっているが、Parallel Combinatorial なども選択することが出来る。Wishbone のインターフェースでやり取りできるモードもあった。
Altium_Designer_C2H_15_120427.png

・インターフェースタイプをParallel Combinatorialにした。
Altium_Designer_C2H_16_120427.png

・以前の図と比べると、CLOCK、RESET、DONE、RESET_DONE が無くなったことがわかる。
Altium_Designer_C2H_18_120427.png

・コンパイルしたところ、Generate HDL for ...でエラーが出てしまった。
Altium_Designer_C2H_19_120427.png

・上で表示されているエラーをダブルクリックするとCソースに飛んでいった。
Altium_Designer_C2H_20_120427.png

あ、そうか。もしかして?累算しているから順序回路にするしか方法が無いのか。。。組み合わせ回路にするのは諦めることにする。レイテンシを変える方法がまだ見つからない。レイテンシを変えてみたいのだが。。。
もしかして、制約ファイルの動作周波数を変えるとレイテンシが変わるのか?
  1. 2012年04月27日 05:51 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

Altium Designer でC to Hardware のサンプルを試してみる1

日曜日にFPGA-CAFE でNonoBoard3000シリーズを借りてきた。今回は、Altium Designer でC to Hardware のサンプルを試してみることにする。

まずは、Altium Designer のサンプルデザインのページからTutorials (2 MB) をダウンロードして展開した。その中に入っているCHC Accumulator をやってみることにした。

・CHC Accumulatorの回路図を開くと、CのモジュールとCustom Instrument が入っていた。
Altium_Designer_C2H_1_120426.png

・Cの関数、Accumulateはスタティックな変数を定義して、それに入力の数を累算していくシンプルなプログラムだった。
Altium_Designer_C2H_2_120426.png

・このチュートリアルをコンパイルというかXilinx で言うとインプリメントするのだが、このプロジェクトはもう1つのFPGAボード、Desktop NanoBoard NB2DSK01用のプロジェクトだった。そのためNonoBoard3000シリーズ用に制約ファイルを追加して、新しいコンフィギュレーションを追加し、そっちに切り替える必要がある。

・Documents\Altium\AD 10\Library\FPGAにあるNB3000XN.05.Constraintをプロジェクトに追加した。
Altium_Designer_C2H_3_120426.png

・プロジェクトメニューからコンフィギュレーション マネージャを開く。

・NB3000XNのコンフィギュレーションを追加して、CHC_Accumulator.ConstraintとNB3000XN.05.Constraintにチェックを入れた。
Altium_Designer_C2H_4_120426.png

・表示からデバイスビューを表示して、Program FPGAをクリックした。FPGAのインプリメントが開始されて、FPGAにビットファイルがダウンロードされた。
Altium_Designer_C2H_5_120426.png

・CUSTOM_INSTRUMENT をダブルクリックすると、Instrument Rack が開いた。Totalは最初は0になっている。
Altium_Designer_C2H_6_120426.png

・Value に値をセットしてAdd ボタンをクリックすると足された数がTotalに表示される。
Altium_Designer_C2H_7_120426.png

これでC to Hardware のサンプルはやって見ることができたが、CがどのようにVHDLに落ちているかを見てみよう。

・Cプログラムはchc_accumulator_u_accumulate.VHD という名前のVHDLファイルに変換されて600行程度になったようだ。DONE信号が増えているので、加算処理に複数クロック掛かる可能性があると思う。
Altium_Designer_C2H_8_120426.png

・ISEのプロジェクトを作成して、まずはchc_accumulator_u_accumulate.VHD をコンパイルしてみた。
Altium_Designer_C2H_9_120426.png

・次にシミュレーションを行った。下に示すテストベンチを作成してISimでシミュレーションを行った。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY Accumulate_tb IS
END Accumulate_tb;
 
ARCHITECTURE behavior OF Accumulate_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT CHC_Accumulator_U_Accumulate
    PORT(
         CLOCK : IN  std_logic;
         DONE : OUT  std_logic;
         RESET : IN  std_logic;
         RESET_DONE : OUT  std_logic;
         START : IN  std_logic;
         TOTAL_O : OUT  std_logic_vector(31 downto 0);
         VALUE_I : IN  std_logic_vector(31 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal CLOCK : std_logic := '0';
   signal RESET : std_logic := '0';
   signal START : std_logic := '0';
   signal VALUE_I : std_logic_vector(31 downto 0) := (others => '0');

     --Outputs
   signal DONE : std_logic;
   signal RESET_DONE : std_logic;
   signal TOTAL_O : std_logic_vector(31 downto 0);

   -- Clock period definitions
   constant CLOCK_period : time := 10 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: CHC_Accumulator_U_Accumulate PORT MAP (
          CLOCK => CLOCK,
          DONE => DONE,
          RESET => RESET,
          RESET_DONE => RESET_DONE,
          START => START,
          TOTAL_O => TOTAL_O,
          VALUE_I => VALUE_I
        );

   -- Clock process definitions
   CLOCK_process :process
   begin
        CLOCK <= '0';
        wait for CLOCK_period/2;
        CLOCK <= '1';
        wait for CLOCK_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin
      RESET <= '1';
      START <= '0';
      VALUE_I <= CONV_STD_LOGIC_VECTOR(0,32);
      -- hold reset state for 100 ns.
      wait for 100 ns;    
      
      RESET <= '0';
      
      wait for CLOCK_period*10;

      -- insert stimulus here 
      START <= '1';
      VALUE_I <= CONV_STD_LOGIC_VECTOR(64,32);
      
      wait for CLOCK_period;
      START <= '0';
      
      wait for CLOCK_period*3;
      START <= '1';
      VALUE_I <= CONV_STD_LOGIC_VECTOR(128,32);
      
      wait for CLOCK_period;
      START <= '0';

      wait;
   end process;

END;



・シミュレーション結果の波形を下に示す。
Altium_Designer_C2H_10_120426.png

startが1になると、すぐにdone が0に下がる。done の出力は組み合わせ回路を使用しているようだ。start が1になってから2つ目のclock の立ち上がりでdone が1に上がるので、3つ目のクロックでdone が1になったのをサンプルできる。同時にtotal_o にも累算結果が出てくる。ここでのクロックに対するレイテンシは3クロックと言うことができる。
  1. 2012年04月26日 05:38 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

SPI FLASH ROMでFPGAにコンフィギュレーション2(Atlys ボード)

SPI FLASH ROMでFPGAにコンフィギュレーション(Atlys ボード)”の続き。

コンフィギュレーションの失敗の原因は、FLASH のIDがオール0で読めないというものだった。そこでSPI FLASH ID で検索すると、BRAVO FPGAさんの”SPIコントローラの作成 3”がヒットした。それによると、やはりSPI FLASHのIDが読めずにQIO-SPIモードでRDIDコマンド(MIORDID)を発行したら読めたそうだ。
QIO-SPIモードというのは何?ということで、もう一度検索すると、Micron社の”Software Device Drivers for Micron® N25Q Serial NOR Flash Memory”がヒットした。それによるとQuad SPI (QIO-SPI) protocolとうことで、4ビットデータバスがあるので、それをフルに使ってデータをやりとりするモードのようだ。

iMPACTではx4モードが選べず、AtlysボードのSPI FLASH に書けないようなので、Digilent社の専用ソフトDigilent Adeptを試して見ることにした。Digilent AdeptのWebサイトに行って、Adept 2.9.4 System, 32/64-bit Windowsを落としてきた。
インストールし、起動したが、うまく動かない。Windows XPを再起動してから、Digilent Adeptを起動したらAtlysボードを検出できた。
Atlys_SPI_Config_24_120424.png

SPI FLASHに書き込もう。Flash タブをクリックし、FPGA programming file をBrows...ボタンで選択する。ここではビットファイルを選択することができるので選択した。Verify のチェックボックスをチェックしてから、Programボタンをクリックしたところコンフィギュレーションが完了した。
Atlys_SPI_Config_25_120424.png

Atlysボードの電源をOFFしてからONすると、キャラクタ・ディスプレイ・コントローラの表示が出た。うまくSPI FLASHからコンフィギュレーション出来ているようだ。
cdctest_axi_master_19_120404.jpg

AtlysボードのSPI FLASHにFPGAのコンフィギュレーション・データを書き込む場合は、iMPACTでは書き込むことが出来ない。Digilent Adeptを使用するとAtlysボードのSPI FLASHにFPGAのコンフィギュレーション・データを書き込む事ができることがわかった。
  1. 2012年04月25日 05:50 |
  2. Atlysボード
  3. | トラックバック:0
  4. | コメント:2

SPI FLASH ROMでFPGAにコンフィギュレーション(Atlys ボード)

Atlys ボード(Spartan-6)には、SPI FLASH ROMが実装されていて、電源ON時にSPI FLASH ROMからFPGAをコンフィギュレーションすることができる。今回はこのSPI FLASH ROMにFPGAのコンフィギュレーションデータを書き込むことにした。(使用しているISEのバージョンは13.4、これではSPI FLASH ROM に書き込むことができなかったが、ISE14.4 では書き込むことができた。追記参照)

Xilinx FPGAに接続されたSPI FLASH ROMはiMPACTから書き込む事ができる。今回はその手順を書いておく。
接続はUSBケーブルでAtlysボードのPROGコネクタへ接続した。ちなみに、XUP USB-JTAG Programming Cable で接続しても同じ結果だった。

・Project Navigator のProcessesウインドウのConfigure Target Device を展開して、Generate Target PROM/ACE File をダブルクリックする。
Atlys_SPI_Config_1_120423.png

・私の環境ではワーニングが出るが、OKボタンをクリックする。
Atlys_SPI_Config_2_120423.png

・iMPACT が立ち上がる。Create PROM File (PROM File Formatter) をダブルクリックする。
Atlys_SPI_Config_3_120423.png

・PROM File Formatterが立ち上がる。SPI FlashのConfigure Single FPGA をクリックしてから、矢印をクリックする。(Step 1.)
Atlys_SPI_Config_4_120423.png

・Step 2.では、SPI FLASH ROMの容量を選択する。Atlysボードには128MビットのSPI FLASH ROMが実装されていると書いてあるので、Storage Device (bits) で128Mを選択し、Add Storage Device ボタンをクリックする。
Atlys_SPI_Config_5_120423.png

・Step 2.に128MのSPI FLASH ROMが入ったので、2番目の矢印をクリックする。
Atlys_SPI_Config_6_120423.png

・Step 3.でOutput File NameとOutput File Location を設定し、OKボタンをクリックした。
Atlys_SPI_Config_7_120423.png

・iMPACT の画面に戻って、SPI FLASH ROMに入れるビットファイルを指定する。Add Deviceダイアログが表示されるので、OKボタンをクリックする。まずは最初のビットファイルを指定する。(注:ここでは、1つのビットファイルのみを指定することになる)
Atlys_SPI_Config_8_120423.png

・Add Device ダイアログが開くので、ビットファイルをクリックして開くボタンをクリックする。
Atlys_SPI_Config_9_120423.png

・Add Deviceダイアログが表示される。もう追加するビットファイルが無いのでNoボタンをクリックする。
Atlys_SPI_Config_10_120423.png

・もうビットファイルの指定は終了した。OKボタンをクリックする。
Atlys_SPI_Config_11_120423.png

・iMPACTに戻るので、iMPACT Processes ウインドウからGenerate File...をダブルクリックする。
Atlys_SPI_Config_12_120423.png

・Generate Succeeded が表示されて、SPI FLASHのダウンロード用ファイルの生成が成功した。
Atlys_SPI_Config_13_120423.png

・次にSPI FLASH をコンフィギュレーションする。iMPACT のInitialize Chain アイコンをクリックして、JTAG Chain につながっているFPGAなどを検索する。
Atlys_SPI_Config_14_120423.png

・Spartan-6 FPGAが見つかった。コンフィギュレーション・ファイルを指定するため、ダイアログのYes ボタンをクリックする。
Atlys_SPI_Config_15_120423.png

・コンフィギュレーション・ファイルを指定する。
Atlys_SPI_Config_16_120423.png

・次にSPI FLASH のコンフィギュレーション・ファイルを指定するため、ダイアログのYes ボタンをクリックする。
Atlys_SPI_Config_17_120423.png

・先ほど生成したSPI FLASHのコンフィギュレーション・ファイルを指定して、開くボタンをクリックする。
Atlys_SPI_Config_18_120423.png

・Select Attached SPI/BPI が開く。SPI PROM のN25Q128, Data Width 1 を選択する。(Atlys の回路図(PDFです)では25Q12 と表示されていた)
Atlys_SPI_Config_19_120423.png

・Device Programming Properties が開く。OKボタンをクリックする。
Atlys_SPI_Config_20_120423.png

・Boundary Scan タブのFLASH をクリックし、iMPACT Processes ウインドウでProgram をダブルクリックする。
Atlys_SPI_Config_21_120423.png

・Device Programming Properties が開く。OKボタンをクリックする。
Atlys_SPI_Config_22_120423.png

・Program Failed になってしまった。
Atlys_SPI_Config_23_120423.png

実際に基板に搭載されているSPI FLASH ROMの型番は、25Q2813B40 だった。25Q128 じゃないのか?データシートを検索しても出てこない。情報があったら教えて下さい。

(2012/04/25:追記)
Digilent Adeptソフトウェアを使用して、AtlysボードのSPI FLASHにFPGAのコンフィギュレーション・データを書き込む事ができました。詳しくは、"SPI FLASH ROMでFPGAにコンフィギュレーション2(Atlys ボード)"を御覧ください。

(注)
Spatan-3A Starter Kit などでしたら、SPI FLASH の型番は違うかも知れませんが、今回の手順でコンフィギュレーション・データをSPI FLASH に書くことができると思います。

(2013/01/30:追記)
ISE14.4でSPI FLASH ROM に書き込んだところ、Passして書き込めました
Atlys_SPI_Config_24_130130.png 
  1. 2012年04月24日 05:54 |
  2. Atlysボード
  3. | トラックバック:0
  4. | コメント:2

Altium Designer のFPGA設計入門をやってみる4

Altium Designer のFPGA設計入門をやってみる3”の続き

前回はProgram FPGAでFPGAをコンフィギュレーションする時にフェイルしてしまった。前回は既存のNanoBoard用のチュートリアルを改造して使っていたので、今回は1から自分で作ることにする。

もうすでに自分で作って試しているが、作る過程を書いておく。
・最初にFPGAデザインのプロジェクトを作る。ファイルメニューから新規 -> プロジェクト -> FPGAプロジェクト を選択する。
Altium_Desiger_FPGA_26_120421.png

・普通に回路図を書くようにポートを置いていってSWからLEDの線を接続した。これで良いみたいだ。下の図は制約ファイルを書いてあるので、ピン番号が表示されている。
Altium_Desiger_FPGA_27_120421.png

・次に制約ファイルを作った。ファイルメニューから新規 -> その他 -> コンストレイント ファイル を選択した。
Altium_Desiger_FPGA_6_120419.png

・コンストレイント ファイルを開いた。

・SW_LED_TEST.ucfを作成した。

NET "SW0" LOC = "V8" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW1" LOC = "U10"| IOSTANDARD = LVTTL | PULLUP ;
NET "SW2" LOC = "U8" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW3" LOC = "T9" | IOSTANDARD = LVTTL | PULLUP ;
NET "LED3" LOC = "U19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LED2" LOC = "U20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LED1" LOC = "T19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LED0" LOC = "R20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;


・デザインメニューからPinファイルのレポート -> ファイル選択 を選択する。(このあたりは”Altium Designer のFPGA設計入門をやってみる2”を参照のこと)

・Open FPGA Vender PIN File ダイアログが開く。SW_LED_TEST.ucfを選択し、開くボタンをクリックする。

・コンストレイント エディタ設定ダイアログが開く。OKボタンをクリックする。

・Altium Designer のコンストレイント・ファイルに制約が追加された。

・それに、FPGAの型番の制約を追加したのが下のファイルだ。

;...............................................................................
;Constraints File
; Device :
; Board :
; Project :
;
; Created 2012/04/21
;...............................................................................

;...............................................................................
Record=FileHeader | Id=DXP Constraints v1.0
;...............................................................................

Record=Constraint | TargetKind=Part | TargetId=XC3S700A-4FGG484C

Record=Constraint | TargetKind=Port | TargetId=LED[3..0] | FPGA_PINNUM=U19,U20,T19,R20 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_DRIVE=4mA,4mA,4mA,4mA
Record=Constraint | TargetKind=Port | TargetId=SW[3..0] | FPGA_PINNUM=T9,U8,U10,V8 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_PULLUP=True,True,True,True


・プロジェクトメニューからコンフィギュレーション マネージャを開く。
Altium_Desiger_FPGA_12_120419.png

・上のウインドウで追加ボタンをクリックして、Test_FPGA_Project1を追加して、下のウインドウでTest_FPGA_Project1.Constraint のチェックボックスにチェックを入れる。
Altium_Desiger_FPGA_28_120421.png

・ファイルとプロジェクトをセーブした。

・プロジェクトメニューからプロジェクトのコンパイルをした。

・表示メニューからデバイスビューを選択した。Devices が開く。Spartan-3A Starter Kit の電源を入れて、Live にチェックを入れると下のような画面が開く。下の画面はビットファイルの生成まで終了しているが、実際には、”Altium Designer のFPGA設計入門をやってみる3”の様にFPGAのインプリメントを行う
Altium_Desiger_FPGA_29_120421.png

・Program FPGAをクリックして、FPGAをコンフィギュレーションする。その際に、FPGA下のプルダウンメニューの設定が、Test_FPGA_Project1であることを確認する。

・DONEランプは付くのだが、やはりフェイルする。

・すべてのSWが下にスライドしているのに、LED1だけが点灯している。他のSWとLEDは上にスライドすると関係するLEDがつくが、LED1だけはSW1をどうスライドさせても点灯したままだ。
Altium_Desiger_FPGA_30_120421.png

・ちなみにAltium Designer で作られたビットファイルをiMPACTでコンフィギュレーションすると正常にコンフィギュレーション出来て、SWとLEDの関係も正しい。
ビットファイルは問題なく生成されているが、コンフィギュレーションがおかしいみたいだ。
  1. 2012年04月21日 20:18 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

ももへの手紙を見てきました(映画)

ももへの手紙を見てきました。奥さんは仕事なので、私一人で見てきました。全く期待しないでいったんですが、良かったです。前半は少し退屈かな?と思ってましたが、満足の行く映画でした。声優さんも良かったです。ジブリの映画では声優さんが残念なことも多いのですが、この映画は全く違和感なかったです。

家に帰ったら娘も見に行きたかったとのこと。それじゃ、また明日もう一度見ようと言ったら予定があるそうです。それじゃ、DVDかブルーレイを買うことにしようと思います。
  1. 2012年04月21日 13:36 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ISimの unexpected error

昨日、ISimでシミュレーションしていたのですが、unexpected error で落ちまくっていました。
ISim_unexpected_error_120420.png

Waveウインドウに信号をたくさん入れるとこうなりました。デフォルトの信号数のままだと1ms 程度シミュレーションできるのですが、たくさん入れるとシミュレーション開始してすぐにISimが落ちてしまいます。
ISEのバージョンはISE13.4、OSはWindows 7 professional 64ビット版です。
この現象で1日悩んでしまいました。MIGなどを含めた全体でシミュレーションしているのですが、部分的にシミュレーションしても、Wave波形をスライドさせた時に落ちてしまい、どうもおかしいようでした。

Google で検索すると、”Isim crashing Windows 7 VM”という記事が見つかりました。それによると、Xilinxの方がWin7 64ビット版でおかしい時は、Win XPの32/64ビット版かWin 7の32ビット版を使ってくれとのことでした。ちなみにISE13.4では直るとかいてあるようですが、直ってないです。

Win 7 32ビット版のパソコンがあったので、それにISE13.4 を入れてISimでシミュレーションしてみましたが問題ないようです。Win 7 64ビット版でISimが unexpected error で落ちる場合には、Win XPの32/64ビット版かWin 7の32ビット版を使ってみてください。

(追加です)
以前の同じような回路では大丈夫だったと思うのですが?なぜダメに成ったか不思議です。今回はVHDLでconstantによるパラメタライズな回路にしたので、2次元配列を多用しています。モジュール間も2次元配列で受け渡ししたりしています。そのような回路構成がダメなんでしょうかね?パラーメータを変えると回路規模が変化するので、簡単に推測できなかったのでしょうか?でも、Win7 32ビット版で動いてますから、そんなことはないはずですね?
  1. 2012年04月20日 09:28 |
  2. ISim
  3. | トラックバック:0
  4. | コメント:2

Altium Designer のFPGA設計入門をやってみる3

Altium Designer のFPGA設計入門をやってみる2”の続き。

前回は、エラーが出てしまって困ったと言うことで終わってしまったが、エラーの原因を調べることにした。(当たり前)
その前に参考となるPDFファイルを示す。”FPGA デザイン入門”と”制約条件ファイルリファレンス”だ。いつもながらWebページみるより、PDFファイル見るほうが見やすい。

・前回のエラー画面を下に示す。
Altium_Desiger_FPGA_14_120419.png

・一番上のエラーを表示してみた。どうやらターゲットのデバイスを指定していないためらしい。
Altium_Desiger_FPGA_18_120419.png

他のチュートリアルのコンストレイント・ファルを見てみたが、PCBが指定してあった。どうやらコンストレイント・ファイルで指定すれば良いようだ。

・”制約条件ファイルリファレンス”を見ると、ターゲットのデバイスを指定する制約があった。これを真似して、Spartan-3A Starter Kit のFPGAデバイスの制約を加えた。

Record=Constraint | TargetKind=Part | TargetId=XC3S700A-4FGG484C

Record=Constraint | TargetKind=Port | TargetId=LEDS[7..0] | FPGA_PINNUM=W21,Y22,V20,V19,U19,U20,T19,R20 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_DRIVE=4mA,4mA,4mA,4mA,4mA,4mA,4mA,4mA
Record=Constraint | TargetKind=Port | TargetId=SW[7..0] | FPGA_PINNUM=,,,,,U8,U10,V8 | FPGA_IOSTANDARD=,,,,,LVTTL33,LVTTL33,LVTTL33
Record=Constraint | TargetKind=Port | TargetId=CLK_REF | FPGA_PINNUM=E12 | FPGA_IOSTANDARD=LVCMOS33
Record=Constraint | TargetKind=Port | TargetId=TEST_BUTTON | FPGA_PINNUM=T15 | FPGA_IOSTANDARD=LVTTL33



・次に、プロジェクトメニューからプロジェクトのコンパイルをした。

・デバイスビューを見てみると、FPGAのメニューがデバイスの上に出てきた。(現在の状態はミスって最初のコンパイルを行った状態で青丸になっている)
Altium_Desiger_FPGA_19_120420.png

・最初の項目のCompile を実行した状態だ。ワーニングが出ている。
Altium_Desiger_FPGA_20_120420.png

・次にSynthesize を行った。メッセージでは Compile successful,no error found. が出ている。
Altium_Desiger_FPGA_21_120420.png

・Build をしたらリザルトサマリが出た。ビットファイルまで生成されたようだ。
Altium_Desiger_FPGA_22_120420.png

・Map Design To FPGA のOpen Report File をクリックしてみた。
Altium_Desiger_FPGA_23_120420.png

・おなじみのISEのMAPリポートが表示された。
Altium_Desiger_FPGA_24_120420.png

・Program FPGA でエラーが出てしまった。
Altium_Desiger_FPGA_25_120420.png

・エラーは出たが、Spartan-3A Starter Kit のDONEランプはコンフィギュレーションの時に消えて、新たに点灯しているし、ボタンを押すと何らかの動作はするので、何らかのコンフィギュレーションはできているようだ。

  1. 2012年04月20日 05:24 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

Zynq 7000 EPP in Action - Exploring the Low Cost Zedboard

Xilinx 社の Zynq-7000 EPP ボードとキット のページには、ZedBoard の項目がある。登録すると情報を送ってくるとのことだった。登録したけど、まだ送られていない。
昨日、YouTubeで、”Zynq 7000 EPP in Action - Exploring the Low Cost Zedboard”のビデオを見つけた。
ZedBoardが写っている。コンパクトで音声入出力があるみたいだ。よく見えないけど、LANやディスプレイ出力もあるのだろう?(推測)どうやらAvnet社の展示会Xfest で見られるのかも?
  1. 2012年04月19日 20:50 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

Altium Designer のFPGA設計入門をやってみる2

Altium Designer のFPGA設計入門をやってみる1(準備編)”の続き。

今回は、”チュートリアル - FPGA 設計入門”と”Using Altium Designer with a Third-Party Board”を見ながらチュートリアルをやってみることにした。ただし、チュートリアルはNano Board用なので、適宜ビデオを見ながらやり方を探っていく。チュートリアルはすでに出来ているものを使用したので、デザインの入力は省略した。

・チュートリアルを開くとこんな感じだ。(すでにConstraint ファイルを生成してあるのは見ないことにしてください)
Altium_Desiger_FPGA_5_120419.png

・ファイルメニューから新規 -> その他 -> コンストレイント ファイル を選択する。
Altium_Desiger_FPGA_6_120419.png

・コンストレイント ファイルが開く。
Altium_Desiger_FPGA_7_120419.png

・Spa3ASKit_Altium.ucf を作った。その内容を下に示す。

NET "SW<0>" LOC = "V8" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<1>" LOC = "U10"| IOSTANDARD = LVTTL | PULLUP ;
NET "SW<2>" LOC = "U8" | IOSTANDARD = LVTTL | PULLUP ;
NET "TEST_BUTTON" LOC = "T15" | IOSTANDARD = LVTTL | PULLDOWN ;
NET "LEDS<7>" LOC = "W21" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<6>" LOC = "Y22" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<5>" LOC = "V20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<4>" LOC = "V19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<3>" LOC = "U19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<2>" LOC = "U20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<1>" LOC = "T19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<0>" LOC = "R20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "CLK_REF" LOC = "E12"| IOSTANDARD = LVCMOS33 ;
NET "CLK_REF" PERIOD = 20.0ns HIGH 40%;


・デザインメニューからPinファイルのレポート -> ファイル選択 を選択する。
Altium_Desiger_FPGA_8_120419.png

・Open FPGA Vender PIN File ダイアログが開く。Spa3ASKit_Altium.ucf を選択し、開くボタンをクリックする。
Altium_Desiger_FPGA_9_120419.png

・コンストレイント エディタ設定ダイアログが開く。OKボタンをクリックする。
Altium_Desiger_FPGA_10_120419.png

・Altium Designer のコンストレイント・ファイルに制約が追加された。
Altium_Desiger_FPGA_11_120419.png

追加された制約を下に示す。

Record=Constraint | TargetKind=Port | TargetId=LEDS[7..0] | FPGA_PINNUM=W21,Y22,V20,V19,U19,U20,T19,R20 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_DRIVE=4mA,4mA,4mA,4mA,4mA,4mA,4mA,4mA
Record=Constraint | TargetKind=Port | TargetId=SW[7..0] | FPGA_PINNUM=,,,,,U8,U10,V8 | FPGA_IOSTANDARD=,,,,,LVTTL33,LVTTL33,LVTTL33
Record=Constraint | TargetKind=Port | TargetId=CLK_REF | FPGA_PINNUM=E12 | FPGA_IOSTANDARD=LVCMOS33
Record=Constraint | TargetKind=Port | TargetId=TEST_BUTTON | FPGA_PINNUM=T15 | FPGA_IOSTANDARD=LVTTL33


・ファイルやプロジェクトを保存しておく

・プロジェクトメニューからコンフィギュレーション マネージャを開く。
Altium_Desiger_FPGA_12_120419.png

・コンフィギュレーション マネージャが開く。コンフィギュレーションの追加ボタンをクリックし、Spartan3A_Starter_Kit_Demo を追加した。下のコンストレイント ファイルでは、チェックボックスをチェックした。OKボタンをクリックする。
Altium_Desiger_FPGA_13_120419.png

・エラーが出てしまった。
Altium_Desiger_FPGA_14_120419.png

Nono Board用のライブラリを使っているせいかもしれない。Nono Board用のライブラリを外してみようと思う。Nano Board でないという設定がどこかにあるのだろうか?


1つ面白い機能があったので、紹介しておく。

・Devices でSpartan3A を右クリックしてインストゥルメントを選択する。
Altium_Desiger_FPGA_15_120419.png

・Instrument Rack が開く。JTAG Viewer Panel ボタンをクリックする。
Altium_Desiger_FPGA_16_120419.png

・XC3S700A-4FGG484C Pin Status on JTAG 0 ダイアログが表示されて、Live更新チェックボックを入れておくと、リアルタイムにFPGAのピンの状況が見える。実際に見ていると、右下のFPGAのパッケージのピンの赤い点がチカチカしている。
Altium_Desiger_FPGA_17_120419.png
  1. 2012年04月19日 05:44 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

Altium Designer のFPGA設計入門をやってみる1(準備編)

Altium Designer は回路図、PCB設計だけでなく、FPGA設計やソフトウエア開発ができる統合ツールだ。FPGA設計はVHDLやVerilogだけでなく、C to Hardware 機能も付いている。FPGA設計機能を確かめてみたいと思っていたのだが、Altium's Universal JTAG Interface がないとFPGAをコンフィギュレーションすることができない。
今回、FPGA-CAFE からAltium's Universal JTAG Interface をお借りすることができたので、Altium のFPGA設計をやってみたい。(参照ページ、Using Altium Designer with a Third-Party Board

下の写真は、Spratan-3A Starter Kit にAltium's Universal JTAG Interface を接続したところだ。
Altium_Desiger_FPGA_1_120418.jpg

Altium's Universal JTAG Interfaceは、Hardware のJTAGコネクタに接続するのはもちろんだが、Soft JTAGもあってFPGAの汎用ピンに接続する。この接続方法は、Using Altium Designer with a custom or 3rd-party FPGA dev board (youtube です)のやり方を見て接続した。

Altium Designer でDevice を表示させるとSpartan-3Aが見つかったが、ISEが未サポートだと言われてしまった。
Altium_Desiger_FPGA_2_120418.png

このパソコンには、ISE10.1から11.1、12.1 とインストールしてあるので、後でISEのバージョンを変える方法を探ってみようと思う。もしかして、環境変数に登録すれば良いのか?今のところ最新の13.4のパスを登録してある。

次回から、”チュートリアル - FPGA 設計入門”を参考にチュートリアルをやってみたい。

(2012/04/19:追加)
shigeji さんに教えていただいたので、ISEが未サポートだと言われた問題を解消できました。

ツールメニューからプリファレンス -> FPGA -> Device View を選択して、フローオプションの”ペンダツールのバージョンは確認しない”のチェックボックスにチェックを入れました。
Altium_Desiger_FPGA_3_120418.png

そうしたところ、Devices の画面は正常になりました。
Altium_Desiger_FPGA_4_120418.png
  1. 2012年04月18日 05:49 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:3

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製4

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製3”の続き。

前回ブログにVHDLコードを貼ったaxi_master_BFM.vhd のRAMをbit_vector のarray にしてもstd_logic_vector のarray と僅かな差しかないとのご指摘をツイッターで受けたのでやってみました。

・bit_vector 版

宣言部分
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));

インスタンス部分
    -- RAM
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if cdc_we='1' then
                for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
                    if M_AXI_WSTRB(i)='1' then -- Byte Enable
                        ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
                    end if;
                end loop;
            end if;
        end if;
    end process;
    M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));


・std_logic_vector版

宣言部分
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));

インスタンス部分
    -- RAM
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if cdc_we='1' then
                for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
                    if M_AXI_WSTRB(i)='1' then -- Byte Enable
                        ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= M_AXI_WDATA(i*8+7 downto i*8);
                    end if;
                end loop;
            end if;
        end if;
    end process;
    M_AXI_RDATA <= ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)));


この2つのメモリ使用量とシミュレーション時間を比較してみました。メモリ消費量はタスクマネージャーで比べたので、余り正確ではないです。シミュレーション時間は1usec ~ 1.001msec の1msec 間のシミュレーション時間をiPhone のストップウォッチで計測しました。なお、シミュレーション時間はシミュレーション時間が長くなるほど多くかかるようです。(1usec ~ 1.001msec の1msec 間のシミュレーション時間よりも、1.001usec ~ 2.001msec の1msec 間のシミュレーション時間の方が長い)

bit_vector 版、   メモリ消費量170MB、シミュレーション時間 2.8sec
std_logic_vector版、 メモリ消費量180MB、シミュレーション時間 2.8sec

std_logic_vector版のほうが少しだけメモリ消費量が多いような気がしますが、メモリ消費量の有効数字は2ケタなので、誤差範囲内のような気がします。
よって、std_logic_vector版を使用することにします。
  1. 2012年04月17日 05:00 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製3

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製2”の続き。

axi_master_BFM.vhd を貼っておく。
Writeデータ転送時にランダムなWaitを発生できるようにしてある (WRITE_RANDOM_WAIT=1)。Readデータ転送時はWaitしない設定 (READ_RANDOM_WAIT=0) にしてある。

-----------------------------------------------------------------------------
--
-- AXI Master用 Bus Function Mode (BFM)
--
-----------------------------------------------------------------------------
-- 2012/02/25 : M_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;

package m_seq_bfm_pack is
    function M_SEQ16_BFM_F(mseq16in : std_logic_vector
        )return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
    function M_SEQ16_BFM_F(mseq16in : std_logic_vector
        )return std_logic_vector is
            variable mseq16 : std_logic_vector(15 downto 0);
            variable xor_result : std_logic;
    begin
        xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
        mseq16 := mseq16in(14 downto 0) & xor_result;
        return mseq16;
    end M_SEQ16_BFM_F;
end m_seq_bfm_pack;


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

library work;
use work.m_seq_bfm_pack.all;

--library unisim;
--use unisim.vcomponents.all;

entity axi_master_bfm is
  generic (
    C_M_AXI_ID_WIDTH     : integer := 1;
    C_M_AXI_ADDR_WIDTH   : integer := 32;
    C_M_AXI_DATA_WIDTH   : integer := 32;
    C_M_AXI_AWUSER_WIDTH : integer := 1;
    C_M_AXI_ARUSER_WIDTH : integer := 1;
    C_M_AXI_WUSER_WIDTH  : integer := 1;
    C_M_AXI_RUSER_WIDTH  : integer := 1;
    C_M_AXI_BUSER_WIDTH  : integer := 1;
    
    C_M_AXI_TARGET        : integer := 0;
    C_OFFSET_WIDTH        : integer := 10; -- 割り当てるRAMのアドレスのビット幅
    C_M_AXI_BURST_LEN    : integer := 256;
    
    WRITE_RANDOM_WAIT    : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
    READ_RANDOM_WAIT    : integer := 0 -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
    );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Master Interface Write Address Ports
    M_AXI_AWID     : in  std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_AWADDR   : in  std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_AWLEN    : in  std_logic_vector(8-1 downto 0);
    M_AXI_AWSIZE   : in  std_logic_vector(3-1 downto 0);
    M_AXI_AWBURST  : in  std_logic_vector(2-1 downto 0);
    -- M_AXI_AWLOCK   : in  std_logic_vector(2-1 downto 0);
    M_AXI_AWLOCK   : in  std_logic;
    M_AXI_AWCACHE  : in  std_logic_vector(4-1 downto 0);
    M_AXI_AWPROT   : in  std_logic_vector(3-1 downto 0);
    M_AXI_AWQOS    : in  std_logic_vector(4-1 downto 0);
    M_AXI_AWUSER   : in  std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
    M_AXI_AWVALID  : in  std_logic;
    M_AXI_AWREADY  : out std_logic;

    -- Master Interface Write Data Ports
    M_AXI_WDATA  : in  std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_WSTRB  : in  std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
    M_AXI_WLAST  : in  std_logic;
    M_AXI_WUSER  : in  std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
    M_AXI_WVALID : in  std_logic;
    M_AXI_WREADY : out std_logic;

    -- Master Interface Write Response Ports
    M_AXI_BID    : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_BRESP  : out std_logic_vector(2-1 downto 0);
    M_AXI_BUSER  : out std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
    M_AXI_BVALID : out std_logic;
    M_AXI_BREADY : in  std_logic;

    -- Master Interface Read Address Ports
    M_AXI_ARID     : in  std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_ARADDR   : in  std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_ARLEN    : in  std_logic_vector(8-1 downto 0);
    M_AXI_ARSIZE   : in  std_logic_vector(3-1 downto 0);
    M_AXI_ARBURST  : in  std_logic_vector(2-1 downto 0);
    M_AXI_ARLOCK   : in  std_logic_vector(2-1 downto 0);
    M_AXI_ARCACHE  : in  std_logic_vector(4-1 downto 0);
    M_AXI_ARPROT   : in  std_logic_vector(3-1 downto 0);
    M_AXI_ARQOS    : in  std_logic_vector(4-1 downto 0);
    M_AXI_ARUSER   : in  std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
    M_AXI_ARVALID  : in  std_logic;
    M_AXI_ARREADY  : out std_logic;

    -- Master Interface Read Data Ports
    M_AXI_RID    : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_RDATA  : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_RRESP  : out std_logic_vector(2-1 downto 0);
    M_AXI_RLAST  : out std_logic;
    M_AXI_RUSER  : out std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
    M_AXI_RVALID : out std_logic;
    M_AXI_RREADY : in  std_logic
    );

end axi_master_bfm;

architecture implementation of axi_master_bfm is

constant    AxBURST_FIXED    : std_logic_vector := "00";
constant    AxBURST_INCR    : std_logic_vector := "01";
constant    AxBURST_WRAP    : std_logic_vector := "10";

constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

constant    DATA_BUS_BYTES     : natural := C_M_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant    ADD_INC_OFFSET    : natural := natural(log(real(DATA_BUS_BYTES), 2.0));

-- RAMの生成
constant    SLAVE_ADDR_NUMBER    : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));

-- for write transaction
type write_transaction_state is (idle_wr, awr_wait, awr_accept, wr_burst);
type write_response_state is (idle_wres, bvalid_assert);
type write_wready_state is (idle_wrdy, wready_assert);
signal wrt_cs : write_transaction_state;
signal wrres : write_response_state;
signal wrwr : write_wready_state;
signal addr_inc_step_wr : integer := 1;
signal awready         : std_logic;
signal wr_addr         : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bid         : std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp     : std_logic_vector(1 downto 0);
signal wr_bvalid     : std_logic;
signal m_seq16_wr    : std_logic_vector(15 downto 0);
signal wready        : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;

-- for read transaction
type read_transaction_state is (idle_rd, arr_wait, arr_accept, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdt_cs : read_transaction_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready         : std_logic;
signal rd_addr         : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count    : std_logic_vector(7 downto 0);
signal rvalid        : std_logic;
signal rlast        : std_logic;
signal m_seq16_rd    : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;

signal reset_1d, reset_2d, reset : std_logic := '1';

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- AXI4バス Write Transaction State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wrt_cs <= idle_wr;
                awready <= '0';
            else
                case (wrt_cs) is
                    when idle_wr =>
                        if M_AXI_AWVALID='1' then -- M_AXI_AWVALID が1にアサートされた
                            if rdt_cs=idle_rd then -- Read Transaction が終了している(Writeの方が優先順位が高い)
                                wrt_cs <= awr_accept;
                                awready <= '1';
                            else -- Read Transaction が終了していないのでWait
                                wrt_cs <= awr_wait;
                            end if;
                        end if;
                    when awr_wait => -- Read Transaction の終了待ち
                        if rdt_cs=idle_rd or rdt_cs=arr_wait then -- Read Transaction が終了
                            wrt_cs <= awr_accept;
                            awready <= '1';
                        end if;
                    when awr_accept => -- M_AXI_AWREADY をアサート
                        wrt_cs <= wr_burst;
                        awready <= '0';
                    when wr_burst => -- Writeデータの転送
                        if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
                            wrt_cs <= idle_wr;
                        end if;
                end case;
            end if;
        end if;
    end process;
    M_AXI_AWREADY <= awready;
    
    -- m_seq_wr、16ビットのM系列を計算する
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                m_seq16_wr <= (0 => '1', others => '0');
            else
                if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
                    if wrt_cs=wr_burst and M_AXI_WVALID='1' then
                        m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
                    end if;
                else -- Wait無し
                    m_seq16_wr <= (others => '0');
                end if;
            end if;
        end if;
    end process;
                
    -- wready の処理、M系列を計算して128以上だったらWaitする。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                cs_wready <= idle_wready;
                wready <= '0';
            else
                case (cs_wready) is
                    when idle_wready =>
                        if wrt_cs=awr_accept then -- 次はwr_burst
                            if m_seq16_wr(7)='0' then -- wready='1'
                                cs_wready <= assert_wready;
                                wready <= '1';
                            else -- m_seq16_wr(7)='1' then -- wready='0'
                                cs_wready <= deassert_wready;
                                wready <= '0';
                            end if;
                        end if;
                    when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
                        if wrt_cs=wr_burst and M_AXI_WLAST='1' and M_AXI_WVALID='1' then -- 終了
                            cs_wready <= idle_wready;
                            wready <= '0';
                        elsif wrt_cs=wr_burst and M_AXI_WVALID='1' then -- 1つのトランザクション終了。
                            if m_seq16_wr(7)='1' then
                                cs_wready <= deassert_wready;
                                wready <= '0';
                            end if;
                        end if;
                    when deassert_wready =>
                        if m_seq16_wr(7)='0' then -- wready='1'
                            cs_wready <= assert_wready;
                            wready <= '1';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    M_AXI_WREADY <= wready;
    cdc_we <= '1' when wrt_cs=wr_burst and wready='1' and M_AXI_WVALID='1' else '0';
    
    -- addr_inc_step_wr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                addr_inc_step_wr <= 1;
            else
                if wrt_cs=awr_accept then
                    case (M_AXI_AWSIZE) is
                        when "000" => -- 8ビット転送
                            addr_inc_step_wr <= 1;
                        when "001" => -- 16ビット転送
                            addr_inc_step_wr <= 2;
                        when "010" => -- 32ビット転送
                            addr_inc_step_wr <= 4;
                        when "011" => -- 64ビット転送
                            addr_inc_step_wr <= 8;
                        when "100" => -- 128ビット転送
                            addr_inc_step_wr <= 16;
                        when "101" => -- 256ビット転送
                            addr_inc_step_wr <= 32;
                        when "110" => -- 512ビット転送
                            addr_inc_step_wr <= 64;
                        when others => --"111" => -- 1024ビット転送
                            addr_inc_step_wr <= 128;
                    end case;
                end if;
            end if;
        end if;
    end process;
    
    -- wr_addr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_addr <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    wr_addr <= M_AXI_AWADDR(C_OFFSET_WIDTH-1 downto 0);
                elsif wrt_cs=wr_burst and M_AXI_WVALID='1' and wready='1' then -- アドレスを進める
                    wr_addr <= wr_addr + addr_inc_step_wr;
                end if;
            end if;
        end if;
    end process;
    
    -- wr_bid の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_bid <= "0";
            else
                if wrt_cs=awr_accept then
                    wr_bid <= M_AXI_AWID;
                end if;
            end if;
        end if;
    end process;
    M_AXI_BID <= wr_bid;
    
    -- wr_bresp の処理
    -- M_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_bresp <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    if M_AXI_AWBURST=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
                        wr_bresp <= RESP_OKAY; -- Write Transaction は成功
                    else
                        wr_bresp <= RESP_SLVERR; -- エラー
                    end if;
                end if;
            end if;
        end if;
    end process;
    M_AXI_BRESP <= wr_bresp;
    
    -- wr_bvalid の処理
    -- Write Transaction State Machineには含まない。axi_master のシミュレーションを見ると1クロックで終了しているので、長い間、Master側の都合でWaitしていることは考えない。
    -- 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れてブロックすることも考える必要がある。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_bvalid <= '0';
            else
                if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
                    wr_bvalid <= '1';
                elsif wr_bvalid='1' and M_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
                    wr_bvalid <= '0';
                end if;
            end if;
        end if;
    end process;
    M_AXI_BVALID <= wr_bvalid;
    M_AXI_BUSER <= (others => '0');
    
    
    -- AXI4バス Read Transaction State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rdt_cs <= idle_rd;
                arready <= '0';
            else
                case (rdt_cs) is
                    when idle_rd =>
                        if M_AXI_ARVALID='1' then -- Read Transaction 要求
                            if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
                                rdt_cs <= arr_accept;
                                arready <= '1';
                            else -- Write Transaction が終了していないのでWait
                                rdt_cs <= arr_wait;
                            end if;
                        end if;
                    when arr_wait => -- Write Transaction の終了待ち
                        if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
                            rdt_cs <= arr_accept;
                            arready <= '1';
                        end if;
                    when arr_accept => -- M_AXI_ARREADY をアサート
                        rdt_cs <= rd_burst;
                        arready <= '0';
                    when rd_burst => -- Readデータの転送
                        if rd_axi_count=0 and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了
                            rdt_cs <= idle_rd;
                        end if;
                end case;
            end if;
        end if;
    end process;
    M_AXI_ARREADY <= arready;

    -- m_seq_rd、16ビットのM系列を計算する
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
            else
                if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
                    if rdt_cs=rd_burst and M_AXI_RREADY='1' then
                        m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
                    end if;
                else -- Wati無し
                    m_seq16_rd <= (others => '0');
                end if;
            end if;
        end if;
    end process;
                
    -- rvalid の処理、M系列を計算して128以上だったらWaitする。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                cs_rvalid <= idle_rvalid;
                rvalid <= '0';
            else
                case (cs_rvalid) is
                    when idle_rvalid =>
                        if rdt_cs=arr_accept then -- 次はrd_burst
                            if m_seq16_rd(7)='0' then -- rvalid='1'
                                cs_rvalid <= assert_rvalid;
                                rvalid <= '1';
                            else -- m_seq16_rd(7)='1' then -- rvalid='0'
                                cs_rvalid <= deassert_rvalid;
                                rvalid <= '0';
                            end if;
                        end if;
                    when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
                        if rdt_cs=rd_burst and rlast='1' and M_AXI_RREADY='1' then -- 終了
                            cs_rvalid <= idle_rvalid;
                            rvalid <= '0';
                        elsif rdt_cs=rd_burst and M_AXI_RREADY='1' then -- 1つのトランザクション終了。
                            if m_seq16_rd(7)='1' then
                                cs_rvalid <= deassert_rvalid;
                                rvalid <= '0';
                            end if;
                        end if;
                    when deassert_rvalid =>
                        if m_seq16_rd(7)='0' then -- rvalid='1'
                            cs_rvalid <= assert_rvalid;
                            rvalid <= '1';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    M_AXI_RVALID <= rvalid;
    
    -- addr_inc_step_rd の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                addr_inc_step_rd <= 1;
            else
                if rdt_cs=arr_accept then
                    case (M_AXI_ARSIZE) is
                        when "000" => -- 8ビット転送
                            addr_inc_step_rd <= 1;
                        when "001" => -- 16ビット転送
                            addr_inc_step_rd <= 2;
                        when "010" => -- 32ビット転送
                            addr_inc_step_rd <= 4;
                        when "011" => -- 64ビット転送
                            addr_inc_step_rd <= 8;
                        when "100" => -- 128ビット転送
                            addr_inc_step_rd <= 16;
                        when "101" => -- 256ビット転送
                            addr_inc_step_rd <= 32;
                        when "110" => -- 512ビット転送
                            addr_inc_step_rd <= 64;
                        when others => -- "111" => -- 1024ビット転送
                            addr_inc_step_rd <= 128;
                    end case;
                end if;
            end if;
        end if;
    end process;
    
    -- rd_addr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rd_addr <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    rd_addr <= M_AXI_ARADDR(C_OFFSET_WIDTH-1 downto 0);
                elsif rdt_cs=rd_burst and M_AXI_RREADY='1' and rvalid='1' then
                    rd_addr <= rd_addr + addr_inc_step_rd;
                end if;
            end if;
        end if;
    end process;
    
    -- rd_axi_count の処理(AXIバス側のデータカウント)
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rd_axi_count <= (others => '0');
            else
                if rdt_cs=arr_accept then -- rd_axi_count のロード
                    rd_axi_count <= M_AXI_ARLEN;
                elsif rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
                    rd_axi_count <= rd_axi_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- rdlast State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rdlast <= idle_rlast;
                rlast <= '0';
            else
                case (rdlast) is
                    when idle_rlast =>
                        if rd_axi_count=1 and rvalid='1' and M_AXI_RREADY='1' then -- バーストする場合
                            rdlast <= rlast_assert;
                            rlast <= '1';
                        elsif rdt_cs=arr_accept and M_AXI_ARLEN=0 then -- 転送数が1の場合
                            rdlast <= rlast_assert;
                            rlast <= '1';
                        end if;
                    when rlast_assert => 
                        if rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
                            rdlast <= idle_rlast;
                            rlast <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    M_AXI_RLAST <= rlast;
    
    -- M_AXI_RID, M_AXI_RUSER の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                M_AXI_RID <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    M_AXI_RID <= M_AXI_ARID;
                end if;
            end if;
        end if;
    end process;
    M_AXI_RUSER <= (others => '0');
    
    -- M_AXI_RRESP は、M_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                M_AXI_RRESP <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    if M_AXI_ARBURST=AxBURST_INCR then
                        M_AXI_RRESP <= RESP_OKAY;
                    else
                        M_AXI_RRESP <= RESP_SLVERR;
                    end if;
                end if;
            end if;
        end if;
    end process;
    
    -- RAM
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if cdc_we='1' then
                for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
                    if M_AXI_WSTRB(i)='1' then -- Byte Enable
                        ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
                    end if;
                end loop;
            end if;
        end if;
    end process;
    M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));

end implementation;


AWアスセスとARアクセスではAWアクセスの方の優先順位を上げてある。本当はどっちも同時でも大丈夫なのだが、Writeを早くしてあるはず。

テストベンチ (cdc_axi_master_tb.v) も貼っておく。

`default_nettype none

`timescale 100ps / 1ps

module cdctest_axi_master_tb;

    // Inputs
    wire ACLK;
    wire ARESETN;
    wire M_AXI_AWREADY;
    wire M_AXI_WREADY;
    wire [0:0] M_AXI_BID;
    wire [1:0] M_AXI_BRESP;
    wire [0:0] M_AXI_BUSER;
    wire M_AXI_BVALID;
    wire M_AXI_ARREADY;
    wire [0:0] M_AXI_RID;
    wire [31:0] M_AXI_RDATA;
    wire [1:0] M_AXI_RRESP;
    wire M_AXI_RLAST;
    wire [0:0] M_AXI_RUSER;
    wire M_AXI_RVALID;

    // Outputs
    wire [0:0] M_AXI_AWID;
    wire [31:0] M_AXI_AWADDR;
    wire [7:0] M_AXI_AWLEN;
    wire [2:0] M_AXI_AWSIZE;
    wire [1:0] M_AXI_AWBURST;
    wire M_AXI_AWLOCK;
    wire [3:0] M_AXI_AWCACHE;
    wire [2:0] M_AXI_AWPROT;
    wire [3:0] M_AXI_AWQOS;
    wire [0:0] M_AXI_AWUSER;
    wire M_AXI_AWVALID;
    wire [31:0] M_AXI_WDATA;
    wire [3:0] M_AXI_WSTRB;
    wire M_AXI_WLAST;
    wire [0:0] M_AXI_WUSER;
    wire M_AXI_WVALID;
    wire M_AXI_BREADY;
    wire [0:0] M_AXI_ARID;
    wire [31:0] M_AXI_ARADDR;
    wire [7:0] M_AXI_ARLEN;
    wire [2:0] M_AXI_ARSIZE;
    wire [1:0] M_AXI_ARBURST;
    wire [1:0] M_AXI_ARLOCK;
    wire [3:0] M_AXI_ARCACHE;
    wire [2:0] M_AXI_ARPROT;
    wire [3:0] M_AXI_ARQOS;
    wire [0:0] M_AXI_ARUSER;
    wire M_AXI_ARVALID;
    wire M_AXI_RREADY;
    wire wr_error;
    wire rd_error;

    // Instantiate the Unit Under Test (UUT_MASTER)
    cdctest_axi_master uut_master (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .M_AXI_AWID(M_AXI_AWID), 
        .M_AXI_AWADDR(M_AXI_AWADDR), 
        .M_AXI_AWLEN(M_AXI_AWLEN), 
        .M_AXI_AWSIZE(M_AXI_AWSIZE), 
        .M_AXI_AWBURST(M_AXI_AWBURST), 
        .M_AXI_AWLOCK(M_AXI_AWLOCK), 
        .M_AXI_AWCACHE(M_AXI_AWCACHE), 
        .M_AXI_AWPROT(M_AXI_AWPROT), 
        .M_AXI_AWQOS(M_AXI_AWQOS), 
        .M_AXI_AWUSER(M_AXI_AWUSER), 
        .M_AXI_AWVALID(M_AXI_AWVALID), 
        .M_AXI_AWREADY(M_AXI_AWREADY), 
        .M_AXI_WDATA(M_AXI_WDATA), 
        .M_AXI_WSTRB(M_AXI_WSTRB), 
        .M_AXI_WLAST(M_AXI_WLAST), 
        .M_AXI_WUSER(M_AXI_WUSER), 
        .M_AXI_WVALID(M_AXI_WVALID), 
        .M_AXI_WREADY(M_AXI_WREADY), 
        .M_AXI_BID(M_AXI_BID), 
        .M_AXI_BRESP(M_AXI_BRESP), 
        .M_AXI_BUSER(M_AXI_BUSER), 
        .M_AXI_BVALID(M_AXI_BVALID), 
        .M_AXI_BREADY(M_AXI_BREADY), 
        .M_AXI_ARID(M_AXI_ARID), 
        .M_AXI_ARADDR(M_AXI_ARADDR), 
        .M_AXI_ARLEN(M_AXI_ARLEN), 
        .M_AXI_ARSIZE(M_AXI_ARSIZE), 
        .M_AXI_ARBURST(M_AXI_ARBURST), 
        .M_AXI_ARLOCK(M_AXI_ARLOCK), 
        .M_AXI_ARCACHE(M_AXI_ARCACHE), 
        .M_AXI_ARPROT(M_AXI_ARPROT), 
        .M_AXI_ARQOS(M_AXI_ARQOS), 
        .M_AXI_ARUSER(M_AXI_ARUSER), 
        .M_AXI_ARVALID(M_AXI_ARVALID), 
        .M_AXI_ARREADY(M_AXI_ARREADY), 
        .M_AXI_RID(M_AXI_RID), 
        .M_AXI_RDATA(M_AXI_RDATA), 
        .M_AXI_RRESP(M_AXI_RRESP), 
        .M_AXI_RLAST(M_AXI_RLAST), 
        .M_AXI_RUSER(M_AXI_RUSER), 
        .M_AXI_RVALID(M_AXI_RVALID), 
        .M_AXI_RREADY(M_AXI_RREADY), 
        .wr_error(wr_error), 
        .rd_error(rd_error)
    );

    // clk_gen のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );

    // Instantiate the Unit Under Test (UUT_slave)
    axi_master_bfm uut_slave (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .M_AXI_AWID(M_AXI_AWID), 
        .M_AXI_AWADDR(M_AXI_AWADDR), 
        .M_AXI_AWLEN(M_AXI_AWLEN), 
        .M_AXI_AWSIZE(M_AXI_AWSIZE), 
        .M_AXI_AWBURST(M_AXI_AWBURST), 
        .M_AXI_AWLOCK(M_AXI_AWLOCK), 
        .M_AXI_AWCACHE(M_AXI_AWCACHE), 
        .M_AXI_AWPROT(M_AXI_AWPROT), 
        .M_AXI_AWQOS(M_AXI_AWQOS), 
        .M_AXI_AWUSER(M_AXI_AWUSER), 
        .M_AXI_AWVALID(M_AXI_AWVALID), 
        .M_AXI_AWREADY(M_AXI_AWREADY), 
        .M_AXI_WDATA(M_AXI_WDATA), 
        .M_AXI_WSTRB(M_AXI_WSTRB), 
        .M_AXI_WLAST(M_AXI_WLAST), 
        .M_AXI_WUSER(M_AXI_WUSER), 
        .M_AXI_WVALID(M_AXI_WVALID), 
        .M_AXI_WREADY(M_AXI_WREADY), 
        .M_AXI_BID(M_AXI_BID), 
        .M_AXI_BRESP(M_AXI_BRESP), 
        .M_AXI_BUSER(M_AXI_BUSER), 
        .M_AXI_BVALID(M_AXI_BVALID), 
        .M_AXI_BREADY(M_AXI_BREADY), 
        .M_AXI_ARID(M_AXI_ARID), 
        .M_AXI_ARADDR(M_AXI_ARADDR), 
        .M_AXI_ARLEN(M_AXI_ARLEN), 
        .M_AXI_ARSIZE(M_AXI_ARSIZE), 
        .M_AXI_ARBURST(M_AXI_ARBURST), 
        .M_AXI_ARLOCK(M_AXI_ARLOCK), 
        .M_AXI_ARCACHE(M_AXI_ARCACHE), 
        .M_AXI_ARPROT(M_AXI_ARPROT), 
        .M_AXI_ARQOS(M_AXI_ARQOS), 
        .M_AXI_ARUSER(M_AXI_ARUSER), 
        .M_AXI_ARVALID(M_AXI_ARVALID), 
        .M_AXI_ARREADY(M_AXI_ARREADY), 
        .M_AXI_RID(M_AXI_RID), 
        .M_AXI_RDATA(M_AXI_RDATA), 
        .M_AXI_RRESP(M_AXI_RRESP), 
        .M_AXI_RLAST(M_AXI_RLAST), 
        .M_AXI_RUSER(M_AXI_RUSER), 
        .M_AXI_RVALID(M_AXI_RVALID), 
        .M_AXI_RREADY(M_AXI_RREADY)
    );
      
endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


cdctest_axi_master.vhd は、”AXI4マスタIPの作製2(単体シミュレーション)”に貼ってあります。

なお、今までのコードもそうですが無保証です。ご自分の責任でお使いください。商用に使用する場合はご相談ください。
  1. 2012年04月15日 20:20 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

エレキジャック・フォーラム2012に行って来ました

今日はエレキジャック・フォーラム2012に行って来ました。

最初に基調講演を聞いてきました。ボーカロイドの元となる音素片音声合成のエンジンを作った方です。ご自身も音楽が趣味でバイオリンだったかな?を引いてらっしゃる方だそうです。母音ー子音、子音―母音の変化を細かくサンプルして、ピッチを合わせたり、なめらかにしながら合成しているそうです。あと、楽器の音の周波数は一定ですが、人間の音声は揺らいでいるので、その揺らぎも再現しているとのことでした。凄いですね。
ボーカロイドの操作画面も初めて見ました。簡単そうでした。欲しくなりました。iPhone版もあるとのことなので買ってみようかな?

展示はいろいろと楽しいのがありました。ちっちゃいものくらぶさんが出ていて、NanoBoard AGのキットを購入しました。楽しみです。モーター付きでした。スクラッチで簡単に動かせるそうです。
eleki-jack_1_120414.jpg
eleki-jack_2_120414.jpg

Simさんにもお会いして、hamayan さんを紹介して頂きました。ご両方とも、ありがとうございました。

そのあとでショートプレゼンを聞いてきました。
ショートプレゼンの会場の様子です。今年はショートプレゼンのスペースが大きくて聞き易かったです。
eleki-jack_3_120414.jpg

飯島 幸太 氏 B-1  おさんぽガイガーG ~ Androidでスマートな放射線測定 ~
途中から聞いたんですが、お散歩時の放射線測定でも犬の話でした。人間の話もあったのかな?

れすぽん 氏 B-3  片面感光基板で作るFPGA基板 / 基板少女の裏の裏
基板を作る話でした。裏面に女の子の絵柄が入っています。裏表にコネクタへのパターンがあるので、上下どっちの向きに基板を付けても良いそうです。

内藤 竜治 氏/特殊電子回路(株) B-4  RXマイコンとAndroid携帯でいつでもどこでも電子工作!
後でブースで説明を受けたんですが、Android とRXマイコンを接続する話でした。最近、Android の勉強をしているので、興味深く聞かせて頂きました。私の持っているAndroid は2.1 なので、ADKは使えずADBのみの対応のようです。勉強になりました。

会場の様子です。まだ午前中なので、そんなに混んでいない時です。
eleki-jack_4_120414.jpg

セミナは結局、2つ見てきました。
A-4  オープン・ソース・ハードウェア“Arduino”用の3G通信拡張キットが登場
最初の講師の方の喋り方が早口でジャパネットタカタの社長さんみたいでした、声質は違いますが。
タイトル通りのお話でしたが、途中でスイッチ・サイエンスの方に交代して、スイッチ・サイエンスでUSB接続の3Gシールドの紹介がありました。USB接続の3Gモジュールを挿してArduino の接続できるシールドです。とっても良さそうでした。
あと、センサーデータは、Pachube(パッチベイ)に上げているそうです。このサイトとっても便利そうでした。

A-5  手作りカメラで宇宙の渚の撮影に挑戦
これは凄かったです。ブラボーです。森岡さんが高層気球で宇宙の撮影に挑戦した話です。NHKでやっていたんですね。ツイッターでもレ聞いていたんですが、内容は知りませんでした。10台のカメラシステムを自作して高層圏の画像を360度取ってきたとのことです。-60度から放熱のできない宇宙での使用に耐えるシステムを作った話でした。とっても面白かったです。

ラズベリーパイも見てきました。欲しくなりましたね。ケースを自作したいです。
eleki-jack_5_120414.jpg

とっても面白かったです。来年も行きたい。
  1. 2012年04月14日 20:34 |
  2. エレキジャック・フォーラム
  3. | トラックバック:0
  4. | コメント:0

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製2

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製1”の続き。

ここでは、AXI4マスタIPを自作して、それを単体テストするために、AXI4スレーブIPの代わりのBFMモデルを作成している。(axi_master_BFM.vhd)

一応完成したので、cdctest_axi_master.vhd と接続してテストしてみた。
シミュレーションを行ったので、その結果を下に示す。まずはWrite Transaction。Writeデータ転送時にランダムなWaitを発生できるようにしてある (WRITE_RANDOM_WAIT=1) が、現在はWaitしない設定 (WRITE_RANDOM_WAIT=0) にしてある。
cdctest_axi_master_20_120414.png

次にRead Transactionのシミュレーション波形を下に示す。Readデータ転送時にランダムなWaitを発生できるようにしてある (READ_RANDOM_WAIT=1) が、現在はWaitしない設定 (READ_RANDOM_WAIT=0) にしてある。
cdctest_axi_master_21_120414.png

axi_master_BFM.vhdは論理合成可能でもある。試しにインプリメントしてみた。
”C_OFFSET_WIDTH : integer := 8; -- 割り当てるRAMのアドレスのビット幅”の場合だ。余り大きな領域を割り当てると論理合成に時間がかかるし、FPGAに入らなくなってしまう。Project Navigator の画面を下に示す。
cdctest_axi_master_22_120414.png

MAPリポート (axi_master_bfm_map.mrp) の一部を下に示す。

Release 13.4 Map O.87xd (nt)
Xilinx Mapping Report File for Design 'axi_master_bfm'

Design Information
------------------
Command Line   : map -intstyle ise -p xc6slx45-csg324-2 -w -logic_opt off -ol
high -t 1 -xt 0 -register_duplication off -r 4 -global_opt off -mt off -ir off
-pr off -lc off -power off -o axi_master_bfm_map.ncd axi_master_bfm.ngd
axi_master_bfm.pcf 
Target Device  : xc6slx45
Target Package : csg324
Target Speed   : -2
Mapper Version : spartan6 -- $Revision: 1.55 $
Mapped Date    : SAT 14 APR 4:40:4 2012

Design Summary
--------------
Number of errors:      0
Number of warnings:    0
Slice Logic Utilization:
  Number of Slice Registers:                 2,121 out of  54,576    3%
    Number used as Flip Flops:               2,121
    Number used as Latches:                      0
    Number used as Latch-thrus:                  0
    Number used as AND/OR logics:                0
  Number of Slice LUTs:                      2,848 out of  27,288   10%
    Number used as logic:                    2,845 out of  27,288   10%
      Number using O6 output only:           2,817
      Number using O5 output only:               0
      Number using O5 and O6:                   28
      Number used as ROM:                        0
    Number used as Memory:                       1 out of   6,408    1%
      Number used as Dual Port RAM:              0
      Number used as Single Port RAM:            0
      Number used as Shift Register:             1
        Number using O6 output only:             1
        Number using O5 output only:             0
        Number using O5 and O6:                  0
    Number used exclusively as route-thrus:      2
      Number with same-slice register load:      2
      Number with same-slice carry load:         0
      Number with other load:                    0

Slice Logic Distribution:
  Number of occupied Slices:                   918 out of   6,822   13%
  Nummber of MUXCYs used:                       24 out of  13,644    1%
  Number of LUT Flip Flop pairs used:        2,858
    Number with an unused Flip Flop:           743 out of   2,858   25%
    Number with an unused LUT:                  10 out of   2,858    1%
    Number of fully used LUT-FF pairs:       2,105 out of   2,858   73%
    Number of unique control sets:               9
    Number of slice register sites lost
      to control set restrictions:              30 out of  54,576    1%

  A LUT Flip Flop pair for this architecture represents one LUT paired with
  one Flip Flop within a slice.  A control set is a unique combination of
  clock, reset, set, and enable signals for a registered element.
  The Slice Logic Distribution report is not meaningful if the design is
  over-mapped for a non-slice resource or if Placement fails.

IO Utilization:
  Number of bonded IOBs:                       126 out of     218   57%

Specific Feature Utilization:
  Number of RAMB16BWERs:                         0 out of     116    0%
  Number of RAMB8BWERs:                          0 out of     232    0%
  Number of BUFIO2/BUFIO2_2CLKs:                 0 out of      32    0%
  Number of BUFIO2FB/BUFIO2FB_2CLKs:             0 out of      32    0%
  Number of BUFG/BUFGMUXs:                       1 out of      16    6%
    Number used as BUFGs:                        1
    Number used as BUFGMUX:                      0
  Number of DCM/DCM_CLKGENs:                     0 out of       8    0%
  Number of ILOGIC2/ISERDES2s:                   0 out of     376    0%
  Number of IODELAY2/IODRP2/IODRP2_MCBs:         0 out of     376    0%
  Number of OLOGIC2/OSERDES2s:                   0 out of     376    0%
  Number of BSCANs:                              0 out of       4    0%
  Number of BUFHs:                               0 out of     256    0%
  Number of BUFPLLs:                             0 out of       8    0%
  Number of BUFPLL_MCBs:                         0 out of       4    0%
  Number of DSP48A1s:                            0 out of      58    0%
  Number of ICAPs:                               0 out of       1    0%
  Number of MCBs:                                0 out of       2    0%
  Number of PCILOGICSEs:                         0 out of       2    0%
  Number of PLL_ADVs:                            0 out of       4    0%
  Number of PMVs:                                0 out of       1    0%
  Number of STARTUPs:                            0 out of       1    0%
  Number of SUSPEND_SYNCs:                       0 out of       1    0%

Average Fanout of Non-Clock Nets:                5.80

Peak Memory Usage:  305 MB
Total REAL time to MAP completion:  1 mins 7 secs 
Total CPU time to MAP completion:   1 mins 6 secs 


FPGA Editor を立ちあげてram_array の実装状況を見てみた。
cdctest_axi_master_23_120414.png

スライスのFFとして実装されている。
RAMのVHDLコードを下に示す。

constant    SLAVE_ADDR_NUMBER    : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def;

...............

    -- RAM
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                ram_array <= (others => (others => '0'));
            else
                if cdc_we='1' then
                    for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
                        if M_AXI_WSTRB(i)='1' then -- Byte Enable
                            ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
                        end if;
                    end loop;
                end if;
            end if;
        end if;
    end process;
    M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));


process文の中でresetをかけてしまっているので分散RAMにアサインされない。
そこで分散RAMにアサインされるように、resetの記述を削除した。VHDLコードを下に示す。

constant    SLAVE_ADDR_NUMBER    : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));

...............

    -- RAM
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if cdc_we='1' then
                for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
                    if M_AXI_WSTRB(i)='1' then -- Byte Enable
                        ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
                    end if;
                end loop;
            end if;
        end if;
    end process;
    M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));


これでインプリメントした時のMAPリポートの一部を下に示す。

Release 13.4 Map O.87xd (nt)
Xilinx Mapping Report File for Design 'axi_master_bfm'

Design Information
------------------
Command Line   : map -intstyle ise -p xc6slx45-csg324-2 -w -logic_opt off -ol
high -t 1 -xt 0 -register_duplication off -r 4 -global_opt off -mt off -ir off
-pr off -lc off -power off -o axi_master_bfm_map.ncd axi_master_bfm.ngd
axi_master_bfm.pcf 
Target Device  : xc6slx45
Target Package : csg324
Target Speed   : -2
Mapper Version : spartan6 -- $Revision: 1.55 $
Mapped Date    : SAT 14 APR 5:5:44 2012

Design Summary
--------------
Number of errors:      0
Number of warnings:    0
Slice Logic Utilization:
  Number of Slice Registers:                    68 out of  54,576    1%
    Number used as Flip Flops:                  68
    Number used as Latches:                      0
    Number used as Latch-thrus:                  0
    Number used as AND/OR logics:                0
  Number of Slice LUTs:                        174 out of  27,288    1%
    Number used as logic:                      109 out of  27,288    1%
      Number using O6 output only:              86
      Number using O5 output only:               0
      Number using O5 and O6:                   23
      Number used as ROM:                        0
    Number used as Memory:                      64 out of   6,408    1%
      Number used as Dual Port RAM:             64
        Number using O6 output only:            64
        Number using O5 output only:             0
        Number using O5 and O6:                  0
      Number used as Single Port RAM:            0
      Number used as Shift Register:             0
    Number used exclusively as route-thrus:      1
      Number with same-slice register load:      1
      Number with same-slice carry load:         0
      Number with other load:                    0

Slice Logic Distribution:
  Number of occupied Slices:                    78 out of   6,822    1%
  Nummber of MUXCYs used:                       24 out of  13,644    1%
  Number of LUT Flip Flop pairs used:          183
    Number with an unused Flip Flop:           117 out of     183   63%
    Number with an unused LUT:                   9 out of     183    4%
    Number of fully used LUT-FF pairs:          57 out of     183   31%
    Number of unique control sets:              11
    Number of slice register sites lost
      to control set restrictions:              44 out of  54,576    1%

  A LUT Flip Flop pair for this architecture represents one LUT paired with
  one Flip Flop within a slice.  A control set is a unique combination of
  clock, reset, set, and enable signals for a registered element.
  The Slice Logic Distribution report is not meaningful if the design is
  over-mapped for a non-slice resource or if Placement fails.

IO Utilization:
  Number of bonded IOBs:                       126 out of     218   57%

Specific Feature Utilization:
  Number of RAMB16BWERs:                         0 out of     116    0%
  Number of RAMB8BWERs:                          0 out of     232    0%
  Number of BUFIO2/BUFIO2_2CLKs:                 0 out of      32    0%
  Number of BUFIO2FB/BUFIO2FB_2CLKs:             0 out of      32    0%
  Number of BUFG/BUFGMUXs:                       1 out of      16    6%
    Number used as BUFGs:                        1
    Number used as BUFGMUX:                      0
  Number of DCM/DCM_CLKGENs:                     0 out of       8    0%
  Number of ILOGIC2/ISERDES2s:                   0 out of     376    0%
  Number of IODELAY2/IODRP2/IODRP2_MCBs:         0 out of     376    0%
  Number of OLOGIC2/OSERDES2s:                   0 out of     376    0%
  Number of BSCANs:                              0 out of       4    0%
  Number of BUFHs:                               0 out of     256    0%
  Number of BUFPLLs:                             0 out of       8    0%
  Number of BUFPLL_MCBs:                         0 out of       4    0%
  Number of DSP48A1s:                            0 out of      58    0%
  Number of ICAPs:                               0 out of       1    0%
  Number of MCBs:                                0 out of       2    0%
  Number of PCILOGICSEs:                         0 out of       2    0%
  Number of PLL_ADVs:                            0 out of       4    0%
  Number of PMVs:                                0 out of       1    0%
  Number of STARTUPs:                            0 out of       1    0%
  Number of SUSPEND_SYNCs:                       0 out of       1    0%

Average Fanout of Non-Clock Nets:                3.81

Peak Memory Usage:  279 MB
Total REAL time to MAP completion:  30 secs 
Total CPU time to MAP completion:   29 secs 


Number of occupied Slicesが13% から1% に劇的に減った。これは分散RAMが使用されたからだ。FPGA Editor を起動してRAMを見てみたのが下の図だ。
cdctest_axi_master_24_120414.png

SLICEMが分散RAMとしてアサインされているのがわかる。

なお、”C_OFFSET_WIDTH : integer := 15; -- 割り当てるRAMのアドレスのビット幅”の場合は、スライスが足りなくてMAPできなかった。

次に、Write Transaction。Writeデータ転送時にランダムなWaitを発生できるようにしてシミュレーションしてみた。 (WRITE_RANDOM_WAIT=1)
cdctest_axi_master_25_120414.png

3つ目以降のWrite Transaction でM_AXI_WREADY が変化してWaitしているのがわかると思う。

長くなったので、この辺で終了。axi_master_BFM.vhd のVHDLコードは次回ブログに貼る予定だ。

(追加)
なぜ、RAM をbit_vector のarray で定義したかというと、インプリメントは関係無いですが、シミュレーションでstd_logic は9値を持つので、それだけ領域を確保するのにパソコンのメモリ領域を食うと思われます。bit ならば2値なので、メモリ領域を食わないかな?と思い使いました。実際に、bit_vector で定義したほうがstd_logic で定義したよりメモリ領域を消費しないかどうか?は確認してみたことがないので、良く分かりません。知っている方がいらっしゃったら教えて下さい。
  1. 2012年04月14日 05:27 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

VHDLのとっても有用なExamples

VHDLのとっても有用な Examples があったのでリンクを張って置く

・E.1 access types: はVHDLのポインタの使い方。

・E.2 array and record aggregates: は、配列へのリテラルの代入 bvec <= (1=>'1', OTHERS=>'0');

・E.3 array and record types: 2次元配列にリテラルを代入 VARIABLE mem : memory := (OTHERS => (OTHERS => '1'));

・E.12 incomplete type declaration: 片方向リスト
  1. 2012年04月13日 12:24 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

AXI4スレーブ・バス・ファンクション・モデル(BFM)の作製1

AXI4マスタIPの作製2(単体シミュレーション)”で対応するキャラクタ・ディスプレイ・コントローラのAXI4スレーブIPをインターコネクトを通さずに直接テストベンチで接続してシミュレーションを行った。
今回はAXI4マスタIPを作る際に、対応するAXI4スレーブIPが出来ていたので、それで良いが、AXI4スレーブIPが無かった時に使える、なるべく汎用のAXI4スレーブのBFMを作ることにした。全部の場合は網羅できないので、AXI4スレーブIPのタイプはRAMタイプとして、AXI4バスのトランザクションをシミュレーションできることを目的とする。つまり、バーストのタイプは INCR のみの対応となる。

キャラクタ・ディスプレイ・コントローラのAXI4スレーブIPを元にして、汎用のAXI4スレーブBFMとするために C_M_AXI_DATA_WIDTH などの設定値を使用することにした。

・Write Transaction, Read Transaction 中のバーストについては、以前のM系列を使った擬似乱数を使用してある一定値以上だったらWaitする。(擬似乱数、M系列を使う1擬似乱数、M系列を使う2

現在作成中。うまくAXI4マスタと組みでシミュレーション出来たら公開します。VHDLで書いてます。

#現在、Writeはできたのですが、今朝はもうHDL書くのに飽きたので、また帰宅したら続きのVHDLを書きます。
  1. 2012年04月12日 05:33 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

Altium Designer FPGAデザイン機能のまとめ2

Altium Designer FPGAデザイン機能を調べてツイートしたのですが、そのまとめ2です。

・Altium のC to Hardware のサンプルいっぱいあることがわかった。

・ハードウェアが無いので、シミュレーションしたいのだが、やり方が分からない?

・かなりのコードがCで書いてある。生成されたHDLコードがみたい。

・FPGAの図の外側に、SPIの石やSRAMとかついてるし、これそのまま回路図にコンバートできるんだろうか?後は、パスコンや電源を追加すれば、回路図出来上がり?

・もしかしたらお宝か?マニュアルを読む必要が有りそうだ。

・Altium のFPGAデザインで、ザイリンクスのコアジェネレータ コンポーネントのサポートもあるそうです。EDIFで追加。

・Altium のC to Hardware はどうやらFPGAボードが無いと試せないみたいだ?

・Altium Designer のFPGAデザインは専用FPGAボードかダウンロード・ケーブルが無いとダメそうなので、とりあえず諦めた。

Altium_Designer7_1_120411.png

  1. 2012年04月11日 08:26 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

Altium Designer FPGAデザイン機能のまとめ

Altium Designer FPGAデザイン機能を調べてツイートしたのですが、そのまとめです。

・Using Altium Designer with a custom or 3rd-party FPGA dev boardを見ると、Alitum でFPGAをコンフィグする時は専用のダウンロード・ケーブルが必要のようだ。 ow.ly/aaldv (youtube)

・仮想測定器やデバッガと通信する為に4 本のIOピンが必要だったんだ。。。

・Spartan3A Starter Kit をAltium でコンフィグ、デバックするにはユニバーサル JTAG アダプタが必要のようだ。(Using Altium Designer with a custom or 3rd-party FPGA dev board)

・FPGA 論理データから基板回路図を自動生成。FPGA 論理データのピン情報と制約ファイルの情報を使い、回路シンボルと組み合わせ、 PCB プロジェクトを自動生成します。だそうです。Altium これは良いよね。

・Altium Designer の紹介の元ネタはこれ。 ow.ly/aamXa (PDF)

・Altium でFPGA 論理データから基板回路図を自動生成させるまでの道のりは長そうな気がする。果たして、学習時間に見合うだけの効果が得られるのか?

・お、デザインウェーブマガジンの2009年2月号にAltiumで”C 言語を使用したFPGA 設計を体験する”という記事が載っている。見てみよう。 ow.ly/aanni (PDF)

(追加資料 PDF)
Altium Designer FPGA Design Basics
FPGA デザイン入門
Altium Designer 次世代の統一設計環境
  1. 2012年04月10日 05:24 |
  2. Altium Designer
  3. | トラックバック:0
  4. | コメント:0

AXI4マスタIPのパラメータ

AXI4マスタIPの作製3(インプリメント)”で、CDCTEST AXI Master をAdd IPしてAXI4マスタIPとしてシステムに入れたが、その際にパラメータはデフォルトとした。ダイアログにどのようなパラメータがあるかを見ていきたい。

なお、AXI4バスの信号とパラメータについては、LogiCORE IP AXIインターコネクト(v1.05.a) DS768 2012年1月18日 を参照した。(以下マニュアルと呼ぶ)なお、マスタ、スレーブで共通の信号はスレーブでは S_ が、マスタでは M_ がパラメータ名から抜けているようだ。

ダイアログで設定できるパラメータを列挙して、説明する。

・XPS Core Config ダイアログ(Userタブ)
cdctest_axi_master_7_120402.png

* Common

- C_M_AXI_TARGET
 マニュアルに書いてない。ターゲットのスレーブのベース・アドレス。デフォルト値は 0x00000000。

- C_M_AXI_BURST_LEN
 マニュアルに書いていない。バースト長。デフォルト値は16。バースト長だとしても、16以上バースト出来ているのでなぞ?

- C_OFFSET_WIDTH
 マニュアルに書いていない。ターゲットのスレーブのアドレスビット幅。デフォルト値は9。0x00007fff 近くまでアクセス出来ているので、なぞ?

- C_M_AXI_PROTOCOL
 マスタデバイスのプロトコル。AXI4とAXI4Lite に設定できる。デフォルト値はAXI4。

・XPS Core Config ダイアログ(Systemタブ)
cdctest_axi_master_8_120402.png

* AXI

- C_M_AXI_ADDR_WIDTH
 アドレスのビット幅、マニュアルによると12~64らしいが、ここでは32に固定されれている。

- C_M_AXI_DATA_WIDTH
 データの幅、32, 64, 128, 256 に設定することが出来る。デフォルト値は32。

- C_M_AXI_SUPPORTS_READ
 マスタIPがReadを行うか?を示す。デフォルトではチェックされている。Wirte のみのスレーブIPの場合はチェックを外す。

- C_M_AXI_SUPPORTS_WRITE
 マスタIPがWriteを行うか?を示す。デフォルトではチェックされている。Read のみのスレーブIPの場合はチェックを外す。

- C_M_AXI_SUPPORTS_THREADS
 マニュアルによると”エンドポイント マスター デバイスで使用され、 マスターのスレッドの有効幅が 0 であ ることを示します。”だそうだ。何のことか不明だ? デフォルト値はチェックなし。

- C_M_AXI_THREAD_ID_WIDTH
 マニュアルによると”各 SI スロットの ID の下位にある可変ビットの数 (N-1:0)。 それぞれの値は <= C_AXI_ID_WIDTH の必要があります。”だそうだ。何のことか不明だ? デフォルト値は1。

- C_M_AXI_SUPPORTS_NARROW_BURST
 データ幅寄りも狭い幅のバーストを生成できるかどうかを決めるそうだ。たぶん32ビット幅で16ビット幅のバーストや8ビット幅のバーストをするということだろうと思う。デフォルト値はチェックなし。

- C_M_AXI_SUPPORTS_USER_SIGNALS
 USER信号 (5チャネルすべて) をAXI インターコネクトコアに伝搬するかどうかを示すそうだ。このチェックを外していてもUSER信号はデフォルト値の1になるようだ。
 チェックをすると下のUSER信号のグレーアウトがとれて、設定ができるようになる。

- C_M_AXI_AWUSER_WIDTH
 AWUSER信号の幅。1 ~ 256。デフォルトは1。

- C_M_AXI_ARUSER_WIDTH
 ARUSER信号の幅。1 ~ 256。デフォルトは1。

- C_M_AXI_WUSER_WIDTH
 WUSER信号の幅。1 ~ 256。デフォルトは1。

- C_M_AXI_RUSER_WIDTH
 RUSER信号の幅。1 ~ 256。デフォルトは1。

- C_M_AXI_BUSER_WIDTH
 BUSER信号の幅。1 ~ 256。デフォルトは1。

・XPS Core Config ダイアログ(Interconnect Settings for BUSIFタブ)
cdctest_axi_master_9_120402.png

* M_AXI

- Unique Master ID (C_INTERCONNECT_M_AXI_BASE_ID)
 マスタ・インターフェースのユニークなマスタID。デフォルト値はAutoで、値は 0b0 だった。

- Is ACLK Asynchronous to Interconnect_ACLK (C_INTERCONNECT_M_AXI_IS_ACLK_ASYNC)
 0の時はインターコネクトとクロック同期、1の時はインターコネクトとクロック非同期。デフォルト値は0でチェックなし

- ACLK Frequency Ratio (C_INTERCONNECT_M_AXI_ACLK_RATIO)
 ACLKの動作周波数がセットされる。上の図での表示は1だが、現在の値は100000000Hz、つまり100MHz。たぶんXPSでクロックをACLKに接続するとその値が反映されるようだ。よって、Add IP時には設定せずに後でクロックをXPS上で接続したほうが良い。

- Arbitration Priority (C_INTERCONNECT_M_AXI_ABR_PRIORITY)
 ここの値を大きくすると優先順位が高くなる。すべてのマスタの Arbitration Priority が0の時には、ラウンドロビンで優先順位が決定される。デフォルト値は0。

- Use register slice on AW channel (C_INTERCONNECT_M_AXI_AW_REGISTER)
 AWチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on AR channel (C_INTERCONNECT_M_AXI_AR_REGISTER)
 ARチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on W channel (C_INTERCONNECT_M_AXI_W_REGISTER)
 Wチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on R channel (C_INTERCONNECT_M_AXI_R_REGISTER)
 Rチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on B channel (C_INTERCONNECT_M_AXI_B_REGISTER)
 Bチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Write Data FIFO Depth (C_INTERCONNECT_M_AXI_WRITE_FIFO_DEPTH)
 Write Data FIFOの深度。0(None), 32(SRL), 512(BRAM)から選択。デフォルトは0(None)。

- Write Data FIFO Burst Delay (C_INTERCONNECT_M_AXI_WRITE_FIFO_DELAY)
 マニュアルによると”パケットFIFO 書き込み動作。 バースト全体がSI側の各 SIスロットの書き込みデータFIFOに格納されるまでアービタへの AWVALID 発行を遅延させます (対応するスロットのC_M_AXI_WRITE_FIFO_DEPTH = 0x200 とする必要がある)。”そうだ。チェックを入れる場合は、前のWrite Data FIFO Depthを512(BRAM)にする必要がある。デフォルト値はチェックなし。

- Read Data FIFO Depth (C_INTERCONNECT_M_AXI_READ_FIFO_DEPTH)
 Read Data FIFOの深度。0(None), 32(SRL), 512(BRAM)から選択。デフォルトは0(None)。

- Read Data FIFO Burst Delay (C_INTERCONNECT_M_AXI_READ_FIFO_DELAY)
 マニュアルによると”パケットFIFO読み出し動作。SI側の各SIスロットの読み出しデータFIFOに全バースト長を格納する のに十分な空きが生じるまで、アービタへのARVALID 発行を遅延させます (対応するスロットのC_M_AXI_READ_FIFO_DEPTH = 0x200とする必要がある)。”そうだ。チェックを入れる場合は、前のRead Data FIFO Depthを512(BRAM)にする必要がある。デフォルト値はチェックなし。

- Write Transaction Issuing Limit (C_INTERCONNECT_M_AXI_WRITE_ISSUING)
 AXI4バスインターフェースが生成できるアクティブな最大のWrite Transaction。Shared-Access mode の時は無視される。デフォルト値は8。

- Read Transaction Issuing Limit (C_INTERCONNECT_M_AXI_READ_ISSUING)
 AXI4バスインターフェースが生成できるアクティブな最大のRead Transaction。Shared-Access mode の時は無視される。デフォルト値は8。

- Accept only ID thread at a time (C_INTERCONNECT_M_AXI_SINGLE_THREAD)
 あるIDのトランザクションが未解決の時には、そのIDのトランザクションしかスレーブに発行しない。デフォルト値はチェックなし。
  1. 2012年04月08日 20:14 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

映画『マーガレット・サッチャー 鉄の女の涙』を見てきました

今日は、うちの奥さんと、映画『マーガレット・サッチャー 鉄の女の涙』を見てきました。何か不思議な映画でした。現在の状況と過去の首相時代の情景が混じり合ってました。TVで上映されても見ないと思いますが、映画館で見る文にはそんなに面白くないということもなかったです。映画に見入ってました。女優さんの演技が良かったです。

  1. 2012年04月07日 16:21 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

AXIスレーブIPのパラメータ

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする9(インプリメント1)”でXPSからAdd IPでキャラクタ・ディスプレイ・コントローラをAXI4スレーブIPとしてシステムに入れたが、その際にパラメータはデフォルトとした。ダイアログにどのようなパラメータがあるかを見ていきたい。

なお、AXI4バスの信号とパラメータについては、LogiCORE IP AXIインターコネクト(v1.05.a) DS768 2012年1月18日 を参照した。(以下マニュアルと呼ぶ)なお、マスタ、スレーブで共通の信号はスレーブでは S_ が、マスタでは M_ がパラメータ名から抜けているようだ。

ダイアログで設定できるパラメータを列挙して、説明する。

・XPS Core Config ダイアログ(Systemタブ)
CDC_axi_slave_25_120317.png

* Address

- Slave AXI Number of Address Ranges (C_S_AXI_NUM_ADDR_RANGES)
 マニュアルには記述が無いが、アドレス範囲を4つまで選べて、その内の幾つを有効にするかを数で選択する。デフォルトはAutoで1。

- Slave AXI RNG00 Base Base Address (C_S_AXI_RNG00_BASEADDR)
 これもマニュアルには記述が無いが、最初のアドレス範囲のスタートアドレス。XPSのAddressタブでアドレスを入力すると反映されている。

- Slave AXI RNG00 High Base Address (C_S_AXI_RNG00_HIGHADDR)
最初のアドレス範囲のエンドアドレス。XPSのAddressタブでアドレスを入力すると反映されている。

- Slave AXI RNG01 Base Base Address ~ Slave AXI RNG03 High Base Address は省略

* S_AXI

- Slave AXI Protcol (C_S_AXI_PROTOCOL)
 AXI4, AXI4Lite, AXI3 を選択できる。ここでのデフォルト値はAXI4

- Slave AXI ID Width (C_S_AXI_ID_WIDTH)
 IDのビット幅。1~16ビットに設定可。ここでのデフォルト値は1。

- Slave AXI Address Width (C_S_AXI_ADDR_WIDTH)
 アドレスビット幅。ここでのデフォルト値は32。ここは設定できない。

- Slave AXI Supports Read (C_S_AXI_SUPPORTS_READ)
 スレーブIPがReadを行うか?を示す。デフォルトではAuto になっているが、チェックされている。Wirte のみのスレーブIPの場合はチェックを外す。

- Slave AXI Supports Write (C_S_AXI_SUPPORTS_WRITE)
 スレーブIPがWriteを行うか?を示す。デフォルトではAuto になっているが、チェックされている。Read のみのスレーブIPの場合はチェックを外す。

- Slave AXI Supports User Signals (C_S_AXI_SUPPORTS_USER_SIGNALS)
 USER信号 (5チャネルすべて) をAXI インターコネクトコアに伝搬するかどうかを示すそうだ。このチェックを外していてもUSER信号はデフォルト値の1になるようだ。
 チェックをすると下のUSER信号のグレーアウトがとれて、設定ができるようになる。

- Slave AXI AWUSER Width (C_S_AXI_AWUSER_WIDTH)
 AWUSER信号の幅。1 ~ 256。デフォルトは1。

- Slave AXI ARUSER Width (C_S_AXI_ARUSER_WIDTH)
 ARUSER信号の幅。1 ~ 256。デフォルトは1。

- Slave AXI WUSER Width (C_S_AXI_WUSER_WIDTH)
 WUSER信号の幅。1 ~ 256。デフォルトは1。

- Slave AXI RUSER Width (C_S_AXI_RUSER_WIDTH)
 RUSER信号の幅。1 ~ 256。デフォルトは1。

- Slave AXI BUSER Width (C_S_AXI_BUSER_WIDTH)
 BUSER信号の幅。1 ~ 256。デフォルトは1。

・XPS Core Config ダイアログ(Interconnect Settings for BUSIF)
CDC_axi_slave_26_120317.png

* S_AXI

- Is ACLK Asynchronous to Interconnect_ACLK (C_INTERCONNECT_S_AXI_IS_ACLK_ASYNC)
 0の時はインターコネクトとクロック同期、1の時はインターコネクトとクロック非同期。デフォルト値は0でチェックなし

- ACLK Frequency Ratio (C_INTERCONNECT_S_AXI_ACLK_RATIO)
 ACLKの動作周波数がセットされる。上の図での表示は1だが、現在の値は100000000Hz、つまり100MHz。たぶんXPSでクロックをACLKに接続するとその値が反映されるようだ。よって、Add IP時には設定せずに後でクロックをXPS上で接続したほうが良い。

- Require TrustZone Secure on all accesses (C_INTERCONNECT_S_AXI_SECURE)
 マニュアルによると”各MIスロットがセキュアなスレーブ デバイス(TrustZone のセキュアアクセスを許可)に接続されているかどうかを示します。”だそうです。0がセキュアでないスレーブデバイスで、1がセキュアなスレーブデバイス。デフォルトは0でチェックなし。

- Use register slice on AW channel (C_INTERCONNECT_S_AXI_AW_REGISTER)
 AWチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on AR channel (C_INTERCONNECT_S_AXI_AR_REGISTER)
 ARチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on W channel (C_INTERCONNECT_S_AXI_W_REGISTER)
 Wチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on R channel (C_INTERCONNECT_S_AXI_R_REGISTER)
 Rチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Use register slice on B channel (C_INTERCONNECT_S_AXI_B_REGISTER)
 Bチャネルにレジスタを挿入する。レジスタを挿入するとレイテンシが増える代わりに高速動作するようになると思われる。BYPASS, AUTOMATIC, FULLY REGISTERED, LIGHT WEIGHTから選択。デフォルトはBYPASS。

- Write Data FIFO Depth (C_INTERCONNECT_S_AXI_WRITE_FIFO_DEPTH)
 Write Data FIFOの深度。0(None), 32(SRL), 512(BRAM)から選択。デフォルトは0(None)。

- Write Data FIFO Burst Delay (C_INTERCONNECT_S_AXI_WRITE_FIFO_DELAY)
 マニュアルによると”パケットFIFO 書き込み動作。 バースト全体がSI側の各 SIスロットの書き込みデータFIFOに格納されるまでアービタへの AWVALID 発行を遅延させます (対応するスロットのC_S_AXI_WRITE_FIFO_DEPTH = 0x200 とする必要がある)。”そうだ。チェックを入れる場合は、前のWrite Data FIFO Depthを512(BRAM)にする必要がある。デフォルト値はチェックなし。

- Read Data FIFO Depth (C_INTERCONNECT_S_AXI_READ_FIFO_DEPTH)
 Read Data FIFOの深度。0(None), 32(SRL), 512(BRAM)から選択。デフォルトは0(None)。

- Read Data FIFO Burst Delay (C_INTERCONNECT_S_AXI_READ_FIFO_DELAY)
 マニュアルによると”パケットFIFO 読み出し動作。SI側の各SIスロットの読み出しデータFIFOに全バースト長を格納する のに十分な空きが生じるまで、アービタへのARVALID 発行を遅延させます (対応するスロットのC_S_AXI_READ_FIFO_DEPTH = 0x200とする必要がある)。”そうだ。チェックを入れる場合は、前のRead Data FIFO Depthを512(BRAM)にする必要がある。デフォルト値はチェックなし。

- Write Transaction Acceptance Limit (C_INTERCONNECT_S_AXI_WRITE_ACCEPTANCE)
 インターコネクトから発行されるアクティブなWrite Transaction の数。デフォルトはAuto で1。

- Read Transaction Acceptance Limit (C_INTERCONNECT_S_AXI_READ_ACCEPTANCE)
 インターコネクトから発行されるアクティブなRead Transaction の数。デフォルトはAuto で1。
  1. 2012年04月06日 05:54 |
  2. AXI4 Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0

AXI4マスタIPの作製3(インプリメント)

AXI4マスタIPの作製2(単体シミュレーション)”の続き。
単体シミュレーションを行なって大丈夫そうだったので、XPSでAXI4マスタIPをAddして、ISEでインプリメントしてみた。

・Atlys_XPS_CDC_SVGA_134\pcores\cdctest_axi_master_v1_00_a\dataフォルダのcdctest_axi_master_v2_1_0.mpd の名前を変更して、wr_error, rd_error ポートを追加した。

BEGIN cdctest_axi_master

...............


PORT wr_error = "", DIR = O
PORT rd_error = "", DIR = O


・Atlys_XPS_CDC_SVGA_134\pcores\cdctest_axi_master_v1_00_a\dataフォルダのcdctest_axi_master_v2_1_0.pao ファイルにcdctest_axi_master.v の項目を書いた。

lib cdctest_axi_master_v1_00_a cdctest_axi_master.vhd vhdl


・Atlys_XPS_CDC_SVGA_134\pcores\cdctest_axi_master_v1_00_a\hdl\vhdlフォルダにcdctest_axi_master.vhd をコピーした。

・XPSのPoject メニューからRescan User Repositoriesを選択し、リポジトリを更新した。

・CDCTEST AXI Master で右クリックメニューからAdd IPを選択する。
cdctest_axi_master_6_120402.png

・XPS Core Config ダイアログが立ち上がる。Userタブの画面。wr_error, rd_error信号が見える。
cdctest_axi_master_7_120402.png

・Systemタブの内容
cdctest_axi_master_8_120402.png

・Interconnect Settings for BUSIFタブの内容。
cdctest_axi_master_9_120402.png

すべてデフォルトにしてみた。

・次のInstantiate and Connect IPダイアログは、User will make necessary connections and settings のラジオボタンをクリックした。(独自のAXI4バスを新規作成して接続する予定だ)
cdctest_axi_master_10_120402.png

・cdc_axi_slave_0 のmicroblaze_0 へのAXIバス接続を解除した。

・microblaze_0のデータキャッシュの設定の設定を元に戻した。Hight Address 0xcfffffff → 0xc7fffffff

・AXI Interconnect v1.05a をAdd IPした。

・axi4_1 という名前を付けて生成した。(設定はデフォルトのまま)
cdctest_axi_master_12_120403.png

・cdctest_axi_master_0 のM_AXI とcdc_axi_slave_0 のS_AXI をaxi4_1 に接続した。
cdctest_axi_master_13_120403.png

・cdctest_axi_master_0のwr_error, rd_error ポートをExternal Ports に指定した。
・cdctest_axi_master_0のM_AXI のACLKをclock_generator_0::CLKOUT2 に接続した。
cdctest_axi_master_14_120403.png

・axi4_1 のACLK とARESETN を接続した。
cdctest_axi_master_16_120403.png

・Addressタブでcdc_axi_slave_0 のアドレスを0x00000000 番地から0x00007fff 番地の32Kバイトに変更した。
cdctest_axi_master_15_120403.png

・cdctest_wr_error とcdctest_rd_error ポート用の制約をUCFファイルに書き加えた。LEDはIPにすでに使われているので、PMODコネクタのピンとして割り当てた。

NET "cdctest_wr_error" LOC = "T3"; #PMOD for test
NET "cdctest_rd_error" LOC = "R3"; #PMOD for test



・ProjectメニューからDesign Rule Check を行ったがエラーはなかった。
cdctest_axi_master_17_120403.png

・念のため、ProjectメニューからClean All Generated Files を実行した。(この時、SDKのフォルダの中身も全て消えてしまうので注意)

・XPSを終了して、Project Navigator に戻りインプリメントを行った。(Project Navigator でも念のため、ProjectメニューからClenup Project Files を実行した)

・インプリメントが終了した。ビットファイルをダウンロードしてみた。

・0.2秒間隔でランダムな数のキャラクタが表示された。
cdctest_axi_master_19_120404.jpg

・これでうまく行ったと思っていた。しかしある所で止まってしまう。それはなぜだろうか?ChipScope でトラブルシュートする。

・ChipScope で問題の部分を捉えたのが下の図だ。
cdctest_axi_master_18_120403.png

これは、cdc_axi_slave.vhd つまりAXI4スレーブIPにChipScope をかけた時のタイミングチャートを表す。S_AXI_ARLENがFFの時に、S_AXI_RREADY が1のままで、全くReadされていない。

cdc_axi_slave.vhd のソースを見る。rd_cdc_count の処理の部分を下に示す。

    -- rd_cdc_count の処理(CDC側のデータカウント)
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rd_cdc_count <= (others => '0');
            else
                if rdt_cs=arr_accept then -- ロード
                    rd_cdc_count <= S_AXI_ARLEN + 1;
                elsif rdt_cs=rd_burst and rdfifo_almost_full='0' and rd_cdc_count/=0 then -- FIFOに余裕がある
                    rd_cdc_count <= rd_cdc_count - 1;
                end if;
            end if;
        end if;
    end process;


ロードの時にrd_cdc_countにS_AXI_ARLEN + 1を入れている。S_AXI_ARLENが0xFF の時は1つ桁が上がって、0x100になる。rd_cdc_countの宣言は下に示すように、7 downto 0と宣言してあった。

signal rd_cdc_count : std_logic_vector(7 downto 0);


上の宣言を下に書き換えた。

signal rd_cdc_count : std_logic_vector(8 downto 0);


ビット幅が合わないので、rd_cdc_countの処理もロードの部分を以下の様に書き換えた。

                if rdt_cs=arr_accept then -- ロード
                    rd_cdc_count <= ('0'& S_AXI_ARLEN) + 1;


これでうまく行きました。
前に貼ったcdc_axi_slave.vhd のVHDLコードを修正します。
  1. 2012年04月03日 05:31 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

AXI4マスタIPの作製2(単体シミュレーション)

キャラクタ・ディスプレイ・コントローラAXI4スレーブIPを駆動するAXI4マスタIPが一応できたので、シミュレーションしてみた。
仕様は、”AXI4マスタIPの作製(仕様の策定)"を参照のこと。

2012/10/22:(注)この記事は全面的に書き換えた。理由はAXIの書き込みトランザクションにやるハンドシェークの依存関係を誤解していた。書き込みトランザクションにおいて、WVALIDをアサートする前に、AWREADYがアサートされるのを待っていてはダメだそうだ。デッドロック状態を引き起こす可能性があるそうだ。


まずは、AXI4マスタIPを下に示す。まだ、インプリメントして実際に確かめていないので、ミスっているかも知れない。その場合は後で修正する。長いです。(cdctest_axi_master.vhd) (2012/04/04:cdctest_axi_master.vhd を修正)

-------------------------------------------------------------------------------
--
-- AXI Master
--
-- VHDL-Standard:   VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
--   cdctest_axi_master
--
----------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;

package m_seq_pack is
    function M_SEQ16_F(mseq16in : std_logic_vector
        )return std_logic_vector;
end package m_seq_pack;
package body m_seq_pack is
    function M_SEQ16_F(mseq16in : std_logic_vector
        )return std_logic_vector is
            variable mseq16 : std_logic_vector(15 downto 0);
            variable xor_result : std_logic;
    begin
        xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
        mseq16 := mseq16in(14 downto 0) & xor_result;
        return mseq16;
    end M_SEQ16_F;
end m_seq_pack;


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

library work;
use work.m_seq_pack.all;

--library unisim;
--use unisim.vcomponents.all;

entity cdctest_axi_master is
  generic(
    C_M_AXI_THREAD_ID_WIDTH : integer := 1;
    C_M_AXI_ADDR_WIDTH      : integer := 32;
    C_M_AXI_DATA_WIDTH      : integer := 32;
    C_M_AXI_AWUSER_WIDTH    : integer := 1;
    C_M_AXI_ARUSER_WIDTH    : integer := 1;
    C_M_AXI_WUSER_WIDTH     : integer := 1;
    C_M_AXI_RUSER_WIDTH     : integer := 1;
    C_M_AXI_BUSER_WIDTH     : integer := 1
    );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Master Interface Write Address
    M_AXI_AWID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_AWADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_AWLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_AWSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_AWBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_AWLOCK  : out std_logic;
    M_AXI_AWCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_AWPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3    M_AXI_AWREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_AWQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_AWUSER  : out std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
    M_AXI_AWVALID : out std_logic;
    M_AXI_AWREADY : in  std_logic;

    -- Master Interface Write Data
    -- AXI3   M_AXI_WID(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_WDATA  : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_WSTRB  : out std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
    M_AXI_WLAST  : out std_logic;
    M_AXI_WUSER  : out std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
    M_AXI_WVALID : out std_logic;
    M_AXI_WREADY : in  std_logic;

    -- Master Interface Write Response
    M_AXI_BID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_BRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_BUSER  : in  std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
    M_AXI_BVALID : in  std_logic;
    M_AXI_BREADY : out std_logic;

    -- Master Interface Read Address
    M_AXI_ARID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_ARADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_ARLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_ARSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_ARBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_ARLOCK  : out std_logic_vector(2-1 downto 0);
    M_AXI_ARCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_ARPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3   M_AXI_ARREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_ARQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_ARUSER  : out std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
    M_AXI_ARVALID : out std_logic;
    M_AXI_ARREADY : in  std_logic;

    -- Master Interface Read Data 
    M_AXI_RID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_RDATA  : in  std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_RRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_RLAST  : in  std_logic;
    M_AXI_RUSER  : in  std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
    M_AXI_RVALID : in  std_logic;
    M_AXI_RREADY : out std_logic;

    -- Example Design only
    wr_error : out std_logic;
    rd_error : out std_logic
);

end cdctest_axi_master;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of cdctest_axi_master is
constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

constant    SVGA_ADDR_LIMIT : integer := 800/8*600/8*4; -- SVGAのアドレスリミット(横ドット数/1文字の横ドット数 * 縦ドット数/1文字の縦のドット数 * 1文字を表すバイト数)

constant    DISP_INTERVAL_DIV : integer := 20000000; -- インプリメント 0.2sec
-- constant    DISP_INTERVAL_DIV : integer := 3; -- シミュレーション

signal reset_1d, reset_2d, reset : std_logic;
type wr_rd_transaction_state is (write_state, read_state, wait_state);
signal wr_rd_cs : wr_rd_transaction_state;
type write_transaction_state is (idle_wr, awvalid_assert, data_write_hold, bready_assert, wr_tran_end);
signal wrt_cs : write_transaction_state;
type write_wvalid_state is (idle_wvalid, wvalid_assert, wvalid_hold);
signal wrt_wv_cs : write_wvalid_state;

signal awvalid, wvalid, bready : std_logic;
signal w_r_addr : std_logic_vector(31 downto 0);
signal write_data : std_logic_vector(15 downto 0);
signal awlen16 : std_logic_vector(15 downto 0);
signal awlen, write_count : std_logic_vector(7 downto 0);
signal wlast : std_logic;
type read_transaction_state is (idle_rd, arvalid_assert, data_read, rd_tran_end);
signal rdt_cs : read_transaction_state;
signal arvalid : std_logic;
signal arlen, read_count : std_logic_vector(7 downto 0);
signal read_data : std_logic_vector(15 downto 0);
signal rready : std_logic;
signal disp_count : integer;
signal disp_ena : std_logic;

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- インプリメントでは0.2秒に1回表示する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                disp_count <= 0;
                disp_ena <= '0';
            else
                if disp_count = DISP_INTERVAL_DIV then
                    disp_count <= 0;
                    disp_ena <= '1';
                else
                    disp_count <= disp_count + 1;
                    disp_ena <= '0';
                end if;
            end if;
        end if;
    end process;
    
    -- Write, Read Transaction State Machine
    -- Writeが終了したらReadを行う。シーケンシャルにWrite, Readを繰り返す。
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_rd_cs <= write_state;
            else
                case (wr_rd_cs) is
                    when write_state =>
                        if wrt_cs = wr_tran_end then
                            wr_rd_cs <= read_state;
                        end if;
                    when read_state =>
                        if rdt_cs = rd_tran_end then
                            wr_rd_cs <= wait_state;
                        end if;
                    when wait_state =>
                        if disp_ena='1' then
                            wr_rd_cs <= write_state;
                        end if;
                end case;
            end if;
        end if;
    end process;

    -- Write
    M_AXI_AWID        <= "0";
    M_AXI_AWSIZE     <= "010";    -- 4bytes fixed
    M_AXI_AWBURST    <= "01";    -- INCR
    M_AXI_AWLOCK    <= '0';    -- Normal Access
    M_AXI_AWCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    M_AXI_AWPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_AWQOS        <= "0000";    -- default
    M_AXI_AWUSER    <= "0";
    M_AXI_WSTRB        <= "1111";
    M_AXI_WUSER        <= "0";
    
    -- AXI4バス Write Transaction State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_cs <= idle_wr;
                awvalid <= '0';
                bready <= '0';
            else 
                case(wrt_cs) is
                    when idle_wr =>
                        if wr_rd_cs = write_state then
                            wrt_cs <= awvalid_assert;
                            awvalid <= '1';
                        end if;
                    when awvalid_assert =>
                        if M_AXI_AWREADY='1' then
                            if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
                                wrt_cs <= bready_assert;
                                bready <= '1';
                            else
                                wrt_cs <= data_write_hold;
                            end if;
                            awvalid <= '0';
                        end if;
                    when data_write_hold =>
                        if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
                            wrt_cs <= bready_assert;
                            bready <= '1';
                        end if;
                    when bready_assert =>
                        if M_AXI_BVALID='1' then
                            wrt_cs <= wr_tran_end;
                            bready <= '0';
                        end if;
                    when wr_tran_end =>
                        wrt_cs <= idle_wr;
                end case;
            end if;
        end if;
    end process;
    -- AXI4 バス Write Transaction WVALID State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_wv_cs <= idle_wvalid;
                wvalid <= '0';
            else 
                case(wrt_wv_cs) is
                    when idle_wvalid =>
                        if wrt_cs=awvalid_assert then
                            wrt_wv_cs <= wvalid_assert;
                            wvalid <= '1';
                        end if;
                    when wvalid_assert =>
                        if write_count=0 and M_AXI_WREADY='1' then -- 終了
                            wrt_wv_cs <= wvalid_hold;
                            wvalid <= '0';
                        end if;
                    when wvalid_hold =>
                        if wrt_cs=bready_assert then
                            wrt_wv_cs <= idle_wvalid;
                        end if;
                end case;
            end if;
        end if;
    end process;

    M_AXI_AWVALID    <= awvalid;
    M_AXI_WVALID    <= wvalid;
    M_AXI_BREADY    <= bready;
    
    -- w_r_addr の処理、Write Transaction が終了するたびにawlen+1を加える。加える途中でSVGA_ADDR_LIMITを超える時はどうするかだが、そこは無視する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                w_r_addr <= (others => '0');
            else
                if wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    w_r_addr <= w_r_addr + 4;
                elsif wrt_cs=bready_assert and w_r_addr >= SVGA_ADDR_LIMIT then
                    w_r_addr <= (others => '0');
                end if;
            end if;
        end if;
    end process;
    M_AXI_AWADDR <= w_r_addr;
    
    -- M_AXI_AWLEN の値を決定する。M系列を使用してランダムな値とする
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                awlen16 <= CONV_STD_LOGIC_VECTOR(1, 16); -- 0 はダメ
            else
                if wr_rd_cs=write_state and  wrt_cs=idle_wr then
                    awlen16 <= M_SEQ16_F(awlen16);
                end if;
            end if;
        end if;
    end process;
    awlen <= awlen16(7 downto 0);
    M_AXI_AWLEN <= awlen;
    
    -- write_data の処理、0から0xffffまで
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_data <= (others => '0');
            else
                if wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    if write_data = x"FFFF" then -- 終了なのでクリア
                        write_data <= (others => '0'); -- これをしなくても0に戻るが将来他の値でリミットするためにコードを入れておく
                    else -- data write
                        write_data <= write_data + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;
    M_AXI_WDATA(31 downto 16) <= (others => '0');
    M_AXI_WDATA(15 downto 0) <= write_data;
    
    -- write_count の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_count <= (others => '0');
            else
                if wrt_cs=awvalid_assert then
                    write_count <= awlen;
                elsif wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    write_count <= write_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- wlastの処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wlast <= '0';
            else
                if wrt_cs=awvalid_assert and awlen=0 and M_AXI_AWREADY='1' then -- awlen が0の時はデータ転送の最初からwlast をアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and write_count=1 and M_AXI_WREADY='1' then -- awlen が0で無い時はwrite_count が1でM_AXI_WREADY='1'の時、つまりwrite_count が0の時にwlastをアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1' then -- データ転送が終了なのでwlast を0にする
                    wlast <= '0';
                end if;
            end if;
        end if;
    end process;
    M_AXI_WLAST <= wlast;
    
    -- wr_error の処理、M_AXI_BRESPがRESP_OKAY以外の時にwr_errorを点灯する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_error <= '0';
            else
                if wrt_cs=bready_assert and M_AXI_BVALID='1' and M_AXI_BRESP/=RESP_OKAY then
                    wr_error <= '1';
                end if;
            end if;
        end if;
    end process;
    
    -- Read
    M_AXI_ARID        <= "0";
    M_AXI_ARLEN        <= awlen;
    M_AXI_ARSIZE    <= "010";    -- 4bytes
    M_AXI_ARBURST    <= "01";    -- INCR
    M_AXI_ARLOCK    <= "00";    -- Normal Access
    M_AXI_ARCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    M_AXI_ARPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_ARQOS        <= "0000";    -- default
    M_AXI_ARUSER    <= "0";
    
    -- M_AXI_ARADDR の処理、M_AXI_AWVALIDが1の時のw_r_addr を保存しておく
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                M_AXI_ARADDR <= (others => '0');
            else
                if awvalid='1' then
                    M_AXI_ARADDR <= w_r_addr;
                end if;
            end if;
        end if;
    end process;
    
    -- AXI4バス Read Transaction State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                rdt_cs <= idle_rd;
                arvalid <= '0';
                rready <= '0';
            else
                case rdt_cs is
                    when idle_rd =>
                        if wr_rd_cs=read_state then
                            rdt_cs <= arvalid_assert;
                            arvalid <= '1';
                        end if;
                    when arvalid_assert =>
                        if M_AXI_ARREADY='1' then
                            rdt_cs <= data_read;
                            arvalid <= '0';
                            rready <= '1';
                        end if;
                    when data_read =>
                        if read_count=0 and M_AXI_RVALID='1' then -- 終了
                            rdt_cs <= rd_tran_end;
                            rready <= '0';
                        end if;
                    when rd_tran_end =>
                        rdt_cs <= idle_rd;
                end case;
            end if;
        end if;
    end process;
    M_AXI_ARVALID <= arvalid;
    M_AXI_RREADY <= rready;
    
    -- read_data の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                read_data <= (others => '0');
            else
                if rdt_cs=data_read and M_AXI_RVALID='1' then
                    if read_data=x"FFFF" then -- 終了なのでクリア
                        read_data <= (others => '0');
                    else -- data read
                        read_data <= read_data + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;
    
    -- read_count の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                read_count <= (others => '0');
            else
                if rdt_cs=arvalid_assert then
                    read_count <= awlen;
                elsif rdt_cs=data_read and M_AXI_RVALID='1' then
                    read_count <= read_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- rd_error の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                rd_error <= '0';
            else
                if rdt_cs=data_read and M_AXI_RVALID='1' then -- Read Transaction
                    if M_AXI_RDATA(15 downto 0) /= read_data then
                        rd_error <= '1';
                    elsif M_AXI_RRESP /= RESP_OKAY then
                        rd_error <= '1';
                    end if;
                end if;
            end if;
        end if;
    end process;

end implementation;


インプリメントでは、キャラクタをランダム・バースト長で書く間隔を0.2秒に設定している。だが、シミュレーションでは、そんなに長くインターバルを設定してしまうと、2回のトランザクションを見るには、膨大なシミュレーション時間を必要とする。そのため、シミュレーション時には分周比を小さくした。それを下に示す。

constant DISP_INTERVAL_DIV : integer := 20000000; -- インプリメント 0.2sec
-- constant DISP_INTERVAL_DIV : integer := 3; -- シミュレーション


上の記述は、インプリメントとシミュレーションでコメントにする方を切り替えて使って欲しい。(現在はインプリメント用)

次に、テストベンチファイル (cdctest_axi_master_tb.v) を下に示す。テストベンチはVerilog ファイルにした。テストベンチでは、cdctest_axi_master.vhd とcdc_axi_slave.vhd をインスタンスして、その間を接続している。後で汎用的なAXI4スレーブBFMを作っても良いかな?と思っている。

`default_nettype none

`timescale 100ps / 1ps

module cdctest_axi_master_tb;

    // Inputs
    wire ACLK;
    wire ARESETN;
    wire M_AXI_AWREADY;
    wire M_AXI_WREADY;
    wire [0:0] M_AXI_BID;
    wire [1:0] M_AXI_BRESP;
    wire [0:0] M_AXI_BUSER;
    wire M_AXI_BVALID;
    wire M_AXI_ARREADY;
    wire [0:0] M_AXI_RID;
    wire [31:0] M_AXI_RDATA;
    wire [1:0] M_AXI_RRESP;
    wire M_AXI_RLAST;
    wire [0:0] M_AXI_RUSER;
    wire M_AXI_RVALID;

    // Outputs
    wire [0:0] M_AXI_AWID;
    wire [31:0] M_AXI_AWADDR;
    wire [7:0] M_AXI_AWLEN;
    wire [2:0] M_AXI_AWSIZE;
    wire [1:0] M_AXI_AWBURST;
    wire M_AXI_AWLOCK;
    wire [3:0] M_AXI_AWCACHE;
    wire [2:0] M_AXI_AWPROT;
    wire [3:0] M_AXI_AWQOS;
    wire [0:0] M_AXI_AWUSER;
    wire M_AXI_AWVALID;
    wire [31:0] M_AXI_WDATA;
    wire [3:0] M_AXI_WSTRB;
    wire M_AXI_WLAST;
    wire [0:0] M_AXI_WUSER;
    wire M_AXI_WVALID;
    wire M_AXI_BREADY;
    wire [0:0] M_AXI_ARID;
    wire [31:0] M_AXI_ARADDR;
    wire [7:0] M_AXI_ARLEN;
    wire [2:0] M_AXI_ARSIZE;
    wire [1:0] M_AXI_ARBURST;
    wire [1:0] M_AXI_ARLOCK;
    wire [3:0] M_AXI_ARCACHE;
    wire [2:0] M_AXI_ARPROT;
    wire [3:0] M_AXI_ARQOS;
    wire [0:0] M_AXI_ARUSER;
    wire M_AXI_ARVALID;
    wire M_AXI_RREADY;
    wire wr_error;
    wire rd_error;

    wire pixclk;
    wire TMDS_tx_clk_p;
    wire TMDS_tx_clk_n;
    wire TMDS_tx_2_G_p;
    wire TMDS_tx_2_G_n;
    wire TMDS_tx_1_R_p;
    wire TMDS_tx_1_R_n;
    wire TMDS_tx_0_B_p;
    wire TMDS_tx_0_B_n;
    
    wire [3:0]    S_AXI_AWREGION = 0;
    wire [0:0]    S_AXI_WID = 0;
    wire [3:0]    S_AXI_ARREGION = 0;

    // Instantiate the Unit Under Test (UUT_MASTER)
    cdctest_axi_master uut_master (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .M_AXI_AWID(M_AXI_AWID), 
        .M_AXI_AWADDR(M_AXI_AWADDR), 
        .M_AXI_AWLEN(M_AXI_AWLEN), 
        .M_AXI_AWSIZE(M_AXI_AWSIZE), 
        .M_AXI_AWBURST(M_AXI_AWBURST), 
        .M_AXI_AWLOCK(M_AXI_AWLOCK), 
        .M_AXI_AWCACHE(M_AXI_AWCACHE), 
        .M_AXI_AWPROT(M_AXI_AWPROT), 
        .M_AXI_AWQOS(M_AXI_AWQOS), 
        .M_AXI_AWUSER(M_AXI_AWUSER), 
        .M_AXI_AWVALID(M_AXI_AWVALID), 
        .M_AXI_AWREADY(M_AXI_AWREADY), 
        .M_AXI_WDATA(M_AXI_WDATA), 
        .M_AXI_WSTRB(M_AXI_WSTRB), 
        .M_AXI_WLAST(M_AXI_WLAST), 
        .M_AXI_WUSER(M_AXI_WUSER), 
        .M_AXI_WVALID(M_AXI_WVALID), 
        .M_AXI_WREADY(M_AXI_WREADY), 
        .M_AXI_BID(M_AXI_BID), 
        .M_AXI_BRESP(M_AXI_BRESP), 
        .M_AXI_BUSER(M_AXI_BUSER), 
        .M_AXI_BVALID(M_AXI_BVALID), 
        .M_AXI_BREADY(M_AXI_BREADY), 
        .M_AXI_ARID(M_AXI_ARID), 
        .M_AXI_ARADDR(M_AXI_ARADDR), 
        .M_AXI_ARLEN(M_AXI_ARLEN), 
        .M_AXI_ARSIZE(M_AXI_ARSIZE), 
        .M_AXI_ARBURST(M_AXI_ARBURST), 
        .M_AXI_ARLOCK(M_AXI_ARLOCK), 
        .M_AXI_ARCACHE(M_AXI_ARCACHE), 
        .M_AXI_ARPROT(M_AXI_ARPROT), 
        .M_AXI_ARQOS(M_AXI_ARQOS), 
        .M_AXI_ARUSER(M_AXI_ARUSER), 
        .M_AXI_ARVALID(M_AXI_ARVALID), 
        .M_AXI_ARREADY(M_AXI_ARREADY), 
        .M_AXI_RID(M_AXI_RID), 
        .M_AXI_RDATA(M_AXI_RDATA), 
        .M_AXI_RRESP(M_AXI_RRESP), 
        .M_AXI_RLAST(M_AXI_RLAST), 
        .M_AXI_RUSER(M_AXI_RUSER), 
        .M_AXI_RVALID(M_AXI_RVALID), 
        .M_AXI_RREADY(M_AXI_RREADY), 
        .wr_error(wr_error), 
        .rd_error(rd_error)
    );

    // clk_gen のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    
    clk_gen #(
        .CLK_PERIOD(250),    // 25nsec, 40MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) PIXCLKi (
        .clk_out(pixclk)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );

    // Instantiate the Unit Under Test (UUT_slave)
    CDC_axi_slave uut_slave (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .S_AXI_AWID(M_AXI_AWID), 
        .S_AXI_AWADDR(M_AXI_AWADDR), 
        .S_AXI_AWLEN(M_AXI_AWLEN), 
        .S_AXI_AWSIZE(M_AXI_AWSIZE), 
        .S_AXI_AWBURST(M_AXI_AWBURST), 
        .S_AXI_AWLOCK(2'b00), 
        .S_AXI_AWCACHE(M_AXI_AWCACHE), 
        .S_AXI_AWPROT(M_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(M_AXI_AWQOS), 
        .S_AXI_AWUSER(M_AXI_AWUSER), 
        .S_AXI_AWVALID(M_AXI_AWVALID), 
        .S_AXI_AWREADY(M_AXI_AWREADY), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(M_AXI_WDATA), 
        .S_AXI_WSTRB(M_AXI_WSTRB), 
        .S_AXI_WLAST(M_AXI_WLAST), 
        .S_AXI_WUSER(M_AXI_WUSER), 
        .S_AXI_WVALID(M_AXI_WVALID), 
        .S_AXI_WREADY(M_AXI_WREADY), 
        .S_AXI_BID(M_AXI_BID), 
        .S_AXI_BRESP(M_AXI_BRESP), 
        .S_AXI_BUSER(M_AXI_BUSER), 
        .S_AXI_BVALID(M_AXI_BVALID), 
        .S_AXI_BREADY(M_AXI_BREADY), 
        .S_AXI_ARID(M_AXI_ARID), 
        .S_AXI_ARADDR(M_AXI_ARADDR), 
        .S_AXI_ARLEN(M_AXI_ARLEN), 
        .S_AXI_ARSIZE(M_AXI_ARSIZE), 
        .S_AXI_ARBURST(M_AXI_ARBURST), 
        .S_AXI_ARLOCK(M_AXI_ARLOCK), 
        .S_AXI_ARCACHE(M_AXI_ARCACHE), 
        .S_AXI_ARPROT(M_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(M_AXI_ARQOS), 
        .S_AXI_ARUSER(M_AXI_ARUSER), 
        .S_AXI_ARVALID(M_AXI_ARVALID), 
        .S_AXI_ARREADY(M_AXI_ARREADY), 
        .S_AXI_RID(M_AXI_RID), 
        .S_AXI_RDATA(M_AXI_RDATA), 
        .S_AXI_RRESP(M_AXI_RRESP), 
        .S_AXI_RLAST(M_AXI_RLAST), 
        .S_AXI_RUSER(M_AXI_RUSER), 
        .S_AXI_RVALID(M_AXI_RVALID), 
        .S_AXI_RREADY(M_AXI_RREADY), 
        .pixclk(pixclk), 
        .TMDS_tx_clk_p(TMDS_tx_clk_p), 
        .TMDS_tx_clk_n(TMDS_tx_clk_n), 
        .TMDS_tx_2_G_p(TMDS_tx_2_G_p), 
        .TMDS_tx_2_G_n(TMDS_tx_2_G_n), 
        .TMDS_tx_1_R_p(TMDS_tx_1_R_p), 
        .TMDS_tx_1_R_n(TMDS_tx_1_R_n), 
        .TMDS_tx_0_B_p(TMDS_tx_0_B_p), 
        .TMDS_tx_0_B_n(TMDS_tx_0_B_n)
    );
      
endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


ISEのプロジェクトを作成した。下に階層図を示す。
cdctest_axi_master_1_120401.png

ISimでシミュレーションを行った。シミュレーション時間は51usec。Writeデータ転送の全体図を下に示す。
cdctest_axi_master_2_120401.png

M_AXI_WVALID の長さがデータ転送長を表している。いろいろな長さがあるのがわかると思う。M系列を使用した擬似乱数を使用している。間が開いているのは、Writeデータ転送の次に、同じ量のReadデータ転送を行なっているからだ。(WriteとReadはシーケンシャルにアクセスを行なっている)

次に、Readデータ転送の全体図を示す。
cdctest_axi_master_3_120401.png

こちらは、M_AXI_RVALID でReadデータ転送長がわかる。

Writeデータ転送の拡大図を下に示す。
cdctest_axi_master_4_120402.png

上のWriteデータ転送の拡大図に続くReadデータ転送を下に示す。Writeデータ転送の直後に同じアドレスで同じ転送長でReadすることによって直前に書き込んだWriteデータをReadすることができるかどうか?をテストする。テストして値が違っている場合はrd_error 出力を1にする。
cdctest_axi_master_5_120402.png

これで単体シミュレーションは終了したので、XPSでAXI4マスタIPを組み込んで実機で確認する。
  1. 2012年04月02日 04:38 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋の3月のアクセス数

現在、キャラクタ・ディスプレイ・コントローラ(CDC) AXI4バス・スレーブIPをテストするAXI4バス・マスタIPを作っています。VHDLが書き上がったので、テストベンチを作って、CDC AXIバス・スレーブIPと接続しているところです。

さて、FPGAの部屋の3月のアクセス数は、43,862アクセスでした。皆さん見て頂いて、ありがとうございます。
FPGAroom_3_120401.png

3月の検索キーワードを見てみます。まずは1位から20位までです。
FPGAroom_1_120401.png

CLOCK_DEDICATED_ROUTE が結構検索されている。Realtek PCIe GBE Family Controller は、”休止状態から復帰した後でネットにつながらなくなる2”が検索にヒットするようだ。私のパソコンはマザーボードのLANポートがダメなので、USBポートにLANアダプタをつけている。
DE0もやはり多いですね。DE0にOV7670を付けるプロジェクトも途中だが、やってみようかな?
DesignSparak PCBのアクセスも多かった。DesignSparak PCBでは、”プリント基板作成”も参照ください。
OV7670も検索キーワードに入っている。トラ技のおかげだろうか?

次に20位から40位まで。
FPGAroom_2_120401.png

QUCSもランクに入っている。OV9655も入っているね。そう言えば、OV9655はプロジェクトを公開していない。公開したほうが良いか?OV7670, OV9655 のステレオカメラボードも余っている。誰か必要な人はいないかな?でもターゲットが狭いんだよね。Spartan-3A Starter Kit用だからね。
DOXYGENもアクセスが多い。VHDLが基本だが、Verilogもマニュアル化出来るよ。自分でもあまりやってはいないんだけど。今度やってみよう。
  1. 2012年04月01日 07:19 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0